From 99c22b2ebdd8dec2c91af828518b2521b3cfe6be Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 28 Feb 2024 21:02:24 -0500 Subject: [PATCH] more tests and fixes --- .../src/funcApi/plainDateTime.test.ts | 32 +- .../src/funcApi/plainDateTime.ts | 2 +- .../src/funcApi/plainTime.test.ts | 293 ++++++++++++++++++ .../src/funcApi/plainTime.ts | 9 +- .../src/funcApi/zonedDateTime.test.ts | 48 ++- 5 files changed, 355 insertions(+), 29 deletions(-) create mode 100644 packages/temporal-polyfill/src/funcApi/plainTime.test.ts diff --git a/packages/temporal-polyfill/src/funcApi/plainDateTime.test.ts b/packages/temporal-polyfill/src/funcApi/plainDateTime.test.ts index fdb40c70..bed86713 100644 --- a/packages/temporal-polyfill/src/funcApi/plainDateTime.test.ts +++ b/packages/temporal-polyfill/src/funcApi/plainDateTime.test.ts @@ -144,7 +144,7 @@ describe('withPlainDate', () => { }) describe('withPlainTime', () => { - it('works', () => { + it('works with a time argument', () => { const pdt0 = PlainDateTimeFns.fromString('2024-01-01T12:30:00') const pt = PlainTimeFns.create(3) // 3:00 const pdt1 = PlainDateTimeFns.withPlainTime(pdt0, pt) @@ -155,6 +155,16 @@ describe('withPlainTime', () => { isoHour: 3, }) }) + + it('works without an argument', () => { + const pdt0 = PlainDateTimeFns.fromString('2024-01-01T12:30:00') + const pdt1 = PlainDateTimeFns.withPlainTime(pdt0) + expectPlainDateTimeEquals(pdt1, { + isoYear: 2024, + isoMonth: 1, + isoDay: 1, + }) + }) }) describe('withCalendar', () => { @@ -501,14 +511,11 @@ describe('toLocaleStringParts', () => { const parts = testHotCache(() => PlainDateTimeFns.toLocaleStringParts(pdt, locale, options), ) - expect( - // Hard to compare some weird whitespace characters - // Filter away whitespace-only parts - parts.filter((part) => part.value.trim()), - ).toEqual([ + expect(parts).toEqual([ { type: 'weekday', value: 'Sunday' }, { type: 'literal', value: ', ' }, { type: 'month', value: 'December' }, + { type: 'literal', value: ' ' }, { type: 'day', value: '31' }, { type: 'literal', value: ', ' }, { type: 'year', value: '2023' }, @@ -518,7 +525,9 @@ describe('toLocaleStringParts', () => { { type: 'minute', value: '30' }, { type: 'literal', value: ':' }, { type: 'second', value: '00' }, + { type: 'literal', value: ' ' }, { type: 'dayPeriod', value: 'PM' }, + { type: 'literal', value: ' ' }, { type: 'timeZoneName', value: 'Eastern Standard Time' }, ]) }) @@ -556,14 +565,11 @@ describe('rangeToLocaleStringParts', () => { const parts = testHotCache(() => PlainDateTimeFns.rangeToLocaleStringParts(pdt0, pdt1, locale, options), ) - expect( - // Hard to compare some weird whitespace characters - // Filter away whitespace-only parts - parts.filter((part) => part.value.trim()), - ).toEqual([ + expect(parts).toEqual([ { source: 'shared', type: 'weekday', value: 'Sunday' }, { source: 'shared', type: 'literal', value: ', ' }, { source: 'shared', type: 'month', value: 'December' }, + { source: 'shared', type: 'literal', value: ' ' }, { source: 'shared', type: 'day', value: '31' }, { source: 'shared', type: 'literal', value: ', ' }, { source: 'shared', type: 'year', value: '2023' }, @@ -573,7 +579,9 @@ describe('rangeToLocaleStringParts', () => { { source: 'startRange', type: 'minute', value: '30' }, { source: 'startRange', type: 'literal', value: ':' }, { source: 'startRange', type: 'second', value: '00' }, + { source: 'startRange', type: 'literal', value: ' ' }, { source: 'startRange', type: 'dayPeriod', value: 'PM' }, + { source: 'startRange', type: 'literal', value: ' ' }, { source: 'startRange', type: 'timeZoneName', value: 'EST' }, { source: 'shared', type: 'literal', value: ' – ' }, { source: 'endRange', type: 'hour', value: '2' }, @@ -581,7 +589,9 @@ describe('rangeToLocaleStringParts', () => { { source: 'endRange', type: 'minute', value: '59' }, { source: 'endRange', type: 'literal', value: ':' }, { source: 'endRange', type: 'second', value: '00' }, + { source: 'endRange', type: 'literal', value: ' ' }, { source: 'endRange', type: 'dayPeriod', value: 'PM' }, + { source: 'endRange', type: 'literal', value: ' ' }, { source: 'endRange', type: 'timeZoneName', value: 'EST' }, ]) }) diff --git a/packages/temporal-polyfill/src/funcApi/plainDateTime.ts b/packages/temporal-polyfill/src/funcApi/plainDateTime.ts index db3e48aa..90b38bde 100644 --- a/packages/temporal-polyfill/src/funcApi/plainDateTime.ts +++ b/packages/temporal-polyfill/src/funcApi/plainDateTime.ts @@ -140,7 +140,7 @@ export const withPlainDate = plainDateTimeWithPlainDate as ( export const withPlainTime = plainDateTimeWithPlainTime as ( plainDateTimeSlots: PlainDateTimeSlots, - plainTimeSlots: PlainTimeSlots, + plainTimeSlots?: PlainTimeSlots, ) => PlainDateTimeSlots export function withCalendar( diff --git a/packages/temporal-polyfill/src/funcApi/plainTime.test.ts b/packages/temporal-polyfill/src/funcApi/plainTime.test.ts new file mode 100644 index 00000000..f0b77b1b --- /dev/null +++ b/packages/temporal-polyfill/src/funcApi/plainTime.test.ts @@ -0,0 +1,293 @@ +import { describe, expect, it } from 'vitest' +import * as DurationFns from './duration' +import * as PlainDateFns from './plainDate' +import * as PlainTimeFns from './plainTime' +import { + expectDurationEquals, + expectPlainDateTimeEquals, + expectPlainTimeEquals, + expectZonedDateTimeEquals, + testHotCache, +} from './testUtils' + +describe('create', () => { + it('works', () => { + const pt = PlainTimeFns.create(12, 30) + expectPlainTimeEquals(pt, { + isoHour: 12, + isoMinute: 30, + }) + }) +}) + +describe('fromString', () => { + it('works', () => { + const pt = PlainTimeFns.fromString('12:30') + expectPlainTimeEquals(pt, { + isoHour: 12, + isoMinute: 30, + }) + }) +}) + +describe('fromFields', () => { + it('works without options', () => { + const pt = PlainTimeFns.fromFields({ + hour: 12, + }) + expectPlainTimeEquals(pt, { + isoHour: 12, + }) + }) +}) + +describe('getFields', () => { + it('works', () => { + const pt = PlainTimeFns.create(12, 30) + const fields = PlainTimeFns.getFields(pt) + expect(fields).toEqual({ + hour: 12, + minute: 30, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + }) + }) +}) + +describe('withFields', () => { + it('works', () => { + const pt0 = PlainTimeFns.create(12, 30) + const pt1 = PlainTimeFns.withFields(pt0, { + minute: 45, + second: 1, + }) + expectPlainTimeEquals(pt1, { + isoHour: 12, + isoMinute: 45, + isoSecond: 1, + }) + }) +}) + +describe('add', () => { + it('works', () => { + const pt0 = PlainTimeFns.create(12, 30) + const d = DurationFns.create(0, 0, 0, 0, 14, 15) // +14:15 + const pt1 = PlainTimeFns.add(pt0, d) + expectPlainTimeEquals(pt1, { + isoHour: 2, + isoMinute: 45, + }) + }) +}) + +describe('subtract', () => { + it('works', () => { + const pt0 = PlainTimeFns.create(12, 30) + const d = DurationFns.create(0, 0, 0, 0, 14, 15) // +14:15 + const pt1 = PlainTimeFns.subtract(pt0, d) + expectPlainTimeEquals(pt1, { + isoHour: 22, + isoMinute: 15, + }) + }) +}) + +describe('until', () => { + it('works', () => { + const pt0 = PlainTimeFns.create(12, 30) + const pt1 = PlainTimeFns.create(22, 45) + const d = PlainTimeFns.until(pt0, pt1) + expectDurationEquals(d, { + hours: 10, + minutes: 15, + }) + }) +}) + +describe('since', () => { + it('works', () => { + const pt0 = PlainTimeFns.create(12, 30) + const pt1 = PlainTimeFns.create(22, 45) + const d = PlainTimeFns.since(pt0, pt1) + expectDurationEquals(d, { + hours: -10, + minutes: -15, + }) + }) +}) + +describe('round', () => { + it('works with single unit arg', () => { + const pt0 = PlainTimeFns.create(12, 30) + const pt1 = PlainTimeFns.round(pt0, 'hour') + expectPlainTimeEquals(pt1, { + isoHour: 13, + }) + }) + + it('works with options arg', () => { + const pt0 = PlainTimeFns.create(12, 30) + const pt1 = PlainTimeFns.round(pt0, { smallestUnit: 'hour' }) + expectPlainTimeEquals(pt1, { + isoHour: 13, + }) + }) +}) + +describe('equals', () => { + it('works', () => { + const pt0 = PlainTimeFns.create(12, 30) + const pt1 = PlainTimeFns.create(22, 45) + expect(PlainTimeFns.equals(pt0, pt1)).toBe(false) + expect(PlainTimeFns.equals(pt0, pt0)).toBe(true) + }) +}) + +describe('compare', () => { + it('works', () => { + const pt0 = PlainTimeFns.create(12, 30) + const pt1 = PlainTimeFns.create(22, 45) + expect(PlainTimeFns.compare(pt0, pt1)).toBe(-1) + expect(PlainTimeFns.compare(pt1, pt0)).toBe(1) + expect(PlainTimeFns.compare(pt0, pt0)).toBe(0) + }) +}) + +describe('toPlainDateTime', () => { + it('works', () => { + const pt = PlainTimeFns.create(12, 30) + const pd = PlainDateFns.create(2024, 6, 3) + const pdt = PlainTimeFns.toPlainDateTime(pt, pd) + expectPlainDateTimeEquals(pdt, { + isoYear: 2024, + isoMonth: 6, + isoDay: 3, + isoHour: 12, + isoMinute: 30, + }) + }) +}) + +describe('toZonedDateTime', () => { + it('works', () => { + const pt = PlainTimeFns.create(12, 30) + const pd = PlainDateFns.create(2024, 6, 3) + const zdt = PlainTimeFns.toZonedDateTime(pt, { + timeZone: 'America/New_York', + plainDate: pd, + }) + expectZonedDateTimeEquals(zdt, { + timeZone: 'America/New_York', + epochNanoseconds: 1717432200000000000n, + }) + }) +}) + +describe('toString', () => { + it('works without options', () => { + const pt = PlainTimeFns.create(12, 30) + const s = PlainTimeFns.toString(pt) + expect(s).toBe('12:30:00') + }) + + it('works with options', () => { + const pt = PlainTimeFns.create(12, 30) + const s = PlainTimeFns.toString(pt, { + fractionalSecondDigits: 2, + }) + expect(s).toBe('12:30:00.00') + }) +}) + +describe('toLocaleString', () => { + it('works', () => { + const pt = PlainTimeFns.create(12, 30) + const locale = 'en' + const options: Intl.DateTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + } + const s = testHotCache(() => + PlainTimeFns.toLocaleString(pt, locale, options), + ) + expect(s).toBe('12:30:00 PM') + }) +}) + +describe('toLocaleStringParts', () => { + it('works', () => { + const pt = PlainTimeFns.create(12, 30) + const locale = 'en' + const options: Intl.DateTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + } + const parts = testHotCache(() => + PlainTimeFns.toLocaleStringParts(pt, locale, options), + ) + expect(parts).toEqual([ + { type: 'hour', value: '12' }, + { type: 'literal', value: ':' }, + { type: 'minute', value: '30' }, + { type: 'literal', value: ':' }, + { type: 'second', value: '00' }, + { type: 'literal', value: ' ' }, + { type: 'dayPeriod', value: 'PM' }, + ]) + }) +}) + +describe('rangeToLocaleString', () => { + it('works', () => { + const pt0 = PlainTimeFns.create(12, 30) + const pt1 = PlainTimeFns.create(14, 45) + const locale = 'en' + const options: Intl.DateTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + } + const s = testHotCache(() => + PlainTimeFns.rangeToLocaleString(pt0, pt1, locale, options), + ) + expect(s).toBe('12:30:00 PM – 2:45:00 PM') + }) +}) + +describe('rangeToLocaleStringParts', () => { + it('works', () => { + const pt0 = PlainTimeFns.create(12, 30) + const pt1 = PlainTimeFns.create(14, 45) + const locale = 'en' + const options: Intl.DateTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + } + const parts = testHotCache(() => + PlainTimeFns.rangeToLocaleStringParts(pt0, pt1, locale, options), + ) + expect(parts).toEqual([ + { source: 'startRange', type: 'hour', value: '12' }, + { source: 'startRange', type: 'literal', value: ':' }, + { source: 'startRange', type: 'minute', value: '30' }, + { source: 'startRange', type: 'literal', value: ':' }, + { source: 'startRange', type: 'second', value: '00' }, + { source: 'startRange', type: 'literal', value: ' ' }, + { source: 'startRange', type: 'dayPeriod', value: 'PM' }, + { source: 'shared', type: 'literal', value: ' – ' }, + { source: 'endRange', type: 'hour', value: '2' }, + { source: 'endRange', type: 'literal', value: ':' }, + { source: 'endRange', type: 'minute', value: '45' }, + { source: 'endRange', type: 'literal', value: ':' }, + { source: 'endRange', type: 'second', value: '00' }, + { source: 'endRange', type: 'literal', value: ' ' }, + { source: 'endRange', type: 'dayPeriod', value: 'PM' }, + ]) + }) +}) diff --git a/packages/temporal-polyfill/src/funcApi/plainTime.ts b/packages/temporal-polyfill/src/funcApi/plainTime.ts index 9f02b137..2567686f 100644 --- a/packages/temporal-polyfill/src/funcApi/plainTime.ts +++ b/packages/temporal-polyfill/src/funcApi/plainTime.ts @@ -28,10 +28,10 @@ export type { PlainTimeSlots, TimeBag } export const create = constructPlainTimeSlots -export const fromFields = refinePlainTimeBag - export const fromString = parsePlainTime +export const fromFields = refinePlainTimeBag + export const getFields = memoize(isoTimeFieldsToCal, WeakMap) as ( slots: PlainTimeSlots, ) => TimeFields @@ -51,13 +51,14 @@ export const until = bindArgs(diffPlainTimes, false) export const since = bindArgs(diffPlainTimes, true) export const round = roundPlainTime + export const equals = plainTimesEqual export const compare = compareIsoTimeFields as ( slots0: PlainTimeSlots, slots1: PlainTimeSlots, ) => NumberSign -export const toString = formatPlainTimeIso +export const toPlainDateTime = plainTimeToPlainDateTime export const toZonedDateTime = bindArgs( plainTimeToZonedDateTime>, @@ -66,7 +67,7 @@ export const toZonedDateTime = bindArgs( queryNativeTimeZone, ) -export const toPlainDateTime = plainTimeToPlainDateTime +export const toString = formatPlainTimeIso export function toLocaleString( slots: PlainTimeSlots, diff --git a/packages/temporal-polyfill/src/funcApi/zonedDateTime.test.ts b/packages/temporal-polyfill/src/funcApi/zonedDateTime.test.ts index 86fc8d3c..5e82c08f 100644 --- a/packages/temporal-polyfill/src/funcApi/zonedDateTime.test.ts +++ b/packages/temporal-polyfill/src/funcApi/zonedDateTime.test.ts @@ -238,7 +238,7 @@ describe('withPlainDate', () => { }) describe('withPlainTime', () => { - it('works', () => { + it('works with a time argument', () => { const zdt0 = ZonedDateTimeFns.create( 1709055000000000000n, 'America/New_York', @@ -262,9 +262,31 @@ describe('withPlainTime', () => { offset: '-05:00', }) }) -}) -// --- + it('works with a time argument', () => { + const zdt0 = ZonedDateTimeFns.create( + 1709055000000000000n, + 'America/New_York', + ) + const zdt1 = ZonedDateTimeFns.withPlainTime(zdt0) + const combinedFields = ZonedDateTimeFns.getFields(zdt1) + expect(combinedFields).toEqual({ + era: undefined, + eraYear: undefined, + year: 2024, + monthCode: 'M02', + month: 2, + day: 27, + hour: 0, + minute: 0, + second: 0, + microsecond: 0, + millisecond: 0, + nanosecond: 0, + offset: '-05:00', + }) + }) +}) describe('dayOfWeek', () => { it('works', () => { @@ -687,14 +709,11 @@ describe('toLocaleStringParts', () => { const parts = testHotCache(() => ZonedDateTimeFns.toLocaleStringParts(zdt, locale, options), ) - expect( - // Hard to compare some weird whitespace characters - // Filter away whitespace-only parts - parts.filter((part) => part.value.trim()), - ).toEqual([ + expect(parts).toEqual([ { type: 'weekday', value: 'Sunday' }, { type: 'literal', value: ', ' }, { type: 'month', value: 'December' }, + { type: 'literal', value: ' ' }, { type: 'day', value: '31' }, { type: 'literal', value: ', ' }, { type: 'year', value: '2023' }, @@ -704,7 +723,9 @@ describe('toLocaleStringParts', () => { { type: 'minute', value: '30' }, { type: 'literal', value: ':' }, { type: 'second', value: '00' }, + { type: 'literal', value: ' ' }, { type: 'dayPeriod', value: 'PM' }, + { type: 'literal', value: ' ' }, { type: 'timeZoneName', value: 'Eastern Standard Time' }, ]) }) @@ -768,14 +789,11 @@ describe('rangeToLocaleStringParts', () => { const parts = testHotCache(() => ZonedDateTimeFns.rangeToLocaleStringParts(zdt0, zdt1, locale, options), ) - expect( - // Hard to compare some weird whitespace characters - // Filter away whitespace-only parts - parts.filter((part) => part.value.trim()), - ).toEqual([ + expect(parts).toEqual([ { source: 'shared', type: 'weekday', value: 'Sunday' }, { source: 'shared', type: 'literal', value: ', ' }, { source: 'shared', type: 'month', value: 'December' }, + { source: 'shared', type: 'literal', value: ' ' }, { source: 'shared', type: 'day', value: '31' }, { source: 'shared', type: 'literal', value: ', ' }, { source: 'shared', type: 'year', value: '2023' }, @@ -785,7 +803,9 @@ describe('rangeToLocaleStringParts', () => { { source: 'startRange', type: 'minute', value: '30' }, { source: 'startRange', type: 'literal', value: ':' }, { source: 'startRange', type: 'second', value: '00' }, + { source: 'startRange', type: 'literal', value: ' ' }, { source: 'startRange', type: 'dayPeriod', value: 'PM' }, + { source: 'startRange', type: 'literal', value: ' ' }, { source: 'startRange', type: 'timeZoneName', value: 'EST' }, { source: 'shared', type: 'literal', value: ' – ' }, { source: 'endRange', type: 'hour', value: '2' }, @@ -793,7 +813,9 @@ describe('rangeToLocaleStringParts', () => { { source: 'endRange', type: 'minute', value: '59' }, { source: 'endRange', type: 'literal', value: ':' }, { source: 'endRange', type: 'second', value: '00' }, + { source: 'endRange', type: 'literal', value: ' ' }, { source: 'endRange', type: 'dayPeriod', value: 'PM' }, + { source: 'endRange', type: 'literal', value: ' ' }, { source: 'endRange', type: 'timeZoneName', value: 'EST' }, ]) })