From 9b8d9cf66cdc4c4fedaef7a83c856aeb9dc2a27e Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Thu, 9 Mar 2023 17:39:19 -0800 Subject: [PATCH] Temporal: Fast-path dateUntil() when difference largest unit is days This removes several loopholes where it was possible to return particular values from user calls that would cause infinite loops, or calculate zero-length days. --- ...euntil-called-with-singular-largestunit.js | 22 +-- ...nanoseconds-to-days-loop-indefinitely-1.js | 58 ------- ... nanoseconds-to-days-loop-indefinitely.js} | 0 .../prototype/add/order-of-operations.js | 6 - ...euntil-called-with-singular-largestunit.js | 46 +++--- ...nanoseconds-to-days-loop-indefinitely-1.js | 58 ------- ... nanoseconds-to-days-loop-indefinitely.js} | 0 .../prototype/round/order-of-operations.js | 4 - .../prototype/round/zero-day-length-2.js | 53 ------ ...ero-day-length-1.js => zero-day-length.js} | 0 ...euntil-called-with-singular-largestunit.js | 22 +-- ...nanoseconds-to-days-loop-indefinitely-1.js | 59 ------- ... nanoseconds-to-days-loop-indefinitely.js} | 0 .../prototype/subtract/order-of-operations.js | 6 - ...euntil-called-with-singular-largestunit.js | 17 +- ...nanoseconds-to-days-loop-indefinitely-1.js | 59 ------- ... nanoseconds-to-days-loop-indefinitely.js} | 0 .../prototype/total/order-of-operations.js | 4 - .../prototype/total/zero-day-length-2.js | 53 ------ ...ero-day-length-1.js => zero-day-length.js} | 0 ...ntil-called-with-null-prototype-options.js | 2 +- ...euntil-called-with-singular-largestunit.js | 2 +- .../since/calendar-invalid-return.js | 6 +- .../PlainDate/prototype/since/custom.js | 4 +- .../prototype/since/order-of-operations.js | 26 ++- ...ntil-called-with-null-prototype-options.js | 2 +- ...euntil-called-with-singular-largestunit.js | 2 +- .../until/calendar-invalid-return.js | 5 +- .../PlainDate/prototype/until/custom.js | 4 +- .../prototype/until/order-of-operations.js | 26 ++- .../balance-infinite-nanoseconds-duration.js | 44 ----- ...ntil-called-with-null-prototype-options.js | 2 +- ...euntil-called-with-singular-largestunit.js | 14 +- .../prototype/since/order-of-operations.js | 28 +++- .../balance-infinite-nanoseconds-duration.js | 44 ----- ...ntil-called-with-null-prototype-options.js | 2 +- ...euntil-called-with-singular-largestunit.js | 14 +- .../prototype/until/order-of-operations.js | 28 +++- .../prototype/since/order-of-operations.js | 21 ++- .../prototype/until/order-of-operations.js | 21 ++- ...ntil-called-with-null-prototype-options.js | 2 +- ...euntil-called-with-singular-largestunit.js | 26 +-- ...nanoseconds-to-days-loop-indefinitely-1.js | 59 ------- ... nanoseconds-to-days-loop-indefinitely.js} | 0 .../prototype/since/order-of-operations.js | 151 +++++++++++++++++- ...ntil-called-with-null-prototype-options.js | 2 +- ...euntil-called-with-singular-largestunit.js | 26 +-- ...nanoseconds-to-days-loop-indefinitely-1.js | 59 ------- ... nanoseconds-to-days-loop-indefinitely.js} | 0 .../prototype/until/order-of-operations.js | 151 +++++++++++++++++- 50 files changed, 538 insertions(+), 702 deletions(-) delete mode 100644 test/built-ins/Temporal/Duration/prototype/add/nanoseconds-to-days-loop-indefinitely-1.js rename test/built-ins/Temporal/Duration/prototype/add/{nanoseconds-to-days-loop-indefinitely-2.js => nanoseconds-to-days-loop-indefinitely.js} (100%) delete mode 100644 test/built-ins/Temporal/Duration/prototype/round/nanoseconds-to-days-loop-indefinitely-1.js rename test/built-ins/Temporal/Duration/prototype/round/{nanoseconds-to-days-loop-indefinitely-2.js => nanoseconds-to-days-loop-indefinitely.js} (100%) delete mode 100644 test/built-ins/Temporal/Duration/prototype/round/zero-day-length-2.js rename test/built-ins/Temporal/Duration/prototype/round/{zero-day-length-1.js => zero-day-length.js} (100%) delete mode 100644 test/built-ins/Temporal/Duration/prototype/subtract/nanoseconds-to-days-loop-indefinitely-1.js rename test/built-ins/Temporal/Duration/prototype/subtract/{nanoseconds-to-days-loop-indefinitely-2.js => nanoseconds-to-days-loop-indefinitely.js} (100%) delete mode 100644 test/built-ins/Temporal/Duration/prototype/total/nanoseconds-to-days-loop-indefinitely-1.js rename test/built-ins/Temporal/Duration/prototype/total/{nanoseconds-to-days-loop-indefinitely-2.js => nanoseconds-to-days-loop-indefinitely.js} (100%) delete mode 100644 test/built-ins/Temporal/Duration/prototype/total/zero-day-length-2.js rename test/built-ins/Temporal/Duration/prototype/total/{zero-day-length-1.js => zero-day-length.js} (100%) delete mode 100644 test/built-ins/Temporal/PlainDateTime/prototype/since/balance-infinite-nanoseconds-duration.js delete mode 100644 test/built-ins/Temporal/PlainDateTime/prototype/until/balance-infinite-nanoseconds-duration.js delete mode 100644 test/built-ins/Temporal/ZonedDateTime/prototype/since/nanoseconds-to-days-loop-indefinitely-1.js rename test/built-ins/Temporal/ZonedDateTime/prototype/since/{nanoseconds-to-days-loop-indefinitely-2.js => nanoseconds-to-days-loop-indefinitely.js} (100%) delete mode 100644 test/built-ins/Temporal/ZonedDateTime/prototype/until/nanoseconds-to-days-loop-indefinitely-1.js rename test/built-ins/Temporal/ZonedDateTime/prototype/until/{nanoseconds-to-days-loop-indefinitely-2.js => nanoseconds-to-days-loop-indefinitely.js} (100%) diff --git a/test/built-ins/Temporal/Duration/prototype/add/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/Duration/prototype/add/calendar-dateuntil-called-with-singular-largestunit.js index ced56a7461..b773dc7c97 100644 --- a/test/built-ins/Temporal/Duration/prototype/add/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/Duration/prototype/add/calendar-dateuntil-called-with-singular-largestunit.js @@ -46,13 +46,13 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( years: ["year"], months: ["month"], weeks: ["week"], - days: ["day"], - hours: ["day"], - minutes: ["day"], - seconds: ["day"], - milliseconds: ["day"], - microseconds: ["day"], - nanoseconds: ["day"] + days: [], + hours: [], + minutes: [], + seconds: [], + milliseconds: [], + microseconds: [], + nanoseconds: [] } ); @@ -64,10 +64,10 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( one.add(two, { relativeTo, largestUnit }); }, { - years: ["year", "day"], - months: ["month", "day"], - weeks: ["week", "day"], - days: ["day", "day"], + years: ["year"], + months: ["month"], + weeks: ["week"], + days: [], hours: [], minutes: [], seconds: [], diff --git a/test/built-ins/Temporal/Duration/prototype/add/nanoseconds-to-days-loop-indefinitely-1.js b/test/built-ins/Temporal/Duration/prototype/add/nanoseconds-to-days-loop-indefinitely-1.js deleted file mode 100644 index cfb3b2e5f8..0000000000 --- a/test/built-ins/Temporal/Duration/prototype/add/nanoseconds-to-days-loop-indefinitely-1.js +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2022 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: > - NanosecondsToDays can loop arbitrarily long, performing observable operations each iteration. -info: | - NanosecondsToDays ( nanoseconds, relativeTo ) - - ... - 15. If sign is 1, then - a. Repeat, while days > 0 and intermediateNs > endNs, - i. Set days to days - 1. - ii. Set intermediateNs to ℝ(? AddZonedDateTime(ℤ(startNs), relativeTo.[[TimeZone]], - relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0, 0, 0, 0)). - ... -includes: [temporalHelpers.js] -features: [Temporal] ----*/ - -const calls = []; -const duration = Temporal.Duration.from({ days: 1 }); - -function createRelativeTo(count) { - const tz = new Temporal.TimeZone("UTC"); - // Record calls in calls[] - TemporalHelpers.observeMethod(calls, tz, "getPossibleInstantsFor"); - const cal = new Temporal.Calendar("iso8601"); - // Return _count_ days for the second call to dateUntil, behaving normally after - TemporalHelpers.substituteMethod(cal, "dateUntil", [ - TemporalHelpers.SUBSTITUTE_SKIP, - Temporal.Duration.from({ days: count }), - ]); - return new Temporal.ZonedDateTime(0n, tz, cal); -} - -let zdt = createRelativeTo(200); -calls.splice(0); // Reset calls list after ZonedDateTime construction -duration.add(duration, { - relativeTo: zdt, -}); -assert.sameValue( - calls.length, - 200 + 2, - "Expected duration.add to call getPossibleInstantsFor correct number of times" -); - -zdt = createRelativeTo(300); -calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction -duration.add(duration, { - relativeTo: zdt, -}); -assert.sameValue( - calls.length, - 300 + 2, - "Expected duration.add to call getPossibleInstantsFor correct number of times" -); diff --git a/test/built-ins/Temporal/Duration/prototype/add/nanoseconds-to-days-loop-indefinitely-2.js b/test/built-ins/Temporal/Duration/prototype/add/nanoseconds-to-days-loop-indefinitely.js similarity index 100% rename from test/built-ins/Temporal/Duration/prototype/add/nanoseconds-to-days-loop-indefinitely-2.js rename to test/built-ins/Temporal/Duration/prototype/add/nanoseconds-to-days-loop-indefinitely.js diff --git a/test/built-ins/Temporal/Duration/prototype/add/order-of-operations.js b/test/built-ins/Temporal/Duration/prototype/add/order-of-operations.js index 7c65dd8f97..0cb316f5c7 100644 --- a/test/built-ins/Temporal/Duration/prototype/add/order-of-operations.js +++ b/test/built-ins/Temporal/Duration/prototype/add/order-of-operations.js @@ -229,9 +229,6 @@ const expectedOpsForPlainRelativeToNoCalendarOperations = [ // InterpretTemporalDateTimeFields "get options.relativeTo.calendar.dateFromFields", "call options.relativeTo.calendar.dateFromFields", - // AddDuration - "get options.relativeTo.calendar.dateUntil", - "call options.relativeTo.calendar.dateUntil", ]; const noCalendarInstance = new Temporal.Duration(0, 0, 0, 4, 5, 6, 7, 987, 654, 321); @@ -355,9 +352,6 @@ const expectedOpsForZonedRelativeTo = expected.concat([ "call options.relativeTo.timeZone.getOffsetNanosecondsFor", "get options.relativeTo.timeZone.getOffsetNanosecondsFor", "call options.relativeTo.timeZone.getOffsetNanosecondsFor", - // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → DifferenceISODateTime - "get options.relativeTo.calendar.dateUntil", - "call options.relativeTo.calendar.dateUntil", // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 1 "get options.relativeTo.timeZone.getPossibleInstantsFor", "call options.relativeTo.timeZone.getPossibleInstantsFor", diff --git a/test/built-ins/Temporal/Duration/prototype/round/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/Duration/prototype/round/calendar-dateuntil-called-with-singular-largestunit.js index 951417a6d3..98e7b8e3cf 100644 --- a/test/built-ins/Temporal/Duration/prototype/round/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/Duration/prototype/round/calendar-dateuntil-called-with-singular-largestunit.js @@ -76,13 +76,13 @@ features: [Temporal] ---*/ // Check with smallestUnit nanoseconds but roundingIncrement > 1; each call -// should result in two calls to dateUntil() originating from -// AdjustRoundedDurationDays, one with largestUnit equal to the largest unit in -// the duration higher than "day", and one with largestUnit: "day". +// should result in one call to dateUntil() originating from +// AdjustRoundedDurationDays, with largestUnit equal to the largest unit in +// the duration higher than "day". // Additionally one call with largestUnit: "month" in BalanceDurationRelative -// when the largestUnit given to round() is "year", and one call with -// largestUnit: "day" when the largestUnit given to round() is "year", "month", -// "week", or "day". +// when the largestUnit given to round() is "year". +// Other calls have largestUnit: "day" so the difference is taken in ISO +// calendar space. const durations = [ [1, 0, 0, 0, 0, 0, 0, 0, 0, 86399_999_999_999], @@ -104,16 +104,16 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( duration.round({ largestUnit, roundingIncrement: 2, roundingMode: 'ceil', relativeTo }); }, { - years: ["year", "day", "day", "month"], - months: ["month", "day", "day"], - weeks: ["week", "day", "day"], - days: ["day", "day", "day"], - hours: ["day", "day"], - minutes: ["day", "day"], - seconds: ["day", "day"], - milliseconds: ["day", "day"], - microseconds: ["day", "day"], - nanoseconds: ["day", "day"] + years: ["year", "month"], + months: ["month"], + weeks: ["week"], + days: [], + hours: [], + minutes: [], + seconds: [], + milliseconds: [], + microseconds: [], + nanoseconds: [] } ); @@ -142,18 +142,18 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( // Check the paths that call dateUntil() in RoundDuration. These paths do not // call dateUntil() in AdjustRoundedDurationDays. Note that there is no -// largestUnit: "month" call in BalanceDurationRelative and no largestUnit: -// "day" call in BalanceDuration, because the durations have rounded down to 0. +// largestUnit: "month" call in BalanceDurationRelative, because the durations +// have rounded down to 0. TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( (calendar, largestUnit) => { - const duration = new Temporal.Duration(0, 0, 0, 0, 1, 1, 1, 1, 1, 1); + const duration = new Temporal.Duration(0, 1, 0, 0, 1, 1, 1, 1, 1, 1); const relativeTo = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", calendar); duration.round({ largestUnit, smallestUnit: largestUnit, relativeTo }); }, { - years: ["day", "year"], - months: ["day"], - weeks: ["day"], - days: ["day"] + years: ["year"], + months: [], + weeks: [], + days: [] } ); diff --git a/test/built-ins/Temporal/Duration/prototype/round/nanoseconds-to-days-loop-indefinitely-1.js b/test/built-ins/Temporal/Duration/prototype/round/nanoseconds-to-days-loop-indefinitely-1.js deleted file mode 100644 index 5613cd7e8c..0000000000 --- a/test/built-ins/Temporal/Duration/prototype/round/nanoseconds-to-days-loop-indefinitely-1.js +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2022 André Bargull. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-temporal.duration.prototype.round -description: > - NanosecondsToDays can loop arbitrarily long, performing observable operations each iteration. -info: | - NanosecondsToDays ( nanoseconds, relativeTo ) - - ... - 15. If sign is 1, then - a. Repeat, while days > 0 and intermediateNs > endNs, - i. Set days to days - 1. - ii. Set intermediateNs to ℝ(? AddZonedDateTime(ℤ(startNs), relativeTo.[[TimeZone]], - relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0, 0, 0, 0)). - ... -includes: [temporalHelpers.js] -features: [Temporal] ----*/ - -const calls = []; -const duration = Temporal.Duration.from({ days: 1 }); - -function createRelativeTo(count) { - const tz = new Temporal.TimeZone("UTC"); - // Record calls in calls[] - TemporalHelpers.observeMethod(calls, tz, "getPossibleInstantsFor"); - const cal = new Temporal.Calendar("iso8601"); - // Return _count_ days for the first call to dateUntil, behaving normally after - TemporalHelpers.substituteMethod(cal, "dateUntil", [ - Temporal.Duration.from({ days: count }), - ]); - return new Temporal.ZonedDateTime(0n, tz, cal); -} - -let zdt = createRelativeTo(200); -calls.splice(0); // Reset calls list after ZonedDateTime construction -duration.round({ - largestUnit: "days", - relativeTo: zdt, -}); -assert.sameValue( - calls.length, - 200 + 2, - "Expected duration.round to call getPossibleInstantsFor correct number of times" -); - -zdt = createRelativeTo(300); -calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction -duration.round({ - largestUnit: "days", - relativeTo: zdt, -}); -assert.sameValue( - calls.length, - 300 + 2, - "Expected duration.round to call getPossibleInstantsFor correct number of times" -); diff --git a/test/built-ins/Temporal/Duration/prototype/round/nanoseconds-to-days-loop-indefinitely-2.js b/test/built-ins/Temporal/Duration/prototype/round/nanoseconds-to-days-loop-indefinitely.js similarity index 100% rename from test/built-ins/Temporal/Duration/prototype/round/nanoseconds-to-days-loop-indefinitely-2.js rename to test/built-ins/Temporal/Duration/prototype/round/nanoseconds-to-days-loop-indefinitely.js diff --git a/test/built-ins/Temporal/Duration/prototype/round/order-of-operations.js b/test/built-ins/Temporal/Duration/prototype/round/order-of-operations.js index fad6339db9..8b6cc03d33 100644 --- a/test/built-ins/Temporal/Duration/prototype/round/order-of-operations.js +++ b/test/built-ins/Temporal/Duration/prototype/round/order-of-operations.js @@ -380,8 +380,6 @@ const expectedOpsForMinimalYearRoundingZoned = expectedOpsForZonedRelativeTo.con "call options.relativeTo.timeZone.getOffsetNanosecondsFor", "get options.relativeTo.timeZone.getOffsetNanosecondsFor", // 11. GetPlainDateTimeFor "call options.relativeTo.timeZone.getOffsetNanosecondsFor", - "get options.relativeTo.calendar.dateUntil", // 12. DifferenceISODateTime - "call options.relativeTo.calendar.dateUntil", // NanosecondsToDays → AddDaysToZonedDateTime "get options.relativeTo.timeZone.getPossibleInstantsFor", "call options.relativeTo.timeZone.getPossibleInstantsFor", @@ -421,8 +419,6 @@ const expectedOpsForYearRoundingZoned = expectedOpsForZonedRelativeTo.concat([ "call options.relativeTo.timeZone.getOffsetNanosecondsFor", "get options.relativeTo.timeZone.getOffsetNanosecondsFor", // 11. GetPlainDateTimeFor "call options.relativeTo.timeZone.getOffsetNanosecondsFor", - "get options.relativeTo.calendar.dateUntil", // 12. DifferenceISODateTime - "call options.relativeTo.calendar.dateUntil", // NanosecondsToDays → AddDaysToZonedDateTime "get options.relativeTo.timeZone.getPossibleInstantsFor", "call options.relativeTo.timeZone.getPossibleInstantsFor", diff --git a/test/built-ins/Temporal/Duration/prototype/round/zero-day-length-2.js b/test/built-ins/Temporal/Duration/prototype/round/zero-day-length-2.js deleted file mode 100644 index 60d5fbee15..0000000000 --- a/test/built-ins/Temporal/Duration/prototype/round/zero-day-length-2.js +++ /dev/null @@ -1,53 +0,0 @@ -// 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: A malicious time zone resulting a day length of zero is handled correctly -info: | - Based on a test by André Bargull. - - RoundDuration step 6: - d. Let _result_ be ? NanosecondsToDays(_nanoseconds_, _intermediate_). - e. Set _days_ to _days_ + _result_.[[Days]] + _result_.[[Nanoseconds]] / _result_.[[DayLength]]. - - NanosecondsToDays steps 19-23: - 19. If _days_ < 0 and _sign_ = 1, throw a *RangeError* exception. - 20. If _days_ > 0 and _sign_ = -1, throw a *RangeError* exception. - 21. If _nanoseconds_ < 0, then - a. Assert: sign is -1. - 22. If _nanoseconds_ > 0 and _sign_ = -1, throw a *RangeError* exception. - 23. Assert: The inequality abs(_nanoseconds_) < abs(_dayLengthNs_) holds. -features: [Temporal] ----*/ - -const instance = new Temporal.Duration(0, 0, 0, 0, 24, 0, 0, 0, 0, 1); - -const tz = new class extends Temporal.TimeZone { - #getPossibleInstantsForCalls = 0; - - getPossibleInstantsFor(dt) { - this.#getPossibleInstantsForCalls++; - - if (this.#getPossibleInstantsForCalls <= 2) { - return [new Temporal.Instant(86400_000_000_000n + 2n)] - } - return super.getPossibleInstantsFor(dt); - } -}("UTC"); - -const cal = new class extends Temporal.Calendar { - #dateUntilCalls = 0; - - dateUntil(one, two, options) { - this.#dateUntilCalls++; - - if (this.#dateUntilCalls === 1) { - return new Temporal.Duration(0, 0, 0, -2); - } - return super.dateUntil(one, two, options); - } -}("iso8601"); - -const relativeTo = new Temporal.ZonedDateTime(0n, tz, cal); -assert.throws(RangeError, () => instance.round({ relativeTo, smallestUnit: "days" })); diff --git a/test/built-ins/Temporal/Duration/prototype/round/zero-day-length-1.js b/test/built-ins/Temporal/Duration/prototype/round/zero-day-length.js similarity index 100% rename from test/built-ins/Temporal/Duration/prototype/round/zero-day-length-1.js rename to test/built-ins/Temporal/Duration/prototype/round/zero-day-length.js diff --git a/test/built-ins/Temporal/Duration/prototype/subtract/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/Duration/prototype/subtract/calendar-dateuntil-called-with-singular-largestunit.js index ef5fbbfedb..0f4ac38f2e 100644 --- a/test/built-ins/Temporal/Duration/prototype/subtract/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/Duration/prototype/subtract/calendar-dateuntil-called-with-singular-largestunit.js @@ -46,13 +46,13 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( years: ["year"], months: ["month"], weeks: ["week"], - days: ["day"], - hours: ["day"], - minutes: ["day"], - seconds: ["day"], - milliseconds: ["day"], - microseconds: ["day"], - nanoseconds: ["day"] + days: [], + hours: [], + minutes: [], + seconds: [], + milliseconds: [], + microseconds: [], + nanoseconds: [] } ); @@ -64,10 +64,10 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( two.subtract(one, { relativeTo }); }, { - years: ["year", "day"], - months: ["month", "day"], - weeks: ["week", "day"], - days: ["day", "day"], + years: ["year"], + months: ["month"], + weeks: ["week"], + days: [], hours: [], minutes: [], seconds: [], diff --git a/test/built-ins/Temporal/Duration/prototype/subtract/nanoseconds-to-days-loop-indefinitely-1.js b/test/built-ins/Temporal/Duration/prototype/subtract/nanoseconds-to-days-loop-indefinitely-1.js deleted file mode 100644 index 240be973f0..0000000000 --- a/test/built-ins/Temporal/Duration/prototype/subtract/nanoseconds-to-days-loop-indefinitely-1.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2022 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: > - NanosecondsToDays can loop arbitrarily long, performing observable operations each iteration. -info: | - NanosecondsToDays ( nanoseconds, relativeTo ) - - ... - 15. If sign is 1, then - a. Repeat, while days > 0 and intermediateNs > endNs, - i. Set days to days - 1. - ii. Set intermediateNs to ℝ(? AddZonedDateTime(ℤ(startNs), relativeTo.[[TimeZone]], - relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0, 0, 0, 0)). - ... -includes: [temporalHelpers.js] -features: [Temporal] ----*/ - -const calls = []; -const duration = Temporal.Duration.from({ days: 1 }); -const other = Temporal.Duration.from({ hours: 1 }); - -function createRelativeTo(count) { - const tz = new Temporal.TimeZone("UTC"); - // Record calls in calls[] - TemporalHelpers.observeMethod(calls, tz, "getPossibleInstantsFor"); - const cal = new Temporal.Calendar("iso8601"); - // Return _count_ days for the second call to dateUntil, behaving normally after - TemporalHelpers.substituteMethod(cal, "dateUntil", [ - TemporalHelpers.SUBSTITUTE_SKIP, - Temporal.Duration.from({ days: count }), - ]); - return new Temporal.ZonedDateTime(0n, tz, cal); -} - -let zdt = createRelativeTo(200); -calls.splice(0); // Reset calls list after ZonedDateTime construction -duration.subtract(other, { - relativeTo: zdt, -}); -assert.sameValue( - calls.length, - 200 + 2, - "Expected duration.subtract to call getPossibleInstantsFor correct number of times" -); - -zdt = createRelativeTo(300); -calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction -duration.subtract(other, { - relativeTo: zdt, -}); -assert.sameValue( - calls.length, - 300 + 2, - "Expected duration.subtract to call getPossibleInstantsFor correct number of times" -); diff --git a/test/built-ins/Temporal/Duration/prototype/subtract/nanoseconds-to-days-loop-indefinitely-2.js b/test/built-ins/Temporal/Duration/prototype/subtract/nanoseconds-to-days-loop-indefinitely.js similarity index 100% rename from test/built-ins/Temporal/Duration/prototype/subtract/nanoseconds-to-days-loop-indefinitely-2.js rename to test/built-ins/Temporal/Duration/prototype/subtract/nanoseconds-to-days-loop-indefinitely.js diff --git a/test/built-ins/Temporal/Duration/prototype/subtract/order-of-operations.js b/test/built-ins/Temporal/Duration/prototype/subtract/order-of-operations.js index 1653736102..3c421fff54 100644 --- a/test/built-ins/Temporal/Duration/prototype/subtract/order-of-operations.js +++ b/test/built-ins/Temporal/Duration/prototype/subtract/order-of-operations.js @@ -229,9 +229,6 @@ const expectedOpsForPlainRelativeToNoCalendarOperations = [ // InterpretTemporalDateTimeFields "get options.relativeTo.calendar.dateFromFields", "call options.relativeTo.calendar.dateFromFields", - // AddDuration - "get options.relativeTo.calendar.dateUntil", - "call options.relativeTo.calendar.dateUntil", ]; const noCalendarInstance = new Temporal.Duration(0, 0, 0, 4, 5, 6, 7, 987, 654, 321); @@ -355,9 +352,6 @@ const expectedOpsForZonedRelativeTo = expected.concat([ "call options.relativeTo.timeZone.getOffsetNanosecondsFor", "get options.relativeTo.timeZone.getOffsetNanosecondsFor", "call options.relativeTo.timeZone.getOffsetNanosecondsFor", - // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → DifferenceISODateTime - "get options.relativeTo.calendar.dateUntil", - "call options.relativeTo.calendar.dateUntil", // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 1 "get options.relativeTo.timeZone.getPossibleInstantsFor", "call options.relativeTo.timeZone.getPossibleInstantsFor", diff --git a/test/built-ins/Temporal/Duration/prototype/total/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/Duration/prototype/total/calendar-dateuntil-called-with-singular-largestunit.js index d9fb7ec05e..8a74793867 100644 --- a/test/built-ins/Temporal/Duration/prototype/total/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/Duration/prototype/total/calendar-dateuntil-called-with-singular-largestunit.js @@ -44,10 +44,9 @@ includes: [compareArray.js, temporalHelpers.js] features: [Temporal] ---*/ -// Check the paths that go through NanosecondsToDays: one call to dateUntil() in -// BalanceDuration and one in RoundDuration with largestUnit: "day" when the -// unit is "year", "month", "week", or "day", and one extra call with -// largestUnit: "year" in RoundDuration when the unit is "year". +// Check the paths that go through NanosecondsToDays: only one call with +// largestUnit: "year" in RoundDuration when the unit is "year". The others all +// have largestUnit: "day" so the difference is taken in ISO calendar space. const duration = new Temporal.Duration(0, 1, 1, 1, 1, 1, 1, 1, 1, 1); @@ -57,10 +56,10 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( duration.total({ unit, relativeTo }); }, { - years: ["day", "day", "year"], - months: ["day", "day"], - weeks: ["day", "day"], - days: ["day", "day"], + years: ["year"], + months: [], + weeks: [], + days: [], hours: [], minutes: [], seconds: [], @@ -74,7 +73,7 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( (calendar, unit) => { - const duration = new Temporal.Duration(5); + const duration = new Temporal.Duration(5, 1); const relativeTo = new Temporal.PlainDateTime(2000, 5, 2, 0, 0, 0, 0, 0, 0, calendar); duration.total({ unit, relativeTo }); }, diff --git a/test/built-ins/Temporal/Duration/prototype/total/nanoseconds-to-days-loop-indefinitely-1.js b/test/built-ins/Temporal/Duration/prototype/total/nanoseconds-to-days-loop-indefinitely-1.js deleted file mode 100644 index 912c21be8a..0000000000 --- a/test/built-ins/Temporal/Duration/prototype/total/nanoseconds-to-days-loop-indefinitely-1.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2022 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: > - NanosecondsToDays can loop arbitrarily long, performing observable operations each iteration. -info: | - NanosecondsToDays ( nanoseconds, relativeTo ) - - ... - 15. If sign is 1, then - a. Repeat, while days > 0 and intermediateNs > endNs, - i. Set days to days - 1. - ii. Set intermediateNs to ℝ(? AddZonedDateTime(ℤ(startNs), relativeTo.[[TimeZone]], - relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0, 0, 0, 0)). - ... -includes: [temporalHelpers.js] -features: [Temporal] ----*/ - -const calls = []; -const duration = Temporal.Duration.from({ days: 1 }); - -function createRelativeTo(count) { - const tz = new Temporal.TimeZone("UTC"); - // Record calls in calls[] - TemporalHelpers.observeMethod(calls, tz, "getPossibleInstantsFor"); - const cal = new Temporal.Calendar("iso8601"); - // Return _count_ days for the first call to dateUntil, behaving normally after - TemporalHelpers.substituteMethod(cal, "dateUntil", [ - Temporal.Duration.from({ days: count }), - ]); - return new Temporal.ZonedDateTime(0n, tz, cal); -} - -let zdt = createRelativeTo(200); -calls.splice(0); // Reset calls list after ZonedDateTime construction -duration.total({ - unit: "day", - relativeTo: zdt, -}); -assert.sameValue( - calls.length, - 200 + 3, - "Expected duration.total to call getPossibleInstantsFor correct number of times" -); - -zdt = createRelativeTo(300); -calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction -duration.total({ - unit: "day", - relativeTo: zdt, -}); -assert.sameValue( - calls.length, - 300 + 3, - "Expected duration.total to call getPossibleInstantsFor correct number of times" -); diff --git a/test/built-ins/Temporal/Duration/prototype/total/nanoseconds-to-days-loop-indefinitely-2.js b/test/built-ins/Temporal/Duration/prototype/total/nanoseconds-to-days-loop-indefinitely.js similarity index 100% rename from test/built-ins/Temporal/Duration/prototype/total/nanoseconds-to-days-loop-indefinitely-2.js rename to test/built-ins/Temporal/Duration/prototype/total/nanoseconds-to-days-loop-indefinitely.js diff --git a/test/built-ins/Temporal/Duration/prototype/total/order-of-operations.js b/test/built-ins/Temporal/Duration/prototype/total/order-of-operations.js index 8ab58638a7..8ad302108e 100644 --- a/test/built-ins/Temporal/Duration/prototype/total/order-of-operations.js +++ b/test/built-ins/Temporal/Duration/prototype/total/order-of-operations.js @@ -281,8 +281,6 @@ const expectedOpsForMinimalYearRoundingZoned = expectedOpsForZonedRelativeTo.con "call options.relativeTo.timeZone.getOffsetNanosecondsFor", "get options.relativeTo.timeZone.getOffsetNanosecondsFor", // 11. GetPlainDateTimeFor "call options.relativeTo.timeZone.getOffsetNanosecondsFor", - "get options.relativeTo.calendar.dateUntil", // 12. DifferenceISODateTime - "call options.relativeTo.calendar.dateUntil", // BalancePossiblyInfiniteDuration → NanosecondsToDays → AddDaysToZonedDateTime "get options.relativeTo.timeZone.getPossibleInstantsFor", "call options.relativeTo.timeZone.getPossibleInstantsFor", @@ -328,8 +326,6 @@ const expectedOpsForYearRoundingZoned = expectedOpsForZonedRelativeTo.concat([ "call options.relativeTo.timeZone.getOffsetNanosecondsFor", "get options.relativeTo.timeZone.getOffsetNanosecondsFor", // 11. GetPlainDateTimeFor "call options.relativeTo.timeZone.getOffsetNanosecondsFor", - "get options.relativeTo.calendar.dateUntil", // 12. DifferenceISODateTime - "call options.relativeTo.calendar.dateUntil", // BalancePossiblyInfiniteTimeDurationRelative → NanosecondsToDays → AddDaysToZonedDateTime "get options.relativeTo.timeZone.getPossibleInstantsFor", "call options.relativeTo.timeZone.getPossibleInstantsFor", diff --git a/test/built-ins/Temporal/Duration/prototype/total/zero-day-length-2.js b/test/built-ins/Temporal/Duration/prototype/total/zero-day-length-2.js deleted file mode 100644 index 7d4d75205f..0000000000 --- a/test/built-ins/Temporal/Duration/prototype/total/zero-day-length-2.js +++ /dev/null @@ -1,53 +0,0 @@ -// 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: A malicious time zone resulting a day length of zero is handled correctly -info: | - Based on a test by André Bargull. - - RoundDuration step 6: - d. Let _result_ be ? NanosecondsToDays(_nanoseconds_, _intermediate_). - e. Set _days_ to _days_ + _result_.[[Days]] + _result_.[[Nanoseconds]] / _result_.[[DayLength]]. - - NanosecondsToDays steps 19-23: - 19. If _days_ < 0 and _sign_ = 1, throw a *RangeError* exception. - 20. If _days_ > 0 and _sign_ = -1, throw a *RangeError* exception. - 21. If _nanoseconds_ < 0, then - a. Assert: sign is -1. - 22. If _nanoseconds_ > 0 and _sign_ = -1, throw a *RangeError* exception. - 23. Assert: The inequality abs(_nanoseconds_) < abs(_dayLengthNs_) holds. -features: [Temporal] ----*/ - -const instance = new Temporal.Duration(0, 0, 0, 0, 24, 0, 0, 0, 0, 1); - -const tz = new class extends Temporal.TimeZone { - #getPossibleInstantsForCalls = 0; - - getPossibleInstantsFor(dt) { - this.#getPossibleInstantsForCalls++; - - if (this.#getPossibleInstantsForCalls <= 2) { - return [new Temporal.Instant(86400_000_000_000n + 2n)] - } - return super.getPossibleInstantsFor(dt); - } -}("UTC"); - -const cal = new class extends Temporal.Calendar { - #dateUntilCalls = 0; - - dateUntil(one, two, options) { - this.#dateUntilCalls++; - - if (this.#dateUntilCalls === 1) { - return new Temporal.Duration(0, 0, 0, -2); - } - return super.dateUntil(one, two, options); - } -}("iso8601"); - -const relativeTo = new Temporal.ZonedDateTime(0n, tz, cal); -assert.throws(RangeError, () => instance.total({ relativeTo, unit: "days" })); diff --git a/test/built-ins/Temporal/Duration/prototype/total/zero-day-length-1.js b/test/built-ins/Temporal/Duration/prototype/total/zero-day-length.js similarity index 100% rename from test/built-ins/Temporal/Duration/prototype/total/zero-day-length-1.js rename to test/built-ins/Temporal/Duration/prototype/total/zero-day-length.js diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js b/test/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js index 1c47820624..e7d05784ff 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js +++ b/test/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js @@ -13,5 +13,5 @@ features: [Temporal] const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); const instance = new Temporal.PlainDate(2000, 5, 2, calendar); const argument = new Temporal.PlainDate(2022, 6, 14, calendar); -instance.since(argument); +instance.since(argument, { largestUnit: "months" }); assert.sameValue(calendar.dateUntilCallCount, 1, "dateUntil should have been called on the calendar"); diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js index 1d52ad2046..8febb2b34e 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js @@ -22,6 +22,6 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( years: ["year"], months: ["month"], weeks: ["week"], - days: ["day"] + days: [] } ); diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/calendar-invalid-return.js b/test/built-ins/Temporal/PlainDate/prototype/since/calendar-invalid-return.js index 6ecd46d277..27c463b6f9 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/since/calendar-invalid-return.js +++ b/test/built-ins/Temporal/PlainDate/prototype/since/calendar-invalid-return.js @@ -32,5 +32,9 @@ const tests = [ ]; for (const [test, description = typeof test] of tests) { const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar(test)); - assert.throws(TypeError, () => plainDate.since("2022-06-20"), `Expected error with ${description}`); + assert.throws( + TypeError, + () => plainDate.since("2022-06-20", { largestUnit: "years" }), + `Expected error with ${description}` + ); } diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/custom.js b/test/built-ins/Temporal/PlainDate/prototype/since/custom.js index d768512f54..a59f4af781 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/since/custom.js +++ b/test/built-ins/Temporal/PlainDate/prototype/since/custom.js @@ -9,7 +9,7 @@ features: [Temporal] ---*/ const result = new Temporal.Duration(1, 3, 5, 7, 9); -const options = {}; +const options = { largestUnit: "years" }; let calls = 0; class CustomCalendar extends Temporal.Calendar { constructor() { @@ -20,7 +20,7 @@ class CustomCalendar extends Temporal.Calendar { assert.sameValue(args.length, 3, "Three arguments"); assert.sameValue(args[0], plainDate, "First argument"); assert.sameValue(args[1], other, "Second argument"); - assert.sameValue(args[2].largestUnit, "day", "Third argument: largestUnit"); + assert.sameValue(args[2].largestUnit, "year", "Third argument: largestUnit"); return result; } } diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js b/test/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js index 8eb8ca076f..3adeae51fd 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js +++ b/test/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js @@ -86,8 +86,8 @@ const instance = new Temporal.PlainDate(2000, 5, 2, ownCalendar); const otherDatePropertyBag = TemporalHelpers.propertyBagObserver(actual, { year: 2001, - month: 5, - monthCode: 'M05', + month: 6, + monthCode: "M06", day: 2, calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), }, "other"); @@ -107,8 +107,8 @@ function createOptionsObserver({ smallestUnit = "days", largestUnit = "auto", ro // clear any observable things that happened while constructing the objects actual.splice(0); -// basic order of observable operations, without rounding: -instance.since(otherDatePropertyBag, createOptionsObserver()); +// basic order of observable operations with calendar call, without rounding: +instance.since(otherDatePropertyBag, createOptionsObserver({ largestUnit: "years" })); assert.compareArray(actual, expected, "order of operations"); actual.splice(0); // clear @@ -138,6 +138,24 @@ instance.since(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "year assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); actual.splice(0); // clear +// code path through RoundDuration that rounds to the nearest year and skips a DateUntil call: +const otherDatePropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + "get this.calendar.dateAdd", // 7.c.i + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateAdd", // 7.y MoveRelativeDate +]); // (7.o not called because months and weeks == 0) +instance.since(otherDatePropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years and no excess months/weeks"); +actual.splice(0); // clear + // code path through RoundDuration that rounds to the nearest month: const expectedOpsForMonthRounding = expected.concat([ "get this.calendar.dateAdd", // 10.b diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js b/test/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js index 32f3812d6d..ad5c782d4f 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js +++ b/test/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js @@ -13,5 +13,5 @@ features: [Temporal] const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); const instance = new Temporal.PlainDate(2000, 5, 2, calendar); const argument = new Temporal.PlainDate(2022, 6, 14, calendar); -instance.until(argument); +instance.until(argument, { largestUnit: "months" }); assert.sameValue(calendar.dateUntilCallCount, 1, "dateUntil should have been called on the calendar"); diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js index 49cfdbbc71..f85e886ebe 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js @@ -22,6 +22,6 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( years: ["year"], months: ["month"], weeks: ["week"], - days: ["day"] + days: [] } ); diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/calendar-invalid-return.js b/test/built-ins/Temporal/PlainDate/prototype/until/calendar-invalid-return.js index 5e66a55532..a7f898c5de 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/until/calendar-invalid-return.js +++ b/test/built-ins/Temporal/PlainDate/prototype/until/calendar-invalid-return.js @@ -32,5 +32,8 @@ const tests = [ ]; for (const [test, description = typeof test] of tests) { const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar(test)); - assert.throws(TypeError, () => plainDate.until("2022-06-20"), `Expected error with ${description}`); + assert.throws( + TypeError, () => plainDate.until("2022-06-20", { largestUnit: "years" }), + `Expected error with ${description}` + ); } diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/custom.js b/test/built-ins/Temporal/PlainDate/prototype/until/custom.js index 1d332af5c6..d11dc68640 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/until/custom.js +++ b/test/built-ins/Temporal/PlainDate/prototype/until/custom.js @@ -9,7 +9,7 @@ features: [Temporal] ---*/ const result = new Temporal.Duration(1, 3, 5, 7, 9); -const options = {}; +const options = { largestUnit: "years" }; let calls = 0; class CustomCalendar extends Temporal.Calendar { constructor() { @@ -20,7 +20,7 @@ class CustomCalendar extends Temporal.Calendar { assert.sameValue(args.length, 3, "Three arguments"); assert.sameValue(args[0], plainDate, "First argument"); assert.sameValue(args[1], other, "Second argument"); - assert.sameValue(args[2].largestUnit, "day", "Third argument: largestUnit"); + assert.sameValue(args[2].largestUnit, "year", "Third argument: largestUnit"); return result; } } diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js b/test/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js index 0cf68208bb..9a5b27fee3 100644 --- a/test/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js +++ b/test/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js @@ -86,8 +86,8 @@ const instance = new Temporal.PlainDate(2000, 5, 2, ownCalendar); const otherDatePropertyBag = TemporalHelpers.propertyBagObserver(actual, { year: 2001, - month: 5, - monthCode: "M05", + month: 6, + monthCode: "M06", day: 2, calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), }, "other"); @@ -107,8 +107,8 @@ function createOptionsObserver({ smallestUnit = "days", largestUnit = "auto", ro // clear any observable things that happened while constructing the objects actual.splice(0); -// basic order of observable operations, without rounding: -instance.until(otherDatePropertyBag, createOptionsObserver()); +// basic order of observable operations with calendar call, without rounding: +instance.until(otherDatePropertyBag, createOptionsObserver({ largestUnit: "years" })); assert.compareArray(actual, expected, "order of operations"); actual.splice(0); // clear @@ -139,6 +139,24 @@ instance.until(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "year assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); actual.splice(0); // clear +// code path through RoundDuration that rounds to the nearest year and skips a DateUntil call: +const otherDatePropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + "get this.calendar.dateAdd", // 7.c.i + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateAdd", // 7.y MoveRelativeDate +]); // (7.o not called because months and weeks == 0) +instance.until(otherDatePropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years and no excess months/weeks"); +actual.splice(0); // clear + // code path through RoundDuration that rounds to the nearest month: const expectedOpsForMonthRounding = expected.concat([ "get this.calendar.dateAdd", // 10.b diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/since/balance-infinite-nanoseconds-duration.js b/test/built-ins/Temporal/PlainDateTime/prototype/since/balance-infinite-nanoseconds-duration.js deleted file mode 100644 index 236cc9fb7a..0000000000 --- a/test/built-ins/Temporal/PlainDateTime/prototype/since/balance-infinite-nanoseconds-duration.js +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2022 André Bargull. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -esid: sec-temporal.plaindatetime.prototype.since -description: > - BalanceDuration throws when the result duration is invalid. -info: | - DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, - y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2, - calendar, largestUnit, options ) - - ... - 12. Let dateDifference be ? CalendarDateUntil(calendar, date1, date2, untilOptions). - 13. Let balanceResult be ? BalanceDuration(dateDifference.[[Days]], timeDifference.[[Hours]], - timeDifference.[[Minutes]], timeDifference.[[Seconds]], timeDifference.[[Milliseconds]], - timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]], largestUnit). - ... - - BalanceDuration ( days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, - largestUnit [ , relativeTo ] ) - - ... - 3. Else, - a. Set nanoseconds to ! TotalDurationNanoseconds(days, hours, minutes, seconds, milliseconds, - microseconds, nanoseconds, 0). - ... - 15. Return ? CreateTimeDurationRecord(days, hours × sign, minutes × sign, seconds × sign, - milliseconds × sign, microseconds × sign, nanoseconds × sign). -features: [Temporal] ----*/ - -var cal = new class extends Temporal.Calendar { - dateUntil(date1, date2, options) { - return Temporal.Duration.from({days: Number.MAX_VALUE}); - } -}("iso8601"); - -var dt1 = new Temporal.PlainDateTime(1970, 1, 1, 0, 0, 0, 0, 0, 0, cal); -var dt2 = new Temporal.PlainDateTime(1970, 1, 2, 0, 0, 0, 0, 0, 0, cal); -var options = {largestUnit: "nanoseconds"}; - -assert.throws(RangeError, () => dt1.since(dt2, options)); -assert.throws(RangeError, () => dt2.since(dt1, options)); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js b/test/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js index b36cab23ac..c4cc4df467 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js @@ -13,5 +13,5 @@ features: [Temporal] const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); const argument = new Temporal.PlainDateTime(2022, 6, 14, 18, 21, 36, 660, 690, 387, calendar); -instance.since(argument); +instance.since(argument, { largestUnit: "months" }); assert.sameValue(calendar.dateUntilCallCount, 1, "dateUntil should have been called on the calendar"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js index b6f71c759d..0f2b56f9af 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js @@ -25,12 +25,12 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( years: ["year"], months: ["month"], weeks: ["week"], - days: ["day"], - hours: ["day"], - minutes: ["day"], - seconds: ["day"], - milliseconds: ["day"], - microseconds: ["day"], - nanoseconds: ["day"] + days: [], + hours: [], + minutes: [], + seconds: [], + milliseconds: [], + microseconds: [], + nanoseconds: [] } ); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js b/test/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js index 13899ff959..ced1b1d57e 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js @@ -131,8 +131,8 @@ function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "au // clear any observable things that happened while constructing the objects actual.splice(0); -// basic order of observable operations, without rounding: -instance.since(otherDateTimePropertyBag, createOptionsObserver()); +// basic order of observable operations with calendar call, without rounding: +instance.since(otherDateTimePropertyBag, createOptionsObserver({ largestUnit: "years" })); assert.compareArray(actual, expected, "order of operations"); actual.splice(0); // clear @@ -168,6 +168,30 @@ instance.since(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: " assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); actual.splice(0); // clear +// code path through RoundDuration that rounds to the nearest year and skips a DateUntil call: +const otherDatePropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + hour: 12, + minute: 34, + second: 56, + millisecond: 987, + microsecond: 654, + nanosecond: 321, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + "get this.calendar.dateAdd", // 7.c.i + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateAdd", // 7.y MoveRelativeDate +]); // (7.o not called because months and weeks == 0) +instance.until(otherDatePropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years and no excess months/weeks"); +actual.splice(0); // clear + // code path through RoundDuration that rounds to the nearest month: const expectedOpsForMonthRounding = expected.concat([ "get this.calendar.dateAdd", // 10.b diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/until/balance-infinite-nanoseconds-duration.js b/test/built-ins/Temporal/PlainDateTime/prototype/until/balance-infinite-nanoseconds-duration.js deleted file mode 100644 index 153c2324fd..0000000000 --- a/test/built-ins/Temporal/PlainDateTime/prototype/until/balance-infinite-nanoseconds-duration.js +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2022 André Bargull. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -esid: sec-temporal.plaindatetime.prototype.since -description: > - BalanceDuration throws when the result duration is invalid. -info: | - DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, - y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2, - calendar, largestUnit, options ) - - ... - 12. Let dateDifference be ? CalendarDateUntil(calendar, date1, date2, untilOptions). - 13. Let balanceResult be ? BalanceDuration(dateDifference.[[Days]], timeDifference.[[Hours]], - timeDifference.[[Minutes]], timeDifference.[[Seconds]], timeDifference.[[Milliseconds]], - timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]], largestUnit). - ... - - BalanceDuration ( days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, - largestUnit [ , relativeTo ] ) - - ... - 3. Else, - a. Set nanoseconds to ! TotalDurationNanoseconds(days, hours, minutes, seconds, milliseconds, - microseconds, nanoseconds, 0). - ... - 15. Return ? CreateTimeDurationRecord(days, hours × sign, minutes × sign, seconds × sign, - milliseconds × sign, microseconds × sign, nanoseconds × sign). -features: [Temporal] ----*/ - -var cal = new class extends Temporal.Calendar { - dateUntil(date1, date2, options) { - return Temporal.Duration.from({days: Number.MAX_VALUE}); - } -}("iso8601"); - -var dt1 = new Temporal.PlainDateTime(1970, 1, 1, 0, 0, 0, 0, 0, 0, cal); -var dt2 = new Temporal.PlainDateTime(1970, 1, 2, 0, 0, 0, 0, 0, 0, cal); -var options = {largestUnit: "nanoseconds"}; - -assert.throws(RangeError, () => dt1.until(dt2, options)); -assert.throws(RangeError, () => dt2.until(dt1, options)); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js b/test/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js index a83d413dee..111ba10c35 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js @@ -13,5 +13,5 @@ features: [Temporal] const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); const argument = new Temporal.PlainDateTime(2022, 6, 14, 18, 21, 36, 660, 690, 387, calendar); -instance.until(argument); +instance.until(argument, { largestUnit: "months" }); assert.sameValue(calendar.dateUntilCallCount, 1, "dateUntil should have been called on the calendar"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js index c3e0447a15..5e444caf38 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js @@ -25,12 +25,12 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( years: ["year"], months: ["month"], weeks: ["week"], - days: ["day"], - hours: ["day"], - minutes: ["day"], - seconds: ["day"], - milliseconds: ["day"], - microseconds: ["day"], - nanoseconds: ["day"] + days: [], + hours: [], + minutes: [], + seconds: [], + milliseconds: [], + microseconds: [], + nanoseconds: [] } ); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js b/test/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js index 7370f65bfc..a15ce67156 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js @@ -131,8 +131,8 @@ function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "au // clear any observable things that happened while constructing the objects actual.splice(0); -// basic order of observable operations, without rounding: -instance.until(otherDateTimePropertyBag, createOptionsObserver()); +// basic order of observable operations with calendar call, without rounding: +instance.until(otherDateTimePropertyBag, createOptionsObserver({ largestUnit: "years" })); assert.compareArray(actual, expected, "order of operations"); actual.splice(0); // clear @@ -168,6 +168,30 @@ instance.until(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: " assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); actual.splice(0); // clear +// code path through RoundDuration that rounds to the nearest year and skips a DateUntil call: +const otherDatePropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + hour: 12, + minute: 34, + second: 56, + millisecond: 987, + microsecond: 654, + nanosecond: 321, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + "get this.calendar.dateAdd", // 7.c.i + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateAdd", // 7.y MoveRelativeDate +]); // (7.o not called because months and weeks == 0) +instance.until(otherDatePropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years and no excess months/weeks"); +actual.splice(0); // clear + // code path through RoundDuration that rounds to the nearest month: const expectedOpsForMonthRounding = expected.concat([ "get this.calendar.dateAdd", // 10.b diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js b/test/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js index 315aaecd95..d281177251 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js @@ -100,8 +100,8 @@ const instance = new Temporal.PlainYearMonth(2000, 5, ownCalendar, 1); const otherYearMonthPropertyBag = TemporalHelpers.propertyBagObserver(actual, { year: 2001, - month: 5, - monthCode: "M05", + month: 6, + monthCode: "M06", calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), }, "other"); @@ -150,6 +150,23 @@ instance.since(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); actual.splice(0); // clear +// code path through RoundDuration that rounds to the nearest year and skips a DateUntil call +const otherYearMonthPropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + "get this.calendar.dateAdd", // 7.c.i + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateAdd", // 7.y MoveRelativeDate +]); // (7.o not called because months and weeks == 0) +instance.since(otherYearMonthPropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years"); +actual.splice(0); // clear + // code path through RoundDuration that rounds to the nearest month: const expectedOpsForMonthRounding = expected.concat([ "get this.calendar.dateAdd", // 10.b diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js b/test/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js index fca9e43e6d..5a72f1e7db 100644 --- a/test/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js @@ -100,8 +100,8 @@ const instance = new Temporal.PlainYearMonth(2000, 5, ownCalendar, 1); const otherYearMonthPropertyBag = TemporalHelpers.propertyBagObserver(actual, { year: 2001, - month: 5, - monthCode: "M05", + month: 6, + monthCode: "M06", calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), }, "other"); @@ -150,6 +150,23 @@ instance.until(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); actual.splice(0); // clear +// code path through RoundDuration that rounds to the nearest year and skips a DateUntil call +const otherYearMonthPropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + "get this.calendar.dateAdd", // 7.c.i + "call this.calendar.dateAdd", // 7.e + "call this.calendar.dateAdd", // 7.g + "call this.calendar.dateAdd", // 7.y MoveRelativeDate +]); // (7.o not called because months and weeks == 0) +instance.until(otherYearMonthPropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years"); +actual.splice(0); // clear + // code path through RoundDuration that rounds to the nearest month: const expectedOpsForMonthRounding = expected.concat([ "get this.calendar.dateAdd", // 10.b diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js index 24f34ef3e8..aca6c7bf7a 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js @@ -14,4 +14,4 @@ const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); const instance = new Temporal.ZonedDateTime(0n, "UTC", calendar); const argument = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", calendar); instance.since(argument, { largestUnit: "year" }); -assert.sameValue(calendar.dateUntilCallCount, 2, "dateUntil should have been called on the calendar"); +assert.sameValue(calendar.dateUntilCallCount, 1, "dateUntil should have been called on the calendar"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js index 6365c6224c..6f6e4eaf08 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js @@ -55,10 +55,10 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( later.since(earlier, { largestUnit }); }, { - years: ["year", "day"], - months: ["month", "day"], - weeks: ["week", "day"], - days: ["day", "day"], + years: ["year"], + months: ["month"], + weeks: ["week"], + days: [], hours: [], minutes: [], seconds: [], @@ -72,15 +72,15 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( (calendar, largestUnit) => { - const earlier = new Temporal.ZonedDateTime(0n, "UTC", calendar); + const earlier = new Temporal.ZonedDateTime(-31536000_000_000_000n /* = -365 days */, "UTC", calendar); const later = new Temporal.ZonedDateTime(86_399_999_999_999n, "UTC", calendar); later.since(earlier, { largestUnit, roundingIncrement: 2, roundingMode: 'ceil' }); }, { - years: ["year", "day", "day", "day"], - months: ["month", "day", "day", "day"], - weeks: ["week", "day", "day", "day"], - days: ["day", "day", "day", "day"], + years: ["year", "year"], + months: ["month", "month"], + weeks: ["week", "week"], + days: [], hours: [], minutes: [], seconds: [], @@ -100,10 +100,10 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( later.since(earlier, { smallestUnit }); }, { - years: ["year", "day", "day", "year"], - months: ["month", "day", "day"], - weeks: ["week", "day", "day"], - days: ["day", "day", "day"], + years: ["year", "year"], + months: ["month"], + weeks: ["week"], + days: [], hours: [], minutes: [], seconds: [], diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/nanoseconds-to-days-loop-indefinitely-1.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/nanoseconds-to-days-loop-indefinitely-1.js deleted file mode 100644 index 1bb9a0bd95..0000000000 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/since/nanoseconds-to-days-loop-indefinitely-1.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2022 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: > - NanosecondsToDays can loop arbitrarily long, performing observable operations each iteration. -info: | - NanosecondsToDays ( nanoseconds, relativeTo ) - - ... - 15. If sign is 1, then - a. Repeat, while days > 0 and intermediateNs > endNs, - i. Set days to days - 1. - ii. Set intermediateNs to ℝ(? AddZonedDateTime(ℤ(startNs), relativeTo.[[TimeZone]], - relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0, 0, 0, 0)). - ... -includes: [temporalHelpers.js] -features: [Temporal] ----*/ - -const calls = []; -const dayLengthNs = 86400000000000n; -const other = new Temporal.ZonedDateTime(dayLengthNs, "UTC", "iso8601"); - -function createRelativeTo(count) { - const tz = new Temporal.TimeZone("UTC"); - // Record calls in calls[] - TemporalHelpers.observeMethod(calls, tz, "getPossibleInstantsFor"); - const cal = new Temporal.Calendar("iso8601"); - // Return _count_ days for the second call to dateUntil, behaving normally after - TemporalHelpers.substituteMethod(cal, "dateUntil", [ - TemporalHelpers.SUBSTITUTE_SKIP, - Temporal.Duration.from({ days: count }), - ]); - return new Temporal.ZonedDateTime(0n, tz, cal); -} - -let zdt = createRelativeTo(200); -calls.splice(0); // Reset calls list after ZonedDateTime construction -zdt.since(other, { - largestUnit: "day", -}); -assert.sameValue( - calls.length, - 200 + 1, - "Expected ZonedDateTime.since to call getPossibleInstantsFor correct number of times" -); - -zdt = createRelativeTo(300); -calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction -zdt.since(other, { - largestUnit: "day", -}); -assert.sameValue( - calls.length, - 300 + 1, - "Expected ZonedDateTime.since to call getPossibleInstantsFor correct number of times" -); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/nanoseconds-to-days-loop-indefinitely-2.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/nanoseconds-to-days-loop-indefinitely.js similarity index 100% rename from test/built-ins/Temporal/ZonedDateTime/prototype/since/nanoseconds-to-days-loop-indefinitely-2.js rename to test/built-ins/Temporal/ZonedDateTime/prototype/since/nanoseconds-to-days-loop-indefinitely.js diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js index 889272a97f..9e067ee70a 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js @@ -108,6 +108,18 @@ const ownTimeZone = TemporalHelpers.timeZoneObserver(actual, "this.timeZone"); const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); const instance = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, ownTimeZone, ownCalendar); +const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone(); +const ownDstTimeZone = TemporalHelpers.timeZoneObserver(actual, "this.timeZone", { + getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor, + getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor, +}); +const otherDstTimeZone = TemporalHelpers.timeZoneObserver(actual, "other.timeZone", { + getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor, + getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor, +}); +/* 2000-10-29T01:30-07:00, in the middle of the first repeated hour: */ +const fallBackInstance = new Temporal.ZonedDateTime(972808200_000_000_000n, ownDstTimeZone, ownCalendar); + const otherDateTimePropertyBag = TemporalHelpers.propertyBagObserver(actual, { year: 2004, month: 5, @@ -169,6 +181,139 @@ assert.compareArray(actual, expected.concat([ ]), "order of operations with identical dates and largestUnit a calendar unit"); actual.splice(0); // clear +// two ZonedDateTimes that denote the same wall-clock time in the time zone can +// avoid calling some calendar methods: +const fallBackPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 10, + monthCode: "M10", + day: 29, + hour: 1, + minute: 30, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + offset: "-08:00", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), + timeZone: otherDstTimeZone, +}, "other"); +fallBackInstance.since(fallBackPropertyBag, createOptionsObserver({ largestUnit: "days" })); +assert.compareArray(actual, [ + // ToTemporalZonedDateTime + "get other.calendar", + "has other.calendar.dateAdd", + "has other.calendar.dateFromFields", + "has other.calendar.dateUntil", + "has other.calendar.day", + "has other.calendar.dayOfWeek", + "has other.calendar.dayOfYear", + "has other.calendar.daysInMonth", + "has other.calendar.daysInWeek", + "has other.calendar.daysInYear", + "has other.calendar.fields", + "has other.calendar.id", + "has other.calendar.inLeapYear", + "has other.calendar.mergeFields", + "has other.calendar.month", + "has other.calendar.monthCode", + "has other.calendar.monthDayFromFields", + "has other.calendar.monthsInYear", + "has other.calendar.weekOfYear", + "has other.calendar.year", + "has other.calendar.yearMonthFromFields", + "has other.calendar.yearOfWeek", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "get other.hour", + "get other.hour.valueOf", + "call other.hour.valueOf", + "get other.microsecond", + "get other.microsecond.valueOf", + "call other.microsecond.valueOf", + "get other.millisecond", + "get other.millisecond.valueOf", + "call other.millisecond.valueOf", + "get other.minute", + "get other.minute.valueOf", + "call other.minute.valueOf", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.nanosecond", + "get other.nanosecond.valueOf", + "call other.nanosecond.valueOf", + "get other.offset", + "get other.offset.toString", + "call other.offset.toString", + "get other.second", + "get other.second.valueOf", + "call other.second.valueOf", + "get other.timeZone", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "has other.timeZone.getOffsetNanosecondsFor", + "has other.timeZone.getPossibleInstantsFor", + "has other.timeZone.id", + "get other.calendar.dateFromFields", + "call other.calendar.dateFromFields", + "get other.timeZone.getPossibleInstantsFor", + "call other.timeZone.getPossibleInstantsFor", + "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", + "get other.calendar.id", + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.roundingIncrement", + "get options.roundingIncrement", + "getOwnPropertyDescriptor options.roundingMode", + "get options.roundingMode", + "getOwnPropertyDescriptor options.largestUnit", + "get options.largestUnit", + "getOwnPropertyDescriptor options.smallestUnit", + "get options.smallestUnit", + "getOwnPropertyDescriptor options.additional", + "get options.additional", + // GetDifferenceSettings + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + // TimeZoneEquals + "get this.timeZone.id", + "get other.timeZone.id", + // DifferenceZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // NanosecondsToDays + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // NanosecondsToDays → AddDaysToZonedDateTime + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", +], "order of operations with identical wall-clock times and largestUnit a calendar unit"); +actual.splice(0); // clear + // Making largestUnit a calendar unit adds the following observable operations: const expectedOpsForCalendarDifference = [ // TimeZoneEquals @@ -192,9 +337,6 @@ const expectedOpsForCalendarDifference = [ "call this.timeZone.getOffsetNanosecondsFor", "get this.timeZone.getOffsetNanosecondsFor", "call this.timeZone.getOffsetNanosecondsFor", - // NanosecondsToDays → DifferenceISODateTime - "get this.calendar.dateUntil", - "call this.calendar.dateUntil", // NanosecondsToDays → AddDaysToZonedDateTime "get this.timeZone.getPossibleInstantsFor", "call this.timeZone.getPossibleInstantsFor", @@ -218,9 +360,6 @@ const expectedOpsForCalendarRounding = [ "call this.timeZone.getOffsetNanosecondsFor", "get this.timeZone.getOffsetNanosecondsFor", "call this.timeZone.getOffsetNanosecondsFor", - // RoundDuration → NanosecondsToDays → DifferenceISODateTime - "get this.calendar.dateUntil", - "call this.calendar.dateUntil", // RoundDuration → NanosecondsToDays → AddDaysToZonedDateTime "get this.timeZone.getPossibleInstantsFor", "call this.timeZone.getPossibleInstantsFor", diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js index da645b430b..adb200001c 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js @@ -14,4 +14,4 @@ const calendar = TemporalHelpers.calendarCheckOptionsPrototypePollution(); const instance = new Temporal.ZonedDateTime(0n, "UTC", calendar); const argument = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", calendar); instance.until(argument, { largestUnit: "year" }); -assert.sameValue(calendar.dateUntilCallCount, 2, "dateUntil should have been called on the calendar"); +assert.sameValue(calendar.dateUntilCallCount, 1, "dateUntil should have been called on the calendar"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js index c07900f71b..6842f08dcf 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js @@ -55,10 +55,10 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( earlier.until(later, { largestUnit }); }, { - years: ["year", "day"], - months: ["month", "day"], - weeks: ["week", "day"], - days: ["day", "day"], + years: ["year"], + months: ["month"], + weeks: ["week"], + days: [], hours: [], minutes: [], seconds: [], @@ -72,15 +72,15 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( (calendar, largestUnit) => { - const earlier = new Temporal.ZonedDateTime(0n, "UTC", calendar); + const earlier = new Temporal.ZonedDateTime(-31536000_000_000_000n /* = -365 days */, "UTC", calendar); const later = new Temporal.ZonedDateTime(86_399_999_999_999n, "UTC", calendar); earlier.until(later, { largestUnit, roundingIncrement: 2, roundingMode: 'ceil' }); }, { - years: ["year", "day", "day", "day"], - months: ["month", "day", "day", "day"], - weeks: ["week", "day", "day", "day"], - days: ["day", "day", "day", "day"], + years: ["year", "year"], + months: ["month", "month"], + weeks: ["week", "week"], + days: [], hours: [], minutes: [], seconds: [], @@ -100,10 +100,10 @@ TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( earlier.until(later, { smallestUnit }); }, { - years: ["year", "day", "day", "year"], - months: ["month", "day", "day"], - weeks: ["week", "day", "day"], - days: ["day", "day", "day"], + years: ["year", "year"], + months: ["month"], + weeks: ["week"], + days: [], hours: [], minutes: [], seconds: [], diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/nanoseconds-to-days-loop-indefinitely-1.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/nanoseconds-to-days-loop-indefinitely-1.js deleted file mode 100644 index fc2ef8e782..0000000000 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/until/nanoseconds-to-days-loop-indefinitely-1.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2022 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: > - NanosecondsToDays can loop arbitrarily long, performing observable operations each iteration. -info: | - NanosecondsToDays ( nanoseconds, relativeTo ) - - ... - 15. If sign is 1, then - a. Repeat, while days > 0 and intermediateNs > endNs, - i. Set days to days - 1. - ii. Set intermediateNs to ℝ(? AddZonedDateTime(ℤ(startNs), relativeTo.[[TimeZone]], - relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0, 0, 0, 0)). - ... -includes: [temporalHelpers.js] -features: [Temporal] ----*/ - -const calls = []; -const dayLengthNs = 86400000000000n; -const other = new Temporal.ZonedDateTime(dayLengthNs, "UTC", "iso8601"); - -function createRelativeTo(count) { - const tz = new Temporal.TimeZone("UTC"); - // Record calls in calls[] - TemporalHelpers.observeMethod(calls, tz, "getPossibleInstantsFor"); - const cal = new Temporal.Calendar("iso8601"); - // Return _count_ days for the second call to dateUntil, behaving normally after - TemporalHelpers.substituteMethod(cal, "dateUntil", [ - TemporalHelpers.SUBSTITUTE_SKIP, - Temporal.Duration.from({ days: count }), - ]); - return new Temporal.ZonedDateTime(0n, tz, cal); -} - -let zdt = createRelativeTo(200); -calls.splice(0); // Reset calls list after ZonedDateTime construction -zdt.until(other, { - largestUnit: "day", -}); -assert.sameValue( - calls.length, - 200 + 1, - "Expected ZonedDateTime.until to call getPossibleInstantsFor correct number of times" -); - -zdt = createRelativeTo(300); -calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction -zdt.until(other, { - largestUnit: "day", -}); -assert.sameValue( - calls.length, - 300 + 1, - "Expected ZonedDateTime.until to call getPossibleInstantsFor correct number of times" -); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/nanoseconds-to-days-loop-indefinitely-2.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/nanoseconds-to-days-loop-indefinitely.js similarity index 100% rename from test/built-ins/Temporal/ZonedDateTime/prototype/until/nanoseconds-to-days-loop-indefinitely-2.js rename to test/built-ins/Temporal/ZonedDateTime/prototype/until/nanoseconds-to-days-loop-indefinitely.js diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js index 173edb99da..a7ddb56da3 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js @@ -108,6 +108,18 @@ const ownTimeZone = TemporalHelpers.timeZoneObserver(actual, "this.timeZone"); const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); const instance = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, ownTimeZone, ownCalendar); +const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone(); +const ownDstTimeZone = TemporalHelpers.timeZoneObserver(actual, "this.timeZone", { + getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor, + getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor, +}); +const otherDstTimeZone = TemporalHelpers.timeZoneObserver(actual, "other.timeZone", { + getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor, + getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor, +}); +/* 2000-10-29T01:30-07:00, in the middle of the first repeated hour: */ +const fallBackInstance = new Temporal.ZonedDateTime(972808200_000_000_000n, ownDstTimeZone, ownCalendar); + const otherDateTimePropertyBag = TemporalHelpers.propertyBagObserver(actual, { year: 2004, month: 5, @@ -169,6 +181,139 @@ assert.compareArray(actual, expected.concat([ ]), "order of operations with identical dates and largestUnit a calendar unit"); actual.splice(0); // clear +// two ZonedDateTimes that denote the same wall-clock time in the time zone can +// avoid calling some calendar methods: +const fallBackPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 10, + monthCode: "M10", + day: 29, + hour: 1, + minute: 30, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + offset: "-08:00", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), + timeZone: otherDstTimeZone, +}, "other"); +fallBackInstance.until(fallBackPropertyBag, createOptionsObserver({ largestUnit: "days" })); +assert.compareArray(actual, [ + // ToTemporalZonedDateTime + "get other.calendar", + "has other.calendar.dateAdd", + "has other.calendar.dateFromFields", + "has other.calendar.dateUntil", + "has other.calendar.day", + "has other.calendar.dayOfWeek", + "has other.calendar.dayOfYear", + "has other.calendar.daysInMonth", + "has other.calendar.daysInWeek", + "has other.calendar.daysInYear", + "has other.calendar.fields", + "has other.calendar.id", + "has other.calendar.inLeapYear", + "has other.calendar.mergeFields", + "has other.calendar.month", + "has other.calendar.monthCode", + "has other.calendar.monthDayFromFields", + "has other.calendar.monthsInYear", + "has other.calendar.weekOfYear", + "has other.calendar.year", + "has other.calendar.yearMonthFromFields", + "has other.calendar.yearOfWeek", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "get other.hour", + "get other.hour.valueOf", + "call other.hour.valueOf", + "get other.microsecond", + "get other.microsecond.valueOf", + "call other.microsecond.valueOf", + "get other.millisecond", + "get other.millisecond.valueOf", + "call other.millisecond.valueOf", + "get other.minute", + "get other.minute.valueOf", + "call other.minute.valueOf", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.nanosecond", + "get other.nanosecond.valueOf", + "call other.nanosecond.valueOf", + "get other.offset", + "get other.offset.toString", + "call other.offset.toString", + "get other.second", + "get other.second.valueOf", + "call other.second.valueOf", + "get other.timeZone", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "has other.timeZone.getOffsetNanosecondsFor", + "has other.timeZone.getPossibleInstantsFor", + "has other.timeZone.id", + "get other.calendar.dateFromFields", + "call other.calendar.dateFromFields", + "get other.timeZone.getPossibleInstantsFor", + "call other.timeZone.getPossibleInstantsFor", + "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", + "get other.calendar.id", + // CopyDataProperties + "ownKeys options", + "getOwnPropertyDescriptor options.roundingIncrement", + "get options.roundingIncrement", + "getOwnPropertyDescriptor options.roundingMode", + "get options.roundingMode", + "getOwnPropertyDescriptor options.largestUnit", + "get options.largestUnit", + "getOwnPropertyDescriptor options.smallestUnit", + "get options.smallestUnit", + "getOwnPropertyDescriptor options.additional", + "get options.additional", + // GetDifferenceSettings + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + // TimeZoneEquals + "get this.timeZone.id", + "get other.timeZone.id", + // DifferenceZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // NanosecondsToDays + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // NanosecondsToDays → AddDaysToZonedDateTime + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", +], "order of operations with identical wall-clock times and largestUnit a calendar unit"); +actual.splice(0); // clear + // Making largestUnit a calendar unit adds the following observable operations: const expectedOpsForCalendarDifference = [ // TimeZoneEquals @@ -192,9 +337,6 @@ const expectedOpsForCalendarDifference = [ "call this.timeZone.getOffsetNanosecondsFor", "get this.timeZone.getOffsetNanosecondsFor", "call this.timeZone.getOffsetNanosecondsFor", - // NanosecondsToDays → DifferenceISODateTime - "get this.calendar.dateUntil", - "call this.calendar.dateUntil", // NanosecondsToDays → AddDaysToZonedDateTime "get this.timeZone.getPossibleInstantsFor", "call this.timeZone.getPossibleInstantsFor", @@ -218,9 +360,6 @@ const expectedOpsForCalendarRounding = [ "call this.timeZone.getOffsetNanosecondsFor", "get this.timeZone.getOffsetNanosecondsFor", "call this.timeZone.getOffsetNanosecondsFor", - // RoundDuration → NanosecondsToDays → DifferenceISODateTime - "get this.calendar.dateUntil", - "call this.calendar.dateUntil", // RoundDuration → NanosecondsToDays → AddDaysToZonedDateTime "get this.timeZone.getPossibleInstantsFor", "call this.timeZone.getPossibleInstantsFor",