Import SpiderMonkey Temporal tests

Temporal tests written for the SpiderMonkey implementation. Mostly
covers edge cases around mathematical operations and regression tests
for reported spec bugs.
This commit is contained in:
André Bargull 2022-07-05 12:48:26 +02:00 committed by Philip Chimento
parent 91a61b29ac
commit a3040a5047
34 changed files with 1205 additions and 0 deletions

View File

@ -0,0 +1,33 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.calendar.prototype.dateadd
description: >
Call BalanceISOYearMonth with Number.MAX_VALUE and -Number.MAX_VALUE for years/months.
info: |
Temporal.Calendar.prototype.dateAdd ( date, duration [ , options ] )
...
9. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]],
duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]],
overflow).
10. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
AddISODate ( year, month, day, years, months, weeks, days, overflow )
...
3. Let intermediate be ! BalanceISOYearMonth(year + years, month + months).
...
features: [Temporal]
---*/
var cal = new Temporal.Calendar("iso8601");
var date = new Temporal.PlainDate(1970, 1, 1);
var maxValue = new Temporal.Duration(Number.MAX_VALUE, Number.MAX_VALUE);
var minValue = new Temporal.Duration(-Number.MAX_VALUE, -Number.MAX_VALUE);
assert.throws(RangeError, () => cal.dateAdd(date, maxValue), "years/months is +Number.MAX_VALUE");
assert.throws(RangeError, () => cal.dateAdd(date, minValue), "years/months is -Number.MAX_VALUE");

View File

@ -0,0 +1,18 @@
// 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.add
description: >
AddZonedDateTime throws a RangeError when the intermediate instant is too large.
features: [Temporal]
---*/
const plainDate = new Temporal.PlainDate(1970, 1, 1);
const zonedDateTime = new Temporal.ZonedDateTime(0n, "UTC", "iso8601");
var duration = Temporal.Duration.from({days: 1, nanoseconds: Number.MAX_VALUE});
var options = {relativeTo: zonedDateTime};
assert.throws(RangeError, () => duration.add(duration, options));

View File

@ -0,0 +1,13 @@
// 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.add
description: >
BalanceDuration throws a RangeError when the result is too large.
features: [Temporal]
---*/
var duration = Temporal.Duration.from({days: Number.MAX_VALUE});
assert.throws(RangeError, () => duration.add(duration));

View File

@ -0,0 +1,27 @@
// 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.add
description: >
BalanceDuration throws a RangeError when the result is too large.
features: [Temporal]
---*/
const plainDate = new Temporal.PlainDate(1970, 1, 1);
const zonedDateTime = new Temporal.ZonedDateTime(0n, "UTC", "iso8601");
// Largest temporal unit is "nanosecond".
const duration = Temporal.Duration.from({nanoseconds: Number.MAX_VALUE});
assert.throws(RangeError, () => {
duration.add(duration);
});
assert.throws(RangeError, () => {
duration.add(duration, {relativeTo: plainDate});
});
assert.throws(RangeError, () => {
duration.add(duration, {relativeTo: zonedDateTime});
});

View File

@ -0,0 +1,72 @@
// 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 indefinitely.
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]
---*/
// Intentionally not Test262Error to ensure assertion errors are correctly propagated.
class StopExecution extends Error {}
const stopAt = 1000;
// Always add two days to the start date, this ensures the intermediate date
// is larger than the end date.
let twoDays = Temporal.Duration.from({days: 2});
// Number of calls to dateAdd.
let count = 0;
let cal = new class extends Temporal.Calendar {
// Set `days` to a number larger than `Number.MAX_SAFE_INTEGER`.
dateUntil(start, end, options) {
return Temporal.Duration.from({days: Number.MAX_VALUE});
}
dateAdd(date, duration, options) {
// Stop when we've reached the test limit.
count += 1;
if (count === stopAt) {
throw new StopExecution();
}
if (count === 1) {
return Temporal.Calendar.prototype.dateAdd.call(this, date, duration, options);
}
TemporalHelpers.assertPlainDate(date, 1970, 1, "M01", 1);
TemporalHelpers.assertDuration(
duration,
0, 0, 0, Number.MAX_VALUE,
0, 0, 0,
0, 0, 0,
);
return Temporal.Calendar.prototype.dateAdd.call(this, date, twoDays, options);
}
}("iso8601");
let zdt = new Temporal.ZonedDateTime(0n, "UTC", cal);
let duration = Temporal.Duration.from({days: 1});
let options = {
largestUnit: "days",
relativeTo: zdt,
};
assert.throws(StopExecution, () => duration.round(options));
assert.sameValue(count, stopAt);

View File

@ -0,0 +1,65 @@
// 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 indefinitely.
info: |
NanosecondsToDays ( nanoseconds, relativeTo )
...
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.
iii. Set days to days + sign.
d. Else,
i. Set done to true.
includes: [temporalHelpers.js]
features: [Temporal]
---*/
// Intentionally not Test262Error to ensure assertion errors are correctly propagated.
class StopExecution extends Error {}
const stopAt = 1000;
// Number of calls to getPossibleInstantsFor.
let count = 0;
// UTC time zones so we don't have to worry about time zone offsets.
let tz = new class extends Temporal.TimeZone {
getPossibleInstantsFor(dt) {
// Stop when we've reached the test limit.
count += 1;
if (count === stopAt) {
throw new StopExecution();
}
if (count < 4) {
// The first couple calls request the instant for 1970-01-02.
TemporalHelpers.assertPlainDateTime(dt, 1970, 1, "M01", 2, 0, 0, 0, 0, 0, 0);
} else {
// Later on the instant for 1970-01-03 is requested.
TemporalHelpers.assertPlainDateTime(dt, 1970, 1, "M01", 3, 0, 0, 0, 0, 0, 0);
}
// Always return "1970-01-02T00:00:00Z". This leads to iterating indefinitely
// in NanosecondsToDays.
return [new Temporal.Instant(86400000000000n)];
}
}("UTC");
let zdt = new Temporal.ZonedDateTime(0n, tz);
let duration = Temporal.Duration.from({days: 1});
let options = {
smallestUnit: "days",
relativeTo: zdt,
};
assert.throws(StopExecution, () => duration.round(options));
assert.sameValue(count, stopAt);

View File

@ -0,0 +1,27 @@
// 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: >
RoundDuration throws a RangeError when the result duration is invalid.
features: [Temporal]
---*/
function test(unit, nextSmallestUnit) {
var duration = Temporal.Duration.from({
[unit]: Number.MAX_VALUE,
[nextSmallestUnit]: Number.MAX_VALUE,
});
var options = {smallestUnit: unit, largestUnit: unit};
assert.throws(RangeError, () => duration.round(options));
}
test("days", "hours");
test("hours", "minutes");
test("minutes", "seconds");
test("seconds", "milliseconds");
test("milliseconds", "microseconds");
test("microseconds", "nanoseconds");

View File

@ -0,0 +1,48 @@
// 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: >
BalanceDuration throws when the duration signs don't match.
info: |
BalanceDuration ( days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds,
largestUnit [ , relativeTo ] )
...
4. If largestUnit is one of "year", "month", "week", or "day", then
a. Let result be ? NanosecondsToDays(nanoseconds, relativeTo).
b. Set days to result.[[Days]].
c. Set nanoseconds to result.[[Nanoseconds]].
...
15. Return ? CreateTimeDurationRecord(days, hours × sign, minutes × sign, seconds × sign,
milliseconds × sign, microseconds × sign, nanoseconds × sign).
features: [Temporal]
---*/
let duration = Temporal.Duration.from({
hours: -(24 * 1),
nanoseconds: -1,
});
let tz = new class extends Temporal.TimeZone {
#getPossibleInstantsFor = 0;
getPossibleInstantsFor(dt) {
this.#getPossibleInstantsFor++;
if (this.#getPossibleInstantsFor === 1) {
return [new Temporal.Instant(-86400_000_000_000n - 2n)]
}
return super.getPossibleInstantsFor(dt);
}
}("UTC");
let zdt = new Temporal.ZonedDateTime(0n, tz, "iso8601");
let options = {
relativeTo: zdt,
largestUnit: "days",
};
assert.throws(RangeError, () => duration.round(options));

View File

@ -0,0 +1,33 @@
// 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: >
UnbalanceDurationRelative throws a RangeError when duration signs don't match.
features: [Temporal]
---*/
var duration = Temporal.Duration.from({
years: 1,
months: 0,
weeks: 1,
});
var cal = new class extends Temporal.Calendar {
dateUntil(one, two, options) {
var result = super.dateUntil(one, two, options);
return result.negated();
}
}("iso8601");
var relativeTo = new Temporal.PlainDateTime(1970, 1, 1, 0, 0, 0, 0, 0, 0, cal);
assert.sameValue(relativeTo.calendar, cal);
var options = {
smallestUnit: "days",
largestUnit: "month",
relativeTo,
};
assert.throws(RangeError, () => duration.round(options));

View File

@ -0,0 +1,23 @@
// 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 throws a RangeError when the number of nanoseconds is too large.
features: [Temporal]
---*/
var duration = Temporal.Duration.from({
nanoseconds: Number.MAX_VALUE,
});
var zonedDateTime = new Temporal.ZonedDateTime(0n, "UTC");
var options = {
smallestUnit: "day",
largestUnit: "day",
relativeTo: zonedDateTime,
};
assert.throws(RangeError, () => duration.round(options));

View File

@ -0,0 +1,19 @@
// 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.subtract
description: >
AddZonedDateTime throws a RangeError when the intermediate instant is too large.
features: [Temporal]
---*/
const plainDate = new Temporal.PlainDate(1970, 1, 1);
const zonedDateTime = new Temporal.ZonedDateTime(0n, "UTC", "iso8601");
var duration1 = Temporal.Duration.from({days: 1, nanoseconds: Number.MAX_VALUE});
var duration2 = Temporal.Duration.from({days: -1, nanoseconds: -Number.MAX_VALUE});
var options = {relativeTo: zonedDateTime};
assert.throws(RangeError, () => duration1.subtract(duration2, options));

View File

@ -0,0 +1,14 @@
// 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.subtract
description: >
BalanceDuration throws a RangeError when the result is too large.
features: [Temporal]
---*/
var duration1 = Temporal.Duration.from({days: Number.MAX_VALUE});
var duration2 = Temporal.Duration.from({days: -Number.MAX_VALUE});
assert.throws(RangeError, () => duration1.subtract(duration2));

View File

@ -0,0 +1,28 @@
// 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.subtract
description: >
BalanceDuration throws a RangeError when the result is too large.
features: [Temporal]
---*/
const plainDate = new Temporal.PlainDate(1970, 1, 1);
const zonedDateTime = new Temporal.ZonedDateTime(0n, "UTC", "iso8601");
// Largest temporal unit is "nanosecond".
const duration1 = Temporal.Duration.from({nanoseconds: Number.MAX_VALUE});
const duration2 = Temporal.Duration.from({nanoseconds: -Number.MAX_VALUE});
assert.throws(RangeError, () => {
duration1.subtract(duration2);
});
assert.throws(RangeError, () => {
duration1.subtract(duration2, {relativeTo: plainDate});
});
assert.throws(RangeError, () => {
duration1.subtract(duration2, {relativeTo: zonedDateTime});
});

View File

@ -0,0 +1,44 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal-temporaldurationtostring
description: >
Duration components are formatted as precise decimal numbers.
info: |
TemporalDurationToString ( years, months, weeks, days, hours, minutes, seconds, milliseconds,
microseconds, nanoseconds, precision )
...
9. If years is not 0, then
a. Set datePart to the string concatenation of abs(years) formatted as a decimal number and
the code unit 0x0059 (LATIN CAPITAL LETTER Y).
10. If months is not 0, then
a. Set datePart to the string concatenation of datePart, abs(months) formatted as a decimal
number, and the code unit 0x004D (LATIN CAPITAL LETTER M).
If weeks is not 0, then
a. Set datePart to the string concatenation of datePart, abs(weeks) formatted as a decimal
number, and the code unit 0x0057 (LATIN CAPITAL LETTER W).
...
features: [Temporal]
---*/
{
let d = Temporal.Duration.from({weeks: 10000000000000004000});
// Number(10000000000000004000).toString() is "10000000000000004000".
assert.sameValue(d.toString(), "P10000000000000004096W");
}
{
let d = Temporal.Duration.from({months: 9e59});
// Number(9e+59).toString() is "9e+59".
assert.sameValue(d.toString(), "P899999999999999918767229449717619953810131273674690656206848M");
}
{
let d = Temporal.Duration.from({years: Number.MAX_VALUE});
// Number.MAX_VALUE.toString() is "1.7976931348623157e+308".
assert.sameValue(d.toString(), "P179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368Y");
}

View File

@ -0,0 +1,45 @@
// 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.tostring
description: >
RoundDuration throws when the rounded duration can't be represented using
float64-representable integers.
info: |
Temporal.Duration.prototype.toString ( [ options ] )
...
7. Let result be (? RoundDuration(...)).[[DurationRecord]].
...
RoundDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds,
nanoseconds, increment, unit, roundingMode [ , relativeTo ] )
...
15. Else if unit is "second", then
a. Set seconds to RoundNumberToIncrement(fractionalSeconds, increment, roundingMode).
b. Set remainder to fractionalSeconds - seconds.
c. Set milliseconds, microseconds, and nanoseconds to 0.
...
19. Let duration be ? CreateDurationRecord(years, months, weeks, days, hours, minutes, seconds,
milliseconds, microseconds, nanoseconds).
...
CreateDurationRecord ( years, months, weeks, days, hours, minutes, seconds, milliseconds,
microseconds, nanoseconds )
1. If ! IsValidDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds,
microseconds, nanoseconds) is false, throw a RangeError exception.
...
features: [Temporal]
---*/
var duration = Temporal.Duration.from({
seconds: Number.MAX_VALUE,
milliseconds: Number.MAX_VALUE,
});
var options = {smallestUnit: "seconds"};
assert.throws(RangeError, () => duration.toString(options));

View File

@ -0,0 +1,23 @@
// 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.total
description: >
Throws a RangeError if "relativeTo" is a date/time value outside the valid limits.
info: |
Temporal.Duration.prototype.total ( totalOf )
...
6. Let relativeTo be ? ToRelativeTemporalObject(totalOf).
...
ToRelativeTemporalObject ( options )
...
9. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
features: [Temporal]
---*/
var duration = Temporal.Duration.from({nanoseconds: 0});
var options = {unit: "nanoseconds", relativeTo: "+999999-01-01"};
assert.throws(RangeError, () => duration.total(options));

View File

@ -0,0 +1,35 @@
// 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.total
description: >
Relative to a ZonedDateTime with a fractional number of days and different sign.
features: [Temporal]
---*/
let duration = Temporal.Duration.from({
weeks: 1,
days: 0,
hours: 1,
});
let cal = new class extends Temporal.Calendar {
#dateAdd = 0;
dateAdd(date, duration, options) {
if (++this.#dateAdd === 1) {
duration = "-P1W";
}
return super.dateAdd(date, duration, options);
}
}("iso8601");
let zdt = new Temporal.ZonedDateTime(0n, "UTC", cal);
let result = duration.total({
relativeTo: zdt,
unit: "days",
});
assert.sameValue(result, -7 + 1 / 24);

View File

@ -0,0 +1,24 @@
// 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.total
description: >
Relative to a ZonedDateTime with a fractional number of days.
features: [Temporal]
---*/
let duration = Temporal.Duration.from({
weeks: 1,
days: 0,
hours: 1,
});
let zdt = new Temporal.ZonedDateTime(0n, "UTC", "iso8601");
let result = duration.total({
relativeTo: zdt,
unit: "days",
});
assert.sameValue(result, 7 + 1 / 24);

View File

@ -0,0 +1,20 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.instant.compare
description: >
Throws when argument at maximum representable date/time value with a negative offset.
features: [Temporal]
---*/
// Not a valid epoch nanoseconds value due to the offset.
var one = "+275760-09-13T00:00:00.000-12";
var two = {
toString() {
throw new Test262Error();
}
};
assert.throws(RangeError, () => Temporal.Instant.compare(one, two));

View File

@ -0,0 +1,45 @@
// 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, 1, 0, 0, 0, 0, 0, 0, cal);
var options = {largestUnit: "nanoseconds"};
assert.throws(RangeError, () => dt1.since(dt1, options));
assert.throws(RangeError, () => dt1.since(dt2, options));
assert.throws(RangeError, () => dt2.since(dt1, options));

View File

@ -0,0 +1,30 @@
// 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.tozoneddatetime
description: >
Throws when at minimum resp. maximum value and possible instants is an empty List.
info: |
DisambiguatePossibleInstants ( possibleInstants, timeZone, dateTime, disambiguation )
...
9. If ! IsValidEpochNanoseconds(dayBeforeNs) is false, throw a RangeError exception.
...
12. If ! IsValidEpochNanoseconds(dayAfterNs) is false, throw a RangeError exception.
...
features: [Temporal]
---*/
class TZ extends Temporal.TimeZone {
getPossibleInstantsFor() {
return [];
}
}
var tz = new TZ("UTC");
var min = new Temporal.PlainDateTime(-271821, 4, 20);
var max = new Temporal.PlainDateTime(275760, 9, 13);
assert.throws(RangeError, () => min.toZonedDateTime(tz), "minimum date-time");
assert.throws(RangeError, () => max.toZonedDateTime(tz), "maximum date-time");

View File

@ -0,0 +1,34 @@
// 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.tozoneddatetime
description: >
Throws a RangeError if the date/time value is outside the instant limits
info: |
Temporal.PlainDateTime.prototype.toZonedDateTime ( temporalTimeZoneLike [ , options ] )
...
6. Let instant be ? BuiltinTimeZoneGetInstantFor(timeZone, dateTime, disambiguation).
...
features: [Temporal]
---*/
// Try to create from the minimum date-time.
{
let dt = new Temporal.PlainDateTime(-271821, 4, 19, 0, 0, 0, 0, 0, 1);
assert.throws(RangeError, () => dt.toZonedDateTime("UTC"));
}
{
let dt = new Temporal.PlainDateTime(-271821, 4, 19, 1, 0, 0, 0, 0, 0);
assert.throws(RangeError, () => dt.toZonedDateTime("UTC"));
}
// Try to create from the maximum date-time.
{
let dt = new Temporal.PlainDateTime(275760, 9, 13, 0, 0, 0, 0, 0, 1);
assert.throws(RangeError, () => dt.toZonedDateTime("UTC"));
}
{
let dt = new Temporal.PlainDateTime(275760, 9, 13, 1, 0, 0, 0, 0, 0);
assert.throws(RangeError, () => dt.toZonedDateTime("UTC"));
}

View File

@ -0,0 +1,45 @@
// 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, 1, 0, 0, 0, 0, 0, 0, cal);
var options = {largestUnit: "nanoseconds"};
assert.throws(RangeError, () => dt1.until(dt1, options));
assert.throws(RangeError, () => dt1.until(dt2, options));
assert.throws(RangeError, () => dt2.until(dt1, options));

View File

@ -0,0 +1,18 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.plaintime.prototype.add
description: >
ParseTemporalDurationString throws a RangeError when the result is too large.
features: [Temporal]
---*/
// Number string too long to be representable as a Number value.
var ones = "1".repeat(1000);
assert.sameValue(Number(ones), Infinity);
var time = new Temporal.PlainTime();
var str = "PT" + ones + "S";
assert.throws(RangeError, () => time.add(str));

View File

@ -0,0 +1,18 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.plaintime.prototype.subtract
description: >
ParseTemporalDurationString throws a RangeError when the result is too large.
features: [Temporal]
---*/
// Number string too long to be representable as a Number value.
var ones = "1".repeat(1000);
assert.sameValue(Number(ones), Infinity);
var time = new Temporal.PlainTime();
var str = "PT" + ones + "S";
assert.throws(RangeError, () => time.subtract(str));

View File

@ -0,0 +1,54 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.timezone.prototype.getpossibleinstantsfor
description: >
Call getPossibleInstantsFor with values near the date/time limit and a fixed offset.
features: [Temporal]
---*/
const oneHour = 1n * 60n * 60n * 1000n**3n;
const minDt = new Temporal.PlainDateTime(-271821, 4, 19, 1, 0, 0, 0, 0, 0);
const minValidDt = new Temporal.PlainDateTime(-271821, 4, 20, 0, 0, 0, 0, 0, 0);
const maxDt = new Temporal.PlainDateTime(275760, 9, 13, 0, 0, 0, 0, 0, 0);
let zero = new Temporal.TimeZone("+00");
let plusOne = new Temporal.TimeZone("+01");
let minusOne = new Temporal.TimeZone("-01");
// Try the minimum date-time.
assert.throws(RangeError, () => zero.getPossibleInstantsFor(minDt));
assert.throws(RangeError, () => plusOne.getPossibleInstantsFor(minDt));
assert.throws(RangeError, () => minusOne.getPossibleInstantsFor(minDt));
// Try the minimum valid date-time.
{
let r = zero.getPossibleInstantsFor(minValidDt);
assert.sameValue(r.length, 1);
assert.sameValue(r[0].epochNanoseconds, -86_40000_00000_00000_00000n);
}
{
let r = minusOne.getPossibleInstantsFor(minValidDt);
assert.sameValue(r.length, 1);
assert.sameValue(r[0].epochNanoseconds, -86_40000_00000_00000_00000n + oneHour);
}
assert.throws(RangeError, () => plusOne.getPossibleInstantsFor(minValidDt));
// Try the maximum valid date-time.
{
let r = zero.getPossibleInstantsFor(maxDt);
assert.sameValue(r.length, 1);
assert.sameValue(r[0].epochNanoseconds, 86_40000_00000_00000_00000n);
}
{
let r = plusOne.getPossibleInstantsFor(maxDt);
assert.sameValue(r.length, 1);
assert.sameValue(r[0].epochNanoseconds, 86_40000_00000_00000_00000n - oneHour);
}
assert.throws(RangeError, () => minusOne.getPossibleInstantsFor(maxDt));

View File

@ -0,0 +1,85 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.prototype.round
description: >
Round smallestUnit "day" with very large or very small divisor (dayLengthNs).
info: |
Temporal.ZonedDateTime.prototype.round ( roundTo )
...
18. Let dayLengthNs be (endNs - startNs).
...
20. Let roundResult be ! RoundISODateTime(temporalDateTime.[[ISOYear]],
temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], temporalDateTime.[[ISOHour]],
temporalDateTime.[[ISOMinute]], temporalDateTime.[[ISOSecond]],
temporalDateTime.[[ISOMillisecond]], temporalDateTime.[[ISOMicrosecond]],
temporalDateTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode,
dayLengthNs).
...
RoundISODateTime ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond,
increment, unit, roundingMode [ , dayLength ] )
...
4. Let roundedTime be ! RoundTime(hour, minute, second, millisecond, microsecond, nanosecond,
increment, unit, roundingMode, dayLength).
...
RoundTime ( hour, minute, second, millisecond, microsecond, nanosecond, increment, unit,
roundingMode [ , dayLengthNs ] )
...
4. If unit is "day", then
...
b. Let quantity be (((((hour × 60 + minute) × 60 + second) × 1000 + millisecond) × 1000 +
microsecond) × 1000 + nanosecond) / dayLengthNs.
...
features: [Temporal]
---*/
class TimeZone extends Temporal.TimeZone {
#count = 0;
#nanoseconds;
constructor(nanoseconds) {
super("UTC");
this.#nanoseconds = nanoseconds;
}
getPossibleInstantsFor(dateTime) {
if (++this.#count === 2) {
return [new Temporal.Instant(this.#nanoseconds)];
}
return super.getPossibleInstantsFor(dateTime);
}
}
const maxInstant = 86_40000_00000_00000_00000n;
const minInstant = -86_40000_00000_00000_00000n;
const oneDay = 24n * 60n * 60n * 1000n * 1000n * 1000n
// Divisor too large.
{
let tz = new TimeZone(maxInstant);
let zoned = new Temporal.ZonedDateTime(0n, tz);
let result = zoned.round({ smallestUnit: "days" });
assert(zoned.equals(result));
}
{
let tz = new TimeZone(maxInstant);
let zoned = new Temporal.ZonedDateTime(minInstant, tz);
let result = zoned.round({ smallestUnit: "days" });
assert(zoned.equals(result));
}
// Divisor too small.
{
let tz = new TimeZone(minInstant);
let zoned = new Temporal.ZonedDateTime(0n, tz);
let result = zoned.round({ smallestUnit: "days" });
assert(zoned.equals(result));
}
{
let tz = new TimeZone(minInstant);
let zoned = new Temporal.ZonedDateTime(maxInstant - oneDay, tz);
let result = zoned.round({ smallestUnit: "days" });
assert(zoned.equals(result));
}

View File

@ -0,0 +1,67 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.prototype.round
description: >
Round smallestUnit "day" with zero or negative day length.
info: |
Temporal.ZonedDateTime.prototype.round ( roundTo )
...
18. Let dayLengthNs be (endNs - startNs).
19. If dayLengthNs is 0, then
a. Throw a RangeError exception.
20. Let roundResult be ! RoundISODateTime(temporalDateTime.[[ISOYear]],
temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], temporalDateTime.[[ISOHour]],
temporalDateTime.[[ISOMinute]], temporalDateTime.[[ISOSecond]],
temporalDateTime.[[ISOMillisecond]], temporalDateTime.[[ISOMicrosecond]],
temporalDateTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode,
dayLengthNs).
...
RoundISODateTime ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond,
increment, unit, roundingMode [ , dayLength ] )
...
4. Let roundedTime be ! RoundTime(hour, minute, second, millisecond, microsecond, nanosecond,
increment, unit, roundingMode, dayLength).
...
RoundTime ( hour, minute, second, millisecond, microsecond, nanosecond, increment, unit,
roundingMode [ , dayLengthNs ] )
...
4. If unit is "day", then
...
b. Let quantity be (((((hour × 60 + minute) × 60 + second) × 1000 + millisecond) × 1000 +
microsecond) × 1000 + nanosecond) / dayLengthNs.
...
features: [Temporal]
---*/
class TimeZone extends Temporal.TimeZone {
#count = 0;
#nanoseconds;
constructor(nanoseconds) {
super("UTC");
this.#nanoseconds = nanoseconds;
}
getPossibleInstantsFor(dateTime) {
if (++this.#count === 2) {
return [new Temporal.Instant(this.#nanoseconds)];
}
return super.getPossibleInstantsFor(dateTime);
}
}
{
let tz = new TimeZone(0n);
let zoned = new Temporal.ZonedDateTime(0n, tz);
assert.throws(RangeError, () => zoned.round({ smallestUnit: "days" }));
}
{
let tz = new TimeZone(-1n);
let zoned = new Temporal.ZonedDateTime(0n, tz);
let result = zoned.round({ smallestUnit: "days" });
assert(zoned.equals(result));
}

View File

@ -0,0 +1,30 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.prototype.with
description: >
Throws a RangeError when ZonedDateTime at minimum instant and an explicit +1h offset.
info: |
Temporal.ZonedDateTime.prototype.with ( temporalZonedDateTimeLike [ , options ] )
...
21. Let epochNanoseconds be ? InterpretISODateTimeOffset(dateTimeResult.[[Year]],
dateTimeResult.[[Month]], dateTimeResult.[[Day]], dateTimeResult.[[Hour]],
dateTimeResult.[[Minute]], dateTimeResult.[[Second]], dateTimeResult.[[Millisecond]],
dateTimeResult.[[Microsecond]], dateTimeResult.[[Nanosecond]], option, offsetNanoseconds,
timeZone, disambiguation, offset, match exactly).
...
features: [Temporal]
---*/
let zdt = new Temporal.ZonedDateTime(-86_40000_00000_00000_00000n, "UTC");
let temporalZonedDateTimeLike = {
offset: "+01",
};
let options = {
offset: "use",
};
assert.throws(RangeError, () => zdt.with(temporalZonedDateTimeLike, options));

View File

@ -0,0 +1,39 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.prototype.with
description: >
Throws a RangeError for the minimum date/value with UTC offset and an explicit offset.
info: |
Temporal.ZonedDateTime.prototype.with ( temporalZonedDateTimeLike [ , options ] )
...
21. Let epochNanoseconds be ? InterpretISODateTimeOffset(dateTimeResult.[[Year]],
dateTimeResult.[[Month]], dateTimeResult.[[Day]], dateTimeResult.[[Hour]],
dateTimeResult.[[Minute]], dateTimeResult.[[Second]], dateTimeResult.[[Millisecond]],
dateTimeResult.[[Microsecond]], dateTimeResult.[[Nanosecond]], option, offsetNanoseconds,
timeZone, disambiguation, offset, match exactly).
...
features: [Temporal]
---*/
let zdt = new Temporal.ZonedDateTime(0n, "UTC");
let temporalZonedDateTimeLike = {
year: -271821,
month: 4,
day: 19,
hour: 1,
minute: 0,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
offset: "+00",
};
let options = {
offset: "use",
};
assert.throws(RangeError, () => zdt.with(temporalZonedDateTimeLike, options));

View File

@ -0,0 +1,34 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.zoneddatetime.prototype.with
description: >
Throws a RangeError for the minimum date/value with UTC offset.
info: |
Temporal.ZonedDateTime.prototype.with ( temporalZonedDateTimeLike [ , options ] )
...
21. Let epochNanoseconds be ? InterpretISODateTimeOffset(dateTimeResult.[[Year]],
dateTimeResult.[[Month]], dateTimeResult.[[Day]], dateTimeResult.[[Hour]],
dateTimeResult.[[Minute]], dateTimeResult.[[Second]], dateTimeResult.[[Millisecond]],
dateTimeResult.[[Microsecond]], dateTimeResult.[[Nanosecond]], option, offsetNanoseconds,
timeZone, disambiguation, offset, match exactly).
...
features: [Temporal]
---*/
let zdt = new Temporal.ZonedDateTime(0n, "UTC");
let temporalZonedDateTimeLike = {
year: -271821,
month: 4,
day: 19,
hour: 1,
minute: 0,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0,
};
assert.throws(RangeError, () => zdt.with(temporalZonedDateTimeLike));

View File

@ -0,0 +1,55 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.timezone.prototype.getnexttransition
description: >
Compute next transition when seconds resp. nanoseconds are subtracted from the last transition.
features: [Temporal]
---*/
// From <https://github.com/eggert/tz/blob/main/europe>:
//
// # Zone NAME STDOFF RULES FORMAT [UNTIL]
// Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15 0:01
// 0:09:21 - PMT 1911 Mar 11 0:01 # Paris MT
let tz = new Temporal.TimeZone("Europe/Paris");
let zdt = new Temporal.PlainDateTime(1800, 1, 1).toZonedDateTime(tz);
assert.sameValue(zdt.toString(), "1800-01-01T00:00:00+00:09[Europe/Paris]");
assert.sameValue(zdt.offsetNanoseconds, (9 * 60 + 21) * 1_000_000_000);
// Ensure the first transition was correctly computed.
let first = tz.getNextTransition(zdt);
assert.sameValue(first.toString(), "1911-03-10T23:50:39Z");
assert.sameValue(new Temporal.ZonedDateTime(first.epochNanoseconds, tz).toString(),
"1911-03-10T23:50:39+00:00[Europe/Paris]");
let next;
// Compute the next transition starting from the first transition minus 1s.
let firstMinus1s = first.add({seconds: -1});
assert.sameValue(firstMinus1s.toString(), "1911-03-10T23:50:38Z");
assert.sameValue(new Temporal.ZonedDateTime(firstMinus1s.epochNanoseconds, tz).toString(),
"1911-03-10T23:59:59+00:09[Europe/Paris]");
assert.sameValue(new Temporal.ZonedDateTime(firstMinus1s.epochNanoseconds, tz).offsetNanoseconds,
(9 * 60 + 21) * 1_000_000_000);
next = tz.getNextTransition(firstMinus1s);
assert.sameValue(next.toString(), "1911-03-10T23:50:39Z");
assert.sameValue(new Temporal.ZonedDateTime(next.epochNanoseconds, tz).toString(),
"1911-03-10T23:50:39+00:00[Europe/Paris]");
// Compute the next transition starting from the first transition minus 1ns.
let firstMinus1ns = first.add({nanoseconds: -1});
assert.sameValue(firstMinus1ns.toString(), "1911-03-10T23:50:38.999999999Z");
assert.sameValue(new Temporal.ZonedDateTime(firstMinus1ns.epochNanoseconds, tz).toString(),
"1911-03-10T23:59:59.999999999+00:09[Europe/Paris]");
assert.sameValue(new Temporal.ZonedDateTime(firstMinus1ns.epochNanoseconds, tz).offsetNanoseconds,
(9 * 60 + 21) * 1_000_000_000);
next = tz.getNextTransition(firstMinus1ns);
assert.sameValue(next.toString(), "1911-03-10T23:50:39Z");
assert.sameValue(new Temporal.ZonedDateTime(next.epochNanoseconds, tz).toString(),
"1911-03-10T23:50:39+00:00[Europe/Paris]");

View File

@ -0,0 +1,24 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.timezone.prototype.getprevioustransition
description: >
Test previous transition when nanoseconds are subtracted resp. added to the DST transition.
features: [Temporal]
---*/
let tz = new Temporal.TimeZone("Europe/Berlin");
let p = Temporal.Instant.from("2021-03-28T01:00:00Z");
assert.sameValue(tz.getPreviousTransition(p.add({nanoseconds: -1})).toString(),
"2020-10-25T01:00:00Z",
"DST transition minus one nanosecond");
assert.sameValue(tz.getPreviousTransition(p).toString(),
"2020-10-25T01:00:00Z",
"DST transition");
assert.sameValue(tz.getPreviousTransition(p.add({nanoseconds: +1})).toString(),
"2021-03-28T01:00:00Z",
"DST transition plus one nanosecond");

View File

@ -0,0 +1,16 @@
// Copyright (C) 2022 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.timezone
description: >
TimeZone constructor accepts all time zone identifiers from Intl.supportedValuesOf.
features: [Temporal, Intl-enumeration]
---*/
// Ensure all identifiers are valid and canonical.
for (let id of Intl.supportedValuesOf("timeZone")) {
let tz = new Temporal.TimeZone(id);
assert.sameValue(tz.id, id);
}