Skip to content
Permalink
Browse files
Finish to/from methods for Temporal.PlainDate[Time]
https://bugs.webkit.org/show_bug.cgi?id=244436

Reviewed by Yusuke Suzuki.

This patch implements the following for the Temporal API:
- PlainDate: `from(object)`, toPlainDateTime
- PlainDateTime: `from(object)`, toPlainDate, toPlainTime
- PlainTime: toPlainDateTime
- Calendar: dateFromFields (where the actual implementation of `PlainDate.from(object)` lives)

It then enables test262 tests for all implemented methods of PlainDate and PlainDateTime,
and subsequently recategorizes all of our existing Temporal failures, while fixing all imminently addressable issues.

* JSTests/stress/temporal-calendar.js:
* JSTests/stress/temporal-plaindate.js:
* JSTests/stress/temporal-plaindatetime.js:
* JSTests/stress/temporal-plaintime.js:
* JSTests/test262/config.yaml:
* JSTests/test262/expectations.yaml:
* Source/JavaScriptCore/runtime/ISO8601.cpp:
(JSC::ISO8601::temporalDateToString): Fix six-digit year handling.
(JSC::ISO8601::monthFromCode): Added.
* Source/JavaScriptCore/runtime/ISO8601.h:
* Source/JavaScriptCore/runtime/TemporalCalendar.cpp:
(JSC::TemporalCalendar::toTemporalCalendarWithISODefault): Moved from TemporalPlainTime.
(JSC::TemporalCalendar::getTemporalCalendarWithISODefault): Moved from TemporalPlainTime.
(JSC::TemporalCalendar::isoDateFromFields): Added.
* Source/JavaScriptCore/runtime/TemporalCalendar.h:
* Source/JavaScriptCore/runtime/TemporalCalendarPrototype.cpp:
* Source/JavaScriptCore/runtime/TemporalPlainDate.cpp:
(JSC::TemporalPlainDate::toPlainDate): Use max/min year constants to ensure that we *actually* stay within 21 bits.
(JSC::TemporalPlainDate::tryCreateIfValid):
(JSC::TemporalPlainDate::from):
* Source/JavaScriptCore/runtime/TemporalPlainDate.h: Use decltype(auto) because year is int32_t.
* Source/JavaScriptCore/runtime/TemporalPlainDateConstructor.cpp:
(JSC::TemporalPlainDateConstructor::finishCreation):
* Source/JavaScriptCore/runtime/TemporalPlainDatePrototype.cpp:
* Source/JavaScriptCore/runtime/TemporalPlainDateTime.cpp:
(JSC::TemporalPlainDateTime::tryCreateIfValid):
(JSC::TemporalPlainDateTime::from):
* Source/JavaScriptCore/runtime/TemporalPlainDateTime.h: Use decltype(auto) because year is int32_t.
* Source/JavaScriptCore/runtime/TemporalPlainDateTimeConstructor.cpp:
(JSC::TemporalPlainDateTimeConstructor::finishCreation):
* Source/JavaScriptCore/runtime/TemporalPlainDateTimePrototype.cpp:
* Source/JavaScriptCore/runtime/TemporalPlainTime.cpp:
(JSC::TemporalPlainTime::toTemporalTimeRecord): Made public static.
(JSC::TemporalPlainTime::regulateTime): Made public static.
(JSC::TemporalPlainTime::from):
(JSC::toTemporalCalendarWithISODefault): Moved to TemporalPlainTime.
(JSC::getTemporalCalendarWithISODefault): Moved to TemporalPlainTime.
* Source/JavaScriptCore/runtime/TemporalPlainTime.h:
* Source/JavaScriptCore/runtime/TemporalPlainTimePrototype.cpp:

Canonical link: https://commits.webkit.org/253876@main
  • Loading branch information
rkirsling committed Aug 28, 2022
1 parent badb430 commit 67370a953ddddcf9b3331cc06bc7e0fab6f79846
Show file tree
Hide file tree
Showing 22 changed files with 731 additions and 488 deletions.
@@ -25,11 +25,10 @@ shouldBe(Object.getOwnPropertyDescriptor(Temporal.Calendar, 'prototype').enumera
shouldBe(Object.getOwnPropertyDescriptor(Temporal.Calendar, 'prototype').configurable, false);
shouldBe(Temporal.Calendar.prototype.constructor, Temporal.Calendar);

{
let calendar = new Temporal.Calendar("iso8601");
shouldBe(calendar.id, `iso8601`);
shouldBe(String(calendar), `iso8601`);
}
const isoCalendar = new Temporal.Calendar("iso8601");
shouldBe(isoCalendar.id, `iso8601`);
shouldBe(String(isoCalendar), `iso8601`);

{
let calendar = new Temporal.Calendar("gregory");
shouldBe(calendar.id, `gregory`);
@@ -97,3 +96,20 @@ shouldThrow(() => {
}
shouldBe(JSON.parse(string, reviver).userCalendar instanceof Temporal.Calendar, true);
}

shouldBe(Temporal.Calendar.prototype.dateFromFields.length, 1);
shouldBe(isoCalendar.dateFromFields({ year: 2007, month: 1, day: 9 }).toString(), '2007-01-09');
shouldBe(isoCalendar.dateFromFields({ year: 2007, monthCode: 'M01', day: 9 }).toString(), '2007-01-09');
shouldBe(isoCalendar.dateFromFields({ year: 2007, month: 20, day: 40 }).toString(), '2007-12-31');
shouldBe(isoCalendar.dateFromFields({ year: 2007, month: 20, day: 40 }, { overflow: 'constrain' }).toString(), '2007-12-31');

shouldThrow(() => { isoCalendar.dateFromFields(null); }, TypeError);
shouldThrow(() => { isoCalendar.dateFromFields({ month: 1, day: 9 }); }, TypeError);
shouldThrow(() => { isoCalendar.dateFromFields({ year: 2007, day: 9 }); }, TypeError);
shouldThrow(() => { isoCalendar.dateFromFields({ year: 2007, month: 1 }); }, TypeError);
shouldThrow(() => { isoCalendar.dateFromFields({ year: Infinity, month: 1, day: 9 }); }, RangeError);
shouldThrow(() => { isoCalendar.dateFromFields({ year: 2007, month: 0, day: 9 }); }, RangeError);
shouldThrow(() => { isoCalendar.dateFromFields({ year: 2007, monthCode: 'M00', day: 9 }); }, RangeError);
shouldThrow(() => { isoCalendar.dateFromFields({ year: 2007, month: 1, day: 0 }); }, RangeError);
shouldThrow(() => { isoCalendar.dateFromFields({ year: 2007, month: 1, monthCode: 'M02', day: 9 }); }, RangeError);
shouldThrow(() => { isoCalendar.dateFromFields({ year: 2007, month: 20, day: 40 }, { overflow: 'reject' }); }, RangeError);
@@ -20,7 +20,7 @@ function shouldThrow(func, errorType, message) {
}

shouldBe(Temporal.PlainDate instanceof Function, true);
shouldBe(Temporal.PlainDate.length, 0);
shouldBe(Temporal.PlainDate.length, 3);
shouldBe(Object.getOwnPropertyDescriptor(Temporal.PlainDate, 'prototype').writable, false);
shouldBe(Object.getOwnPropertyDescriptor(Temporal.PlainDate, 'prototype').enumerable, false);
shouldBe(Object.getOwnPropertyDescriptor(Temporal.PlainDate, 'prototype').configurable, false);
@@ -86,22 +86,29 @@ shouldBe(String(Temporal.PlainDate.from('2007-01-09[u-ca=japanese]')), `2007-01-
let dateTime = Temporal.PlainDateTime.from('2007-01-09T03:24:30+01:00[Europe/Brussels]');
shouldBe(Temporal.PlainDate.from(dateTime).toString(), date.toString());

let time = Temporal.PlainTime.from('2007-01-09T03:24:30+01:00[Europe/Brussels]');
shouldBe(date.toPlainDateTime(time).toString(), dateTime.toString());
shouldBe(date.toPlainDateTime().toString(), Temporal.PlainDateTime.from('2007-01-09').toString());

shouldBe(Temporal.PlainDate.from({ year: 2007, month: 1, day: 9 }).toString(), date.toString());
shouldBe(Temporal.PlainDate.from({ year: 2007, monthCode: 'M01', day: 9 }).toString(), date.toString());

shouldBe(Temporal.PlainDate.from({ year: 2007, month: 20, day: 40 }).toString(), '2007-12-31');
shouldBe(Temporal.PlainDate.from({ year: 2007, month: 20, day: 40 }, { overflow: 'constrain' }).toString(), '2007-12-31');

shouldBe(date.toJSON(), date.toString());
shouldBe(date.toLocaleString(), date.toString());
}


// FIXME: from(object) is note yet implemented.
// {
// let date = Temporal.PlainDate.from({
// year: 2007,
// month: 1,
// day: 9
// });
// shouldBe(String(date), `2007-01-09`);
// }
shouldThrow(() => { Temporal.PlainDate.from({ year: 2007, month: 1, day: 9 }); }, RangeError);

shouldThrow(() => { Temporal.PlainDate.from({ month: 1, day: 9 }); }, TypeError);
shouldThrow(() => { Temporal.PlainDate.from({ year: 2007, day: 9 }); }, TypeError);
shouldThrow(() => { Temporal.PlainDate.from({ year: 2007, month: 1 }); }, TypeError);
shouldThrow(() => { Temporal.PlainDate.from({ year: Infinity, month: 1, day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDate.from({ year: 2007, month: 0, day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDate.from({ year: 2007, monthCode: 'M00', day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDate.from({ year: 2007, month: 1, day: 0 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDate.from({ year: 2007, month: 1, monthCode: 'M02', day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDate.from({ year: 2007, month: 20, day: 40 }, { overflow: 'reject' }); }, RangeError);

shouldThrow(() => { new Temporal.PlainDate(-1); }, RangeError);
shouldThrow(() => { new Temporal.PlainDate(); }, RangeError);
@@ -117,9 +124,9 @@ shouldThrow(() => { new Temporal.PlainDate(2007, -Infinity, 1); }, RangeError);
shouldThrow(() => { new Temporal.PlainDate(2007, 1, Infinity); }, RangeError);
shouldThrow(() => { new Temporal.PlainDate(2007, 1, -Infinity); }, RangeError);
shouldThrow(() => { new Temporal.PlainDate(0x43530, 9, 14); }, RangeError);
shouldBe(String(new Temporal.PlainDate(0x43530, 9, 13)), `275760-09-13`);
shouldThrow(() => { new Temporal.PlainDate(-0x425cd, 4, 19); }, RangeError);
shouldBe(String(new Temporal.PlainDate(-0x425cd, 4, 20)), `-271821-04-20`);
shouldBe(String(new Temporal.PlainDate(0x43530, 9, 13)), `+275760-09-13`);
shouldThrow(() => { new Temporal.PlainDate(-0x425cd, 4, 18); }, RangeError);
shouldBe(String(new Temporal.PlainDate(-0x425cd, 4, 19)), `-271821-04-19`);
shouldThrow(() => { new Temporal.PlainDate(0x80000000, 1, 1); }, RangeError);
shouldThrow(() => { new Temporal.PlainDate(-0x80000000, 1, 1); }, RangeError);
shouldThrow(() => { new Temporal.PlainDate(0x7fffffff, 1, 1); }, RangeError);
@@ -22,7 +22,7 @@ function shouldThrow(func, errorType) {
}

shouldBe(Temporal.PlainDateTime instanceof Function, true);
shouldBe(Temporal.PlainDateTime.length, 0);
shouldBe(Temporal.PlainDateTime.length, 3);
shouldBe(Object.getOwnPropertyDescriptor(Temporal.PlainDateTime, 'prototype').writable, false);
shouldBe(Object.getOwnPropertyDescriptor(Temporal.PlainDateTime, 'prototype').enumerable, false);
shouldBe(Object.getOwnPropertyDescriptor(Temporal.PlainDateTime, 'prototype').configurable, false);
@@ -83,10 +83,31 @@ shouldBe(Temporal.PlainDateTime.from('0001-02-03T04:05:06.007008009').toString()

const date = Temporal.PlainDate.from('2007-01-09T03:24:30+01:00[Europe/Brussels]');
shouldBe(Temporal.PlainDateTime.from(date).toString(), '2007-01-09T00:00:00');

shouldBe(Temporal.PlainDateTime.from({ year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6, millisecond: 7, microsecond: 8, nanosecond: 9 }).toString(), '0001-02-03T04:05:06.007008009');
shouldBe(Temporal.PlainDateTime.from({ year: 2007, monthCode: 'M01', day: 9 }).toString(), '2007-01-09T00:00:00');

shouldBe(Temporal.PlainDateTime.from({ year: 2007, month: 20, day: 40, hour: 30, minute: 80, second: 80, millisecond: 2000, microsecond: 2000, nanosecond: 2000 }).toString(), '2007-12-31T23:59:59.999999999');
shouldBe(Temporal.PlainDateTime.from({ year: 2007, month: 20, day: 40, hour: 30, minute: 80, second: 80, millisecond: 2000, microsecond: 2000, nanosecond: 2000 }, { overflow: 'constrain' }).toString(), '2007-12-31T23:59:59.999999999');
}

shouldThrow(() => Temporal.PlainDateTime.from(pdt, { overflow: 'bogus' }), RangeError);
shouldBe(Temporal.PlainDateTime.from(pdt, { overflow: 'constrain' }).toString(), Temporal.PlainDateTime.from(pdt).toString());
shouldBe(Temporal.PlainDateTime.from(pdt, { overflow: 'constrain' }).toString(), Temporal.PlainDateTime.from(pdt).toString());shouldThrow(() => { Temporal.PlainDate.from({ month: 1, day: 9 }); }, TypeError);

shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, day: 9 }); }, TypeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, month: 1 }); }, TypeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: Infinity, month: 1, day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, month: 0, day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, monthCode: 'M00', day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, monthCode: 'M00', day: 9, hour: Infinity }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, monthCode: 'M00', day: 9, minute: Infinity }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, monthCode: 'M00', day: 9, second: Infinity }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, monthCode: 'M00', day: 9, millisecond: Infinity }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, monthCode: 'M00', day: 9, microsecond: Infinity }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, monthCode: 'M00', day: 9, nanosecond: Infinity }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, month: 1, day: 0 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, month: 1, monthCode: 'M02', day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainDateTime.from({ year: 2007, month: 20, day: 40, hour: 30, minute: 80, second: 80, millisecond: 2000, microsecond: 2000, nanosecond: 2000 }, { overflow: 'reject' }); }, RangeError);

const goodStrings = [
'2007-01-09',
@@ -211,5 +232,10 @@ shouldBe(pdt.toString({ fractionalSecondDigits: 2, roundingMode: 'ceil' }), '000
shouldBe(pdt.toString({ fractionalSecondDigits: 2, roundingMode: 'floor' }), '0001-02-03T04:05:06.00');
shouldBe(new Temporal.PlainDateTime(1999,12,31,23,59,59,999,999,999).toString({ smallestUnit: 'microsecond', roundingMode: 'halfExpand' }), '2000-01-01T00:00:00.000000');

shouldBe(Temporal.PlainDateTime.prototype.toPlainDate.length, 0);
shouldBe(pdt.toPlainDate().toString(), '0001-02-03');
shouldBe(Temporal.PlainDateTime.prototype.toPlainTime.length, 0);
shouldBe(pdt.toPlainTime().toString(), '04:05:06.007008009');

shouldBe(Temporal.PlainDateTime.prototype.valueOf.length, 0);
shouldThrow(() => pdt.valueOf(), TypeError);
@@ -152,10 +152,13 @@ shouldBe(String(Temporal.PlainTime.from('2007-01-09 03:24:30[u-ca=japanese]')),
let dateTime = Temporal.PlainDateTime.from('1995-12-07T03:24:30+01:00[Europe/Brussels]')
shouldBe(Temporal.PlainTime.from(dateTime).toString(), time.toString());

let date = Temporal.PlainDate.from('1995-12-07T03:24:30+01:00[Europe/Brussels]');
shouldBe(time.toPlainDateTime(date).toString(), dateTime.toString());

shouldBe(time.toJSON(), time.toString());
shouldBe(time.toLocaleString(), time.toString());
}
{``
{
let time = Temporal.PlainTime.from({
hour: 19,
minute: 39,

0 comments on commit 67370a9

Please sign in to comment.