diff --git a/lib/core/src/lib/common/utils/date-fns-utils.spec.ts b/lib/core/src/lib/common/utils/date-fns-utils.spec.ts index 0c3e1a99825..55497589a08 100644 --- a/lib/core/src/lib/common/utils/date-fns-utils.spec.ts +++ b/lib/core/src/lib/common/utils/date-fns-utils.spec.ts @@ -41,7 +41,6 @@ describe('DateFnsUtils', () => { }); }); - it('should format a date correctly', () => { const date = new Date('2023-09-22T12:00:00Z'); const dateFormat = 'yyyy-MM-dd'; @@ -53,27 +52,18 @@ describe('DateFnsUtils', () => { }); it('should parse datetime', () => { - const parsed = DateFnsUtils.parseDate( - '09-02-9999 09:10 AM', - 'dd-MM-yyyy hh:mm aa' - ); + const parsed = DateFnsUtils.parseDate('09-02-9999 09:10 AM', 'dd-MM-yyyy hh:mm aa'); expect(isValid(parsed)); expect(parsed.toISOString()).toBe('9999-02-09T09:10:00.000Z'); }); it('should format datetime with custom moment format', () => { - const parsed = DateFnsUtils.formatDate( - new Date('9999-12-30T10:30:00.000Z'), - 'MM-DD-YYYY HH:mm A' - ); + const parsed = DateFnsUtils.formatDate(new Date('9999-12-30T10:30:00.000Z'), 'MM-DD-YYYY HH:mm A'); expect(parsed).toBe('12-30-9999 10:30 AM'); }); it('should parse moment datetime ISO', () => { - const parsed = DateFnsUtils.parseDate( - '1982-03-13T10:00:00Z', - 'YYYY-MM-DDTHH:mm:ssZ' - ); + const parsed = DateFnsUtils.parseDate('1982-03-13T10:00:00Z', 'YYYY-MM-DDTHH:mm:ssZ'); expect(parsed.toISOString()).toBe('1982-03-13T10:00:00.000Z'); }); @@ -87,27 +77,18 @@ describe('DateFnsUtils', () => { }); it('should parse alternative ISO datetime', () => { - const result = DateFnsUtils.parseDate( - '1982-03-13T10:00:000Z', - `yyyy-MM-dd'T'HH:mm:sssXXX` - ); + const result = DateFnsUtils.parseDate('1982-03-13T10:00:000Z', `yyyy-MM-dd'T'HH:mm:sssXXX`); expect(result.toISOString()).toBe('1982-03-13T10:00:00.000Z'); }); it('should parse the datetime with zone', () => { - const result = DateFnsUtils.parseDate( - '1982-03-13T10:00:000+01:00', - `yyyy-MM-dd'T'HH:mm:sssXXX` - ); + const result = DateFnsUtils.parseDate('1982-03-13T10:00:000+01:00', `yyyy-MM-dd'T'HH:mm:sssXXX`); expect(result.toISOString()).toBe('1982-03-13T09:00:00.000Z'); }); it('should parse datetime with zone in moment format', () => { - const result = DateFnsUtils.parseDate( - '1982-03-13T10:00:00+0100', - `YYYY-MM-DDTHH:mm:ssZZ` - ); + const result = DateFnsUtils.parseDate('1982-03-13T10:00:00+0100', `YYYY-MM-DDTHH:mm:ssZZ`); expect(result.toISOString()).toBe('1982-03-13T09:00:00.000Z'); }); @@ -132,4 +113,29 @@ describe('DateFnsUtils', () => { expect(resultLocal).toBeInstanceOf(Date); expect(resultUtc).toBeInstanceOf(Date); }); + + it('should force local and UTC dates to display the same day, month and year in different timezones', () => { + const dateEngland = new Date('Wed Jan 01 2020 00:00:00 GMT+0000'); + const dateUSA = new Date('Tue Dec 31 2019 16:00:00 GMT-0800'); + const dateJapan = new Date('Wed Jan 01 2020 09:00:00 GMT+0900'); + const forceUtcDateEngland = DateFnsUtils.forceUtc(dateEngland); + const forceUtcDateUSA = DateFnsUtils.forceUtc(dateUSA); + const forceUtcDateJapan = DateFnsUtils.forceUtc(dateJapan); + + expect(forceUtcDateEngland).toEqual(forceUtcDateUSA); + expect(forceUtcDateUSA).toEqual(forceUtcDateJapan); + expect(forceUtcDateJapan.getDate()).toBe(1); + expect(forceUtcDateJapan.getMonth()).toBe(0); + expect(forceUtcDateJapan.getFullYear()).toBe(2020); + + const forceLocalDateEngland = DateFnsUtils.forceLocal(forceUtcDateEngland); + const forceLocalDateUSA = DateFnsUtils.forceLocal(forceUtcDateUSA); + const forceLocalDateJapan = DateFnsUtils.forceLocal(forceUtcDateJapan); + + expect(forceLocalDateEngland).toEqual(forceLocalDateUSA); + expect(forceLocalDateUSA).toEqual(forceLocalDateJapan); + expect(forceLocalDateJapan.getDate()).toBe(1); + expect(forceLocalDateJapan.getMonth()).toBe(0); + expect(forceLocalDateJapan.getFullYear()).toBe(2020); + }); }); diff --git a/lib/core/src/lib/common/utils/date-fns-utils.ts b/lib/core/src/lib/common/utils/date-fns-utils.ts index 4f317583be7..5423c392a16 100644 --- a/lib/core/src/lib/common/utils/date-fns-utils.ts +++ b/lib/core/src/lib/common/utils/date-fns-utils.ts @@ -15,9 +15,16 @@ * limitations under the License. */ -import { format, parse, parseISO, isValid, isBefore, isAfter, lightFormat } from 'date-fns'; +import { format, parse, parseISO, isValid, isBefore, isAfter } from 'date-fns'; import { ar, cs, da, de, enUS, es, fi, fr, it, ja, nb, nl, pl, ptBR, ru, sv, zhCN } from 'date-fns/locale'; +const panDate = (num: number = 1): string => { + let text = num.toString(); + while (text.length < 2) { + text = '0' + text; + } + return text; +}; export class DateFnsUtils { static getLocaleFromString(locale: string): Locale { @@ -203,18 +210,19 @@ export class DateFnsUtils { return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()); } - static forceLocal(date: string | Date): Date { - if (typeof date === 'string'){ + static forceLocal(date: Date | string): Date { + if (typeof date === 'string') { date = parseISO(date); } - return new Date(lightFormat(date, 'yyyy-MM-dd')); + const localDate = `${date.getUTCFullYear()}-${panDate(date.getUTCMonth() + 1)}-${panDate(date.getUTCDate())}T00:00:00.000`; + return new Date(localDate); } - static forceUtc(date: string | Date): Date { - if (typeof date === 'string'){ + static forceUtc(date: Date | string): Date { + if (typeof date === 'string') { date = parseISO(date); } - return new Date(lightFormat(date, 'yyyy-MM-dd').concat('T00:00:00.000Z')); + const utcDate = `${date.getFullYear()}-${panDate(date.getMonth() + 1)}-${panDate(date.getDate())}T00:00:00.000Z`; + return new Date(utcDate); } - }