angular-cn/packages/common/test/i18n/format_date_spec.ts

451 lines
15 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import localeAr from '@angular/common/locales/ar';
import localeDe from '@angular/common/locales/de';
import localeEn from '@angular/common/locales/en';
import localeEnExtra from '@angular/common/locales/extra/en';
import localeFi from '@angular/common/locales/fi';
import localeHu from '@angular/common/locales/hu';
import localeSr from '@angular/common/locales/sr';
import localeTh from '@angular/common/locales/th';
import {formatDate, isDate, toDate} from '@angular/common/src/i18n/format_date';
import {ɵDEFAULT_LOCALE_ID, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
describe('Format date', () => {
describe('toDate', () => {
it('should support date', () => {
expect(isDate(toDate(new Date()))).toBeTruthy();
});
it('should support int', () => {
expect(isDate(toDate(123456789))).toBeTruthy();
});
it('should support numeric strings', () => {
expect(isDate(toDate('123456789'))).toBeTruthy();
});
it('should support decimal strings', () => {
expect(isDate(toDate('123456789.11'))).toBeTruthy();
});
it('should support ISO string', () => {
expect(isDate(toDate('2015-06-15T21:43:11Z'))).toBeTruthy();
});
it('should throw for empty string', () => {
expect(() => toDate('')).toThrow();
});
it('should throw for alpha numeric strings', () => {
expect(() => toDate('123456789 hello')).toThrow();
});
it('should throw for NaN', () => {
expect(() => toDate(Number.NaN)).toThrow();
});
it('should support ISO string without time', () => {
expect(isDate(toDate('2015-01-01'))).toBeTruthy();
});
it('should throw for objects', () => {
expect(() => toDate({} as any)).toThrow();
});
});
describe('formatDate', () => {
const isoStringWithoutTime = '2015-01-01';
const isoStringWithoutTimeOrDate = '2015-01';
const isoStringWithoutTimeOrDateOrMonth = '2015';
const defaultFormat = 'mediumDate';
let date: Date;
// Check the transformation of a date into a pattern
function expectDateFormatAs(date: Date|string, pattern: any, output: string): void {
expect(formatDate(date, pattern, ɵDEFAULT_LOCALE_ID))
.toEqual(output, `pattern: "${pattern}"`);
}
beforeAll(() => {
ɵregisterLocaleData(localeEn, localeEnExtra);
ɵregisterLocaleData(localeDe);
ɵregisterLocaleData(localeHu);
ɵregisterLocaleData(localeSr);
ɵregisterLocaleData(localeTh);
ɵregisterLocaleData(localeAr);
ɵregisterLocaleData(localeFi);
});
afterAll(() => ɵunregisterLocaleData());
beforeEach(() => {
date = new Date(2015, 5, 15, 9, 3, 1, 550);
});
it('should format each component correctly', () => {
const dateFixtures: any = {
G: 'AD',
GG: 'AD',
GGG: 'AD',
GGGG: 'Anno Domini',
GGGGG: 'A',
y: '2015',
yy: '15',
yyy: '2015',
yyyy: '2015',
Y: '2015',
YY: '15',
YYY: '2015',
YYYY: '2015',
M: '6',
MM: '06',
MMM: 'Jun',
MMMM: 'June',
MMMMM: 'J',
L: '6',
LL: '06',
LLL: 'Jun',
LLLL: 'June',
LLLLL: 'J',
w: '25',
ww: '25',
W: '3',
d: '15',
dd: '15',
c: '1',
cc: '1',
ccc: 'Mon',
cccc: 'Monday',
ccccc: 'M',
cccccc: 'Mo',
E: 'Mon',
EE: 'Mon',
EEE: 'Mon',
EEEE: 'Monday',
EEEEEE: 'Mo',
h: '9',
hh: '09',
H: '9',
HH: '09',
m: '3',
mm: '03',
s: '1',
ss: '01',
S: '5',
SS: '55',
SSS: '550',
a: 'AM',
aa: 'AM',
aaa: 'AM',
aaaa: 'AM',
aaaaa: 'a',
b: 'morning',
bb: 'morning',
bbb: 'morning',
bbbb: 'morning',
bbbbb: 'morning',
B: 'in the morning',
BB: 'in the morning',
BBB: 'in the morning',
BBBB: 'in the morning',
BBBBB: 'in the morning',
};
const isoStringWithoutTimeFixtures: any = {
G: 'AD',
GG: 'AD',
GGG: 'AD',
GGGG: 'Anno Domini',
GGGGG: 'A',
y: '2015',
yy: '15',
yyy: '2015',
yyyy: '2015',
Y: '2015',
YY: '15',
YYY: '2015',
YYYY: '2015',
M: '1',
MM: '01',
MMM: 'Jan',
MMMM: 'January',
MMMMM: 'J',
L: '1',
LL: '01',
LLL: 'Jan',
LLLL: 'January',
LLLLL: 'J',
w: '1',
ww: '01',
W: '1',
d: '1',
dd: '01',
c: '4',
cc: '4',
ccc: 'Thu',
cccc: 'Thursday',
ccccc: 'T',
cccccc: 'Th',
E: 'Thu',
EE: 'Thu',
EEE: 'Thu',
EEEE: 'Thursday',
EEEEE: 'T',
EEEEEE: 'Th',
h: '12',
hh: '12',
H: '0',
HH: '00',
m: '0',
mm: '00',
s: '0',
ss: '00',
S: '0',
SS: '00',
SSS: '000',
a: 'AM',
aa: 'AM',
aaa: 'AM',
aaaa: 'AM',
aaaaa: 'a',
b: 'midnight',
bb: 'midnight',
bbb: 'midnight',
bbbb: 'midnight',
bbbbb: 'midnight',
B: 'midnight',
BB: 'midnight',
BBB: 'midnight',
BBBB: 'midnight',
BBBBB: 'mi',
};
const midnightCrossingPeriods: any = {
b: 'night',
bb: 'night',
bbb: 'night',
bbbb: 'night',
bbbbb: 'night',
B: 'at night',
BB: 'at night',
BBB: 'at night',
BBBB: 'at night',
BBBBB: 'at night',
};
Object.keys(dateFixtures).forEach((pattern: string) => {
expectDateFormatAs(date, pattern, dateFixtures[pattern]);
});
Object.keys(isoStringWithoutTimeFixtures).forEach((pattern: string) => {
expectDateFormatAs(isoStringWithoutTime, pattern, isoStringWithoutTimeFixtures[pattern]);
});
Object.keys(isoStringWithoutTimeFixtures).forEach((pattern: string) => {
expectDateFormatAs(
isoStringWithoutTimeOrDate, pattern, isoStringWithoutTimeFixtures[pattern]);
});
Object.keys(isoStringWithoutTimeFixtures).forEach((pattern: string) => {
expectDateFormatAs(
isoStringWithoutTimeOrDateOrMonth, pattern, isoStringWithoutTimeFixtures[pattern]);
});
const nightTime = new Date(2015, 5, 15, 2, 3, 1, 550);
Object.keys(midnightCrossingPeriods).forEach(pattern => {
expectDateFormatAs(nightTime, pattern, midnightCrossingPeriods[pattern]);
});
});
it('should format with timezones', () => {
const dateFixtures: any = {
z: /GMT(\+|-)\d/,
zz: /GMT(\+|-)\d/,
zzz: /GMT(\+|-)\d/,
zzzz: /GMT(\+|-)\d{2}\:30/,
Z: /(\+|-)\d{2}30/,
ZZ: /(\+|-)\d{2}30/,
ZZZ: /(\+|-)\d{2}30/,
ZZZZ: /GMT(\+|-)\d{2}\:30/,
ZZZZZ: /(\+|-)\d{2}\:30/,
O: /GMT(\+|-)\d/,
OOOO: /GMT(\+|-)\d{2}\:30/,
};
Object.keys(dateFixtures).forEach((pattern: string) => {
expect(formatDate(date, pattern, ɵDEFAULT_LOCALE_ID, '+0430'))
.toMatch(dateFixtures[pattern]);
});
});
it('should format common multi component patterns', () => {
const dateFixtures: any = {
'EEE, M/d/y': 'Mon, 6/15/2015',
'EEE, M/d': 'Mon, 6/15',
'MMM d': 'Jun 15',
'dd/MM/yyyy': '15/06/2015',
'MM/dd/yyyy': '06/15/2015',
'yMEEEd': '20156Mon15',
'MEEEd': '6Mon15',
'MMMd': 'Jun15',
'EEEE, MMMM d, y': 'Monday, June 15, 2015',
'H:mm a': '9:03 AM',
'ms': '31',
'MM/dd/yy hh:mm': '06/15/15 09:03',
'MM/dd/y': '06/15/2015'
};
Object.keys(dateFixtures).forEach((pattern: string) => {
expectDateFormatAs(date, pattern, dateFixtures[pattern]);
});
});
it('should format with pattern aliases', () => {
const dateFixtures: any = {
'MM/dd/yyyy': '06/15/2015',
shortDate: '6/15/15',
mediumDate: 'Jun 15, 2015',
longDate: 'June 15, 2015',
fullDate: 'Monday, June 15, 2015',
short: '6/15/15, 9:03 AM',
medium: 'Jun 15, 2015, 9:03:01 AM',
long: /June 15, 2015 at 9:03:01 AM GMT(\+|-)\d/,
full: /Monday, June 15, 2015 at 9:03:01 AM GMT(\+|-)\d{2}:\d{2}/,
shortTime: '9:03 AM',
mediumTime: '9:03:01 AM',
longTime: /9:03:01 AM GMT(\+|-)\d/,
fullTime: /9:03:01 AM GMT(\+|-)\d{2}:\d{2}/,
};
Object.keys(dateFixtures).forEach((pattern: string) => {
expect(formatDate(date, pattern, ɵDEFAULT_LOCALE_ID)).toMatch(dateFixtures[pattern]);
});
});
it('should format invalid in IE ISO date',
() => expect(formatDate('2017-01-11T12:00:00.014-0500', defaultFormat, ɵDEFAULT_LOCALE_ID))
.toEqual('Jan 11, 2017'));
it('should format invalid in Safari ISO date',
() => expect(formatDate('2017-01-20T12:00:00+0000', defaultFormat, ɵDEFAULT_LOCALE_ID))
.toEqual('Jan 20, 2017'));
// https://github.com/angular/angular/issues/9524
// https://github.com/angular/angular/issues/9524
it('should format correctly with iso strings that contain time',
() => expect(formatDate('2017-05-07T22:14:39', 'dd-MM-yyyy HH:mm', ɵDEFAULT_LOCALE_ID))
.toMatch(/07-05-2017 \d{2}:\d{2}/));
// https://github.com/angular/angular/issues/21491
it('should not assume UTC for iso strings in Safari if the timezone is not defined', () => {
// this test only works if the timezone is not in UTC
// which is the case for BrowserStack when we test Safari
if (new Date().getTimezoneOffset() !== 0) {
expect(formatDate('2018-01-11T13:00:00', 'HH', ɵDEFAULT_LOCALE_ID))
.not.toEqual(formatDate('2018-01-11T13:00:00Z', 'HH', ɵDEFAULT_LOCALE_ID));
}
});
// https://github.com/angular/angular/issues/16624
// https://github.com/angular/angular/issues/17478
it('should show the correct time when the timezone is fixed', () => {
expect(formatDate('2017-06-13T10:14:39+0000', 'shortTime', ɵDEFAULT_LOCALE_ID, '+0000'))
.toEqual('10:14 AM');
expect(formatDate('2017-06-13T10:14:39+0000', 'h:mm a', ɵDEFAULT_LOCALE_ID, '+0000'))
.toEqual('10:14 AM');
});
// The following test is disabled because backwards compatibility requires that date-only ISO
// strings are parsed with the local timezone.
// it('should create UTC date objects when an ISO string is passed with no time components',
// () => {
// expect(formatDate('2019-09-20', `MMM d, y, h:mm:ss a ZZZZZ`, ɵDEFAULT_LOCALE_ID))
// .toEqual('Sep 20, 2019, 12:00:00 AM Z');
// });
// This test is to ensure backward compatibility for parsing date-only ISO strings.
it('should create local timezone date objects when an ISO string is passed with no time components',
() => {
// Dates created with individual components are evaluated against the local timezone. See
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#Individual_date_and_time_component_values
const localDate = new Date(2019, 8, 20, 0, 0, 0, 0);
expect(formatDate('2019-09-20', `MMM d, y, h:mm:ss a ZZZZZ`, ɵDEFAULT_LOCALE_ID))
.toEqual(formatDate(localDate, `MMM d, y, h:mm:ss a ZZZZZ`, ɵDEFAULT_LOCALE_ID));
});
it('should create local timezone date objects when an ISO string is passed with time components',
() => {
const localDate = new Date(2019, 8, 20, 0, 0, 0, 0);
expect(formatDate('2019-09-20T00:00:00', `MMM d, y, h:mm:ss a ZZZZZ`, ɵDEFAULT_LOCALE_ID))
.toEqual(formatDate(localDate, `MMM d, y, h:mm:ss a ZZZZZ`, ɵDEFAULT_LOCALE_ID));
});
it('should remove bidi control characters',
() => expect(formatDate(date, 'MM/dd/yyyy', ɵDEFAULT_LOCALE_ID)!.length).toEqual(10));
it(`should format the date correctly in various locales`, () => {
expect(formatDate(date, 'short', 'de')).toEqual('15.06.15, 09:03');
expect(formatDate(date, 'short', 'ar')).toEqual('15/6/2015 9:03 ص');
expect(formatDate(date, 'dd-MM-yy', 'th')).toEqual('15-06-15');
expect(formatDate(date, 'a', 'hu')).toEqual('de.');
expect(formatDate(date, 'a', 'sr')).toEqual('пре подне');
// TODO(ocombe): activate this test when we support local numbers
// expect(formatDate(date, 'hh', 'mr')).toEqual('०९');
});
it('should throw if we use getExtraDayPeriods without loading extra locale data', () => {
expect(() => formatDate(date, 'b', 'de'))
.toThrowError(/Missing extra locale data for the locale "de"/);
});
// https://github.com/angular/angular/issues/24384
it('should not round fractional seconds', () => {
expect(formatDate(3999, 'm:ss', 'en')).toEqual('0:03');
expect(formatDate(3999, 'm:ss.S', 'en')).toEqual('0:03.9');
expect(formatDate(3999, 'm:ss.SS', 'en')).toEqual('0:03.99');
expect(formatDate(3999, 'm:ss.SSS', 'en')).toEqual('0:03.999');
expect(formatDate(3000, 'm:ss', 'en')).toEqual('0:03');
expect(formatDate(3000, 'm:ss.S', 'en')).toEqual('0:03.0');
expect(formatDate(3000, 'm:ss.SS', 'en')).toEqual('0:03.00');
expect(formatDate(3000, 'm:ss.SSS', 'en')).toEqual('0:03.000');
expect(formatDate(3001, 'm:ss', 'en')).toEqual('0:03');
expect(formatDate(3001, 'm:ss.S', 'en')).toEqual('0:03.0');
expect(formatDate(3001, 'm:ss.SS', 'en')).toEqual('0:03.00');
expect(formatDate(3001, 'm:ss.SSS', 'en')).toEqual('0:03.001');
});
// https://github.com/angular/angular/issues/38739
it('should return correct ISO 8601 week-numbering year for dates close to year end/beginning',
() => {
expect(formatDate('2013-12-27', 'YYYY', 'en')).toEqual('2013');
expect(formatDate('2013-12-29', 'YYYY', 'en')).toEqual('2014');
expect(formatDate('2010-01-02', 'YYYY', 'en')).toEqual('2009');
expect(formatDate('2010-01-04', 'YYYY', 'en')).toEqual('2010');
expect(formatDate('0049-01-01', 'YYYY', 'en')).toEqual('0048');
expect(formatDate('0049-01-04', 'YYYY', 'en')).toEqual('0049');
});
// https://github.com/angular/angular/issues/40377
it('should format date with year between 0 and 99 correctly', () => {
expect(formatDate('0098-01-11', 'YYYY', ɵDEFAULT_LOCALE_ID)).toEqual('0098');
expect(formatDate('0099-01-11', 'YYYY', ɵDEFAULT_LOCALE_ID)).toEqual('0099');
expect(formatDate('0100-01-11', 'YYYY', ɵDEFAULT_LOCALE_ID)).toEqual('0100');
expect(formatDate('0001-01-11', 'YYYY', ɵDEFAULT_LOCALE_ID)).toEqual('0001');
expect(formatDate('0000-01-11', 'YYYY', ɵDEFAULT_LOCALE_ID)).toEqual('0000');
});
// https://github.com/angular/angular/issues/26922
it('should support fullDate in finnish, which uses standalone week day', () => {
expect(formatDate(date, 'fullDate', 'fi')).toMatch('maanantai 15. kesäkuuta 2015');
});
});
});