From 16b7de64f73ffe76231d37bb9656152717cd19d3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sat, 17 Feb 2024 22:17:15 -0500 Subject: [PATCH] more fn-api tests --- .../src/funcApi/duration.test.ts | 8 +- .../temporal-polyfill/src/funcApi/duration.ts | 1 + .../temporal-polyfill/src/funcApi/instant.ts | 1 + .../temporal-polyfill/src/funcApi/now.test.ts | 235 ++++++++++++++++++ packages/temporal-polyfill/src/funcApi/now.ts | 4 +- .../src/funcApi/plainDate.ts | 3 + .../src/funcApi/plainDateTime.ts | 3 + .../src/funcApi/plainTime.ts | 3 + .../src/funcApi/zonedDateTime.ts | 25 +- 9 files changed, 280 insertions(+), 3 deletions(-) create mode 100644 packages/temporal-polyfill/src/funcApi/now.test.ts diff --git a/packages/temporal-polyfill/src/funcApi/duration.test.ts b/packages/temporal-polyfill/src/funcApi/duration.test.ts index d1382586..dda07d95 100644 --- a/packages/temporal-polyfill/src/funcApi/duration.test.ts +++ b/packages/temporal-polyfill/src/funcApi/duration.test.ts @@ -44,7 +44,13 @@ describe('fromFields', () => { }) }) -// TODO: withFields +describe('withFields', () => { + it('modifies fields and returns a new object', () => { + const d0 = DurationFns.fromFields({ years: 1, months: 1 }) + const d1 = DurationFns.withFields(d0, { months: 2 }) + expectDurationEquals(d1, { years: 1, months: 2 }) + }) +}) describe('blank', () => { it('gives true for blank duration', () => { diff --git a/packages/temporal-polyfill/src/funcApi/duration.ts b/packages/temporal-polyfill/src/funcApi/duration.ts index d6e74ced..53e9735c 100644 --- a/packages/temporal-polyfill/src/funcApi/duration.ts +++ b/packages/temporal-polyfill/src/funcApi/duration.ts @@ -24,6 +24,7 @@ import { queryNativeTimeZone } from '../internal/timeZoneNative' import { totalDuration } from '../internal/total' import { NumberSign, bindArgs, identity } from '../internal/utils' +// TODO: rename to keep scope? Slots/Fields/Bag? export type { DurationSlots, DurationBag } export type RelativeToArg = diff --git a/packages/temporal-polyfill/src/funcApi/instant.ts b/packages/temporal-polyfill/src/funcApi/instant.ts index 36858fc9..ae89fdef 100644 --- a/packages/temporal-polyfill/src/funcApi/instant.ts +++ b/packages/temporal-polyfill/src/funcApi/instant.ts @@ -27,6 +27,7 @@ import { bindArgs } from '../internal/utils' import { prepCachedInstantFormat } from './intlFormatCache' import { refineCalendarIdString, refineTimeZoneIdString } from './utils' +// TODO: rename to keep scope? Slots? export type { InstantSlots } export const create = constructInstantSlots diff --git a/packages/temporal-polyfill/src/funcApi/now.test.ts b/packages/temporal-polyfill/src/funcApi/now.test.ts new file mode 100644 index 00000000..ee9a7a54 --- /dev/null +++ b/packages/temporal-polyfill/src/funcApi/now.test.ts @@ -0,0 +1,235 @@ +import { describe, expect, it } from 'vitest' +import { dayTimeNanoToBigInt } from '../internal/dayTimeNano' +import { isoToEpochNano } from '../internal/timeMath' +import * as InstantFns from './instant' +import * as NowFns from './now' +import * as PlainDateFns from './plainDate' +import * as PlainDateTimeFns from './plainDateTime' +import * as PlainTimeFns from './plainTime' +import * as ZonedDateTimeFns from './zonedDateTime' + +describe('timeZoneId', () => { + it('returns the system time zone', () => { + expect(NowFns.timeZoneId()).toBe(systemTimeZoneId) + }) +}) + +describe('instant', () => { + it('returns now', () => { + const inst0 = NowFns.instant() + const inst1 = getCurrentInstant() + expectInstantsSimilar(inst0, inst1) + }) +}) + +describe('zonedDateTime', () => { + it('returns now, assuming system time zone', () => { + const zdt0 = NowFns.zonedDateTime('hebrew') + const zdt1 = getCurrentZonedDateTime('hebrew', systemTimeZoneId) + expectZonedDateTimesSimilar(zdt0, zdt1) + }) + + it('returns now with a given time zone', () => { + const zdt0 = NowFns.zonedDateTime('hebrew', 'America/Chicago') + const zdt1 = getCurrentZonedDateTime('hebrew', 'America/Chicago') + expectZonedDateTimesSimilar(zdt0, zdt1) + }) +}) + +describe('zonedDateTimeISO', () => { + it('returns now, assuming system time zone', () => { + const zdt0 = NowFns.zonedDateTimeISO() + const zdt1 = getCurrentZonedDateTime('iso8601', systemTimeZoneId) + expectZonedDateTimesSimilar(zdt0, zdt1) + }) + + it('returns now with a given time zone', () => { + const zdt0 = NowFns.zonedDateTimeISO('America/Chicago') + const zdt1 = getCurrentZonedDateTime('iso8601', 'America/Chicago') + expectZonedDateTimesSimilar(zdt0, zdt1) + }) +}) + +describe('plainDateTime', () => { + it('returns current date, assuming system time zone', () => { + const pdt0 = NowFns.plainDateTime('hebrew') + const pdt1 = ZonedDateTimeFns.toPlainDateTime( + getCurrentZonedDateTime('hebrew', systemTimeZoneId), + ) + expectPlainDateTimesSimilar(pdt0, pdt1) + }) + + it('returns current date with a given time zone', () => { + const pdt0 = NowFns.plainDateTime('hebrew', 'America/Chicago') + const pdt1 = ZonedDateTimeFns.toPlainDateTime( + getCurrentZonedDateTime('hebrew', 'America/Chicago'), + ) + expectPlainDateTimesSimilar(pdt0, pdt1) + }) +}) + +describe('plainDateTimeISO', () => { + it('returns current date, assuming system time zone', () => { + const pdt0 = NowFns.plainDateTimeISO() + const pdt1 = ZonedDateTimeFns.toPlainDateTime( + getCurrentZonedDateTime('iso8601', systemTimeZoneId), + ) + expectPlainDateTimesSimilar(pdt0, pdt1) + }) + + it('returns current date with a given time zone', () => { + const pdt0 = NowFns.plainDateTimeISO('America/Chicago') + const pdt1 = ZonedDateTimeFns.toPlainDateTime( + getCurrentZonedDateTime('iso8601', 'America/Chicago'), + ) + expectPlainDateTimesSimilar(pdt0, pdt1) + }) +}) + +describe('plainDate', () => { + it('returns current date, assuming system time zone', () => { + const pd0 = NowFns.plainDate('hebrew') + const pd1 = ZonedDateTimeFns.toPlainDate( + getCurrentZonedDateTime('hebrew', systemTimeZoneId), + ) + expectPlainDatesSimilar(pd0, pd1) + }) + + it('returns current date with a given time zone', () => { + const pd0 = NowFns.plainDate('hebrew', 'America/Chicago') + const pd1 = ZonedDateTimeFns.toPlainDate( + getCurrentZonedDateTime('hebrew', 'America/Chicago'), + ) + expectPlainDatesSimilar(pd0, pd1) + }) +}) + +describe('plainDateISO', () => { + it('returns current date, assuming system time zone', () => { + const pd0 = NowFns.plainDateISO() + const pd1 = ZonedDateTimeFns.toPlainDate( + getCurrentZonedDateTime('iso8601', systemTimeZoneId), + ) + expectPlainDatesSimilar(pd0, pd1) + }) + + it('returns current date with a given time zone', () => { + const pd0 = NowFns.plainDateISO('America/Chicago') + const pd1 = ZonedDateTimeFns.toPlainDate( + getCurrentZonedDateTime('iso8601', 'America/Chicago'), + ) + expectPlainDatesSimilar(pd0, pd1) + }) +}) + +describe('plainTimeISO', () => { + it('returns current time, assuming system time zone', () => { + const pt0 = NowFns.plainTimeISO() + const pt1 = ZonedDateTimeFns.toPlainTime( + getCurrentZonedDateTime('iso8601', systemTimeZoneId), + ) + expectPlainTimesSimilar(pt0, pt1) + }) + + it('returns current time with a given time zone', () => { + const pt0 = NowFns.plainTimeISO('America/Chicago') + const pt1 = ZonedDateTimeFns.toPlainTime( + getCurrentZonedDateTime('iso8601', 'America/Chicago'), + ) + expectPlainTimesSimilar(pt0, pt1) + }) +}) + +// Utils +// ----------------------------------------------------------------------------- + +const systemResolvedOptions = new Intl.DateTimeFormat().resolvedOptions() +const systemTimeZoneId = systemResolvedOptions.timeZone + +function getCurrentInstant() { + return InstantFns.fromEpochMilliseconds(Date.now()) +} + +function getCurrentZonedDateTime( + calendar: string, + timeZone: string, +): ZonedDateTimeFns.ZonedDateTimeSlots { + return InstantFns.toZonedDateTime(getCurrentInstant(), { timeZone, calendar }) +} + +function expectEpochNanosSimilar( + epochNano0: bigint, + epochNano1: bigint, +): boolean { + return Math.abs(Number(epochNano0 - epochNano1)) < 1000 +} + +function expectInstantsSimilar( + inst0: InstantFns.InstantSlots, + inst1: InstantFns.InstantSlots, +): void { + expect(inst0.branding).toBe('Instant') + expect(inst1.branding).toBe('Instant') + expectEpochNanosSimilar( + InstantFns.epochNanoseconds(inst0), + InstantFns.epochNanoseconds(inst1), + ) +} + +function expectZonedDateTimesSimilar( + zdt0: ZonedDateTimeFns.ZonedDateTimeSlots, + zdt1: ZonedDateTimeFns.ZonedDateTimeSlots, +): void { + expect(zdt0.branding).toBe('ZonedDateTime') + expect(zdt1.branding).toBe('ZonedDateTime') + expect(zdt0.calendar).toBe(zdt1.calendar) + expect(zdt0.timeZone).toBe(zdt1.timeZone) + expectEpochNanosSimilar( + ZonedDateTimeFns.epochNanoseconds(zdt0), + ZonedDateTimeFns.epochNanoseconds(zdt1), + ) +} + +function expectPlainDateTimesSimilar( + pdt0: PlainDateTimeFns.PlainDateTimeSlots, + pdt1: PlainDateTimeFns.PlainDateTimeSlots, +): void { + expect(pdt0.branding).toBe('PlainDateTime') + expect(pdt1.branding).toBe('PlainDateTime') + expect(pdt0.calendar).toBe(pdt1.calendar) + expectEpochNanosSimilar( + dayTimeNanoToBigInt(isoToEpochNano(pdt0)!), + dayTimeNanoToBigInt(isoToEpochNano(pdt1)!), + ) +} + +function expectPlainDatesSimilar( + pd0: PlainDateFns.PlainDateSlots, + pd1: PlainDateFns.PlainDateSlots, +): void { + expect(pd0.branding).toBe('PlainDate') + expect(pd1.branding).toBe('PlainDate') + expect(pd0.calendar).toBe(pd1.calendar) + expectEpochNanosSimilar( + dayTimeNanoToBigInt(isoToEpochNano(pd0)!), + dayTimeNanoToBigInt(isoToEpochNano(pd1)!), + ) +} + +function expectPlainTimesSimilar( + pt0: PlainTimeFns.PlainTimeSlots, + pt1: PlainTimeFns.PlainTimeSlots, +): void { + expect(pt0.branding).toBe('PlainTime') + expect(pt1.branding).toBe('PlainTime') + expectEpochNanosSimilar( + dayTimeNanoToBigInt(isoToEpochNano({ ...isoDateDefaults, ...pt0 })!), + dayTimeNanoToBigInt(isoToEpochNano({ ...isoDateDefaults, ...pt1 })!), + ) +} + +const isoDateDefaults = { + isoYear: 0, + isoMonth: 0, + isoDay: 0, +} diff --git a/packages/temporal-polyfill/src/funcApi/now.ts b/packages/temporal-polyfill/src/funcApi/now.ts index b4f46c4a..2370aa65 100644 --- a/packages/temporal-polyfill/src/funcApi/now.ts +++ b/packages/temporal-polyfill/src/funcApi/now.ts @@ -92,7 +92,9 @@ export function plainDateISO( ) } -export function plainTimeISO(timeZoneId: string): PlainTimeSlots { +export function plainTimeISO( + timeZoneId: string = getCurrentTimeZoneId(), +): PlainTimeSlots { return createPlainTimeSlots( getCurrentIsoDateTime( queryNativeTimeZone(refineTimeZoneIdString(timeZoneId)), diff --git a/packages/temporal-polyfill/src/funcApi/plainDate.ts b/packages/temporal-polyfill/src/funcApi/plainDate.ts index 55f05805..545b1861 100644 --- a/packages/temporal-polyfill/src/funcApi/plainDate.ts +++ b/packages/temporal-polyfill/src/funcApi/plainDate.ts @@ -57,6 +57,9 @@ import { // OR do it on the PlainDateSlots? // TODO: name all args properly like 'plainDateSlots'??? +// TODO: rename to keep scope? Slots/Fields/Bag? +export type { PlainDateSlots, DateBag } + export const create = bindArgs( constructPlainDateSlots, refineCalendarIdString, diff --git a/packages/temporal-polyfill/src/funcApi/plainDateTime.ts b/packages/temporal-polyfill/src/funcApi/plainDateTime.ts index ec73f297..add31d1e 100644 --- a/packages/temporal-polyfill/src/funcApi/plainDateTime.ts +++ b/packages/temporal-polyfill/src/funcApi/plainDateTime.ts @@ -64,6 +64,9 @@ import { refineCalendarIdString, } from './utils' +// TODO: rename to keep scope? Slots/Fields/Bag? +export type { PlainDateTimeSlots, DateTimeBag } + export const create = bindArgs( constructPlainDateTimeSlots, refineCalendarIdString, diff --git a/packages/temporal-polyfill/src/funcApi/plainTime.ts b/packages/temporal-polyfill/src/funcApi/plainTime.ts index 181100fa..f32c6b27 100644 --- a/packages/temporal-polyfill/src/funcApi/plainTime.ts +++ b/packages/temporal-polyfill/src/funcApi/plainTime.ts @@ -23,6 +23,9 @@ import { NumberSign, bindArgs, identity } from '../internal/utils' import { prepCachedPlainTimeFormat } from './intlFormatCache' import { refineTimeZoneIdString } from './utils' +// TODO: rename to keep scope? Slots/Fields/Bag? +export type { PlainTimeSlots, TimeBag } + export const create = constructPlainTimeSlots export const fromFields = refinePlainTimeBag diff --git a/packages/temporal-polyfill/src/funcApi/zonedDateTime.ts b/packages/temporal-polyfill/src/funcApi/zonedDateTime.ts index 07228d47..a1fa4c00 100644 --- a/packages/temporal-polyfill/src/funcApi/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/funcApi/zonedDateTime.ts @@ -41,7 +41,14 @@ import { import { moveZonedDateTime } from '../internal/move' import { ZonedFieldOptions } from '../internal/optionsRefine' import { roundZonedDateTime } from '../internal/round' -import { DateSlots, ZonedDateTimeSlots } from '../internal/slots' +import { + DateSlots, + ZonedDateTimeSlots, + getEpochMicroseconds, + getEpochMilliseconds, + getEpochNanoseconds, + getEpochSeconds, +} from '../internal/slots' import { queryNativeTimeZone } from '../internal/timeZoneNative' import { ZonedDateTimeFields, @@ -64,6 +71,9 @@ import { refineTimeZoneIdString, } from './utils' +// TODO: rename to keep scope? Slots/Fields/Bag? +export type { ZonedDateTimeSlots, ZonedDateTimeBag, DateTimeBag } + export const create = bindArgs( constructZonedDateTimeSlots, refineCalendarIdString, @@ -87,6 +97,19 @@ export function fromFields( ) } +export const epochSeconds = getEpochSeconds as ( + slots: ZonedDateTimeSlots, +) => number +export const epochMilliseconds = getEpochMilliseconds as ( + slots: ZonedDateTimeSlots, +) => number +export const epochMicroseconds = getEpochMicroseconds as ( + slots: ZonedDateTimeSlots, +) => bigint +export const epochNanoseconds = getEpochNanoseconds as ( + slots: ZonedDateTimeSlots, +) => bigint + export const getISOFields = bindArgs( buildZonedIsoFields, queryNativeTimeZone,