Skip to content

Commit

Permalink
Limit offset time zones to minute precision
Browse files Browse the repository at this point in the history
Modify/add tests for tc39/proposal-temporal#2607
  • Loading branch information
justingrant authored and ptomato committed Jul 18, 2023
1 parent 60e4752 commit 6f146e6
Show file tree
Hide file tree
Showing 93 changed files with 680 additions and 377 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,25 @@

/*---
esid: sec-temporal.duration.compare
description: relativeTo string accepts an inexact UTC offset rounded to hours and minutes
description: relativeTo string accepts trailing zeroes in sub-minute UTC offset
features: [Temporal]
---*/

const duration1 = new Temporal.Duration(0, 0, 0, 31);
const duration2 = new Temporal.Duration(0, 1);

let relativeTo = "2000-01-01T00:00+00:45[+00:44:30.123456789]";
assert.sameValue(Temporal.Duration.compare(duration1, duration2, { relativeTo }), 0, "rounded HH:MM is accepted in string");
let result;
let relativeTo;

relativeTo = "2000-01-01T00:00+00:44:30[+00:44:30.123456789]";
assert.throws(RangeError, () => Temporal.Duration.compare(duration1, duration2, { relativeTo }), "no other rounding is accepted for offset");
const action = (relativeTo) => Temporal.Duration.compare(duration1, duration2, { relativeTo });

const timeZone = new Temporal.TimeZone("+00:44:30.123456789");
relativeTo = { year: 2000, month: 1, day: 1, offset: "+00:45", timeZone };
assert.throws(RangeError, () => Temporal.Duration.compare(duration1, duration2, { relativeTo }), "rounded HH:MM not accepted as offset in property bag");
relativeTo = "1970-01-01T00:00-00:45:00[-00:45]";
result = action(relativeTo);
assert.sameValue(result, 0, "ISO string offset accepted with zero seconds (string)");

relativeTo = { year: 1970, month: 1, day: 1, offset: "+00:45:00.000000000", timeZone: "+00:45" };
result = action(relativeTo);
assert.sameValue(result, 0, "ISO string offset accepted with zero seconds (property bag)");

relativeTo = "1970-01-01T00:00+00:44:30.123456789[+00:45]";
assert.throws(RangeError, () => action(relativeTo), "rounding is not accepted between ISO offset and time zone");
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@

/*---
esid: sec-temporal.duration.prototype.add
description: relativeTo string accepts an inexact UTC offset rounded to hours and minutes
description: relativeTo string accepts trailing zeroes in sub-minute UTC offset
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const instance = new Temporal.Duration(1, 0, 0, 1);
let result;
let relativeTo;
const action = (relativeTo) => instance.add(new Temporal.Duration(0, 0, 0, 0, -24), { relativeTo });

let relativeTo = "2000-01-01T00:00+00:45[+00:44:30.123456789]";
const result = instance.add(new Temporal.Duration(0, 0, 0, 0, -24), { relativeTo });
TemporalHelpers.assertDuration(result, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounded HH:MM is accepted in string");
relativeTo = "1970-01-01T00:00-00:45:00[-00:45]";
result = action(relativeTo);
TemporalHelpers.assertDateDuration(result, 1, 0, 0, 0, "ISO string offset accepted with zero seconds (string)");

relativeTo = "2000-01-01T00:00+00:44:30[+00:44:30.123456789]";
assert.throws(RangeError, () => instance.add(new Temporal.Duration(0, 0, 0, 0, -24), { relativeTo }), "no other rounding is accepted for offset");
relativeTo = { year: 1970, month: 1, day: 1, offset: "+00:45:00.000000000", timeZone: "+00:45" };
result = action(relativeTo);
TemporalHelpers.assertDateDuration(result, 1, 0, 0, 0, "ISO string offset accepted with zero seconds (property bag)");

const timeZone = new Temporal.TimeZone("+00:44:30.123456789");
relativeTo = { year: 2000, month: 1, day: 1, offset: "+00:45", timeZone };
assert.throws(RangeError, () => instance.add(new Temporal.Duration(0, 0, 0, 0, -24), { relativeTo }), "rounded HH:MM not accepted as offset in property bag");
relativeTo = "1970-01-01T00:00+00:44:30.123456789[+00:45]";
assert.throws(RangeError, () => action(relativeTo), "rounding is not accepted between ISO offset and time zone");
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,25 @@

/*---
esid: sec-temporal.duration.prototype.round
description: relativeTo string accepts an inexact UTC offset rounded to hours and minutes
description: relativeTo string accepts trailing zeroes in sub-minute UTC offset
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const instance = new Temporal.Duration(1, 0, 0, 0, 24);

let relativeTo = "2000-01-01T00:00+00:45[+00:44:30.123456789]";
const result = instance.round({ largestUnit: "years", relativeTo });
TemporalHelpers.assertDuration(result, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, "rounded HH:MM is accepted in string");
let result;
let relativeTo;

relativeTo = "2000-01-01T00:00+00:44:30[+00:44:30.123456789]";
assert.throws(RangeError, () => instance.round({ largestUnit: "years", relativeTo }), "no other rounding is accepted for offset");
const action = (relativeTo) => instance.round({ largestUnit: "years", relativeTo });

const timeZone = new Temporal.TimeZone("+00:44:30.123456789");
relativeTo = { year: 2000, month: 1, day: 1, offset: "+00:45", timeZone };
assert.throws(RangeError, () => instance.round({ largestUnit: "years", relativeTo }), "rounded HH:MM not accepted as offset in property bag");
relativeTo = "1970-01-01T00:00-00:45:00[-00:45]";
result = action(relativeTo);
TemporalHelpers.assertDateDuration(result, 1, 0, 0, 1, "ISO string offset accepted with zero seconds (string)");

relativeTo = { year: 1970, month: 1, day: 1, offset: "+00:45:00.000000000", timeZone: "+00:45" };
result = action(relativeTo);
TemporalHelpers.assertDateDuration(result, 1, 0, 0, 1, "ISO string offset accepted with zero seconds (property bag)");

relativeTo = "1970-01-01T00:00+00:44:30.123456789[+00:45]";
assert.throws(RangeError, () => action(relativeTo), "rounding is not accepted between ISO offset and time zone");
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,24 @@

/*---
esid: sec-temporal.duration.prototype.subtract
description: relativeTo string accepts an inexact UTC offset rounded to hours and minutes
description: relativeTo string accepts trailing zeroes in sub-minute UTC offset
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const instance = new Temporal.Duration(1, 0, 0, 1);

let relativeTo = "2000-01-01T00:00+00:45[+00:44:30.123456789]";
const result = instance.subtract(new Temporal.Duration(0, 0, 0, 0, 24), { relativeTo });
TemporalHelpers.assertDuration(result, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounded HH:MM is accepted in string");
let result;
let relativeTo;
const action = (relativeTo) => instance.subtract(new Temporal.Duration(0, 0, 0, 0, 24), { relativeTo });

relativeTo = "2000-01-01T00:00+00:44:30[+00:44:30.123456789]";
assert.throws(RangeError, () => instance.subtract(new Temporal.Duration(0, 0, 0, 0, 24), { relativeTo }), "no other rounding is accepted for offset");
relativeTo = "1970-01-01T00:00-00:45:00[-00:45]";
result = action(relativeTo);
TemporalHelpers.assertDateDuration(result, 1, 0, 0, 0, "ISO string offset accepted with zero seconds (string)");

const timeZone = new Temporal.TimeZone("+00:44:30.123456789");
relativeTo = { year: 2000, month: 1, day: 1, offset: "+00:45", timeZone };
assert.throws(RangeError, () => instance.subtract(new Temporal.Duration(0, 0, 0, 0, 24), { relativeTo }), "rounded HH:MM not accepted as offset in property bag");
relativeTo = { year: 1970, month: 1, day: 1, offset: "+00:45:00.000000000", timeZone: "+00:45" };
result = action(relativeTo);
TemporalHelpers.assertDateDuration(result, 1, 0, 0, 0, "ISO string offset accepted with zero seconds (property bag)");

relativeTo = "1970-01-01T00:00+00:44:30.123456789[+00:45]";
assert.throws(RangeError, () => action(relativeTo), "rounding is not accepted between ISO offset and time zone");
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,24 @@

/*---
esid: sec-temporal.duration.prototype.total
description: relativeTo string accepts an inexact UTC offset rounded to hours and minutes
description: relativeTo string accepts trailing zeroes in sub-minute UTC offset
features: [Temporal]
---*/

const instance = new Temporal.Duration(1, 0, 0, 0, 24);

let relativeTo = "2000-01-01T00:00+00:45[+00:44:30.123456789]";
const result = instance.total({ unit: "days", relativeTo });
assert.sameValue(result, 367, "rounded HH:MM is accepted in string");
let result;
let relativeTo;

relativeTo = "2000-01-01T00:00+00:44:30[+00:44:30.123456789]";
assert.throws(RangeError, () => instance.total({ unit: "days", relativeTo }), "no other rounding is accepted for offset");
const action = (relativeTo) => instance.total({ unit: "days", relativeTo });

const timeZone = new Temporal.TimeZone("+00:44:30.123456789");
relativeTo = { year: 2000, month: 1, day: 1, offset: "+00:45", timeZone };
assert.throws(RangeError, () => instance.total({ unit: "days", relativeTo }), "rounded HH:MM not accepted as offset in property bag");
relativeTo = "1970-01-01T00:00-00:45:00[-00:45]";
result = action(relativeTo);
assert.sameValue(result, 366, "ISO string offset accepted with zero seconds (string)");

relativeTo = { year: 1970, month: 1, day: 1, offset: "+00:45:00.000000000", timeZone: "+00:45" };
result = action(relativeTo);
assert.sameValue(result, 366, "ISO string offset accepted with zero seconds (property bag)");

relativeTo = "1970-01-01T00:00+00:44:30.123456789[+00:45]";
assert.throws(RangeError, () => action(relativeTo), "rounding is not accepted between ISO offset and time zone");
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ features: [Temporal]
---*/

const epoch = new Temporal.Instant(0n);
const str = "1970-01-01T00:02:00.000000000+00:02[+00:01:30.987654321]";
const str = "1970-01-01T00:02:00.000000000+00:02[+01:30]";

assert.sameValue(Temporal.Instant.compare(str, epoch), 0, "UTC offset determined from offset part of string (first argument)");
assert.sameValue(Temporal.Instant.compare(epoch, str), 0, "UTC offset determined from offset part of string (second argument)");
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: Instant strings with UTC offset fractional part are not confused wi
features: [Temporal]
---*/

const str = "1970-01-01T00:02:00.000000000+00:02[+00:01:30.987654321]";
const str = "1970-01-01T00:02:00.000000000+00:02[+01:30]";

const result = Temporal.Instant.from(str);
assert.sameValue(result.epochNanoseconds, 0n, "UTC offset determined from offset part of string");
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ features: [Temporal]
---*/

const instance = new Temporal.Instant(0n);
const str = "1970-01-01T00:02:00.000000000+00:02[+00:01:30.987654321]";
const str = "1970-01-01T00:02:00.000000000+00:02[+01:30]";

const result = instance.equals(str);
assert.sameValue(result, true, "UTC offset determined from offset part of string");
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ features: [Temporal]
---*/

const instance = new Temporal.Instant(0n);
const str = "1970-01-01T00:02:00.000000000+00:02[+00:01:30.987654321]";
const str = "1970-01-01T00:02:00.000000000+00:02[+01:30]";

const result = instance.since(str);
TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "UTC offset determined from offset part of string");
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,3 @@ function test(timeZoneIdentifier, expected, description) {
test("UTC", "1970-01-01T00:00:00+00:00", "offset of UTC is +00:00");
test("+01:00", "1970-01-01T01:00:00+01:00", "positive offset");
test("-05:00", "1969-12-31T19:00:00-05:00", "negative offset");
test("+00:44:59.123456789", "1970-01-01T00:44:59.123456789+00:45", "sub-minute offset");
test("-00:00:10.987654321", "1969-12-31T23:59:49.012345679+00:00", "sub-minute offset that rounds to zero");
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

/*---
esid: sec-temporal.instant.prototype.tostring
description: Time zone strings with UTC offset fractional part are not confused with time fractional part
description: Time zone strings with UTC offset are not confused with time
features: [Temporal]
---*/

const instance = new Temporal.Instant(0n);
const timeZone = "2021-08-19T17:30:45.123456789+01:46[+01:45:30.987654321]";
const timeZone = "2021-08-19T17:30:45.123456789-12:12[+01:46]";

const result = instance.toString({ timeZone });
assert.sameValue(result.substr(-6), "+01:46", "Time zone string determined from offset");
assert.sameValue(result.substr(-6), "+01:46", "Time zone string determined from bracket name");
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

/*---
esid: sec-temporal.instant.prototype.tozoneddatetime
description: Time zone strings with UTC offset fractional part are not confused with time fractional part
description: Time zone parsing from ISO strings uses the bracketed offset, not the ISO string offset
features: [Temporal]
---*/

const instance = new Temporal.Instant(0n);
const timeZone = "2021-08-19T17:30:45.123456789+01:46[+01:45:30.987654321]";
const timeZone = "2021-08-19T17:30:45.123456789-12:12[+01:46]";

const result = instance.toZonedDateTime({ timeZone, calendar: "iso8601" });
assert.sameValue(result.timeZoneId, "+01:45:30.987654321", "Time zone string determined from bracket name");
assert.sameValue(result.timeZoneId, "+01:46", "Time zone string determined from bracket name");
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

/*---
esid: sec-temporal.instant.prototype.tozoneddatetimeiso
description: Time zone strings with UTC offset fractional part are not confused with time fractional part
description: Time zone parsing from ISO strings uses the bracketed offset, not the ISO string offset
features: [Temporal]
---*/

const instance = new Temporal.Instant(0n);
const timeZone = "2021-08-19T17:30:45.123456789+01:46[+01:45:30.987654321]";
const timeZone = "2021-08-19T17:30:45.123456789-12:12[+01:46]";

const result = instance.toZonedDateTimeISO(timeZone);
assert.sameValue(result.timeZoneId, "+01:45:30.987654321", "Time zone string determined from bracket name");
assert.sameValue(result.timeZoneId, "+01:46", "Time zone string determined from bracket name");
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ features: [Temporal]
---*/

const instance = new Temporal.Instant(0n);
const str = "1970-01-01T00:02:00.000000000+00:02[+00:01:30.987654321]";
const str = "1970-01-01T00:02:00.000000000+00:02[+01:30]";

const result = instance.until(str);
TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "UTC offset determined from offset part of string");
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

/*---
esid: sec-temporal.now.zoneddatetime
description: Time zone strings with UTC offset fractional part are not confused with time fractional part
description: Time zone parsing from ISO strings uses the bracketed offset, not the ISO string offset
features: [Temporal]
---*/

const timeZone = "2021-08-19T17:30:45.123456789+01:46[+01:45:30.987654321]";
const timeZone = "2021-08-19T17:30:45.123456789-12:12[+01:46]";

const result = Temporal.Now.zonedDateTime("iso8601", timeZone);
assert.sameValue(result.timeZoneId, "+01:45:30.987654321", "Time zone string determined from bracket name");
assert.sameValue(result.timeZoneId, "+01:46", "Time zone string determined from bracket name");
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

/*---
esid: sec-temporal.now.zoneddatetimeiso
description: Time zone strings with UTC offset fractional part are not confused with time fractional part
description: Time zone parsing from ISO strings uses the bracketed offset, not the ISO string offset
features: [Temporal]
---*/

const timeZone = "2021-08-19T17:30:45.123456789+01:46[+01:45:30.987654321]";
const timeZone = "2021-08-19T17:30:45.123456789-12:12[+01:46]";

const result = Temporal.Now.zonedDateTimeISO(timeZone);
assert.sameValue(result.timeZoneId, "+01:45:30.987654321", "Time zone string determined from bracket name");
assert.sameValue(result.timeZoneId, "+01:46", "Time zone string determined from bracket name");
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ features: [Temporal]
// This code path is encountered if the time zone offset is negative and its
// absolute value in nanoseconds is greater than the nanosecond field of the
// exact time's epoch parts
const tz = new Temporal.TimeZone("-00:00:00.000000002");
const tz = TemporalHelpers.specificOffsetTimeZone(-2);
const datetime = new Temporal.ZonedDateTime(3661_001_001_001n, tz);

const date = new Temporal.PlainDate(2000, 5, 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ info: |
ii. 1. Set _plainDateTime_ to ? BuiltinTimeZoneGetPlainDateTimeFor(_item_.[[TimeZone]], _instant_, _item_.[[Calendar]]).
sec-temporal.plaindate.prototype.tozoneddatetime step 6.a:
a. Set _temporalTime_ to ? ToTemporalTime(_temporalTime_).
includes: [temporalHelpers.js]
features: [Temporal]
---*/

// This code path is encountered if the time zone offset is negative and its
// absolute value in nanoseconds is greater than the nanosecond field of the
// exact time's epoch parts
const tz = new Temporal.TimeZone("-00:00:00.000000002");
const tz = TemporalHelpers.specificOffsetTimeZone(-2);
const datetime = new Temporal.ZonedDateTime(3661_001_001_001n, tz);

const otherTimeZone = new Temporal.TimeZone("UTC"); // should not be used to convert datetime to PlainTime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

/*---
esid: sec-temporal.plaindate.prototype.tozoneddatetime
description: Time zone strings with UTC offset fractional part are not confused with time fractional part
description: Time zone parsing from ISO strings uses the bracketed offset, not the ISO string offset
features: [Temporal]
---*/

const instance = new Temporal.PlainDate(2000, 5, 2);
const timeZone = "2021-08-19T17:30:45.123456789+01:46[+01:45:30.987654321]";
const timeZone = "2021-08-19T17:30:45.123456789-12:12[+01:46]";

const result = instance.toZonedDateTime(timeZone);
assert.sameValue(result.timeZoneId, "+01:45:30.987654321", "Time zone string determined from bracket name");
assert.sameValue(result.timeZoneId, "+01:46", "Time zone string determined from bracket name");
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ features: [Temporal]
// This code path is encountered if the time zone offset is negative and its
// absolute value in nanoseconds is greater than the nanosecond field of the
// exact time's epoch parts
const tz = new Temporal.TimeZone("-00:00:00.000000002");
const tz = TemporalHelpers.specificOffsetTimeZone(-2);
const datetime = new Temporal.ZonedDateTime(3661_001_001_001n, tz);

const pdt = Temporal.PlainDateTime.from(datetime);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ info: |
ii. 1. Return ? BuiltinTimeZoneGetPlainDateTimeFor(_item_.[[TimeZone]], _instant_, _item_.[[Calendar]]).
sec-temporal.plaindatetime.prototype.until step 3:
3. Set _other_ ? ToTemporalDateTime(_other_).
includes: [temporalHelpers.js]
features: [Temporal]
---*/

// This code path is encountered if the time zone offset is negative and its
// absolute value in nanoseconds is greater than the nanosecond field of the
// exact time's epoch parts
const tz = new Temporal.TimeZone("-00:00:00.000000002");
const tz = TemporalHelpers.specificOffsetTimeZone(-2);
const datetime = new Temporal.ZonedDateTime(3661_001_001_001n, tz);

assert(new Temporal.PlainDateTime(1970, 1, 1, 1, 1, 1, 1, 0, 999).equals(datetime));
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ features: [Temporal]
// This code path is encountered if the time zone offset is negative and its
// absolute value in nanoseconds is greater than the nanosecond field of the
// exact time's epoch parts
const tz = new Temporal.TimeZone("-00:00:00.000000002");
const tz = TemporalHelpers.specificOffsetTimeZone(-2);
const datetime = new Temporal.ZonedDateTime(3661_001_001_001n, tz);

const diff = new Temporal.PlainDateTime(1970, 1, 1).since(datetime);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

/*---
esid: sec-temporal.plaindatetime.prototype.tozoneddatetime
description: Time zone strings with UTC offset fractional part are not confused with time fractional part
description: Time zone parsing from ISO strings uses the bracketed offset, not the ISO string offset
features: [Temporal]
---*/

const instance = new Temporal.PlainDateTime(2000, 5, 2);
const timeZone = "2021-08-19T17:30:45.123456789+01:46[+01:45:30.987654321]";
const timeZone = "2021-08-19T17:30:45.123456789-12:12[+01:46]";

const result = instance.toZonedDateTime(timeZone);
assert.sameValue(result.timeZoneId, "+01:45:30.987654321", "Time zone string determined from bracket name");
assert.sameValue(result.timeZoneId, "+01:46", "Time zone string determined from bracket name");
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ features: [Temporal]
// This code path is encountered if the time zone offset is negative and its
// absolute value in nanoseconds is greater than the nanosecond field of the
// exact time's epoch parts
const tz = new Temporal.TimeZone("-00:00:00.000000002");
const tz = TemporalHelpers.specificOffsetTimeZone(-2);
const datetime = new Temporal.ZonedDateTime(3661_001_001_001n, tz);

const diff = new Temporal.PlainDateTime(1970, 1, 1).until(datetime);
Expand Down
Loading

0 comments on commit 6f146e6

Please sign in to comment.