Skip to content

Commit

Permalink
Test 'T' time designator prefix in PlainTime strings
Browse files Browse the repository at this point in the history
tc39/proposal-temporal#1952 added support for time
designator prefixes in PlainTime strings. This adds three tests to all
entry points that convert an ISO string to a PlainTime:

- no-implicit-midnight: ISO strings with only a date and no time are no
  longer accepted. Previously they were implicitly interpreted as 00:00.
- with-time-designator: Tests that various forms of string with time
  designator are correctly parsed.
- time-designator-required-for-disambiguation: Tests various cases where
  a string without a time designator is ambiguous and therefore the time
  designator is required, as well as various cases that implementations
  might assume are ambiguous but in fact are not.

This was a normative change that achieved consensus at the December 2021
TC39 meeting.
  • Loading branch information
ptomato committed Feb 4, 2022
1 parent 9a6ea29 commit effbdb4
Show file tree
Hide file tree
Showing 27 changed files with 816 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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.plaindate.prototype.toplaindatetime
description: RangeError thrown if a date-only string is passed in a PlainTime context
features: [Temporal, arrow-function]
---*/

const arg = "2019-10-01";
const instance = new Temporal.PlainDate(2000, 5, 2);
assert.throws(
RangeError,
() => instance.toPlainDateTime(arg),
"Date-only string throws, does not implicitly convert to midnight"
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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.plaindate.prototype.toplaindatetime
description: ISO 8601 time designator "T" required in cases of ambiguity
features: [Temporal, arrow-function]
---*/

const instance = new Temporal.PlainDate(2000, 5, 2);

const ambiguousStrings = [
"2021-12", // ambiguity between YYYY-MM and HHMM-UU
"1214", // ambiguity between MMDD and HHMM
"0229", // ditto, including MMDD that doesn't occur every year
"1130", // ditto, including DD that doesn't occur in every month
"12-14", // ambiguity between MM-DD and HH-UU
"202112", // ambiguity between YYYYMM and HHMMSS
];
ambiguousStrings.forEach((arg) => {
assert.throws(
RangeError,
() => instance.toPlainDateTime(arg),
`${arg} is ambiguous and requires T prefix`
);
// The same string with a T prefix should not throw:
arg = `T${arg}`;
instance.toPlainDateTime(arg);
});

// None of these should throw without a T prefix, because they are unambiguously time strings:
const unambiguousStrings = [
"2021-13", // 13 is not a month
"202113", // ditto
"0000-00", // 0 is not a month
"000000", // ditto
"1314", // 13 is not a month
"13-14", // ditto
"1232", // 32 is not a day
"0230", // 30 is not a day in February
"0631", // 31 is not a day in June
"0000", // 0 is neither a month nor a day
"00-00", // ditto
];
unambiguousStrings.forEach((arg) => instance.toPlainDateTime(arg));
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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.plaindate.prototype.toplaindatetime
description: ISO 8601 time designator "T" allowed at the start of PlainTime strings
includes: [temporalHelpers.js]
features: [Temporal, arrow-function]
---*/

const instance = new Temporal.PlainDate(2000, 1, 1);
const validStrings = [
"T00:30",
"t00:30",
"T0030",
"t0030",
"T00:30:00",
"t00:30:00",
"T003000",
"t003000",
"T00:30:00.000000000",
"t00:30:00.000000000",
"T003000.000000000",
"t003000.000000000",
];
validStrings.forEach((arg) => {
const result = instance.toPlainDateTime(arg);
TemporalHelpers.assertPlainDateTime(result, 2000, 1, "M01", 1, 0, 30, 0, 0, 0, 0, `T prefix is accepted: ${arg}`);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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.plaindate.prototype.tozoneddatetime
description: RangeError thrown if a date-only string is passed in a PlainTime context
features: [Temporal, arrow-function]
---*/

const arg = "2019-10-01";
const instance = new Temporal.PlainDate(2000, 5, 2);
assert.throws(
RangeError,
() => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }),
"Date-only string throws, does not implicitly convert to midnight"
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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.plaindate.prototype.tozoneddatetime
description: ISO 8601 time designator "T" required in cases of ambiguity
features: [Temporal, arrow-function]
---*/

const instance = new Temporal.PlainDate(2000, 5, 2);

const ambiguousStrings = [
"2021-12", // ambiguity between YYYY-MM and HHMM-UU
"1214", // ambiguity between MMDD and HHMM
"0229", // ditto, including MMDD that doesn't occur every year
"1130", // ditto, including DD that doesn't occur in every month
"12-14", // ambiguity between MM-DD and HH-UU
"202112", // ambiguity between YYYYMM and HHMMSS
];
ambiguousStrings.forEach((arg) => {
assert.throws(
RangeError,
() => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }),
`${arg} is ambiguous and requires T prefix`
);
// The same string with a T prefix should not throw:
arg = `T${arg}`;
instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" });
});

// None of these should throw without a T prefix, because they are unambiguously time strings:
const unambiguousStrings = [
"2021-13", // 13 is not a month
"202113", // ditto
"0000-00", // 0 is not a month
"000000", // ditto
"1314", // 13 is not a month
"13-14", // ditto
"1232", // 32 is not a day
"0230", // 30 is not a day in February
"0631", // 31 is not a day in June
"0000", // 0 is neither a month nor a day
"00-00", // ditto
];
unambiguousStrings.forEach((arg) => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }));
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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.plaindate.prototype.tozoneddatetime
description: ISO 8601 time designator "T" allowed at the start of PlainTime strings
features: [Temporal, arrow-function]
---*/

const instance = new Temporal.PlainDate(2000, 1, 1);
const validStrings = [
"T00:30",
"t00:30",
"T0030",
"t0030",
"T00:30:00",
"t00:30:00",
"T003000",
"t003000",
"T00:30:00.000000000",
"t00:30:00.000000000",
"T003000.000000000",
"t003000.000000000",
];
validStrings.forEach((arg) => {
const result = instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" });
assert.sameValue(result.epochNanoseconds, 946686600_000_000_000n, `T prefix is accepted: ${arg}`);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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.plaindatetime.prototype.withplaintime
description: RangeError thrown if a date-only string is passed in a PlainTime context
features: [Temporal, arrow-function]
---*/

const arg = "2019-10-01";
const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321);
assert.throws(
RangeError,
() => instance.withPlainTime(arg),
"Date-only string throws, does not implicitly convert to midnight"
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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.plaindatetime.prototype.withplaintime
description: ISO 8601 time designator "T" required in cases of ambiguity
features: [Temporal, arrow-function]
---*/

const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321);

const ambiguousStrings = [
"2021-12", // ambiguity between YYYY-MM and HHMM-UU
"1214", // ambiguity between MMDD and HHMM
"0229", // ditto, including MMDD that doesn't occur every year
"1130", // ditto, including DD that doesn't occur in every month
"12-14", // ambiguity between MM-DD and HH-UU
"202112", // ambiguity between YYYYMM and HHMMSS
];
ambiguousStrings.forEach((arg) => {
assert.throws(
RangeError,
() => instance.withPlainTime(arg),
`${arg} is ambiguous and requires T prefix`
);
// The same string with a T prefix should not throw:
arg = `T${arg}`;
instance.withPlainTime(arg);
});

// None of these should throw without a T prefix, because they are unambiguously time strings:
const unambiguousStrings = [
"2021-13", // 13 is not a month
"202113", // ditto
"0000-00", // 0 is not a month
"000000", // ditto
"1314", // 13 is not a month
"13-14", // ditto
"1232", // 32 is not a day
"0230", // 30 is not a day in February
"0631", // 31 is not a day in June
"0000", // 0 is neither a month nor a day
"00-00", // ditto
];
unambiguousStrings.forEach((arg) => instance.withPlainTime(arg));
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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.plaindatetime.prototype.withplaintime
description: ISO 8601 time designator "T" allowed at the start of PlainTime strings
includes: [temporalHelpers.js]
features: [Temporal, arrow-function]
---*/

const instance = new Temporal.PlainDateTime(2000, 1, 1, 12, 30, 45, 123, 456, 789);
const validStrings = [
"T00:30",
"t00:30",
"T0030",
"t0030",
"T00:30:00",
"t00:30:00",
"T003000",
"t003000",
"T00:30:00.000000000",
"t00:30:00.000000000",
"T003000.000000000",
"t003000.000000000",
];
validStrings.forEach((arg) => {
const result = instance.withPlainTime(arg);
TemporalHelpers.assertPlainDateTime(result, 2000, 1, "M01", 1, 0, 30, 0, 0, 0, 0, `T prefix is accepted: ${arg}`);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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.plaintime.compare
description: RangeError thrown if a date-only string is passed in a PlainTime context
features: [Temporal, arrow-function]
---*/

const arg = "2019-10-01";
const midnight = new Temporal.PlainTime();
assert.throws(
RangeError,
() => Temporal.PlainTime.compare(arg, midnight),
"Date-only string throws, does not implicitly convert to midnight (first argument)"
);
assert.throws(
RangeError,
() => Temporal.PlainTime.compare(midnight, arg),
"Date-only string throws, does not implicitly convert to midnight (second argument)"
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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.plaintime.compare
description: ISO 8601 time designator "T" required in cases of ambiguity
features: [Temporal, arrow-function]
---*/

const midnight = new Temporal.PlainTime();

const ambiguousStrings = [
"2021-12", // ambiguity between YYYY-MM and HHMM-UU
"1214", // ambiguity between MMDD and HHMM
"0229", // ditto, including MMDD that doesn't occur every year
"1130", // ditto, including DD that doesn't occur in every month
"12-14", // ambiguity between MM-DD and HH-UU
"202112", // ambiguity between YYYYMM and HHMMSS
];
ambiguousStrings.forEach((arg) => {
assert.throws(
RangeError,
() => Temporal.PlainTime.compare(arg, midnight),
`${arg} is ambiguous and requires T prefix (first argument)`
);
assert.throws(
RangeError,
() => Temporal.PlainTime.compare(midnight, arg),
`${arg} is ambiguous and requires T prefix (second argument)`
);
// The same string with a T prefix should not throw:
arg = `T${arg}`;
Temporal.PlainTime.compare(arg, midnight);
Temporal.PlainTime.compare(midnight, arg);
});

// None of these should throw without a T prefix, because they are unambiguously time strings:
const unambiguousStrings = [
"2021-13", // 13 is not a month
"202113", // ditto
"0000-00", // 0 is not a month
"000000", // ditto
"1314", // 13 is not a month
"13-14", // ditto
"1232", // 32 is not a day
"0230", // 30 is not a day in February
"0631", // 31 is not a day in June
"0000", // 0 is neither a month nor a day
"00-00", // ditto
];
unambiguousStrings.forEach((arg) => {
Temporal.PlainTime.compare(arg, midnight);
Temporal.PlainTime.compare(midnight, arg);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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.plaintime.compare
description: ISO 8601 time designator "T" allowed at the start of PlainTime strings
features: [Temporal, arrow-function]
---*/

const halfPast = new Temporal.PlainTime(0, 30);
const validStrings = [
"T00:30",
"t00:30",
"T0030",
"t0030",
"T00:30:00",
"t00:30:00",
"T003000",
"t003000",
"T00:30:00.000000000",
"t00:30:00.000000000",
"T003000.000000000",
"t003000.000000000",
];
validStrings.forEach((arg) => {
assert.sameValue(Temporal.PlainTime.compare(arg, halfPast), 0, `T prefix is accepted: ${arg} (first argument)`);
assert.sameValue(Temporal.PlainTime.compare(halfPast, arg), 0, `T prefix is accepted: ${arg} (second argument)`);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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.plaintime.from
description: RangeError thrown if a date-only string is passed in a PlainTime context
features: [Temporal, arrow-function]
---*/

const arg = "2019-10-01";
assert.throws(
RangeError,
() => Temporal.PlainTime.from(arg),
"Date-only string throws, does not implicitly convert to midnight"
);
Loading

0 comments on commit effbdb4

Please sign in to comment.