mirror of https://github.com/tc39/test262.git
Temporal: Limit day length calculations to safe integers
NormalizedTimeDurationToDays can no longer loop indefinitely, because at a certain point we will hit the upper bound of MAX_SAFE_INTEGER, so rename the test to reflect that it can loop an arbitrary but limited number of times. Add a test for the RangeError condition in NormalizedTimeDurationToDays when the time zone calculates a day length that is not a safe integer number of nanoseconds. While editing these tests, rename them to match the current name of the AO and make sure the step numbers are up to date. (Normally I wouldn't care so much about that, but these tests can be pretty confusing so it's good to be able to refer to the spec text.)
This commit is contained in:
parent
092337c8d0
commit
01ec9938bb
|
@ -4,18 +4,19 @@
|
|||
/*---
|
||||
esid: sec-temporal.duration.prototype.add
|
||||
description: >
|
||||
NanosecondsToDays can loop infinitely.
|
||||
NormalizedTimeDurationToDays can loop arbitrarily up to max safe integer
|
||||
info: |
|
||||
NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDatetime ] )
|
||||
...
|
||||
18. Repeat, while done is false,
|
||||
a. Let oneDayFartherNs be ℝ(? AddZonedDateTime(ℤ(intermediateNs), relativeTo.[[TimeZone]],
|
||||
relativeTo.[[Calendar]], 0, 0, 0, sign, 0, 0, 0, 0, 0, 0)).
|
||||
b. Set dayLengthNs to oneDayFartherNs - intermediateNs.
|
||||
c. If (nanoseconds - dayLengthNs) × sign ≥ 0, then
|
||||
i. Set nanoseconds to nanoseconds - dayLengthNs.
|
||||
ii. Set intermediateNs to oneDayFartherNs.
|
||||
21. Repeat, while done is false,
|
||||
a. Let oneDayFarther be ? AddDaysToZonedDateTime(relativeResult.[[Instant]],
|
||||
relativeResult.[[DateTime]], timeZoneRec, zonedRelativeTo.[[Calendar]], sign).
|
||||
b. Set dayLengthNs to NormalizedTimeDurationFromEpochNanosecondsDifference(oneDayFarther.[[EpochNanoseconds]],
|
||||
relativeResult.[[EpochNanoseconds]]).
|
||||
c. Let oneDayLess be ? SubtractNormalizedTimeDuration(norm, dayLengthNs).
|
||||
c. If NormalizedTimeDurationSign(oneDayLess) × sign ≥ 0, then
|
||||
i. Set norm to oneDayLess.
|
||||
ii. Set relativeResult to oneDayFarther.
|
||||
iii. Set days to days + sign.
|
||||
d. Else,
|
||||
i. Set done to true.
|
||||
|
@ -48,24 +49,27 @@ function createRelativeTo(count) {
|
|||
return new Temporal.ZonedDateTime(0n, timeZone);
|
||||
}
|
||||
|
||||
let zdt = createRelativeTo(200);
|
||||
let zdt = createRelativeTo(50);
|
||||
calls.splice(0); // Reset calls list after ZonedDateTime construction
|
||||
duration.add(duration, {
|
||||
relativeTo: zdt,
|
||||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
200 + 1,
|
||||
50 + 1,
|
||||
"Expected duration.add to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(300);
|
||||
zdt = createRelativeTo(100);
|
||||
calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction
|
||||
duration.add(duration, {
|
||||
relativeTo: zdt,
|
||||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
300 + 1,
|
||||
100 + 1,
|
||||
"Expected duration.add to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(107);
|
||||
assert.throws(RangeError, () => duration.add(duration, { relativeTo: zdt }), "107-2 days > 2⁵³ ns");
|
|
@ -3,13 +3,16 @@
|
|||
/*---
|
||||
esid: sec-temporal.duration.prototype.add
|
||||
description: >
|
||||
Called abstract operation NanosecondsToDays can throw three different RangeErrors when paired with a ZonedDateTime.
|
||||
Abstract operation NormalizedTimeDurationToDays can throw four different
|
||||
RangeErrors.
|
||||
info: |
|
||||
6.5.7 NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
19. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
20. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDateTime ] )
|
||||
22. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
23. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
22. If nanoseconds > 0 and sign = -1, throw a RangeError exception.
|
||||
25. If NormalizedTimeDurationSign(_norm_) = 1 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
28. If dayLength ≥ 2⁵³, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
@ -36,22 +39,22 @@ function timeZoneSubstituteValues(
|
|||
return tz;
|
||||
}
|
||||
|
||||
// NanosecondsToDays.19: days < 0 and sign = 1
|
||||
// Step 22: days < 0 and sign = 1
|
||||
let zdt = new Temporal.ZonedDateTime(
|
||||
-1n, // Set DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 9
|
||||
[epochInstant], // Returned for AddDuration step 10, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[epochInstant], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 15
|
||||
[epochInstant], // Returned in AddDuration step 16, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[epochInstant], // Returned in step 16, setting _relativeResult_
|
||||
],
|
||||
[
|
||||
// Behave normally in 3 calls made prior to NanosecondsToDays
|
||||
// Behave normally in 3 calls made prior to NormalizedTimeDurationToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
|
@ -63,22 +66,22 @@ assert.throws(RangeError, () =>
|
|||
"days < 0 and sign = 1"
|
||||
);
|
||||
|
||||
// NanosecondsToDays.20: days > 0 and sign = -1
|
||||
// Step 23: days > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
1n, // Set DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 9
|
||||
[epochInstant], // Returned for AddDuration step 10, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[epochInstant], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 15
|
||||
[epochInstant], // Returned in AddDuration step 16, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[epochInstant], // Returned in step 16, setting _relativeResult_
|
||||
],
|
||||
[
|
||||
// Behave normally in 3 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
-dayNs + 1, // Returned in step 8, setting _startDateTime_
|
||||
dayNs - 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
|
@ -90,23 +93,23 @@ assert.throws(RangeError, () =>
|
|||
"days > 0 and sign = -1"
|
||||
);
|
||||
|
||||
// NanosecondsToDays.22: nanoseconds > 0 and sign = -1
|
||||
// Step 25: nanoseconds > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Set DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 9
|
||||
[new Temporal.Instant(-1n)], // Returned for AddDuration step 10, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[new Temporal.Instant(-2n)], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[new Temporal.Instant(-4n)], // Returned for NanosecondsToDays step 18.a, setting _oneDayFartherNs_
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 15
|
||||
[new Temporal.Instant(-1n)], // Returned in AddDuration step 16, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[new Temporal.Instant(-2n)], // Returned in step 16, setting _relativeResult_
|
||||
[new Temporal.Instant(-4n)], // Returned in step 21.a, setting _oneDayFarther_
|
||||
],
|
||||
[
|
||||
// Behave normally in 3 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
|
@ -117,3 +120,24 @@ assert.throws(RangeError, () =>
|
|||
}),
|
||||
"nanoseconds > 0 and sign = -1"
|
||||
);
|
||||
|
||||
// Step 28: day length is an unsafe integer
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n,
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for AddDuration step 15
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for AddDuration step 16
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for step 16, setting _relativeResult_
|
||||
// Returned in step 21.a, making _oneDayFarther_ 2^53 ns later than _relativeResult_
|
||||
[new Temporal.Instant(2n ** 53n + 2n * BigInt(dayNs))],
|
||||
],
|
||||
[]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
dayDuration.add(dayDuration, {
|
||||
relativeTo: zdt,
|
||||
}),
|
||||
"Should throw RangeError when time zone calculates an outrageous day length"
|
||||
);
|
|
@ -3,18 +3,19 @@
|
|||
/*---
|
||||
esid: sec-temporal.duration.prototype.round
|
||||
description: >
|
||||
NanosecondsToDays can loop infinitely.
|
||||
NormalizedTimeDurationToDays can loop arbitrarily up to max safe integer
|
||||
info: |
|
||||
NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDatetime ] )
|
||||
...
|
||||
18. Repeat, while done is false,
|
||||
a. Let oneDayFartherNs be ℝ(? AddZonedDateTime(ℤ(intermediateNs), relativeTo.[[TimeZone]],
|
||||
relativeTo.[[Calendar]], 0, 0, 0, sign, 0, 0, 0, 0, 0, 0)).
|
||||
b. Set dayLengthNs to oneDayFartherNs - intermediateNs.
|
||||
c. If (nanoseconds - dayLengthNs) × sign ≥ 0, then
|
||||
i. Set nanoseconds to nanoseconds - dayLengthNs.
|
||||
ii. Set intermediateNs to oneDayFartherNs.
|
||||
21. Repeat, while done is false,
|
||||
a. Let oneDayFarther be ? AddDaysToZonedDateTime(relativeResult.[[Instant]],
|
||||
relativeResult.[[DateTime]], timeZoneRec, zonedRelativeTo.[[Calendar]], sign).
|
||||
b. Set dayLengthNs to NormalizedTimeDurationFromEpochNanosecondsDifference(oneDayFarther.[[EpochNanoseconds]],
|
||||
relativeResult.[[EpochNanoseconds]]).
|
||||
c. Let oneDayLess be ? SubtractNormalizedTimeDuration(norm, dayLengthNs).
|
||||
c. If NormalizedTimeDurationSign(oneDayLess) × sign ≥ 0, then
|
||||
i. Set norm to oneDayLess.
|
||||
ii. Set relativeResult to oneDayFarther.
|
||||
iii. Set days to days + sign.
|
||||
d. Else,
|
||||
i. Set done to true.
|
||||
|
@ -47,7 +48,7 @@ function createRelativeTo(count) {
|
|||
return new Temporal.ZonedDateTime(0n, timeZone);
|
||||
}
|
||||
|
||||
let zdt = createRelativeTo(200);
|
||||
let zdt = createRelativeTo(50);
|
||||
calls.splice(0); // Reset calls list after ZonedDateTime construction
|
||||
duration.round({
|
||||
smallestUnit: "days",
|
||||
|
@ -55,11 +56,11 @@ duration.round({
|
|||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
200 + 1,
|
||||
50 + 1,
|
||||
"Expected duration.round to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(300);
|
||||
zdt = createRelativeTo(100);
|
||||
calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction
|
||||
duration.round({
|
||||
smallestUnit: "days",
|
||||
|
@ -67,6 +68,9 @@ duration.round({
|
|||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
300 + 1,
|
||||
100 + 1,
|
||||
"Expected duration.round to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(107);
|
||||
assert.throws(RangeError, () => duration.round({ smallestUnit: "days", relativeTo: zdt }), "107-2 days > 2⁵³ ns");
|
|
@ -3,13 +3,16 @@
|
|||
/*---
|
||||
esid: sec-temporal.duration.prototype.round
|
||||
description: >
|
||||
Called abstract operation NanosecondsToDays can throw three different RangeErrors when paired with a ZonedDateTime.
|
||||
Abstract operation NormalizedTimeDurationToDays can throw four different
|
||||
RangeErrors.
|
||||
info: |
|
||||
6.5.7 NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
19. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
20. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDateTime ] )
|
||||
22. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
23. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
22. If nanoseconds > 0 and sign = -1, throw a RangeError exception.
|
||||
25. If NormalizedTimeDurationSign(_norm_) = 1 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
28. If dayLength ≥ 2⁵³, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
@ -37,15 +40,15 @@ function timeZoneSubstituteValues(
|
|||
return tz;
|
||||
}
|
||||
|
||||
// NanosecondsToDays.19: days < 0 and sign = 1
|
||||
// Step 22: days < 0 and sign = 1
|
||||
let zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Sets _startNs_ to 0
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[[epochInstant]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Pre-conversion in Duration.p.round
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
|
@ -58,15 +61,15 @@ assert.throws(RangeError, () =>
|
|||
"RangeError when days < 0 and sign = 1"
|
||||
);
|
||||
|
||||
// NanosecondsToDays.20: days > 0 and sign = -1
|
||||
// Step 23: days > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Sets _startNs_ to 0
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[[epochInstant]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Pre-conversion in Duration.p.round
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
-dayNs + 1, // Returned in step 8, setting _startDateTime_
|
||||
dayNs - 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
|
@ -79,18 +82,18 @@ assert.throws(RangeError, () =>
|
|||
"RangeError when days > 0 and sign = -1"
|
||||
);
|
||||
|
||||
// NanosecondsToDays.22: nanoseconds > 0 and sign = -1
|
||||
// Step 25: nanoseconds > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Sets _startNs_ to 0
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
[new Temporal.Instant(-2n)], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[new Temporal.Instant(-4n)], // Returned for NanosecondsToDays step 18.a, setting _oneDayFartherNs_
|
||||
[new Temporal.Instant(-2n)], // Returned in step 16, setting _relativeResult_
|
||||
[new Temporal.Instant(-4n)], // Returned in step 21.a, setting _oneDayFarther_
|
||||
],
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Pre-conversion in Duration.p.round
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
|
@ -102,3 +105,21 @@ assert.throws(RangeError, () =>
|
|||
}),
|
||||
"RangeError when nanoseconds > 0 and sign = -1"
|
||||
);
|
||||
|
||||
// Step 28: day length is an unsafe integer
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n,
|
||||
timeZoneSubstituteValues(
|
||||
// Not called in step 16 because _days_ = 0
|
||||
// Returned in step 21.a, making _oneDayFarther_ 2^53 ns later than _relativeResult_
|
||||
[[new Temporal.Instant(2n ** 53n)]],
|
||||
[]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
oneNsDuration.round({
|
||||
relativeTo: zdt,
|
||||
smallestUnit: "days",
|
||||
}),
|
||||
"Should throw RangeError when time zone calculates an outrageous day length"
|
||||
);
|
|
@ -4,18 +4,19 @@
|
|||
/*---
|
||||
esid: sec-temporal.duration.prototype.subtract
|
||||
description: >
|
||||
NanosecondsToDays can loop infinitely.
|
||||
NormalizedTimeDurationToDays can loop arbitrarily up to max safe integer
|
||||
info: |
|
||||
NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDatetime ] )
|
||||
...
|
||||
18. Repeat, while done is false,
|
||||
a. Let oneDayFartherNs be ℝ(? AddZonedDateTime(ℤ(intermediateNs), relativeTo.[[TimeZone]],
|
||||
relativeTo.[[Calendar]], 0, 0, 0, sign, 0, 0, 0, 0, 0, 0)).
|
||||
b. Set dayLengthNs to oneDayFartherNs - intermediateNs.
|
||||
c. If (nanoseconds - dayLengthNs) × sign ≥ 0, then
|
||||
i. Set nanoseconds to nanoseconds - dayLengthNs.
|
||||
ii. Set intermediateNs to oneDayFartherNs.
|
||||
21. Repeat, while done is false,
|
||||
a. Let oneDayFarther be ? AddDaysToZonedDateTime(relativeResult.[[Instant]],
|
||||
relativeResult.[[DateTime]], timeZoneRec, zonedRelativeTo.[[Calendar]], sign).
|
||||
b. Set dayLengthNs to NormalizedTimeDurationFromEpochNanosecondsDifference(oneDayFarther.[[EpochNanoseconds]],
|
||||
relativeResult.[[EpochNanoseconds]]).
|
||||
c. Let oneDayLess be ? SubtractNormalizedTimeDuration(norm, dayLengthNs).
|
||||
c. If NormalizedTimeDurationSign(oneDayLess) × sign ≥ 0, then
|
||||
i. Set norm to oneDayLess.
|
||||
ii. Set relativeResult to oneDayFarther.
|
||||
iii. Set days to days + sign.
|
||||
d. Else,
|
||||
i. Set done to true.
|
||||
|
@ -48,24 +49,27 @@ function createRelativeTo(count) {
|
|||
return new Temporal.ZonedDateTime(0n, timeZone);
|
||||
}
|
||||
|
||||
let zdt = createRelativeTo(200);
|
||||
let zdt = createRelativeTo(50);
|
||||
calls.splice(0); // Reset calls list after ZonedDateTime construction
|
||||
duration.subtract(duration, {
|
||||
relativeTo: zdt,
|
||||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
200 + 1,
|
||||
50 + 1,
|
||||
"Expected duration.subtract to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(300);
|
||||
zdt = createRelativeTo(100);
|
||||
calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction
|
||||
duration.subtract(duration, {
|
||||
relativeTo: zdt,
|
||||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
300 + 1,
|
||||
100 + 1,
|
||||
"Expected duration.subtract to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(107);
|
||||
assert.throws(RangeError, () => duration.subtract(duration, { relativeTo: zdt }), "107-2 days > 2⁵³ ns");
|
|
@ -1,116 +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: >
|
||||
Called abstract operation NanosecondsToDays can throw three different RangeErrors when paired with a ZonedDateTime.
|
||||
info: |
|
||||
6.5.7 NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
19. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
20. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
22. If nanoseconds > 0 and sign = -1, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
const dayNs = 86_400_000_000_000;
|
||||
const dayDuration = Temporal.Duration.from({ days: 1 });
|
||||
const epochInstant = new Temporal.Instant(0n);
|
||||
|
||||
function timeZoneSubstituteValues(
|
||||
getPossibleInstantsFor,
|
||||
getOffsetNanosecondsFor
|
||||
) {
|
||||
const tz = new Temporal.TimeZone("UTC");
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getPossibleInstantsFor",
|
||||
getPossibleInstantsFor
|
||||
);
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getOffsetNanosecondsFor",
|
||||
getOffsetNanosecondsFor
|
||||
);
|
||||
return tz;
|
||||
}
|
||||
|
||||
// NanosecondsToDays.19: days < 0 and sign = 1
|
||||
let zdt = new Temporal.ZonedDateTime(
|
||||
-1n, // Set DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 9
|
||||
[epochInstant], // Returned for AddDuration step 10, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[epochInstant], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
],
|
||||
[
|
||||
// Behave normally in 3 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Subtracting day from day sets largestUnit to 'day', avoids having any week/month/year components in difference
|
||||
dayDuration.subtract(dayDuration, {
|
||||
relativeTo: zdt,
|
||||
})
|
||||
);
|
||||
|
||||
// NanosecondsToDays.20: days > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
1n, // Set DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 9
|
||||
[epochInstant], // Returned for AddDuration step 10, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[epochInstant], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
],
|
||||
[
|
||||
// Behave normally in 3 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Subtracting day from day sets largestUnit to 'day', avoids having any week/month/year components in difference
|
||||
dayDuration.subtract(dayDuration, {
|
||||
relativeTo: zdt,
|
||||
})
|
||||
);
|
||||
|
||||
// NanosecondsToDays.22: nanoseconds > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Set DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 9
|
||||
[new Temporal.Instant(-1n)], // Returned for AddDuration step 10, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[new Temporal.Instant(-2n)], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[new Temporal.Instant(-4n)], // Returned for NanosecondsToDays step 18.a, setting _oneDayFartherNs_
|
||||
],
|
||||
[
|
||||
// Behave normally in 3 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Subtracting day from day sets largestUnit to 'day', avoids having any week/month/year components in difference
|
||||
dayDuration.subtract(dayDuration, {
|
||||
relativeTo: zdt,
|
||||
})
|
||||
);
|
|
@ -0,0 +1,141 @@
|
|||
// 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: >
|
||||
Abstract operation NormalizedTimeDurationToDays can throw four different
|
||||
RangeErrors.
|
||||
info: |
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDateTime ] )
|
||||
22. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
23. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
25. If NormalizedTimeDurationSign(_norm_) = 1 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
28. If dayLength ≥ 2⁵³, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
const dayNs = 86_400_000_000_000;
|
||||
const dayDuration = Temporal.Duration.from({ days: 1 });
|
||||
const epochInstant = new Temporal.Instant(0n);
|
||||
|
||||
function timeZoneSubstituteValues(
|
||||
getPossibleInstantsFor,
|
||||
getOffsetNanosecondsFor
|
||||
) {
|
||||
const tz = new Temporal.TimeZone("UTC");
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getPossibleInstantsFor",
|
||||
getPossibleInstantsFor
|
||||
);
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getOffsetNanosecondsFor",
|
||||
getOffsetNanosecondsFor
|
||||
);
|
||||
return tz;
|
||||
}
|
||||
|
||||
// Step 22: days < 0 and sign = 1
|
||||
let zdt = new Temporal.ZonedDateTime(
|
||||
-1n, // Set DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 15
|
||||
[epochInstant], // Returned in AddDuration step 16, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[epochInstant], // Returned in step 16, setting _relativeResult_
|
||||
],
|
||||
[
|
||||
// Behave normally in 3 calls made prior to NormalizedTimeDurationToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Subtracting day from day sets largestUnit to 'day', avoids having any week/month/year components in difference
|
||||
dayDuration.subtract(dayDuration, {
|
||||
relativeTo: zdt,
|
||||
})
|
||||
);
|
||||
|
||||
// Step 23: days > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
1n, // Set DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 15
|
||||
[epochInstant], // Returned in AddDuration step 16, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[epochInstant], // Returned in step 16, setting _relativeResult_
|
||||
],
|
||||
[
|
||||
// Behave normally in 3 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
-dayNs + 1, // Returned in step 8, setting _startDateTime_
|
||||
dayNs - 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Subtracting day from day sets largestUnit to 'day', avoids having any week/month/year components in difference
|
||||
dayDuration.subtract(dayDuration, {
|
||||
relativeTo: zdt,
|
||||
})
|
||||
);
|
||||
|
||||
// Step 25: nanoseconds > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Set DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 15
|
||||
[new Temporal.Instant(-1n)], // Returned in AddDuration step 16, setting _endNs_ -> DifferenceZonedDateTime _ns2_
|
||||
[new Temporal.Instant(-2n)], // Returned in step 16, setting _relativeResult_
|
||||
[new Temporal.Instant(-4n)], // Returned in step 21.a, setting _oneDayFarther_
|
||||
],
|
||||
[
|
||||
// Behave normally in 3 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Subtracting day from day sets largestUnit to 'day', avoids having any week/month/year components in difference
|
||||
dayDuration.subtract(dayDuration, {
|
||||
relativeTo: zdt,
|
||||
})
|
||||
);
|
||||
|
||||
// Step 28: day length is an unsafe integer
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n,
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for AddDuration step 15
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for AddDuration step 16
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for step 16, setting _relativeResult_
|
||||
// Returned in step 21.a, making _oneDayFarther_ 2^53 ns later than _relativeResult_
|
||||
[new Temporal.Instant(2n ** 53n - 3n * BigInt(dayNs))],
|
||||
],
|
||||
[]
|
||||
)
|
||||
);
|
||||
const twoDaysDuration = new Temporal.Duration(0, 0, 0, 2);
|
||||
assert.throws(RangeError, () =>
|
||||
dayDuration.subtract(twoDaysDuration, {
|
||||
relativeTo: zdt,
|
||||
}),
|
||||
"Should throw RangeError when time zone calculates an outrageous day length"
|
||||
);
|
|
@ -4,18 +4,19 @@
|
|||
/*---
|
||||
esid: sec-temporal.duration.prototype.total
|
||||
description: >
|
||||
NanosecondsToDays can loop infinitely.
|
||||
NormalizedTimeDurationToDays can loop arbitrarily up to max safe integer
|
||||
info: |
|
||||
NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDatetime ] )
|
||||
...
|
||||
18. Repeat, while done is false,
|
||||
a. Let oneDayFartherNs be ℝ(? AddZonedDateTime(ℤ(intermediateNs), relativeTo.[[TimeZone]],
|
||||
relativeTo.[[Calendar]], 0, 0, 0, sign, 0, 0, 0, 0, 0, 0)).
|
||||
b. Set dayLengthNs to oneDayFartherNs - intermediateNs.
|
||||
c. If (nanoseconds - dayLengthNs) × sign ≥ 0, then
|
||||
i. Set nanoseconds to nanoseconds - dayLengthNs.
|
||||
ii. Set intermediateNs to oneDayFartherNs.
|
||||
21. Repeat, while done is false,
|
||||
a. Let oneDayFarther be ? AddDaysToZonedDateTime(relativeResult.[[Instant]],
|
||||
relativeResult.[[DateTime]], timeZoneRec, zonedRelativeTo.[[Calendar]], sign).
|
||||
b. Set dayLengthNs to NormalizedTimeDurationFromEpochNanosecondsDifference(oneDayFarther.[[EpochNanoseconds]],
|
||||
relativeResult.[[EpochNanoseconds]]).
|
||||
c. Let oneDayLess be ? SubtractNormalizedTimeDuration(norm, dayLengthNs).
|
||||
c. If NormalizedTimeDurationSign(oneDayLess) × sign ≥ 0, then
|
||||
i. Set norm to oneDayLess.
|
||||
ii. Set relativeResult to oneDayFarther.
|
||||
iii. Set days to days + sign.
|
||||
d. Else,
|
||||
i. Set done to true.
|
||||
|
@ -48,7 +49,7 @@ function createRelativeTo(count) {
|
|||
return new Temporal.ZonedDateTime(0n, timeZone);
|
||||
}
|
||||
|
||||
let zdt = createRelativeTo(200);
|
||||
let zdt = createRelativeTo(50);
|
||||
calls.splice(0); // Reset calls list after ZonedDateTime construction
|
||||
duration.total({
|
||||
unit: "day",
|
||||
|
@ -56,11 +57,11 @@ duration.total({
|
|||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
200 + 2,
|
||||
50 + 2,
|
||||
"Expected duration.total to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(300);
|
||||
zdt = createRelativeTo(100);
|
||||
calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction
|
||||
duration.total({
|
||||
unit: "day",
|
||||
|
@ -68,6 +69,9 @@ duration.total({
|
|||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
300 + 2,
|
||||
100 + 2,
|
||||
"Expected duration.total to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(106);
|
||||
assert.throws(RangeError, () => duration.total({ unit: "day", relativeTo: zdt }), "106-1 days > 2⁵³ ns");
|
|
@ -1,104 +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: >
|
||||
Called abstract operation NanosecondsToDays can throw three different RangeErrors when paired with a ZonedDateTime.
|
||||
info: |
|
||||
6.5.7 NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
19. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
20. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
22. If nanoseconds > 0 and sign = -1, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
const oneNsDuration = Temporal.Duration.from({ nanoseconds: 1 });
|
||||
const negOneNsDuration = Temporal.Duration.from({ nanoseconds: -1 });
|
||||
const dayNs = 86_400_000_000_000;
|
||||
const epochInstant = new Temporal.Instant(0n);
|
||||
|
||||
function timeZoneSubstituteValues(
|
||||
getPossibleInstantsFor,
|
||||
getOffsetNanosecondsFor
|
||||
) {
|
||||
const tz = new Temporal.TimeZone("UTC");
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getPossibleInstantsFor",
|
||||
getPossibleInstantsFor
|
||||
);
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getOffsetNanosecondsFor",
|
||||
getOffsetNanosecondsFor
|
||||
);
|
||||
return tz;
|
||||
}
|
||||
|
||||
// NanosecondsToDays.19: days < 0 and sign = 1
|
||||
let zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Sets _startNs_ to 0
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // pre-conversion in Duration.p.total
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Using 1ns duration _nanoseconds_ to 1 and _sign_ to 1
|
||||
oneNsDuration.total({
|
||||
relativeTo: zdt,
|
||||
unit: "day",
|
||||
}),
|
||||
"RangeError when days < 0 and sign = 1"
|
||||
);
|
||||
|
||||
// NanosecondsToDays.20: days > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Sets _startNs_ to 0
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // pre-conversion in Duration.p.total
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Using -1ns duration sets _nanoseconds_ to -1 and _sign_ to -1
|
||||
negOneNsDuration.total({
|
||||
relativeTo: zdt,
|
||||
unit: "day",
|
||||
}),
|
||||
"RangeError when days > 0 and sign = -1"
|
||||
);
|
||||
|
||||
// NanosecondsToDays.22: nanoseconds > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Sets _startNs_ to 0
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
[new Temporal.Instant(-2n)], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[new Temporal.Instant(-4n)], // Returned for NanosecondsToDays step 18.a, setting _oneDayFartherNs_
|
||||
],
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // pre-conversion in Duration.p.total
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Using -1ns duration sets _nanoseconds_ to -1 and _sign_ to -1
|
||||
negOneNsDuration.total({
|
||||
relativeTo: zdt,
|
||||
unit: "day",
|
||||
}),
|
||||
"RangeError when nanoseconds > 0 and sign = -1"
|
||||
);
|
|
@ -0,0 +1,125 @@
|
|||
// 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: >
|
||||
Abstract operation NormalizedTimeDurationToDays can throw four different
|
||||
RangeErrors.
|
||||
info: |
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDateTime ] )
|
||||
22. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
23. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
25. If NormalizedTimeDurationSign(_norm_) = 1 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
28. If dayLength ≥ 2⁵³, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
const oneNsDuration = Temporal.Duration.from({ nanoseconds: 1 });
|
||||
const negOneNsDuration = Temporal.Duration.from({ nanoseconds: -1 });
|
||||
const dayNs = 86_400_000_000_000;
|
||||
const epochInstant = new Temporal.Instant(0n);
|
||||
|
||||
function timeZoneSubstituteValues(
|
||||
getPossibleInstantsFor,
|
||||
getOffsetNanosecondsFor
|
||||
) {
|
||||
const tz = new Temporal.TimeZone("UTC");
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getPossibleInstantsFor",
|
||||
getPossibleInstantsFor
|
||||
);
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getOffsetNanosecondsFor",
|
||||
getOffsetNanosecondsFor
|
||||
);
|
||||
return tz;
|
||||
}
|
||||
|
||||
// Step 22: days < 0 and sign = 1
|
||||
let zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Sets _startNs_ to 0
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Pre-conversion in Duration.p.total
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Using 1ns duration _nanoseconds_ to 1 and _sign_ to 1
|
||||
oneNsDuration.total({
|
||||
relativeTo: zdt,
|
||||
unit: "day",
|
||||
}),
|
||||
"RangeError when days < 0 and sign = 1"
|
||||
);
|
||||
|
||||
// Step 23: days > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Sets _startNs_ to 0
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // Pre-conversion in Duration.p.total
|
||||
-dayNs + 1, // Returned in step 8, setting _startDateTime_
|
||||
dayNs - 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Using -1ns duration sets _nanoseconds_ to -1 and _sign_ to -1
|
||||
negOneNsDuration.total({
|
||||
relativeTo: zdt,
|
||||
unit: "day",
|
||||
}),
|
||||
"RangeError when days > 0 and sign = -1"
|
||||
);
|
||||
|
||||
// Step 25: nanoseconds > 0 and sign = -1
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n, // Sets _startNs_ to 0
|
||||
timeZoneSubstituteValues(
|
||||
[
|
||||
[new Temporal.Instant(-2n)], // Returned in step 16, setting _relativeResult_
|
||||
[new Temporal.Instant(-4n)], // Returned in step 21.a, setting _oneDayFarther_
|
||||
],
|
||||
[
|
||||
TemporalHelpers.SUBSTITUTE_SKIP, // pre-conversion in Duration.p.total
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
// Using -1ns duration sets _nanoseconds_ to -1 and _sign_ to -1
|
||||
negOneNsDuration.total({
|
||||
relativeTo: zdt,
|
||||
unit: "day",
|
||||
}),
|
||||
"RangeError when nanoseconds > 0 and sign = -1"
|
||||
);
|
||||
|
||||
// Step 28: day length is an unsafe integer
|
||||
zdt = new Temporal.ZonedDateTime(
|
||||
0n,
|
||||
timeZoneSubstituteValues(
|
||||
// Not called in step 16 because _days_ = 0
|
||||
// Returned in step 21.a, making _oneDayFarther_ 2^53 ns later than _relativeResult_
|
||||
[[new Temporal.Instant(2n ** 53n)]],
|
||||
[]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
oneNsDuration.total({
|
||||
relativeTo: zdt,
|
||||
unit: "days",
|
||||
}),
|
||||
"Should throw RangeError when time zone calculates an outrageous day length"
|
||||
);
|
|
@ -1,102 +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: >
|
||||
Called abstract operation NanosecondsToDays can throw three different RangeErrors when paired with a ZonedDateTime.
|
||||
info: |
|
||||
6.5.7 NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
19. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
20. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
22. If nanoseconds > 0 and sign = -1, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
function timeZoneSubstituteValues(
|
||||
getPossibleInstantsFor,
|
||||
getOffsetNanosecondsFor
|
||||
) {
|
||||
const tz = new Temporal.TimeZone("UTC");
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getPossibleInstantsFor",
|
||||
getPossibleInstantsFor
|
||||
);
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getOffsetNanosecondsFor",
|
||||
getOffsetNanosecondsFor
|
||||
);
|
||||
return tz;
|
||||
}
|
||||
|
||||
const dayNs = 86_400_000_000_000;
|
||||
const zeroZDT = new Temporal.ZonedDateTime(0n, "UTC");
|
||||
const oneZDT = new Temporal.ZonedDateTime(1n, "UTC");
|
||||
const epochInstant = new Temporal.Instant(0n);
|
||||
const options = { largestUnit: "days" };
|
||||
|
||||
// NanosecondsToDays.19: days < 0 and sign = 1
|
||||
let start = new Temporal.ZonedDateTime(
|
||||
0n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.since(
|
||||
oneZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// NanosecondsToDays.20: days > 0 and sign = -1
|
||||
start = new Temporal.ZonedDateTime(
|
||||
1n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.since(
|
||||
zeroZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// NanosecondsToDays.22: nanoseconds > 0 and sign = -1
|
||||
start = new Temporal.ZonedDateTime(
|
||||
1n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[new Temporal.Instant(-1n)]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.since(
|
||||
zeroZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
|
@ -4,18 +4,19 @@
|
|||
/*---
|
||||
esid: sec-temporal.zoneddatetime.prototype.since
|
||||
description: >
|
||||
NanosecondsToDays can loop infinitely.
|
||||
NormalizedTimeDurationToDays can loop arbitrarily up to max safe integer
|
||||
info: |
|
||||
NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDatetime ] )
|
||||
...
|
||||
18. Repeat, while done is false,
|
||||
a. Let oneDayFartherNs be ℝ(? AddZonedDateTime(ℤ(intermediateNs), relativeTo.[[TimeZone]],
|
||||
relativeTo.[[Calendar]], 0, 0, 0, sign, 0, 0, 0, 0, 0, 0)).
|
||||
b. Set dayLengthNs to oneDayFartherNs - intermediateNs.
|
||||
c. If (nanoseconds - dayLengthNs) × sign ≥ 0, then
|
||||
i. Set nanoseconds to nanoseconds - dayLengthNs.
|
||||
ii. Set intermediateNs to oneDayFartherNs.
|
||||
21. Repeat, while done is false,
|
||||
a. Let oneDayFarther be ? AddDaysToZonedDateTime(relativeResult.[[Instant]],
|
||||
relativeResult.[[DateTime]], timeZoneRec, zonedRelativeTo.[[Calendar]], sign).
|
||||
b. Set dayLengthNs to NormalizedTimeDurationFromEpochNanosecondsDifference(oneDayFarther.[[EpochNanoseconds]],
|
||||
relativeResult.[[EpochNanoseconds]]).
|
||||
c. Let oneDayLess be ? SubtractNormalizedTimeDuration(norm, dayLengthNs).
|
||||
c. If NormalizedTimeDurationSign(oneDayLess) × sign ≥ 0, then
|
||||
i. Set norm to oneDayLess.
|
||||
ii. Set relativeResult to oneDayFarther.
|
||||
iii. Set days to days + sign.
|
||||
d. Else,
|
||||
i. Set done to true.
|
||||
|
@ -48,24 +49,27 @@ function createRelativeTo(count) {
|
|||
return new Temporal.ZonedDateTime(0n, timeZone);
|
||||
}
|
||||
|
||||
let zdt = createRelativeTo(200);
|
||||
let zdt = createRelativeTo(50);
|
||||
calls.splice(0); // Reset calls list after ZonedDateTime construction
|
||||
zdt.since(other, {
|
||||
largestUnit: "day",
|
||||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
200 + 1,
|
||||
50 + 1,
|
||||
"Expected ZonedDateTime.since to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(300);
|
||||
zdt = createRelativeTo(100);
|
||||
calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction
|
||||
zdt.since(other, {
|
||||
largestUnit: "day",
|
||||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
300 + 1,
|
||||
100 + 1,
|
||||
"Expected ZonedDateTime.since to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(105);
|
||||
assert.throws(RangeError, () => zdt.since(other, { largestUnit: "day" }), "105 days > 2⁵³ ns");
|
|
@ -0,0 +1,123 @@
|
|||
// 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: >
|
||||
Abstract operation NormalizedTimeDurationToDays can throw four different
|
||||
RangeErrors.
|
||||
info: |
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDateTime ] )
|
||||
22. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
23. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
25. If NormalizedTimeDurationSign(_norm_) = 1 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
28. If dayLength ≥ 2⁵³, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
function timeZoneSubstituteValues(
|
||||
getPossibleInstantsFor,
|
||||
getOffsetNanosecondsFor
|
||||
) {
|
||||
const tz = new Temporal.TimeZone("UTC");
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getPossibleInstantsFor",
|
||||
getPossibleInstantsFor
|
||||
);
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getOffsetNanosecondsFor",
|
||||
getOffsetNanosecondsFor
|
||||
);
|
||||
return tz;
|
||||
}
|
||||
|
||||
const dayNs = 86_400_000_000_000;
|
||||
const zeroZDT = new Temporal.ZonedDateTime(0n, "UTC");
|
||||
const oneZDT = new Temporal.ZonedDateTime(1n, "UTC");
|
||||
const epochInstant = new Temporal.Instant(0n);
|
||||
const options = { largestUnit: "days" };
|
||||
|
||||
// Step 22: days < 0 and sign = 1
|
||||
let start = new Temporal.ZonedDateTime(
|
||||
0n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NormalizedTimeDurationToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.since(
|
||||
oneZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// Step 23: days > 0 and sign = -1
|
||||
start = new Temporal.ZonedDateTime(
|
||||
1n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NormalizedTimeDurationToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
-dayNs + 1, // Returned in step 8, setting _startDateTime_
|
||||
dayNs - 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.since(
|
||||
zeroZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// Step 25: nanoseconds > 0 and sign = -1
|
||||
start = new Temporal.ZonedDateTime(
|
||||
1n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[new Temporal.Instant(-1n)]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NormalizedTimeDurationToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.since(
|
||||
zeroZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// Step 28: day length is an unsafe integer
|
||||
start = new Temporal.ZonedDateTime(
|
||||
0n,
|
||||
timeZoneSubstituteValues(
|
||||
// Not called in step 16 because _days_ = 0
|
||||
// Returned in step 21.a, making _oneDayFarther_ 2^53 ns later than _relativeResult_
|
||||
[[new Temporal.Instant(2n ** 53n)]],
|
||||
[]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.since(
|
||||
oneZDT,
|
||||
options
|
||||
),
|
||||
"Should throw RangeError when time zone calculates an outrageous day length"
|
||||
);
|
|
@ -1,102 +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: >
|
||||
Called abstract operation NanosecondsToDays can throw three different RangeErrors when paired with a ZonedDateTime.
|
||||
info: |
|
||||
6.5.7 NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
19. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
20. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
22. If nanoseconds > 0 and sign = -1, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
function timeZoneSubstituteValues(
|
||||
getPossibleInstantsFor,
|
||||
getOffsetNanosecondsFor
|
||||
) {
|
||||
const tz = new Temporal.TimeZone("UTC");
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getPossibleInstantsFor",
|
||||
getPossibleInstantsFor
|
||||
);
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getOffsetNanosecondsFor",
|
||||
getOffsetNanosecondsFor
|
||||
);
|
||||
return tz;
|
||||
}
|
||||
|
||||
const dayNs = 86_400_000_000_000;
|
||||
const zeroZDT = new Temporal.ZonedDateTime(0n, "UTC");
|
||||
const oneZDT = new Temporal.ZonedDateTime(1n, "UTC");
|
||||
const epochInstant = new Temporal.Instant(0n);
|
||||
const options = { largestUnit: "days" };
|
||||
|
||||
// NanosecondsToDays.19: days < 0 and sign = 1
|
||||
let start = new Temporal.ZonedDateTime(
|
||||
0n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.until(
|
||||
oneZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// NanosecondsToDays.20: days > 0 and sign = -1
|
||||
start = new Temporal.ZonedDateTime(
|
||||
1n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.until(
|
||||
zeroZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// NanosecondsToDays.22: nanoseconds > 0 and sign = -1
|
||||
start = new Temporal.ZonedDateTime(
|
||||
1n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[new Temporal.Instant(-1n)]], // Returned for NanosecondsToDays step 14, setting _intermediateNs_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NanosecondsToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned for NanosecondsToDays step 7, setting _startDateTime_
|
||||
-dayNs + 1, // Returned for NanosecondsToDays step 11, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.until(
|
||||
zeroZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
|
@ -4,18 +4,19 @@
|
|||
/*---
|
||||
esid: sec-temporal.zoneddatetime.prototype.until
|
||||
description: >
|
||||
NanosecondsToDays can loop infinitely.
|
||||
NormalizedTimeDurationToDays can loop arbitrarily up to max safe integer
|
||||
info: |
|
||||
NanosecondsToDays ( nanoseconds, relativeTo )
|
||||
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDatetime ] )
|
||||
...
|
||||
18. Repeat, while done is false,
|
||||
a. Let oneDayFartherNs be ℝ(? AddZonedDateTime(ℤ(intermediateNs), relativeTo.[[TimeZone]],
|
||||
relativeTo.[[Calendar]], 0, 0, 0, sign, 0, 0, 0, 0, 0, 0)).
|
||||
b. Set dayLengthNs to oneDayFartherNs - intermediateNs.
|
||||
c. If (nanoseconds - dayLengthNs) × sign ≥ 0, then
|
||||
i. Set nanoseconds to nanoseconds - dayLengthNs.
|
||||
ii. Set intermediateNs to oneDayFartherNs.
|
||||
21. Repeat, while done is false,
|
||||
a. Let oneDayFarther be ? AddDaysToZonedDateTime(relativeResult.[[Instant]],
|
||||
relativeResult.[[DateTime]], timeZoneRec, zonedRelativeTo.[[Calendar]], sign).
|
||||
b. Set dayLengthNs to NormalizedTimeDurationFromEpochNanosecondsDifference(oneDayFarther.[[EpochNanoseconds]],
|
||||
relativeResult.[[EpochNanoseconds]]).
|
||||
c. Let oneDayLess be ? SubtractNormalizedTimeDuration(norm, dayLengthNs).
|
||||
c. If NormalizedTimeDurationSign(oneDayLess) × sign ≥ 0, then
|
||||
i. Set norm to oneDayLess.
|
||||
ii. Set relativeResult to oneDayFarther.
|
||||
iii. Set days to days + sign.
|
||||
d. Else,
|
||||
i. Set done to true.
|
||||
|
@ -48,24 +49,27 @@ function createRelativeTo(count) {
|
|||
return new Temporal.ZonedDateTime(0n, timeZone);
|
||||
}
|
||||
|
||||
let zdt = createRelativeTo(200);
|
||||
let zdt = createRelativeTo(50);
|
||||
calls.splice(0); // Reset calls list after ZonedDateTime construction
|
||||
zdt.until(other, {
|
||||
largestUnit: "day",
|
||||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
200 + 1,
|
||||
50 + 1,
|
||||
"Expected ZonedDateTime.until to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(300);
|
||||
zdt = createRelativeTo(100);
|
||||
calls.splice(0); // Reset calls list after previous loop + ZonedDateTime construction
|
||||
zdt.until(other, {
|
||||
largestUnit: "day",
|
||||
});
|
||||
assert.sameValue(
|
||||
calls.length,
|
||||
300 + 1,
|
||||
100 + 1,
|
||||
"Expected ZonedDateTime.until to call getPossibleInstantsFor correct number of times"
|
||||
);
|
||||
|
||||
zdt = createRelativeTo(105);
|
||||
assert.throws(RangeError, () => zdt.until(other, { largestUnit: "day" }), "105 days > 2⁵³ ns");
|
|
@ -0,0 +1,123 @@
|
|||
// 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: >
|
||||
Abstract operation NormalizedTimeDurationToDays can throw four different
|
||||
RangeErrors.
|
||||
info: |
|
||||
NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDateTime ] )
|
||||
22. If days < 0 and sign = 1, throw a RangeError exception.
|
||||
23. If days > 0 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
25. If NormalizedTimeDurationSign(_norm_) = 1 and sign = -1, throw a RangeError exception.
|
||||
...
|
||||
28. If dayLength ≥ 2⁵³, throw a RangeError exception.
|
||||
features: [Temporal, BigInt]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
function timeZoneSubstituteValues(
|
||||
getPossibleInstantsFor,
|
||||
getOffsetNanosecondsFor
|
||||
) {
|
||||
const tz = new Temporal.TimeZone("UTC");
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getPossibleInstantsFor",
|
||||
getPossibleInstantsFor
|
||||
);
|
||||
TemporalHelpers.substituteMethod(
|
||||
tz,
|
||||
"getOffsetNanosecondsFor",
|
||||
getOffsetNanosecondsFor
|
||||
);
|
||||
return tz;
|
||||
}
|
||||
|
||||
const dayNs = 86_400_000_000_000;
|
||||
const zeroZDT = new Temporal.ZonedDateTime(0n, "UTC");
|
||||
const oneZDT = new Temporal.ZonedDateTime(1n, "UTC");
|
||||
const epochInstant = new Temporal.Instant(0n);
|
||||
const options = { largestUnit: "days" };
|
||||
|
||||
// Step 22: days < 0 and sign = 1
|
||||
let start = new Temporal.ZonedDateTime(
|
||||
0n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NormalizedTimeDurationToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.until(
|
||||
oneZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// Step 23: days > 0 and sign = -1
|
||||
start = new Temporal.ZonedDateTime(
|
||||
1n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[epochInstant]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NormalizedTimeDurationToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
-dayNs + 1, // Returned in step 8, setting _startDateTime_
|
||||
dayNs - 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.until(
|
||||
zeroZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// Step 25: nanoseconds > 0 and sign = -1
|
||||
start = new Temporal.ZonedDateTime(
|
||||
1n, // Sets DifferenceZonedDateTime _ns1_
|
||||
timeZoneSubstituteValues(
|
||||
[[new Temporal.Instant(-1n)]], // Returned in step 16, setting _relativeResult_
|
||||
[
|
||||
// Behave normally in 2 calls made prior to NormalizedTimeDurationToDays
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
TemporalHelpers.SUBSTITUTE_SKIP,
|
||||
dayNs - 1, // Returned in step 8, setting _startDateTime_
|
||||
-dayNs + 1, // Returned in step 9, setting _endDateTime_
|
||||
]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.until(
|
||||
zeroZDT, // Sets DifferenceZonedDateTime _ns2_
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// Step 28: day length is an unsafe integer
|
||||
start = new Temporal.ZonedDateTime(
|
||||
0n,
|
||||
timeZoneSubstituteValues(
|
||||
// Not called in step 16 because _days_ = 0
|
||||
// Returned in step 21.a, making _oneDayFarther_ 2^53 ns later than _relativeResult_
|
||||
[[new Temporal.Instant(2n ** 53n)]],
|
||||
[]
|
||||
)
|
||||
);
|
||||
assert.throws(RangeError, () =>
|
||||
start.until(
|
||||
oneZDT,
|
||||
options
|
||||
),
|
||||
"Should throw RangeError when time zone calculates an outrageous day length"
|
||||
);
|
Loading…
Reference in New Issue