Skip to content

Commit

Permalink
Temporal: Tests for correct intermediate value in ZonedDateTime diffe…
Browse files Browse the repository at this point in the history
…rence/rounding

These test cases ensure that DST disambiguation does not take place on
intermediate values that are not the start or the end of the calculation.

Note that NormalizedTimeDurationToDays is no longer called inside
Temporal.Duration.prototype.add/subtract, so a few tests can be deleted.

Other tests need to be adjusted because NormalizedTimeDurationToDays is
no longer called inside Temporal.ZonedDateTime.prototype.since/until via
DifferenceZonedDateTime, although it is still called as part of rounding.

In addition, new tests for the now-fixed edge case are added.

See tc39/proposal-temporal#2760
  • Loading branch information
ptomato committed Feb 21, 2024
1 parent 0fd1675 commit 831a285
Show file tree
Hide file tree
Showing 20 changed files with 325 additions and 430 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2024 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: >
Throws a RangeError when custom calendar method returns inconsistent result
info: |
DifferenceZonedDateTime ( ... )
8. Repeat 2 times:
...
h. Set _dayCorrection_ to _dayCorrection_ + 1.
9. NOTE: This step is only reached when custom calendar or time zone methods
return inconsistent values.
10. Throw a *RangeError* exception.
includes: [temporalHelpers.js]
features: [Temporal]
---*/

// Based on a test case by André Bargull

const cal = new (class extends Temporal.Calendar {
dateUntil(one, two, options) {
return super.dateUntil(one, two, options).negated();
}
})("iso8601");

const duration1 = new Temporal.Duration(0, 0, /* weeks = */ 7);
const duration2 = new Temporal.Duration(0, 0, 0, /* days = */ 1);

const relativeTo = new Temporal.ZonedDateTime(0n, "UTC", cal);

assert.throws(RangeError, () => duration1.add(duration2, { relativeTo }),
"Calendar calculation where more than one day correction is needed should cause RangeError");

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -343,13 +343,6 @@ const expectedOpsForZonedRelativeTo = expected.concat([
// AddDuration → DifferenceZonedDateTime → AddZonedDateTime
"call options.relativeTo.calendar.dateAdd",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 1
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 2
"call options.relativeTo.timeZone.getPossibleInstantsFor",
]);

const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (C) 2024 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: >
Rounding the resulting duration takes the time zone's UTC offset shifts
into account
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const timeZone = TemporalHelpers.springForwardFallBackTimeZone();

// Based on a test case by Adam Shaw

{
// Date part of duration lands on skipped DST hour, causing disambiguation
const duration = new Temporal.Duration(0, 1, 0, 15, 12);
const relativeTo = new Temporal.ZonedDateTime(
950868000_000_000_000n /* = 2000-02-18T10Z */,
timeZone); /* = 2000-02-18T02-08 in local time */

TemporalHelpers.assertDuration(duration.round({ smallestUnit: "months", relativeTo }),
0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
"1 month 15 days 12 hours should be exactly 1.5 months, which rounds up to 2 months");
TemporalHelpers.assertDuration(duration.round({ smallestUnit: "months", roundingMode: 'halfTrunc', relativeTo }),
0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
"1 month 15 days 12 hours should be exactly 1.5 months, which rounds down to 1 month");
}

{
// Month-only part of duration lands on skipped DST hour, should not cause
// disambiguation
const duration = new Temporal.Duration(0, 1, 0, 15);
const relativeTo = new Temporal.ZonedDateTime(
951991200_000_000_000n /* = 2000-03-02T10Z */,
timeZone); /* = 2000-03-02T02-08 in local time */

TemporalHelpers.assertDuration(duration.round({ smallestUnit: "months", relativeTo }),
0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
"1 month 15 days should be exactly 1.5 months, which rounds up to 2 months");
TemporalHelpers.assertDuration(duration.round({ smallestUnit: "months", roundingMode: 'halfTrunc', relativeTo }),
0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
"1 month 15 days should be exactly 1.5 months, which rounds down to 1 month");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2024 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: >
Throws a RangeError when custom calendar method returns inconsistent result
info: |
DifferenceZonedDateTime ( ... )
8. Repeat 2 times:
...
h. Set _dayCorrection_ to _dayCorrection_ + 1.
9. NOTE: This step is only reached when custom calendar or time zone methods
return inconsistent values.
10. Throw a *RangeError* exception.
includes: [temporalHelpers.js]
features: [Temporal]
---*/

// Based on a test case by André Bargull

const cal = new (class extends Temporal.Calendar {
dateUntil(one, two, options) {
return super.dateUntil(one, two, options).negated();
}
})("iso8601");

const duration1 = new Temporal.Duration(0, 0, /* weeks = */ 7);
const duration2 = new Temporal.Duration(0, 0, 0, /* days = */ -1);

const relativeTo = new Temporal.ZonedDateTime(0n, "UTC", cal);

assert.throws(RangeError, () => duration1.subtract(duration2, { relativeTo }),
"Calendar calculation where more than one day correction is needed should cause RangeError");

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -343,13 +343,6 @@ const expectedOpsForZonedRelativeTo = expected.concat([
// AddDuration → DifferenceZonedDateTime → AddZonedDateTime
"call options.relativeTo.calendar.dateAdd",
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
"call options.relativeTo.timeZone.getOffsetNanosecondsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 1
"call options.relativeTo.timeZone.getPossibleInstantsFor",
// AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 2
"call options.relativeTo.timeZone.getPossibleInstantsFor",
]);

const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, {
Expand Down
Loading

0 comments on commit 831a285

Please sign in to comment.