Skip to content

Commit

Permalink
[JSC] Disallow sub-minute in TimeZoneAnnotation
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=278207

Reviewed by Yusuke Suzuki.

According to the latest specification of Temporal[1][2][3], sub-minute values cannot be written in
the UTCOffset of a TimeZoneAnnotation within an ISO8601 string.

However, in the current JSC, even if a sub-minute value is written in the TimeZoneAnnotation, no
RangeError is thrown.

This patch makes the following changes:

- In the UTCOffset of a TimeZoneAnnotation within an ISO8601 string, sub-minute values are no longer
parsed, and a RangeError will be thrown.
- Update relevant function names and comments in ISO8601.cpp/ISO8601.h to follow the latest
specification:
  * Rename `parseTimeZoneNumericUTCOffset` to `parseUTCOffset` and update comments
  * Rename `parseTimeZoneBracketedAnnotation` to `parseTimeZoneAnnotation` and update comments

[1]: https://tc39.es/proposal-temporal/#prod-TimeZoneAnnotation
[2]: https://tc39.es/proposal-temporal/#prod-TimeZoneIdentifier
[3]: https://tc39.es/proposal-temporal/#prod-UTCOffset

* JSTests/stress/temporal-plaindate.js:
* JSTests/stress/temporal-plaindatetime.js:
* JSTests/stress/temporal-plaintime.js:
* JSTests/test262/expectations.yaml:
* Source/JavaScriptCore/runtime/ISO8601.cpp:
(JSC::ISO8601::parseTimeSpec):
(JSC::ISO8601::parseUTCOffset):
(JSC::ISO8601::parseTimeZoneAnnotation):
(JSC::ISO8601::parseTimeZone):
(JSC::ISO8601::parseTimeZoneNumericUTCOffset): Deleted.
(JSC::ISO8601::parseTimeZoneBracketedAnnotation): Deleted.
* Source/JavaScriptCore/runtime/ISO8601.h:
* Source/JavaScriptCore/runtime/TemporalTimeZone.cpp:
(JSC::TemporalTimeZone::from):
* Source/JavaScriptCore/runtime/TemporalTimeZoneConstructor.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):

Canonical link: https://commits.webkit.org/282710@main
  • Loading branch information
sosukesuzuki committed Aug 25, 2024
1 parent 4c19011 commit 51ee7ef
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 57 deletions.
10 changes: 5 additions & 5 deletions JSTests/stress/temporal-plaindate.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,6 @@ shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30+01:00[Etc/GMT+20]')
shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30+01:00[Etc/GMT-20]')), `2007-01-09`); // TimeZone error should be ignored.
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[+01]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[+01:00]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[+01:00:00]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[+01:00:00.123]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[+01:00:00.12345]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[+01:00:00.12345678]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[+01:00:00.123456789]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[-01:00]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[u-ca=japanese]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `2007-01-09`);
Expand Down Expand Up @@ -170,6 +165,11 @@ let failures = [
"2007-01-09 03:24:30+01:00[\u221201:00]",
"2007-01-09Z",
"2007-01-09+01:00",
'2007-01-09 03:24:30+01:00[+01:00:00]',
'2007-01-09 03:24:30+01:00[+01:00:00.123]',
'2007-01-09 03:24:30+01:00[+01:00:00.12345]',
'2007-01-09 03:24:30+01:00[+01:00:00.12345678]',
'2007-01-09 03:24:30+01:00[+01:00:00.123456789]',
];

for (let text of failures) {
Expand Down
10 changes: 5 additions & 5 deletions JSTests/stress/temporal-plaindatetime.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,6 @@ const goodStrings = [
'2007-01-09T03:24:30+01:00[Etc/GMT-20]', // TimeZone error should be ignored.
'2007-01-09 03:24:30+01:00[+01]',
'2007-01-09 03:24:30+01:00[+01:00]',
'2007-01-09 03:24:30+01:00[+01:00:00]',
'2007-01-09 03:24:30+01:00[+01:00:00.123]',
'2007-01-09 03:24:30+01:00[+01:00:00.12345]',
'2007-01-09 03:24:30+01:00[+01:00:00.12345678]',
'2007-01-09 03:24:30+01:00[+01:00:00.123456789]',
'2007-01-09 03:24:30+01:00[-01:00]',
'2007-01-09 03:24:30+01:00[u-ca=japanese]',
'2007-01-09 03:24:30+01:00[Europe/Brussels][u-ca=japanese]',
Expand Down Expand Up @@ -188,6 +183,11 @@ const badStrings = [
"2007-01-09 03:24:30+01:00[\u221201:00]",
"2007-01-09Z",
"2007-01-09+01:00",
'2006-01-09 03:24:30+01:00[+01:00:00]',
'2006-01-09 03:24:30+01:00[+01:00:00.123]',
'2006-01-09 03:24:30+01:00[+01:00:00.12345]',
'2006-01-09 03:24:30+01:00[+01:00:00.12345678]',
'2006-01-09 03:24:30+01:00[+01:00:00.123456789]',
];
for (let s of badStrings)
shouldThrow(() => Temporal.PlainDateTime.from(s), RangeError);
Expand Down
10 changes: 5 additions & 5 deletions JSTests/stress/temporal-plaintime.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,6 @@ shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30+01:00[Etc/GMT+20]')
shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30+01:00[Etc/GMT-20]')), `03:24:30`); // TimeZone error should be ignored.
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[+01]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[+01:00]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[+01:00:00]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[+01:00:00.123]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[+01:00:00.12345]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[+01:00:00.12345678]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[+01:00:00.123456789]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[-01:00]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('2007-01-09 03:24:30+01:00[u-ca=japanese]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('2007-01-09 03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `03:24:30`);
Expand Down Expand Up @@ -265,6 +260,11 @@ let failures = [
"2007-01-09 03:24:30+01:00[u-ca=japanese][Europe/Brussels]",
"1995-12-07T03:24:30\u221220:20:59",
"1995-12-07 03:24:30+01:00[\u221201:00]",
"1995-12-07 03:24:30+01:00[+01:00:00]",
"1995-12-07 03:24:30+01:00[+01:00:00.123]",
"1995-12-07 03:24:30+01:00[+01:00:00.12345]",
"1995-12-07 03:24:30+01:00[+01:00:00.12345678]",
"1995-12-07 03:24:30+01:00[+01:00:00.123456789]",
];

for (let text of failures) {
Expand Down
12 changes: 0 additions & 12 deletions JSTests/test262/expectations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1186,18 +1186,9 @@ test/built-ins/Temporal/Duration/prototype/total/relativeto-propertybag-invalid-
test/built-ins/Temporal/Duration/prototype/total/total-of-each-unit-relativeto.js:
default: "TypeError: undefined is not a constructor (evaluating 'new Temporal.ZonedDateTime(63072000_000_000_000n /* = 1972-01-01T00Z */, \"UTC\")')"
strict mode: "TypeError: undefined is not a constructor (evaluating 'new Temporal.ZonedDateTime(63072000_000_000_000n /* = 1972-01-01T00Z */, \"UTC\")')"
test/built-ins/Temporal/Instant/from/instant-string-sub-minute-offset.js:
default: 'Test262Error: ISO strings cannot have sub-minute offsets in time zone annotations: 2021-08-19T17:30-07:00:01[-07:00:01] Expected a RangeError to be thrown but no exception was thrown at all'
strict mode: 'Test262Error: ISO strings cannot have sub-minute offsets in time zone annotations: 2021-08-19T17:30-07:00:01[-07:00:01] Expected a RangeError to be thrown but no exception was thrown at all'
test/built-ins/Temporal/Instant/prototype/epochMilliseconds/basic.js:
default: 'Test262Error: epochMilliseconds pre epoch Expected SameValue(«-217175010876», «-217175010877») to be true'
strict mode: 'Test262Error: epochMilliseconds pre epoch Expected SameValue(«-217175010876», «-217175010877») to be true'
test/built-ins/Temporal/Instant/prototype/equals/instant-string-sub-minute-offset.js:
default: 'Test262Error: ISO strings cannot have sub-minute offsets in time zone annotations: 2021-08-19T17:30-07:00:01[-07:00:01] Expected a RangeError to be thrown but no exception was thrown at all'
strict mode: 'Test262Error: ISO strings cannot have sub-minute offsets in time zone annotations: 2021-08-19T17:30-07:00:01[-07:00:01] Expected a RangeError to be thrown but no exception was thrown at all'
test/built-ins/Temporal/Instant/prototype/since/instant-string-sub-minute-offset.js:
default: 'Test262Error: ISO strings cannot have sub-minute offsets in time zone annotations: 2021-08-19T17:30-07:00:01[-07:00:01] Expected a RangeError to be thrown but no exception was thrown at all'
strict mode: 'Test262Error: ISO strings cannot have sub-minute offsets in time zone annotations: 2021-08-19T17:30-07:00:01[-07:00:01] Expected a RangeError to be thrown but no exception was thrown at all'
test/built-ins/Temporal/Instant/prototype/since/largestunit.js:
default: 'Test262Error: does not include higher units than necessary (largest unit unspecified): nanoseconds result Expected SameValue(«40», «101») to be true'
strict mode: 'Test262Error: does not include higher units than necessary (largest unit unspecified): nanoseconds result Expected SameValue(«40», «101») to be true'
Expand Down Expand Up @@ -1240,9 +1231,6 @@ test/built-ins/Temporal/Instant/prototype/toString/order-of-operations.js:
test/built-ins/Temporal/Instant/prototype/toString/timezone-wrong-type.js:
default: 'Test262Error: null does not convert to a valid ISO string Expected a TypeError but got a RangeError'
strict mode: 'Test262Error: null does not convert to a valid ISO string Expected a TypeError but got a RangeError'
test/built-ins/Temporal/Instant/prototype/until/instant-string-sub-minute-offset.js:
default: 'Test262Error: ISO strings cannot have sub-minute offsets in time zone annotations: 2021-08-19T17:30-07:00:01[-07:00:01] Expected a RangeError to be thrown but no exception was thrown at all'
strict mode: 'Test262Error: ISO strings cannot have sub-minute offsets in time zone annotations: 2021-08-19T17:30-07:00:01[-07:00:01] Expected a RangeError to be thrown but no exception was thrown at all'
test/built-ins/Temporal/Instant/prototype/until/order-of-operations.js:
default: 'Test262Error: Expected [get other.toString, call other.toString, get options.smallestUnit, get options.smallestUnit.toString, call options.smallestUnit.toString, get options.largestUnit, get options.largestUnit.toString, call options.largestUnit.toString, get options.roundingMode, get options.roundingMode.toString, call options.roundingMode.toString, get options.roundingIncrement, get options.roundingIncrement.valueOf, call options.roundingIncrement.valueOf] and [get other.toString, call other.toString, get options.largestUnit, get options.largestUnit.toString, call options.largestUnit.toString, get options.roundingIncrement, get options.roundingIncrement.valueOf, call options.roundingIncrement.valueOf, get options.roundingMode, get options.roundingMode.toString, call options.roundingMode.toString, get options.smallestUnit, get options.smallestUnit.toString, call options.smallestUnit.toString] to have the same contents. order of operations'
strict mode: 'Test262Error: Expected [get other.toString, call other.toString, get options.smallestUnit, get options.smallestUnit.toString, call options.smallestUnit.toString, get options.largestUnit, get options.largestUnit.toString, call options.largestUnit.toString, get options.roundingMode, get options.roundingMode.toString, call options.roundingMode.toString, get options.roundingIncrement, get options.roundingIncrement.valueOf, call options.roundingIncrement.valueOf] and [get other.toString, call other.toString, get options.largestUnit, get options.largestUnit.toString, call options.largestUnit.toString, get options.roundingIncrement, get options.roundingIncrement.valueOf, call options.roundingIncrement.valueOf, get options.roundingMode, get options.roundingMode.toString, call options.roundingMode.toString, get options.smallestUnit, get options.smallestUnit.toString, call options.smallestUnit.toString] to have the same contents. order of operations'
Expand Down
54 changes: 27 additions & 27 deletions Source/JavaScriptCore/runtime/ISO8601.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ std::optional<Duration> parseDuration(StringView string)

enum class Second60Mode { Accept, Reject };
template<typename CharacterType>
static std::optional<PlainTime> parseTimeSpec(StringParsingBuffer<CharacterType>& buffer, Second60Mode second60Mode)
static std::optional<PlainTime> parseTimeSpec(StringParsingBuffer<CharacterType>& buffer, Second60Mode second60Mode, bool parseSubMinutePrecision = true)
{
// https://tc39.es/proposal-temporal/#prod-TimeSpec
// TimeSpec :
Expand Down Expand Up @@ -320,6 +320,9 @@ static std::optional<PlainTime> parseTimeSpec(StringParsingBuffer<CharacterType>
} else if (!(*buffer >= '0' && (second60Mode == Second60Mode::Accept ? (*buffer <= '6') : (*buffer <= '5'))))
return PlainTime(hour, minute, 0, 0, 0, 0);

if (!parseSubMinutePrecision)
return std::nullopt;

unsigned second = 0;
if (buffer.lengthRemaining() < 2)
return std::nullopt;
Expand Down Expand Up @@ -371,17 +374,17 @@ static std::optional<PlainTime> parseTimeSpec(StringParsingBuffer<CharacterType>
}

template<typename CharacterType>
static std::optional<int64_t> parseTimeZoneNumericUTCOffset(StringParsingBuffer<CharacterType>& buffer)
static std::optional<int64_t> parseUTCOffset(StringParsingBuffer<CharacterType>& buffer, bool parseSubMinutePrecision = true)
{
// TimeZoneNumericUTCOffset :
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute : TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
// UTCOffset[SubMinutePrecision] :
// ASCIISign Hour
// ASCIISign Hour TimeSeparator[+Extended] MinuteSecond
// ASCIISign Hour TimeSeparator[~Extended] MinuteSecond
// [+SubMinutePrecision] ASCIISign Hour TimeSeparator[+Extended] MinuteSecond TimeSeparator[+Extended] MinuteSecond TemporalDecimalFractionopt
// [+SubMinutePrecision] ASCIISign Hour TimeSeparator[~Extended] MinuteSecond TimeSeparator[~Extended] MinuteSecond TemporalDecimalFractionopt
//
// This is the same to
// TimeZoneUTCOffsetSign TimeSpec
// ASCIISign TimeSpec
//
// Maximum and minimum values are ±23:59:59.999999999 = ±86399999999999ns, which can be represented by int64_t / double's integer part.

Expand All @@ -398,7 +401,7 @@ static std::optional<int64_t> parseTimeZoneNumericUTCOffset(StringParsingBuffer<
} else
return std::nullopt;

auto plainTime = parseTimeSpec(buffer, Second60Mode::Reject);
auto plainTime = parseTimeSpec(buffer, Second60Mode::Reject, parseSubMinutePrecision);
if (!plainTime)
return std::nullopt;

Expand All @@ -412,10 +415,10 @@ static std::optional<int64_t> parseTimeZoneNumericUTCOffset(StringParsingBuffer<
return (nsPerHour * hour + nsPerMinute * minute + nsPerSecond * second + nsPerMillisecond * millisecond + nsPerMicrosecond * microsecond + nanosecond) * factor;
}

std::optional<int64_t> parseTimeZoneNumericUTCOffset(StringView string)
std::optional<int64_t> parseUTCOffset(StringView string, bool parseSubMinutePrecision)
{
return readCharactersForParsing(string, [](auto buffer) -> std::optional<int64_t> {
auto result = parseTimeZoneNumericUTCOffset(buffer);
return readCharactersForParsing(string, [parseSubMinutePrecision](auto buffer) -> std::optional<int64_t> {
auto result = parseUTCOffset(buffer, parseSubMinutePrecision);
if (!buffer.atEnd())
return std::nullopt;
return result;
Expand Down Expand Up @@ -561,16 +564,14 @@ static bool canBeTimeZone(const StringParsingBuffer<CharacterType>& buffer, Char
}

template<typename CharacterType>
static std::optional<std::variant<Vector<LChar>, int64_t>> parseTimeZoneBracketedAnnotation(StringParsingBuffer<CharacterType>& buffer)
static std::optional<std::variant<Vector<LChar>, int64_t>> parseTimeZoneAnnotation(StringParsingBuffer<CharacterType>& buffer)
{
// https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
// TimeZoneBracketedAnnotation :
// [ TimeZoneBracketedName ]
//
// TimeZoneBracketedName :
// https://tc39.es/proposal-temporal/#prod-TimeZoneAnnotation
// TimeZoneAnnotation :
// [ AnnotationCriticalFlag_opt TimeZoneIdentifier ]
// TimeZoneIdentifier :
// UTCOffset_[~SubMinutePrecision]
// TimeZoneIANAName
// Etc/GMT ASCIISign Hour
// TimeZoneUTCOffsetName

if (buffer.lengthRemaining() < 3)
return std::nullopt;
Expand All @@ -585,8 +586,7 @@ static std::optional<std::variant<Vector<LChar>, int64_t>> parseTimeZoneBrackete
switch (static_cast<UChar>(*buffer)) {
case '+':
case '-': {
// TimeZoneUTCOffsetName is the same to TimeZoneNumericUTCOffset.
auto offset = parseTimeZoneNumericUTCOffset(buffer);
auto offset = parseUTCOffset(buffer, false);
if (!offset)
return std::nullopt;
if (buffer.atEnd())
Expand Down Expand Up @@ -722,7 +722,7 @@ static std::optional<TimeZoneRecord> parseTimeZone(StringParsingBuffer<Character
case 'Z': {
buffer.advance();
if (!buffer.atEnd() && *buffer == '[' && canBeTimeZone(buffer, *buffer)) {
auto timeZone = parseTimeZoneBracketedAnnotation(buffer);
auto timeZone = parseTimeZoneAnnotation(buffer);
if (!timeZone)
return std::nullopt;
return TimeZoneRecord { true, std::nullopt, WTFMove(timeZone.value()) };
Expand All @@ -733,11 +733,11 @@ static std::optional<TimeZoneRecord> parseTimeZone(StringParsingBuffer<Character
// https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSign
case '+':
case '-': {
auto offset = parseTimeZoneNumericUTCOffset(buffer);
auto offset = parseUTCOffset(buffer);
if (!offset)
return std::nullopt;
if (!buffer.atEnd() && *buffer == '[' && canBeTimeZone(buffer, *buffer)) {
auto timeZone = parseTimeZoneBracketedAnnotation(buffer);
auto timeZone = parseTimeZoneAnnotation(buffer);
if (!timeZone)
return std::nullopt;
return TimeZoneRecord { false, offset.value(), WTFMove(timeZone.value()) };
Expand All @@ -747,7 +747,7 @@ static std::optional<TimeZoneRecord> parseTimeZone(StringParsingBuffer<Character
// TimeZoneBracketedAnnotation
// https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
case '[': {
auto timeZone = parseTimeZoneBracketedAnnotation(buffer);
auto timeZone = parseTimeZoneAnnotation(buffer);
if (!timeZone)
return std::nullopt;
return TimeZoneRecord { false, std::nullopt, WTFMove(timeZone.value()) };
Expand Down
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/runtime/ISO8601.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ struct CalendarRecord {
// https://tc39.es/proposal-temporal/#sup-isvalidtimezonename
std::optional<TimeZoneID> parseTimeZoneName(StringView);
std::optional<Duration> parseDuration(StringView);
std::optional<int64_t> parseTimeZoneNumericUTCOffset(StringView);
std::optional<int64_t> parseUTCOffset(StringView, bool parseSubMinutePrecision = true);
std::optional<int64_t> parseUTCOffsetInMinutes(StringView);
enum class ValidateTimeZoneID : bool { No, Yes };
std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>>> parseTime(StringView);
Expand Down
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/runtime/TemporalTimeZone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ JSObject* TemporalTimeZone::from(JSGlobalObject* globalObject, JSValue timeZoneL
auto timeZoneString = timeZoneLike.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, { });

std::optional<int64_t> utcOffset = ISO8601::parseTimeZoneNumericUTCOffset(timeZoneString);
std::optional<int64_t> utcOffset = ISO8601::parseUTCOffset(timeZoneString);
if (utcOffset)
return TemporalTimeZone::createFromUTCOffset(vm, globalObject->timeZoneStructure(), utcOffset.value());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ JSC_DEFINE_HOST_FUNCTION(constructTemporalTimeZone, (JSGlobalObject* globalObjec
auto timeZoneString = callFrame->argument(0).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, { });

std::optional<int64_t> utcOffset = ISO8601::parseTimeZoneNumericUTCOffset(timeZoneString);
std::optional<int64_t> utcOffset = ISO8601::parseUTCOffset(timeZoneString);
if (utcOffset)
return JSValue::encode(TemporalTimeZone::createFromUTCOffset(vm, structure, utcOffset.value()));

Expand Down

0 comments on commit 51ee7ef

Please sign in to comment.