In Chrome, when used locale ‘en-GB’ in Intl.DateTimeFormat for 12:00, it formats to 00:00 PM. The proper format should be 12:00 PM. Date-utils will use ‘en-GB’ only as a workaround for format ‘HH’ (24 hour), because Chrome 80 formats 00:05 as 24:05 in ‘en-US’. Change-Id: I6539315a6a798d580934b46937e050f48b1cf1c9
		
			
				
	
	
		
			178 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * @license
 | 
						|
 * Copyright (C) 2020 The Android Open Source Project
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
const Duration = {
 | 
						|
  HOUR: 1000 * 60 * 60,
 | 
						|
  DAY: 1000 * 60 * 60 * 24,
 | 
						|
};
 | 
						|
 | 
						|
export function parseDate(dateStr) {
 | 
						|
  // Timestamps are given in UTC and have the format
 | 
						|
  // "'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" represents
 | 
						|
  // nanoseconds.
 | 
						|
  // Munge the date into an ISO 8061 format and parse that.
 | 
						|
  return new Date(dateStr.replace(' ', 'T') + 'Z');
 | 
						|
}
 | 
						|
 | 
						|
export function isValidDate(date) {
 | 
						|
  return date instanceof Date && !isNaN(date);
 | 
						|
}
 | 
						|
 | 
						|
// similar to fromNow from moment.js
 | 
						|
export function fromNow(date) {
 | 
						|
  const now = new Date();
 | 
						|
  const secondsAgo = Math.round((now - date) / 1000);
 | 
						|
  if (secondsAgo <= 44) return 'just now';
 | 
						|
  if (secondsAgo <= 89) return 'a minute ago';
 | 
						|
  const minutesAgo = Math.round(secondsAgo / 60);
 | 
						|
  if (minutesAgo <= 44) return `${minutesAgo} minutes ago`;
 | 
						|
  if (minutesAgo <= 89) return 'an hour ago';
 | 
						|
  const hoursAgo = Math.round(minutesAgo / 60);
 | 
						|
  if (hoursAgo <= 21) return `${hoursAgo} hours ago`;
 | 
						|
  if (hoursAgo <= 35) return 'a day ago';
 | 
						|
  const daysAgo = Math.round(hoursAgo / 24);
 | 
						|
  if (daysAgo <= 25) return `${daysAgo} days ago`;
 | 
						|
  if (daysAgo <= 45) return `a month ago`;
 | 
						|
  const monthsAgo = Math.round(daysAgo / 30);
 | 
						|
  if (daysAgo <= 319) return `${monthsAgo} months ago`;
 | 
						|
  if (daysAgo <= 547) return `a year ago`;
 | 
						|
  const yearsAgo = Math.round(daysAgo / 365);
 | 
						|
  return `${yearsAgo} years ago`;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Return true if date is within 24 hours and on the same day.
 | 
						|
 */
 | 
						|
export function isWithinDay(now, date) {
 | 
						|
  const diff = now - date;
 | 
						|
  return diff < Duration.DAY && date.getDay() == now.getDay();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns true if date is from one to six months.
 | 
						|
 */
 | 
						|
export function isWithinHalfYear(now, date) {
 | 
						|
  const diff = now - date;
 | 
						|
  return diff < 180 * Duration.DAY;
 | 
						|
}
 | 
						|
 | 
						|
export function formatDate(date, format) {
 | 
						|
  const options = {};
 | 
						|
  if (format.includes('MM')) {
 | 
						|
    if (format.includes('MMM')) {
 | 
						|
      options.month = 'short';
 | 
						|
    } else {
 | 
						|
      options.month = '2-digit';
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (format.includes('YY')) {
 | 
						|
    if (format.includes('YYYY')) {
 | 
						|
      options.year = 'numeric';
 | 
						|
    } else {
 | 
						|
      options.year = '2-digit';
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('DD')) {
 | 
						|
    options.day = '2-digit';
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('HH')) {
 | 
						|
    options.hour = '2-digit';
 | 
						|
    options.hour12 = false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('h')) {
 | 
						|
    options.hour = 'numeric';
 | 
						|
    options.hour12 = true;
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('mm')) {
 | 
						|
    options.minute = '2-digit';
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('ss')) {
 | 
						|
    options.second = '2-digit';
 | 
						|
  }
 | 
						|
  let locale = 'en-US';
 | 
						|
  // Workaround for Chrome 80, en-US is using h24 (midnight is 24:00),
 | 
						|
  // en-GB is using h23 (midnight is 00:00)
 | 
						|
  if (format.includes('HH')) {
 | 
						|
    locale = 'en-GB';
 | 
						|
  }
 | 
						|
 | 
						|
  const dtf = new Intl.DateTimeFormat(locale, options);
 | 
						|
  const parts = dtf.formatToParts(date).filter(o => o.type != 'literal')
 | 
						|
      .reduce((acc, o) => {
 | 
						|
        acc[o.type] = o.value;
 | 
						|
        return acc;
 | 
						|
      }, {});
 | 
						|
  if (format.includes('YY')) {
 | 
						|
    if (format.includes('YYYY')) {
 | 
						|
      format = format.replace('YYYY', parts.year);
 | 
						|
    } else {
 | 
						|
      format = format.replace('YY', parts.year);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('DD')) {
 | 
						|
    format = format.replace('DD', parts.day);
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('HH')) {
 | 
						|
    format = format.replace('HH', parts.hour);
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('h')) {
 | 
						|
    format = format.replace('h', parts.hour);
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('mm')) {
 | 
						|
    format = format.replace('mm', parts.minute);
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('ss')) {
 | 
						|
    format = format.replace('ss', parts.second);
 | 
						|
  }
 | 
						|
 | 
						|
  if (format.includes('A')) {
 | 
						|
    if (parts.dayperiod) {
 | 
						|
      // Workaround for chrome 70 and below
 | 
						|
      format = format.replace('A', parts.dayperiod.toUpperCase());
 | 
						|
    } else {
 | 
						|
      format = format.replace('A', parts.dayPeriod.toUpperCase());
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (format.includes('MM')) {
 | 
						|
    if (format.includes('MMM')) {
 | 
						|
      format = format.replace('MMM', parts.month);
 | 
						|
    } else {
 | 
						|
      format = format.replace('MM', parts.month);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return format;
 | 
						|
}
 | 
						|
 | 
						|
export function utcOffsetString() {
 | 
						|
  const now = new Date();
 | 
						|
  const tzo = -now.getTimezoneOffset();
 | 
						|
  const pad = num => {
 | 
						|
    const norm = Math.floor(Math.abs(num));
 | 
						|
    return (norm < 10 ? '0' : '') + norm;
 | 
						|
  };
 | 
						|
  return ` UTC${tzo >= 0 ? '+' : '-'}${pad(tzo / 60)}:${pad(tzo%60)}`;
 | 
						|
} |