Temporal: Look up getOffsetNanosecondsFor only once when resolving ambiguous datetime

This commit is contained in:
Philip Chimento 2023-09-06 11:57:56 -07:00 committed by Philip Chimento
parent 9b8d9cf66c
commit 3a57a424e0
21 changed files with 1811 additions and 7 deletions

View File

@ -0,0 +1,94 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.compare
description: >
Correct time zone calls are made when converting a ZonedDateTime-like
relativeTo property bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const duration1 = new Temporal.Duration(0, 0, 0, 1);
const duration2 = new Temporal.Duration(0, 0, 0, 2);
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const dstTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar = TemporalHelpers.calendarObserver(actual, "calendar");
let relativeTo = { year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: dstTimeZoneObserver, calendar };
Temporal.Duration.compare(duration1, duration2, {relativeTo: relativeTo});
const expected = [
// GetTemporalCalendarSlotValueWithISODefault
"has calendar.dateAdd",
"has calendar.dateFromFields",
"has calendar.dateUntil",
"has calendar.day",
"has calendar.dayOfWeek",
"has calendar.dayOfYear",
"has calendar.daysInMonth",
"has calendar.daysInWeek",
"has calendar.daysInYear",
"has calendar.fields",
"has calendar.id",
"has calendar.inLeapYear",
"has calendar.mergeFields",
"has calendar.month",
"has calendar.monthCode",
"has calendar.monthDayFromFields",
"has calendar.monthsInYear",
"has calendar.weekOfYear",
"has calendar.year",
"has calendar.yearMonthFromFields",
"has calendar.yearOfWeek",
// CalendarFields
"get calendar.fields",
"call calendar.fields",
// InterpretTemporalDateTimeFields
"get calendar.dateFromFields",
"call calendar.dateFromFields",
// ToTemporalTimeZoneSlotValue
"has timeZone.getOffsetNanosecondsFor",
"has timeZone.getPossibleInstantsFor",
"has timeZone.id",
];
const expectedSpringForward = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedSpringForward.length), // ignore operations after ToRelativeTemporalObject
expectedSpringForward,
"order of operations converting property bag at skipped wall-clock time"
);
actual.splice(0); // clear
relativeTo = { year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: dstTimeZoneObserver, calendar };
Temporal.Duration.compare(duration1, duration2, {relativeTo: relativeTo});
const expectedFallBack = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedFallBack.length), // ignore operations after ToRelativeTemporalObject
expectedFallBack,
"order of operations converting property bag at repeated wall-clock time"
);
actual.splice(0); // clear

View File

@ -0,0 +1,93 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.add
description: >
Correct time zone calls are made when converting a ZonedDateTime-like
relativeTo property bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const dstTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar = TemporalHelpers.calendarObserver(actual, "calendar");
const instance = new Temporal.Duration(1, 0, 0, 1);
let relativeTo = { year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.add(new Temporal.Duration(0, 0, 0, 0, -24), { relativeTo });
const expected = [
// GetTemporalCalendarSlotValueWithISODefault
"has calendar.dateAdd",
"has calendar.dateFromFields",
"has calendar.dateUntil",
"has calendar.day",
"has calendar.dayOfWeek",
"has calendar.dayOfYear",
"has calendar.daysInMonth",
"has calendar.daysInWeek",
"has calendar.daysInYear",
"has calendar.fields",
"has calendar.id",
"has calendar.inLeapYear",
"has calendar.mergeFields",
"has calendar.month",
"has calendar.monthCode",
"has calendar.monthDayFromFields",
"has calendar.monthsInYear",
"has calendar.weekOfYear",
"has calendar.year",
"has calendar.yearMonthFromFields",
"has calendar.yearOfWeek",
// CalendarFields
"get calendar.fields",
"call calendar.fields",
// InterpretTemporalDateTimeFields
"get calendar.dateFromFields",
"call calendar.dateFromFields",
// ToTemporalTimeZoneSlotValue
"has timeZone.getOffsetNanosecondsFor",
"has timeZone.getPossibleInstantsFor",
"has timeZone.id",
];
const expectedSpringForward = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedSpringForward.length), // ignore operations after ToRelativeTemporalObject
expectedSpringForward,
"order of operations converting property bag at skipped wall-clock time"
);
actual.splice(0); // clear
relativeTo = { year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.add(new Temporal.Duration(0, 0, 0, 0, -24), { relativeTo });
const expectedFallBack = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedFallBack.length), // ignore operations after ToRelativeTemporalObject
expectedFallBack,
"order of operations converting property bag at repeated wall-clock time"
);
actual.splice(0); // clear

View File

@ -0,0 +1,93 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.round
description: >
Correct time zone calls are made when converting a ZonedDateTime-like
relativeTo property bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const dstTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar = TemporalHelpers.calendarObserver(actual, "calendar");
const instance = new Temporal.Duration(1, 0, 0, 0, 24);
let relativeTo = { year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.round({ largestUnit: "years", relativeTo });
const expected = [
// GetTemporalCalendarSlotValueWithISODefault
"has calendar.dateAdd",
"has calendar.dateFromFields",
"has calendar.dateUntil",
"has calendar.day",
"has calendar.dayOfWeek",
"has calendar.dayOfYear",
"has calendar.daysInMonth",
"has calendar.daysInWeek",
"has calendar.daysInYear",
"has calendar.fields",
"has calendar.id",
"has calendar.inLeapYear",
"has calendar.mergeFields",
"has calendar.month",
"has calendar.monthCode",
"has calendar.monthDayFromFields",
"has calendar.monthsInYear",
"has calendar.weekOfYear",
"has calendar.year",
"has calendar.yearMonthFromFields",
"has calendar.yearOfWeek",
// CalendarFields
"get calendar.fields",
"call calendar.fields",
// InterpretTemporalDateTimeFields
"get calendar.dateFromFields",
"call calendar.dateFromFields",
// ToTemporalTimeZoneSlotValue
"has timeZone.getOffsetNanosecondsFor",
"has timeZone.getPossibleInstantsFor",
"has timeZone.id",
];
const expectedSpringForward = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedSpringForward.length), // ignore operations after ToRelativeTemporalObject
expectedSpringForward,
"order of operations converting property bag at skipped wall-clock time"
);
actual.splice(0); // clear
relativeTo = { year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.round({ largestUnit: "years", relativeTo });
const expectedFallBack = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedFallBack.length), // ignore operations after ToRelativeTemporalObject
expectedFallBack,
"order of operations converting property bag at repeated wall-clock time"
);
actual.splice(0); // clear

View File

@ -0,0 +1,93 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.subtract
description: >
Correct time zone calls are made when converting a ZonedDateTime-like
relativeTo property bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const dstTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar = TemporalHelpers.calendarObserver(actual, "calendar");
const instance = new Temporal.Duration(1, 0, 0, 1);
let relativeTo = { year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.subtract(new Temporal.Duration(0, 0, 0, 0, 24), { relativeTo });
const expected = [
// GetTemporalCalendarSlotValueWithISODefault
"has calendar.dateAdd",
"has calendar.dateFromFields",
"has calendar.dateUntil",
"has calendar.day",
"has calendar.dayOfWeek",
"has calendar.dayOfYear",
"has calendar.daysInMonth",
"has calendar.daysInWeek",
"has calendar.daysInYear",
"has calendar.fields",
"has calendar.id",
"has calendar.inLeapYear",
"has calendar.mergeFields",
"has calendar.month",
"has calendar.monthCode",
"has calendar.monthDayFromFields",
"has calendar.monthsInYear",
"has calendar.weekOfYear",
"has calendar.year",
"has calendar.yearMonthFromFields",
"has calendar.yearOfWeek",
// CalendarFields
"get calendar.fields",
"call calendar.fields",
// InterpretTemporalDateTimeFields
"get calendar.dateFromFields",
"call calendar.dateFromFields",
// ToTemporalTimeZoneSlotValue
"has timeZone.getOffsetNanosecondsFor",
"has timeZone.getPossibleInstantsFor",
"has timeZone.id",
];
const expectedSpringForward = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedSpringForward.length), // ignore operations after ToRelativeTemporalObject
expectedSpringForward,
"order of operations converting property bag at skipped wall-clock time"
);
actual.splice(0); // clear
relativeTo = { year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.subtract(new Temporal.Duration(0, 0, 0, 0, 24), { relativeTo });
const expectedFallBack = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedFallBack.length), // ignore operations after ToRelativeTemporalObject
expectedFallBack,
"order of operations converting property bag at repeated wall-clock time"
);
actual.splice(0); // clear

View File

@ -0,0 +1,93 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.total
description: >
Correct time zone calls are made when converting a ZonedDateTime-like
relativeTo property bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const dstTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar = TemporalHelpers.calendarObserver(actual, "calendar");
const instance = new Temporal.Duration(1, 0, 0, 0, 24);
let relativeTo = { year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.total({ unit: "days", relativeTo });
const expected = [
// GetTemporalCalendarSlotValueWithISODefault
"has calendar.dateAdd",
"has calendar.dateFromFields",
"has calendar.dateUntil",
"has calendar.day",
"has calendar.dayOfWeek",
"has calendar.dayOfYear",
"has calendar.daysInMonth",
"has calendar.daysInWeek",
"has calendar.daysInYear",
"has calendar.fields",
"has calendar.id",
"has calendar.inLeapYear",
"has calendar.mergeFields",
"has calendar.month",
"has calendar.monthCode",
"has calendar.monthDayFromFields",
"has calendar.monthsInYear",
"has calendar.weekOfYear",
"has calendar.year",
"has calendar.yearMonthFromFields",
"has calendar.yearOfWeek",
// CalendarFields
"get calendar.fields",
"call calendar.fields",
// InterpretTemporalDateTimeFields
"get calendar.dateFromFields",
"call calendar.dateFromFields",
// ToTemporalTimeZoneSlotValue
"has timeZone.getOffsetNanosecondsFor",
"has timeZone.getPossibleInstantsFor",
"has timeZone.id",
];
const expectedSpringForward = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedSpringForward.length), // ignore operations after ToRelativeTemporalObject
expectedSpringForward,
"order of operations converting property bag at skipped wall-clock time"
);
actual.splice(0); // clear
relativeTo = { year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.total({ unit: "days", relativeTo });
const expectedFallBack = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedFallBack.length), // ignore operations after ToRelativeTemporalObject
expectedFallBack,
"order of operations converting property bag at repeated wall-clock time"
);
actual.splice(0); // clear

View File

@ -0,0 +1,95 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.plaindate.prototype.tozoneddatetime
description: User code calls happen in the correct order
includes: [compareArray.js, temporalHelpers.js]
features: [Temporal]
---*/
const actual = [];
const expected = [
"get item.timeZone",
"has item.timeZone.getOffsetNanosecondsFor",
"has item.timeZone.getPossibleInstantsFor",
"has item.timeZone.id",
"get item.plainTime",
// ToTemporalTime
"get item.plainTime.hour",
"get item.plainTime.hour.valueOf",
"call item.plainTime.hour.valueOf",
"get item.plainTime.microsecond",
"get item.plainTime.microsecond.valueOf",
"call item.plainTime.microsecond.valueOf",
"get item.plainTime.millisecond",
"get item.plainTime.millisecond.valueOf",
"call item.plainTime.millisecond.valueOf",
"get item.plainTime.minute",
"get item.plainTime.minute.valueOf",
"call item.plainTime.minute.valueOf",
"get item.plainTime.nanosecond",
"get item.plainTime.nanosecond.valueOf",
"call item.plainTime.nanosecond.valueOf",
"get item.plainTime.second",
"get item.plainTime.second.valueOf",
"call item.plainTime.second.valueOf",
// GetInstantFor
"get item.timeZone.getPossibleInstantsFor",
"call item.timeZone.getPossibleInstantsFor",
];
const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar");
const instance = new Temporal.PlainDate(2000, 1, 1, calendar);
const springForwardInstance = new Temporal.PlainDate(2000, 4, 2, calendar);
const fallBackInstance = new Temporal.PlainDate(2000, 10, 29, calendar);
actual.splice(0); // clear calendar calls that happened in constructors
const plainTime = TemporalHelpers.propertyBagObserver(actual, {
hour: 2,
minute: 30,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
}, "item.plainTime");
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const timeZone = TemporalHelpers.timeZoneObserver(actual, "item.timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor,
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor,
});
const item = TemporalHelpers.propertyBagObserver(actual, {
plainTime,
timeZone,
}, "item");
instance.toZonedDateTime(item);
assert.compareArray(actual, expected, "order of operations at normal wall-clock time");
actual.splice(0); // clear
const plainTime130 = TemporalHelpers.propertyBagObserver(actual, {
hour: 1,
minute: 30,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
}, "item.plainTime");
const item130 = TemporalHelpers.propertyBagObserver(actual, {
plainTime: plainTime130,
timeZone,
}, "item");
fallBackInstance.toZonedDateTime(item130);
assert.compareArray(actual, expected, "order of operations at repeated wall-clock time");
actual.splice(0); // clear
springForwardInstance.toZonedDateTime(item);
assert.compareArray(actual, expected.concat([
"get item.timeZone.getOffsetNanosecondsFor",
"call item.timeZone.getOffsetNanosecondsFor",
"call item.timeZone.getOffsetNanosecondsFor",
"get item.timeZone.getPossibleInstantsFor",
"call item.timeZone.getPossibleInstantsFor",
]), "order of operations at skipped wall-clock time");
actual.splice(0); // clear

View File

@ -25,12 +25,38 @@ const actual = [];
const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar");
const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar);
// clear observable operations that occurred during the constructor call
const fallBackInstance = new Temporal.PlainDateTime(2000, 10, 29, 1, 30, 0, 0, 0, 0, calendar);
const springForwardInstance = new Temporal.PlainDateTime(2000, 4, 2, 2, 30, 0, 0, 0, 0, calendar);
// clear observable operations that occurred during the constructor calls
actual.splice(0);
const timeZone = TemporalHelpers.timeZoneObserver(actual, "timeZone");
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const timeZone = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor,
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor,
});
const options = TemporalHelpers.propertyBagObserver(actual, { disambiguation: "compatible" }, "options");
instance.toZonedDateTime(timeZone, options);
assert.compareArray(actual, expected, "order of operations");
assert.compareArray(actual, expected, "order of operations at normal wall-clock time");
actual.splice(0); // clear
fallBackInstance.toZonedDateTime(timeZone, options);
assert.compareArray(actual, expected, "order of operations at repeated wall-clock time");
actual.splice(0); // clear
springForwardInstance.toZonedDateTime(timeZone, options);
assert.compareArray(actual, expected.concat([
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]), "order of operations at skipped wall-clock time");
actual.splice(0); // clear
const rejectOptions = TemporalHelpers.propertyBagObserver(actual, { disambiguation: "reject" }, "options");
assert.throws(RangeError, () => springForwardInstance.toZonedDateTime(timeZone, rejectOptions));
assert.compareArray(actual, expected, "order of operations at skipped wall-clock time with disambiguation: reject");
actual.splice(0); // clear

View File

@ -0,0 +1,116 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.plaintime.prototype.tozoneddatetime
description: User code calls happen in the correct order
includes: [compareArray.js, temporalHelpers.js]
features: [Temporal]
---*/
const actual = [];
const expected = [
"get item.plainDate",
"get item.plainDate.calendar",
"has item.plainDate.calendar.dateAdd",
"has item.plainDate.calendar.dateFromFields",
"has item.plainDate.calendar.dateUntil",
"has item.plainDate.calendar.day",
"has item.plainDate.calendar.dayOfWeek",
"has item.plainDate.calendar.dayOfYear",
"has item.plainDate.calendar.daysInMonth",
"has item.plainDate.calendar.daysInWeek",
"has item.plainDate.calendar.daysInYear",
"has item.plainDate.calendar.fields",
"has item.plainDate.calendar.id",
"has item.plainDate.calendar.inLeapYear",
"has item.plainDate.calendar.mergeFields",
"has item.plainDate.calendar.month",
"has item.plainDate.calendar.monthCode",
"has item.plainDate.calendar.monthDayFromFields",
"has item.plainDate.calendar.monthsInYear",
"has item.plainDate.calendar.weekOfYear",
"has item.plainDate.calendar.year",
"has item.plainDate.calendar.yearMonthFromFields",
"has item.plainDate.calendar.yearOfWeek",
"get item.plainDate.calendar.fields",
"call item.plainDate.calendar.fields",
"get item.plainDate.day",
"get item.plainDate.day.valueOf",
"call item.plainDate.day.valueOf",
"get item.plainDate.month",
"get item.plainDate.month.valueOf",
"call item.plainDate.month.valueOf",
"get item.plainDate.monthCode",
"get item.plainDate.monthCode.toString",
"call item.plainDate.monthCode.toString",
"get item.plainDate.year",
"get item.plainDate.year.valueOf",
"call item.plainDate.year.valueOf",
"get item.plainDate.calendar.dateFromFields",
"call item.plainDate.calendar.dateFromFields",
"get item.timeZone",
"has item.timeZone.getOffsetNanosecondsFor",
"has item.timeZone.getPossibleInstantsFor",
"has item.timeZone.id",
"get item.timeZone.getPossibleInstantsFor",
"call item.timeZone.getPossibleInstantsFor",
];
const calendar = TemporalHelpers.calendarObserver(actual, "item.plainDate.calendar");
const instance = new Temporal.PlainTime(2, 30);
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const timeZone = TemporalHelpers.timeZoneObserver(actual, "item.timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor,
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor,
});
const plainDate = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 1,
monthCode: "M01",
day: 1,
calendar,
}, "item.plainDate");
instance.toZonedDateTime(TemporalHelpers.propertyBagObserver(actual, {
plainDate,
timeZone,
}, "item"));
assert.compareArray(actual, expected, "order of operations at normal wall-clock time");
actual.splice(0); // clear
const fallBackPlainDate = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 10,
monthCode: "M10",
day: 29,
calendar,
}, "item.plainDate");
const fallBackInstance = new Temporal.PlainTime(1, 30);
fallBackInstance.toZonedDateTime(TemporalHelpers.propertyBagObserver(actual, {
plainDate: fallBackPlainDate,
timeZone,
}, "item"));
assert.compareArray(actual, expected, "order of operations at repeated wall-clock time");
actual.splice(0); // clear
const springForwardPlainDate = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 4,
monthCode: "M04",
day: 2,
calendar,
}, "item.plainDate");
instance.toZonedDateTime(TemporalHelpers.propertyBagObserver(actual, {
plainDate: springForwardPlainDate,
timeZone,
}, "item"));
assert.compareArray(actual, expected.concat([
"get item.timeZone.getOffsetNanosecondsFor",
"call item.timeZone.getOffsetNanosecondsFor",
"call item.timeZone.getOffsetNanosecondsFor",
"get item.timeZone.getPossibleInstantsFor",
"call item.timeZone.getPossibleInstantsFor",
]), "order of operations at skipped wall-clock time");
actual.splice(0); // clear

View File

@ -0,0 +1,141 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.compare
description: >
Correct time zone calls are made when converting a ZonedDateTime-like property
bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const timeZone1 = TemporalHelpers.timeZoneObserver(actual, "one.timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const timeZone2 = TemporalHelpers.timeZoneObserver(actual, "two.timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar1 = TemporalHelpers.calendarObserver(actual, "one.calendar");
const calendar2 = TemporalHelpers.calendarObserver(actual, "two.calendar");
const expectedOne = [
// GetTemporalCalendarSlotValueWithISODefault
"has one.calendar.dateAdd",
"has one.calendar.dateFromFields",
"has one.calendar.dateUntil",
"has one.calendar.day",
"has one.calendar.dayOfWeek",
"has one.calendar.dayOfYear",
"has one.calendar.daysInMonth",
"has one.calendar.daysInWeek",
"has one.calendar.daysInYear",
"has one.calendar.fields",
"has one.calendar.id",
"has one.calendar.inLeapYear",
"has one.calendar.mergeFields",
"has one.calendar.month",
"has one.calendar.monthCode",
"has one.calendar.monthDayFromFields",
"has one.calendar.monthsInYear",
"has one.calendar.weekOfYear",
"has one.calendar.year",
"has one.calendar.yearMonthFromFields",
"has one.calendar.yearOfWeek",
// CalendarFields
"get one.calendar.fields",
"call one.calendar.fields",
// ToTemporalTimeZoneSlotValue
"has one.timeZone.getOffsetNanosecondsFor",
"has one.timeZone.getPossibleInstantsFor",
"has one.timeZone.id",
// InterpretTemporalDateTimeFields
"get one.calendar.dateFromFields",
"call one.calendar.dateFromFields",
];
const expectedTwo = [
// GetTemporalCalendarSlotValueWithISODefault
"has two.calendar.dateAdd",
"has two.calendar.dateFromFields",
"has two.calendar.dateUntil",
"has two.calendar.day",
"has two.calendar.dayOfWeek",
"has two.calendar.dayOfYear",
"has two.calendar.daysInMonth",
"has two.calendar.daysInWeek",
"has two.calendar.daysInYear",
"has two.calendar.fields",
"has two.calendar.id",
"has two.calendar.inLeapYear",
"has two.calendar.mergeFields",
"has two.calendar.month",
"has two.calendar.monthCode",
"has two.calendar.monthDayFromFields",
"has two.calendar.monthsInYear",
"has two.calendar.weekOfYear",
"has two.calendar.year",
"has two.calendar.yearMonthFromFields",
"has two.calendar.yearOfWeek",
// CalendarFields
"get two.calendar.fields",
"call two.calendar.fields",
// ToTemporalTimeZoneSlotValue
"has two.timeZone.getOffsetNanosecondsFor",
"has two.timeZone.getPossibleInstantsFor",
"has two.timeZone.id",
// InterpretTemporalDateTimeFields
"get two.calendar.dateFromFields",
"call two.calendar.dateFromFields",
];
Temporal.ZonedDateTime.compare(
{ year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: timeZone1, calendar: calendar1 },
{ year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: timeZone2, calendar: calendar2 },
);
const expectedSpringForward = expectedOne.concat([
// InterpretISODateTimeOffset
"get one.timeZone.getPossibleInstantsFor",
"call one.timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get one.timeZone.getOffsetNanosecondsFor",
"call one.timeZone.getOffsetNanosecondsFor",
"call one.timeZone.getOffsetNanosecondsFor",
"get one.timeZone.getPossibleInstantsFor",
"call one.timeZone.getPossibleInstantsFor",
], expectedTwo, [
// InterpretISODateTimeOffset
"get two.timeZone.getPossibleInstantsFor",
"call two.timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get two.timeZone.getOffsetNanosecondsFor",
"call two.timeZone.getOffsetNanosecondsFor",
"call two.timeZone.getOffsetNanosecondsFor",
"get two.timeZone.getPossibleInstantsFor",
"call two.timeZone.getPossibleInstantsFor",
]);
assert.compareArray(actual, expectedSpringForward, "order of operations converting property bags at skipped wall-clock time");
actual.splice(0); // clear
Temporal.ZonedDateTime.compare(
{ year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: timeZone1, calendar: calendar1 },
{ year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: timeZone2, calendar: calendar2 },
);
const expectedFallBack = expectedOne.concat([
// InterpretISODateTimeOffset
"get one.timeZone.getPossibleInstantsFor",
"call one.timeZone.getPossibleInstantsFor",
], expectedTwo, [
// InterpretISODateTimeOffset
"get two.timeZone.getPossibleInstantsFor",
"call two.timeZone.getPossibleInstantsFor",
]);
assert.compareArray(actual, expectedFallBack, "order of operations converting property bags at repeated wall-clock time");
actual.splice(0); // clear

View File

@ -0,0 +1,142 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.from
description: >
Correct time zone calls are made when converting a ZonedDateTime-like property
bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const timeZone = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar = TemporalHelpers.calendarObserver(actual, "calendar");
const expected = [
// GetTemporalCalendarSlotValueWithISODefault
"has calendar.dateAdd",
"has calendar.dateFromFields",
"has calendar.dateUntil",
"has calendar.day",
"has calendar.dayOfWeek",
"has calendar.dayOfYear",
"has calendar.daysInMonth",
"has calendar.daysInWeek",
"has calendar.daysInYear",
"has calendar.fields",
"has calendar.id",
"has calendar.inLeapYear",
"has calendar.mergeFields",
"has calendar.month",
"has calendar.monthCode",
"has calendar.monthDayFromFields",
"has calendar.monthsInYear",
"has calendar.weekOfYear",
"has calendar.year",
"has calendar.yearMonthFromFields",
"has calendar.yearOfWeek",
// CalendarFields
"get calendar.fields",
"call calendar.fields",
// ToTemporalTimeZoneSlotValue
"has timeZone.getOffsetNanosecondsFor",
"has timeZone.getPossibleInstantsFor",
"has timeZone.id",
// InterpretTemporalDateTimeFields
"get calendar.dateFromFields",
"call calendar.dateFromFields",
];
Temporal.ZonedDateTime.from(
{ year: 2000, month: 4, day: 2, hour: 2, minute: 30, offset: "-08:00", timeZone, calendar },
{ offset: "use" }
);
assert.compareArray(actual, expected, "order of operations converting property bag at skipped wall-clock time with offset: use");
actual.splice(0); // clear
Temporal.ZonedDateTime.from(
{ year: 2000, month: 4, day: 2, hour: 2, minute: 30, offset: "-08:00", timeZone, calendar },
{ offset: "ignore" }
);
assert.compareArray(actual, expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]), "order of operations converting property bag at skipped wall-clock time with offset: ignore");
actual.splice(0); // clear
Temporal.ZonedDateTime.from(
{ year: 2000, month: 4, day: 2, hour: 2, minute: 30, offset: "-08:00", timeZone, calendar },
{ offset: "prefer" }
);
assert.compareArray(actual, expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]), "order of operations converting property bag at skipped wall-clock time with offset: prefer");
actual.splice(0); // clear
Temporal.ZonedDateTime.from(
{ year: 2000, month: 10, day: 29, hour: 1, minute: 30, offset: "-08:00", timeZone, calendar },
{ offset: "use" }
);
assert.compareArray(actual, expected, "order of operations converting property bag at repeated wall-clock time with offset: use");
actual.splice(0); // clear
Temporal.ZonedDateTime.from(
{ year: 2000, month: 10, day: 29, hour: 1, minute: 30, offset: "-08:00", timeZone, calendar },
{ offset: "ignore" }
);
assert.compareArray(actual, expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]), "order of operations converting property bag at repeated wall-clock time with offset: ignore");
actual.splice(0); // clear
Temporal.ZonedDateTime.from(
{ year: 2000, month: 10, day: 29, hour: 1, minute: 30, offset: "-08:00", timeZone, calendar },
{ offset: "prefer" }
);
assert.compareArray(actual, expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
]), "order of operations converting property bag at repeated wall-clock time with offset: prefer");
actual.splice(0); // clear
Temporal.ZonedDateTime.from(
{ year: 2000, month: 10, day: 29, hour: 1, minute: 30, offset: "-08:00", timeZone, calendar },
{ offset: "reject" }
);
assert.compareArray(actual, expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
]), "order of operations converting property bag at repeated wall-clock time with offset: reject");
actual.splice(0); // clear

View File

@ -0,0 +1,94 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.prototype.equals
description: >
Correct time zone calls are made when converting a ZonedDateTime-like property
bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const dstTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar = TemporalHelpers.calendarObserver(actual, "calendar");
const timeZone = "UTC";
const instance = new Temporal.ZonedDateTime(0n, timeZone);
let arg = { year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.equals(arg);
const expected = [
// GetTemporalCalendarSlotValueWithISODefault
"has calendar.dateAdd",
"has calendar.dateFromFields",
"has calendar.dateUntil",
"has calendar.day",
"has calendar.dayOfWeek",
"has calendar.dayOfYear",
"has calendar.daysInMonth",
"has calendar.daysInWeek",
"has calendar.daysInYear",
"has calendar.fields",
"has calendar.id",
"has calendar.inLeapYear",
"has calendar.mergeFields",
"has calendar.month",
"has calendar.monthCode",
"has calendar.monthDayFromFields",
"has calendar.monthsInYear",
"has calendar.weekOfYear",
"has calendar.year",
"has calendar.yearMonthFromFields",
"has calendar.yearOfWeek",
// CalendarFields
"get calendar.fields",
"call calendar.fields",
// ToTemporalTimeZoneSlotValue
"has timeZone.getOffsetNanosecondsFor",
"has timeZone.getPossibleInstantsFor",
"has timeZone.id",
// InterpretTemporalDateTimeFields
"get calendar.dateFromFields",
"call calendar.dateFromFields",
];
const expectedSpringForward = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedSpringForward.length), // ignore operations after ToTemporalZonedDateTime
expectedSpringForward,
"order of operations converting property bag at skipped wall-clock time"
);
actual.splice(0); // clear
arg = { year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.equals(arg);
const expectedFallBack = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedFallBack.length), // ignore operations after ToTemporalZonedDateTime
expectedFallBack,
"order of operations converting property bag at repeated wall-clock time"
);
actual.splice(0); // clear

View File

@ -0,0 +1,109 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-get-temporal.zoneddatetime.prototype.hoursinday
description: User code calls happen in the correct order
includes: [compareArray.js, temporalHelpers.js]
features: [Temporal]
---*/
const actual = [];
const expected = [
// GetPlainDateTimeFor
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
// GetInstantFor
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// GetInstantFor
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
];
// Time zone with special requirements for testing DisambiguatePossibleInstants:
// midnight 1970-01-01 and 1970-01-02 are each in the middle of a fall-back
// transition of 1 h. Midnight 1970-01-03 and 1970-01-04 are each in the middle
// of a spring-forward transition of 1 h.
// The fall-back transitions occur 30 minutes after the day boundaries at local
// time: at epoch seconds 1800 and 91800. the spring-forward transitions occur
// 30 minutes before the day boundaries at local time: at epoch seconds 167400
// and 257400.
// This is because calculating the hours in the instance's day requires calling
// getPossibleInstantsFor on both the preceding local midnight and the following
// local midnight.
const timeZone = TemporalHelpers.timeZoneObserver(actual, "this.timeZone", {
getOffsetNanosecondsFor(instant) {
const epochNs = instant.epochNanoseconds;
if (epochNs < 1800_000_000_000n) return 0;
if (epochNs < 91800_000_000_000n) return 3600_000_000_000;
if (epochNs < 167400_000_000_000n) return 7200_000_000_000;
if (epochNs < 257400_000_000_000n) return 3600_000_000_000;
return 0;
},
getPossibleInstantsFor(dt) {
const cmp = Temporal.PlainDateTime.compare;
const zero = new Temporal.TimeZone("+00:00").getInstantFor(dt);
const one = new Temporal.TimeZone("+01:00").getInstantFor(dt);
const two = new Temporal.TimeZone("+02:00").getInstantFor(dt);
const fallBackLocalOne = new Temporal.PlainDateTime(1970, 1, 1, 0, 30);
const fallBackLocalTwo = new Temporal.PlainDateTime(1970, 1, 2, 0, 30);
const springForwardLocalOne = new Temporal.PlainDateTime(1970, 1, 2, 23, 30);
const springForwardLocalTwo = new Temporal.PlainDateTime(1970, 1, 3, 23, 30);
if (cmp(dt, fallBackLocalOne) < 0) return [zero];
if (cmp(dt, fallBackLocalOne.add({ hours: 1 })) < 0) return [zero, one];
if (cmp(dt, fallBackLocalTwo) < 0) return [one];
if (cmp(dt, fallBackLocalTwo.add({ hours: 1 })) < 0) return [one, two];
if (cmp(dt, springForwardLocalOne) < 0) return [two];
if (cmp(dt, springForwardLocalOne.add({ hours: 1 })) < 0) return [];
if (cmp(dt, springForwardLocalTwo) < 0) return [one];
if (cmp(dt, springForwardLocalTwo.add({ hours: 1 })) < 0) return [];
return [zero];
},
});
const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar");
const instance = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, timeZone, calendar);
const fallBackInstance = new Temporal.ZonedDateTime(43200_000_000_000n /* 1970-01-01T12:00 */, timeZone, calendar);
const springForwardInstance = new Temporal.ZonedDateTime(216000_000_000_000n /* 1970-01-03T12:00 */, timeZone, calendar);
actual.splice(0); // clear calls that happened in constructors
instance.hoursInDay;
assert.compareArray(actual, expected, "order of operations with both midnights at normal wall-clock times");
actual.splice(0); // clear
fallBackInstance.hoursInDay;
assert.compareArray(actual, expected, "order of operations with both midnights at repeated wall-clock times");
actual.splice(0); // clear
springForwardInstance.hoursInDay;
assert.compareArray(actual, [
// GetPlainDateTimeFor
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
// GetInstantFor
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
// Note, no call to dateAdd as addition takes place in the ISO calendar
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// GetInstantFor
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
// Note, no call to dateAdd here either
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
], "order of operations with both midnights at skipped wall-clock times");
actual.splice(0); // clear

View File

@ -41,14 +41,126 @@ const options = TemporalHelpers.propertyBagObserver(actual, {
roundingIncrement: 2,
}, "options");
const nextHourOptions = TemporalHelpers.propertyBagObserver(actual, {
smallestUnit: "hour",
roundingMode: "ceil",
roundingIncrement: 1,
}, "options");
const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar");
const instance = new Temporal.ZonedDateTime(
988786472_987_654_321n, /* 2001-05-02T06:54:32.987654321Z */
TemporalHelpers.timeZoneObserver(actual, "this.timeZone"),
TemporalHelpers.calendarObserver(actual, "this.calendar"),
calendar,
);
const fallBackTimeZone = TemporalHelpers.oneShiftTimeZone(Temporal.Instant.fromEpochSeconds(1800), -3600_000_000_000);
const fallBackTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "this.timeZone", {
getOffsetNanosecondsFor: fallBackTimeZone.getOffsetNanosecondsFor.bind(fallBackTimeZone),
getPossibleInstantsFor: fallBackTimeZone.getPossibleInstantsFor.bind(fallBackTimeZone),
});
const fallBackInstance = new Temporal.ZonedDateTime(0n, fallBackTimeZoneObserver, calendar);
const beforeFallBackInstance = new Temporal.ZonedDateTime(-3599_000_000_000n, fallBackTimeZoneObserver, calendar);
const springForwardTimeZone = TemporalHelpers.oneShiftTimeZone(Temporal.Instant.fromEpochSeconds(-1800), 3600_000_000_000);
const springForwardTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "this.timeZone", {
getOffsetNanosecondsFor: springForwardTimeZone.getOffsetNanosecondsFor.bind(springForwardTimeZone),
getPossibleInstantsFor: springForwardTimeZone.getPossibleInstantsFor.bind(springForwardTimeZone),
});
const springForwardInstance = new Temporal.ZonedDateTime(0n, springForwardTimeZoneObserver, calendar);
const beforeSpringForwardInstance = new Temporal.ZonedDateTime(-3599_000_000_000n, springForwardTimeZoneObserver, calendar);
// clear any observable operations that happen due to time zone or calendar
// calls on the constructor
// calls in the constructors
actual.splice(0);
instance.round(options);
assert.compareArray(actual, expected, "order of operations");
actual.splice(0); // clear
fallBackInstance.round(options);
assert.compareArray(actual, expected, "order of operations with preceding midnight at repeated wall-clock time");
actual.splice(0); // clear
beforeFallBackInstance.round(nextHourOptions);
assert.compareArray(actual, expected, "order of operations with rounding result at repeated wall-clock time");
actual.splice(0); // clear
const expectedSkippedDateTime = [
"get options.roundingIncrement",
"get options.roundingIncrement.valueOf",
"call options.roundingIncrement.valueOf",
"get options.roundingMode",
"get options.roundingMode.toString",
"call options.roundingMode.toString",
"get options.smallestUnit",
"get options.smallestUnit.toString",
"call options.smallestUnit.toString",
// GetPlainDateTimeFor on receiver's instant
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
// GetInstantFor on preceding midnight
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// AddZonedDateTime
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// InterpretISODateTimeOffset
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
];
springForwardInstance.round(options);
assert.compareArray(actual, expectedSkippedDateTime, "order of operations with preceding midnight at skipped wall-clock time");
actual.splice(0); // clear
const expectedSkippedResult = [
"get options.roundingIncrement",
"get options.roundingIncrement.valueOf",
"call options.roundingIncrement.valueOf",
"get options.roundingMode",
"get options.roundingMode.toString",
"call options.roundingMode.toString",
"get options.smallestUnit",
"get options.smallestUnit.toString",
"call options.smallestUnit.toString",
// GetPlainDateTimeFor on receiver's instant
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
// GetInstantFor on preceding midnight
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// AddDaysToZonedDateTime
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// InterpretISODateTimeOffset
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
];
beforeSpringForwardInstance.round(nextHourOptions);
assert.compareArray(
actual,
expectedSkippedResult,
"order of operations with following midnight and rounding result at skipped wall-clock time"
);
actual.splice(0); // clear

View File

@ -0,0 +1,94 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.prototype.since
description: >
Correct time zone calls are made when converting a ZonedDateTime-like property
bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const dstTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar = TemporalHelpers.calendarObserver(actual, "calendar");
const timeZone = "UTC";
const instance = new Temporal.ZonedDateTime(0n, timeZone);
let arg = { year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.since(arg);
const expected = [
// GetTemporalCalendarSlotValueWithISODefault
"has calendar.dateAdd",
"has calendar.dateFromFields",
"has calendar.dateUntil",
"has calendar.day",
"has calendar.dayOfWeek",
"has calendar.dayOfYear",
"has calendar.daysInMonth",
"has calendar.daysInWeek",
"has calendar.daysInYear",
"has calendar.fields",
"has calendar.id",
"has calendar.inLeapYear",
"has calendar.mergeFields",
"has calendar.month",
"has calendar.monthCode",
"has calendar.monthDayFromFields",
"has calendar.monthsInYear",
"has calendar.weekOfYear",
"has calendar.year",
"has calendar.yearMonthFromFields",
"has calendar.yearOfWeek",
// CalendarFields
"get calendar.fields",
"call calendar.fields",
// ToTemporalTimeZoneSlotValue
"has timeZone.getOffsetNanosecondsFor",
"has timeZone.getPossibleInstantsFor",
"has timeZone.id",
// InterpretTemporalDateTimeFields
"get calendar.dateFromFields",
"call calendar.dateFromFields",
];
const expectedSpringForward = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedSpringForward.length), // ignore operations after ToTemporalZonedDateTime
expectedSpringForward,
"order of operations converting property bag at skipped wall-clock time"
);
actual.splice(0); // clear
arg = { year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.since(arg);
const expectedFallBack = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedFallBack.length), // ignore operations after ToTemporalZonedDateTime
expectedFallBack,
"order of operations converting property bag at repeated wall-clock time"
);
actual.splice(0); // clear

View File

@ -269,7 +269,6 @@ assert.compareArray(actual, [
"get other.timeZone.getOffsetNanosecondsFor",
"call other.timeZone.getOffsetNanosecondsFor",
// NOTE: extra because of wall-clock time ambiguity:
"get other.timeZone.getOffsetNanosecondsFor",
"call other.timeZone.getOffsetNanosecondsFor",
// CalendarEquals
"get this.calendar.id",

View File

@ -0,0 +1,67 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.prototype.startofday
description: User code calls happen in the correct order
includes: [compareArray.js, temporalHelpers.js]
features: [Temporal]
---*/
const expected = [
// GetPlainDateTimeFor
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
// GetInstantFor on preceding midnight
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
];
const actual = [];
const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar");
const instance = new Temporal.ZonedDateTime(
1_000_000_000_000_000_000n,
TemporalHelpers.timeZoneObserver(actual, "this.timeZone"),
calendar,
);
const fallBackTimeZone = TemporalHelpers.oneShiftTimeZone(Temporal.Instant.fromEpochSeconds(1800), -3600_000_000_000);
const fallBackInstance = new Temporal.ZonedDateTime(
0n,
TemporalHelpers.timeZoneObserver(actual, "this.timeZone", {
getOffsetNanosecondsFor: fallBackTimeZone.getOffsetNanosecondsFor.bind(fallBackTimeZone),
getPossibleInstantsFor: fallBackTimeZone.getPossibleInstantsFor.bind(fallBackTimeZone),
}),
calendar,
);
const springForwardTimeZone = TemporalHelpers.oneShiftTimeZone(Temporal.Instant.fromEpochSeconds(-1800), 3600_000_000_000);
const springForwardInstance = new Temporal.ZonedDateTime(
0n,
TemporalHelpers.timeZoneObserver(actual, "this.timeZone", {
getOffsetNanosecondsFor: springForwardTimeZone.getOffsetNanosecondsFor.bind(springForwardTimeZone),
getPossibleInstantsFor: springForwardTimeZone.getPossibleInstantsFor.bind(springForwardTimeZone),
}),
calendar,
);
// clear any observable operations that happen due to time zone or calendar
// calls in the constructors
actual.splice(0);
instance.startOfDay();
assert.compareArray(actual, expected, "order of operations");
actual.splice(0); // clear
fallBackInstance.startOfDay();
assert.compareArray(actual, expected, "order of operations with preceding midnight at repeated wall-clock time");
actual.splice(0); // clear
springForwardInstance.startOfDay();
assert.compareArray(actual, expected.concat([
// DisambiguatePossibleInstants
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
]), "order of operations with preceding midnight at skipped wall-clock time");
actual.splice(0); // clear

View File

@ -0,0 +1,94 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.prototype.until
description: >
Correct time zone calls are made when converting a ZonedDateTime-like property
bag denoting an ambiguous wall-clock time
includes: [temporalHelpers.js, compareArray.js]
features: [Temporal]
---*/
const actual = [];
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const dstTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor.bind(dstTimeZone),
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor.bind(dstTimeZone),
});
const calendar = TemporalHelpers.calendarObserver(actual, "calendar");
const timeZone = "UTC";
const instance = new Temporal.ZonedDateTime(0n, timeZone);
let arg = { year: 2000, month: 4, day: 2, hour: 2, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.until(arg);
const expected = [
// GetTemporalCalendarSlotValueWithISODefault
"has calendar.dateAdd",
"has calendar.dateFromFields",
"has calendar.dateUntil",
"has calendar.day",
"has calendar.dayOfWeek",
"has calendar.dayOfYear",
"has calendar.daysInMonth",
"has calendar.daysInWeek",
"has calendar.daysInYear",
"has calendar.fields",
"has calendar.id",
"has calendar.inLeapYear",
"has calendar.mergeFields",
"has calendar.month",
"has calendar.monthCode",
"has calendar.monthDayFromFields",
"has calendar.monthsInYear",
"has calendar.weekOfYear",
"has calendar.year",
"has calendar.yearMonthFromFields",
"has calendar.yearOfWeek",
// CalendarFields
"get calendar.fields",
"call calendar.fields",
// ToTemporalTimeZoneSlotValue
"has timeZone.getOffsetNanosecondsFor",
"has timeZone.getPossibleInstantsFor",
"has timeZone.id",
// InterpretTemporalDateTimeFields
"get calendar.dateFromFields",
"call calendar.dateFromFields",
];
const expectedSpringForward = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
// DisambiguatePossibleInstants
"get timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"call timeZone.getOffsetNanosecondsFor",
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedSpringForward.length), // ignore operations after ToTemporalZonedDateTime
expectedSpringForward,
"order of operations converting property bag at skipped wall-clock time"
);
actual.splice(0); // clear
arg = { year: 2000, month: 10, day: 29, hour: 1, minute: 30, timeZone: dstTimeZoneObserver, calendar };
instance.until(arg);
const expectedFallBack = expected.concat([
// InterpretISODateTimeOffset
"get timeZone.getPossibleInstantsFor",
"call timeZone.getPossibleInstantsFor",
]);
assert.compareArray(
actual.slice(0, expectedFallBack.length), // ignore operations after ToTemporalZonedDateTime
expectedFallBack,
"order of operations converting property bag at repeated wall-clock time"
);
actual.splice(0); // clear

View File

@ -269,7 +269,6 @@ assert.compareArray(actual, [
"get other.timeZone.getOffsetNanosecondsFor",
"call other.timeZone.getOffsetNanosecondsFor",
// NOTE: extra because of wall-clock time ambiguity:
"get other.timeZone.getOffsetNanosecondsFor",
"call other.timeZone.getOffsetNanosecondsFor",
// CalendarEquals
"get this.calendar.id",

View File

@ -120,3 +120,55 @@ const options = TemporalHelpers.propertyBagObserver(actual, {
instance.with(fields, options);
assert.compareArray(actual, expected, "order of operations");
actual.splice(0); // clear
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const dstTimeZoneObserver = TemporalHelpers.timeZoneObserver(actual, "this.timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor,
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor,
});
const dstInstance = new Temporal.ZonedDateTime(37800_000_000_000n /* 1970-01-01T02:30-08:00 */, dstTimeZoneObserver, calendar);
actual.splice(0); // clear calls that happened in constructor
const fallBackFields = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 10,
monthCode: "M10",
day: 29,
hour: 1,
minute: 30,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
offset: "+00:00", // ignored
}, "fields");
dstInstance.with(fallBackFields, options);
assert.compareArray(actual, expected.concat([
// extra call in InterpretISODateTimeOffset
"call this.timeZone.getOffsetNanosecondsFor",
]), "order of operations at repeated wall-clock time");
actual.splice(0); // clear
const springForwardFields = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 4,
monthCode: "M04",
day: 2,
hour: 2,
minute: 30,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
offset: "+00:00", // ignored
}, "fields");
dstInstance.with(springForwardFields, options);
assert.compareArray(actual, expected.concat([
// DisambiguatePossibleInstants
"call this.timeZone.getOffsetNanosecondsFor",
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
]), "order of operations at skipped wall-clock time");
actual.splice(0); // clear

View File

@ -0,0 +1,112 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-get-temporal.zoneddatetime.prototype.withplaindate
description: User code calls happen in the correct order
includes: [compareArray.js, temporalHelpers.js]
features: [Temporal]
---*/
const actual = [];
const expected = [
// ToTemporalDate
"get plainDateLike.calendar",
"has plainDateLike.calendar.dateAdd",
"has plainDateLike.calendar.dateFromFields",
"has plainDateLike.calendar.dateUntil",
"has plainDateLike.calendar.day",
"has plainDateLike.calendar.dayOfWeek",
"has plainDateLike.calendar.dayOfYear",
"has plainDateLike.calendar.daysInMonth",
"has plainDateLike.calendar.daysInWeek",
"has plainDateLike.calendar.daysInYear",
"has plainDateLike.calendar.fields",
"has plainDateLike.calendar.id",
"has plainDateLike.calendar.inLeapYear",
"has plainDateLike.calendar.mergeFields",
"has plainDateLike.calendar.month",
"has plainDateLike.calendar.monthCode",
"has plainDateLike.calendar.monthDayFromFields",
"has plainDateLike.calendar.monthsInYear",
"has plainDateLike.calendar.weekOfYear",
"has plainDateLike.calendar.year",
"has plainDateLike.calendar.yearMonthFromFields",
"has plainDateLike.calendar.yearOfWeek",
"get plainDateLike.calendar.fields",
"call plainDateLike.calendar.fields",
"get plainDateLike.day",
"get plainDateLike.day.valueOf",
"call plainDateLike.day.valueOf",
"get plainDateLike.month",
"get plainDateLike.month.valueOf",
"call plainDateLike.month.valueOf",
"get plainDateLike.monthCode",
"get plainDateLike.monthCode.toString",
"call plainDateLike.monthCode.toString",
"get plainDateLike.year",
"get plainDateLike.year.valueOf",
"call plainDateLike.year.valueOf",
"get plainDateLike.calendar.dateFromFields",
"call plainDateLike.calendar.dateFromFields",
// GetPlainDateTimeFor
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
// ConsolidateCalendars
"get this.calendar.id",
"get plainDateLike.calendar.id",
// GetInstantFor
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
];
const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar");
const plainDateCalendar = TemporalHelpers.calendarObserver(actual, "plainDateLike.calendar");
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const timeZone = TemporalHelpers.timeZoneObserver(actual, "this.timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor,
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor,
});
const instance = new Temporal.ZonedDateTime(37800_000_000_000n /* 1970-01-01T02:30-08:00 */, timeZone, calendar);
const fallBackInstance = new Temporal.ZonedDateTime(34200_000_000_000n /* 1970-01-01T01:30-08:00 */, timeZone, calendar);
actual.splice(0); // clear calls that happened in constructor
const plainDateLike = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 1,
monthCode: "M01",
day: 1,
calendar: plainDateCalendar,
}, "plainDateLike");
instance.withPlainDate(plainDateLike);
assert.compareArray(actual, expected, "order of operations at normal wall-clock time");
actual.splice(0); // clear
const fallBackPlainDateLike = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 10,
monthCode: "M10",
day: 29,
calendar: plainDateCalendar,
}, "plainDateLike");
fallBackInstance.withPlainDate(fallBackPlainDateLike);
assert.compareArray(actual, expected, "order of operations at repeated wall-clock time");
actual.splice(0); // clear
const springForwardPlainDateLike = TemporalHelpers.propertyBagObserver(actual, {
year: 2000,
month: 4,
monthCode: "M04",
day: 2,
calendar: plainDateCalendar,
}, "plainDateLike");
instance.withPlainDate(springForwardPlainDateLike);
assert.compareArray(actual, expected.concat([
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
]), "order of operations at skipped wall-clock time");
actual.splice(0); // clear

View File

@ -0,0 +1,86 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-get-temporal.zoneddatetime.prototype.withplaintime
description: User code calls happen in the correct order
includes: [compareArray.js, temporalHelpers.js]
features: [Temporal]
---*/
const actual = [];
const expected = [
// ToTemporalTime
"get plainTimeLike.hour",
"get plainTimeLike.hour.valueOf",
"call plainTimeLike.hour.valueOf",
"get plainTimeLike.microsecond",
"get plainTimeLike.microsecond.valueOf",
"call plainTimeLike.microsecond.valueOf",
"get plainTimeLike.millisecond",
"get plainTimeLike.millisecond.valueOf",
"call plainTimeLike.millisecond.valueOf",
"get plainTimeLike.minute",
"get plainTimeLike.minute.valueOf",
"call plainTimeLike.minute.valueOf",
"get plainTimeLike.nanosecond",
"get plainTimeLike.nanosecond.valueOf",
"call plainTimeLike.nanosecond.valueOf",
"get plainTimeLike.second",
"get plainTimeLike.second.valueOf",
"call plainTimeLike.second.valueOf",
// GetPlainDateTimeFor
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
// GetInstantFor
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
];
const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar");
const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone();
const timeZone = TemporalHelpers.timeZoneObserver(actual, "this.timeZone", {
getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor,
getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor,
});
const instance = new Temporal.ZonedDateTime(946713600_000_000_000n /* 2000-01-01T00:00-08:00 */, timeZone, calendar);
const fallBackInstance = new Temporal.ZonedDateTime(972802800_000_000_000n /* 2000-10-29T00:00-07:00 */, timeZone, calendar);
const springForwardInstance = new Temporal.ZonedDateTime(954662400_000_000_000n /* 2000-04-02T00:00-08:00 */, timeZone, calendar);
actual.splice(0); // clear calls that happened in constructors
const plainTimeLike = TemporalHelpers.propertyBagObserver(actual, {
hour: 2,
minute: 30,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
}, "plainTimeLike");
instance.withPlainTime(plainTimeLike);
assert.compareArray(actual, expected, "order of operations at normal wall-clock time");
actual.splice(0); // clear
const plainTimeLike130 = TemporalHelpers.propertyBagObserver(actual, {
hour: 1,
minute: 30,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
}, "plainTimeLike");
fallBackInstance.withPlainTime(plainTimeLike130);
assert.compareArray(actual, expected, "order of operations at repeated wall-clock time");
actual.splice(0); // clear
springForwardInstance.withPlainTime(plainTimeLike);
assert.compareArray(actual, expected.concat([
"get this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"call this.timeZone.getOffsetNanosecondsFor",
"get this.timeZone.getPossibleInstantsFor",
"call this.timeZone.getPossibleInstantsFor",
]), "order of operations at skipped wall-clock time");
actual.splice(0); // clear