1 // |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
2 // Copyright (C) 2022 Igalia, S.L. All rights reserved.
3 // This code is governed by the BSD license found in the LICENSE file.
5 esid: sec-temporal.duration.prototype.subtract
7 Abstract operation NormalizedTimeDurationToDays can throw four different
10 NormalizedTimeDurationToDays ( norm, zonedRelativeTo, timeZoneRec [ , precalculatedPlainDateTime ] )
11 22. If days < 0 and sign = 1, throw a RangeError exception.
12 23. If days > 0 and sign = -1, throw a RangeError exception.
14 25. If NormalizedTimeDurationSign(_norm_) = 1 and sign = -1, throw a RangeError exception.
16 28. If dayLength ≥ 2⁵³, throw a RangeError exception.
17 features: [Temporal, BigInt]
18 includes: [temporalHelpers.js]
21 const dayNs = 86_400_000_000_000;
22 const dayDuration = Temporal.Duration.from({ days: 1 });
23 const epochInstant = new Temporal.Instant(0n);
25 function timeZoneSubstituteValues(
26 getPossibleInstantsFor,
27 getOffsetNanosecondsFor
29 const tz = new Temporal.TimeZone("UTC");
30 TemporalHelpers.substituteMethod(
32 "getPossibleInstantsFor",
33 getPossibleInstantsFor
35 TemporalHelpers.substituteMethod(
37 "getOffsetNanosecondsFor",
38 getOffsetNanosecondsFor
43 // Step 22: days < 0 and sign = 1
44 let zdt = new Temporal.ZonedDateTime(
45 -1n, // Set DifferenceZonedDateTime _ns1_
46 timeZoneSubstituteValues(
48 TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 15
49 [epochInstant], // Returned in AddDuration step 16, setting _endNs_ -> DifferenceZonedDateTime _ns2_
50 [epochInstant], // Returned in step 16, setting _relativeResult_
53 // Behave normally in 3 calls made prior to NormalizedTimeDurationToDays
54 TemporalHelpers.SUBSTITUTE_SKIP,
55 TemporalHelpers.SUBSTITUTE_SKIP,
56 TemporalHelpers.SUBSTITUTE_SKIP,
57 dayNs - 1, // Returned in step 8, setting _startDateTime_
58 -dayNs + 1, // Returned in step 9, setting _endDateTime_
62 assert.throws(RangeError, () =>
63 // Subtracting day from day sets largestUnit to 'day', avoids having any week/month/year components in difference
64 dayDuration.subtract(dayDuration, {
69 // Step 23: days > 0 and sign = -1
70 zdt = new Temporal.ZonedDateTime(
71 1n, // Set DifferenceZonedDateTime _ns1_
72 timeZoneSubstituteValues(
74 TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 15
75 [epochInstant], // Returned in AddDuration step 16, setting _endNs_ -> DifferenceZonedDateTime _ns2_
76 [epochInstant], // Returned in step 16, setting _relativeResult_
79 // Behave normally in 3 calls made prior to NanosecondsToDays
80 TemporalHelpers.SUBSTITUTE_SKIP,
81 TemporalHelpers.SUBSTITUTE_SKIP,
82 TemporalHelpers.SUBSTITUTE_SKIP,
83 -dayNs + 1, // Returned in step 8, setting _startDateTime_
84 dayNs - 1, // Returned in step 9, setting _endDateTime_
88 assert.throws(RangeError, () =>
89 // Subtracting day from day sets largestUnit to 'day', avoids having any week/month/year components in difference
90 dayDuration.subtract(dayDuration, {
95 // Step 25: nanoseconds > 0 and sign = -1
96 zdt = new Temporal.ZonedDateTime(
97 0n, // Set DifferenceZonedDateTime _ns1_
98 timeZoneSubstituteValues(
100 TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for first call, AddDuration step 15
101 [new Temporal.Instant(-1n)], // Returned in AddDuration step 16, setting _endNs_ -> DifferenceZonedDateTime _ns2_
102 [new Temporal.Instant(-2n)], // Returned in step 16, setting _relativeResult_
103 [new Temporal.Instant(-4n)], // Returned in step 21.a, setting _oneDayFarther_
106 // Behave normally in 3 calls made prior to NanosecondsToDays
107 TemporalHelpers.SUBSTITUTE_SKIP,
108 TemporalHelpers.SUBSTITUTE_SKIP,
109 TemporalHelpers.SUBSTITUTE_SKIP,
110 dayNs - 1, // Returned in step 8, setting _startDateTime_
111 -dayNs + 1, // Returned in step 9, setting _endDateTime_
115 assert.throws(RangeError, () =>
116 // Subtracting day from day sets largestUnit to 'day', avoids having any week/month/year components in difference
117 dayDuration.subtract(dayDuration, {
122 // Step 28: day length is an unsafe integer
123 zdt = new Temporal.ZonedDateTime(
125 timeZoneSubstituteValues(
127 TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for AddDuration step 15
128 TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for AddDuration step 16
129 TemporalHelpers.SUBSTITUTE_SKIP, // Behave normally for step 16, setting _relativeResult_
130 // Returned in step 21.a, making _oneDayFarther_ 2^53 ns later than _relativeResult_
131 [new Temporal.Instant(2n ** 53n - 3n * BigInt(dayNs))],
136 const twoDaysDuration = new Temporal.Duration(0, 0, 0, 2);
137 assert.throws(RangeError, () =>
138 dayDuration.subtract(twoDaysDuration, {
141 "Should throw RangeError when time zone calculates an outrageous day length"