From 053cc90dbea7e64669b4cd208ec8c89bda8bb8bf Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 14 Oct 2022 10:34:24 -0400 Subject: [PATCH] LibJS: Replace GetIANATimeZoneEpochValue with GetNamedTimeZoneEpoch[Ns] This is an editorial change in the Temporal spec. See: https://github.com/tc39/proposal-temporal/commit/e834014 --- .../LibJS/Runtime/Temporal/TimeZone.cpp | 42 +++++++------------ .../LibJS/Runtime/Temporal/TimeZone.h | 1 - .../Runtime/Temporal/TimeZonePrototype.cpp | 13 +++--- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp index 2fea28895a..3230448e78 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp @@ -149,21 +149,7 @@ ISODateTime get_iso_parts_from_epoch(VM& vm, Crypto::SignedBigInteger const& epo return { .year = year, .month = month, .day = day, .hour = hour, .minute = minute, .second = second, .millisecond = millisecond, .microsecond = static_cast(microsecond), .nanosecond = static_cast(nanosecond) }; } -// 11.6.3 GetIANATimeZoneEpochValue ( timeZoneIdentifier, year, month, day, hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneepochvalue -MarkedVector get_iana_time_zone_epoch_value(VM& vm, [[maybe_unused]] StringView time_zone_identifier, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond) -{ - // The implementation-defined abstract operation GetIANATimeZoneEpochValue takes arguments timeZoneIdentifier (a String), year (an integer), month (an integer between 1 and 12 inclusive), day (an integer between 1 and 31 inclusive), hour (an integer between 0 and 23 inclusive), minute (an integer between 0 and 59 inclusive), second (an integer between 0 and 59 inclusive), millisecond (an integer between 0 and 999 inclusive), microsecond (an integer between 0 and 999 inclusive), and nanosecond (an integer between 0 and 999 inclusive) and returns a List of BigInts. - // Each value in the returned List represents a number of nanoseconds since the Unix epoch in UTC that corresponds to the given ISO 8601 calendar date and wall-clock time in the IANA time zone identified by timeZoneIdentifier. - // When the input represents a local time repeating multiple times at a negative time zone transition (e.g. when the daylight saving time ends or the time zone offset is decreased due to a time zone rule change), the returned List will have more than one element. The elements are sorted in numerical order. When the input represents a skipped local time at a positive time zone transition (e.g. when the daylight saving time starts or the time zone offset is increased due to a time zone rule change), the returned List will be empty. Otherwise, the returned List will have one element. - // It is an error to call GetIANATimeZoneEpochValue with arguments such that IsValidISODate(year, month, day) is false. - - // FIXME: Implement this properly for non-UTC timezones. - auto list = MarkedVector { vm.heap() }; - list.append(js_bigint(vm, get_utc_epoch_nanoseconds(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond))); - return list; -} - -// 11.6.4 GetIANATimeZoneOffsetNanoseconds ( epochNanoseconds, timeZoneIdentifier ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneoffsetnanoseconds +// 11.6.3 GetIANATimeZoneOffsetNanoseconds ( epochNanoseconds, timeZoneIdentifier ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneoffsetnanoseconds i64 get_iana_time_zone_offset_nanoseconds(BigInt const& epoch_nanoseconds, String const& time_zone_identifier) { // The implementation-defined abstract operation GetIANATimeZoneOffsetNanoseconds takes arguments epochNanoseconds (a BigInt) and timeZoneIdentifier (a String) and returns an integer. @@ -195,7 +181,7 @@ i64 get_iana_time_zone_offset_nanoseconds(BigInt const& epoch_nanoseconds, Strin return offset->seconds * 1'000'000'000; } -// 11.6.5 GetIANATimeZoneNextTransition ( epochNanoseconds, timeZoneIdentifier ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezonenexttransition +// 11.6.4 GetIANATimeZoneNextTransition ( epochNanoseconds, timeZoneIdentifier ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezonenexttransition BigInt* get_iana_time_zone_next_transition(VM&, [[maybe_unused]] BigInt const& epoch_nanoseconds, [[maybe_unused]] StringView time_zone_identifier) { // The implementation-defined abstract operation GetIANATimeZoneNextTransition takes arguments epochNanoseconds (a BigInt) and timeZoneIdentifier (a String) and returns a BigInt or null. @@ -206,7 +192,7 @@ BigInt* get_iana_time_zone_next_transition(VM&, [[maybe_unused]] BigInt const& e return nullptr; } -// 11.6.6 GetIANATimeZonePreviousTransition ( epochNanoseconds, timeZoneIdentifier ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneprevioustransition +// 11.6.5 GetIANATimeZonePreviousTransition ( epochNanoseconds, timeZoneIdentifier ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneprevioustransition BigInt* get_iana_time_zone_previous_transition(VM&, [[maybe_unused]] BigInt const& epoch_nanoseconds, [[maybe_unused]] StringView time_zone_identifier) { // The implementation-defined abstract operation GetIANATimeZonePreviousTransition takes arguments epochNanoseconds (a BigInt) and timeZoneIdentifier (a String) and returns a BigInt or null. @@ -260,7 +246,7 @@ bool is_valid_time_zone_numeric_utc_offset_syntax(String const& offset_string) return parse_time_zone_numeric_utc_offset_syntax(offset_string, discarded, discarded, optionally_discarded, optionally_discarded, optionally_discarded); } -// 11.6.7 ParseTimeZoneOffsetString ( offsetString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetimezoneoffsetstring +// 11.6.6 ParseTimeZoneOffsetString ( offsetString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetimezoneoffsetstring ThrowCompletionOr parse_time_zone_offset_string(VM& vm, String const& offset_string) { // 1. Let parseResult be ParseText(StringToCodePoints(offsetString), TimeZoneNumericUTCOffset). @@ -333,7 +319,7 @@ ThrowCompletionOr parse_time_zone_offset_string(VM& vm, String const& of return factor * (((hours_mv * 60 + minutes_mv) * 60 + seconds_mv) * 1e9 + nanoseconds_mv); } -// 11.6.8 FormatTimeZoneOffsetString ( offsetNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-formattimezoneoffsetstring +// 11.6.7 FormatTimeZoneOffsetString ( offsetNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-formattimezoneoffsetstring String format_time_zone_offset_string(double offset_nanoseconds) { auto offset = static_cast(offset_nanoseconds); @@ -387,7 +373,7 @@ String format_time_zone_offset_string(double offset_nanoseconds) return builder.to_string(); } -// 11.6.9 FormatISOTimeZoneOffsetString ( offsetNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-formatisotimezoneoffsetstring +// 11.6.8 FormatISOTimeZoneOffsetString ( offsetNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-formatisotimezoneoffsetstring String format_iso_time_zone_offset_string(double offset_nanoseconds) { // 1. Assert: offsetNanoseconds is an integer. @@ -414,7 +400,7 @@ String format_iso_time_zone_offset_string(double offset_nanoseconds) return String::formatted("{}{:02}:{:02}", sign, (u32)hours, (u32)minutes); } -// 11.6.10 ToTemporalTimeZone ( temporalTimeZoneLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaltimezone +// 11.6.9 ToTemporalTimeZone ( temporalTimeZoneLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaltimezone ThrowCompletionOr to_temporal_time_zone(VM& vm, Value temporal_time_zone_like) { // 1. If Type(temporalTimeZoneLike) is Object, then @@ -472,7 +458,7 @@ ThrowCompletionOr to_temporal_time_zone(VM& vm, Value temporal_time_zon return MUST(create_temporal_time_zone(vm, *parse_result.offset_string)); } -// 11.6.11 GetOffsetNanosecondsFor ( timeZone, instant ), https://tc39.es/proposal-temporal/#sec-temporal-getoffsetnanosecondsfor +// 11.6.10 GetOffsetNanosecondsFor ( timeZone, instant ), https://tc39.es/proposal-temporal/#sec-temporal-getoffsetnanosecondsfor ThrowCompletionOr get_offset_nanoseconds_for(VM& vm, Value time_zone, Instant& instant) { // 1. Let getOffsetNanosecondsFor be ? GetMethod(timeZone, "getOffsetNanosecondsFor"). @@ -500,7 +486,7 @@ ThrowCompletionOr get_offset_nanoseconds_for(VM& vm, Value time_zone, In return offset_nanoseconds; } -// 11.6.12 BuiltinTimeZoneGetOffsetStringFor ( timeZone, instant ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetoffsetstringfor +// 11.6.11 BuiltinTimeZoneGetOffsetStringFor ( timeZone, instant ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetoffsetstringfor ThrowCompletionOr builtin_time_zone_get_offset_string_for(VM& vm, Value time_zone, Instant& instant) { // 1. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant). @@ -510,7 +496,7 @@ ThrowCompletionOr builtin_time_zone_get_offset_string_for(VM& vm, Value return format_time_zone_offset_string(offset_nanoseconds); } -// 11.6.13 BuiltinTimeZoneGetPlainDateTimeFor ( timeZone, instant, calendar ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetplaindatetimefor +// 11.6.12 BuiltinTimeZoneGetPlainDateTimeFor ( timeZone, instant, calendar ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetplaindatetimefor ThrowCompletionOr builtin_time_zone_get_plain_date_time_for(VM& vm, Value time_zone, Instant& instant, Object& calendar) { // 1. Assert: instant has an [[InitializedTemporalInstant]] internal slot. @@ -528,7 +514,7 @@ ThrowCompletionOr builtin_time_zone_get_plain_date_time_for(VM& return create_temporal_date_time(vm, result.year, result.month, result.day, result.hour, result.minute, result.second, result.millisecond, result.microsecond, result.nanosecond, calendar); } -// 11.6.14 BuiltinTimeZoneGetInstantFor ( timeZone, dateTime, disambiguation ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetinstantfor +// 11.6.13 BuiltinTimeZoneGetInstantFor ( timeZone, dateTime, disambiguation ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetinstantfor ThrowCompletionOr builtin_time_zone_get_instant_for(VM& vm, Value time_zone, PlainDateTime& date_time, StringView disambiguation) { // 1. Assert: dateTime has an [[InitializedTemporalDateTime]] internal slot. @@ -540,7 +526,7 @@ ThrowCompletionOr builtin_time_zone_get_instant_for(VM& vm, Value time return disambiguate_possible_instants(vm, possible_instants, time_zone, date_time, disambiguation); } -// 11.6.15 DisambiguatePossibleInstants ( possibleInstants, timeZone, dateTime, disambiguation ), https://tc39.es/proposal-temporal/#sec-temporal-disambiguatepossibleinstants +// 11.6.14 DisambiguatePossibleInstants ( possibleInstants, timeZone, dateTime, disambiguation ), https://tc39.es/proposal-temporal/#sec-temporal-disambiguatepossibleinstants ThrowCompletionOr disambiguate_possible_instants(VM& vm, MarkedVector const& possible_instants, Value time_zone, PlainDateTime& date_time, StringView disambiguation) { // 1. Assert: dateTime has an [[InitializedTemporalDateTime]] internal slot. @@ -658,7 +644,7 @@ ThrowCompletionOr disambiguate_possible_instants(VM& vm, MarkedVector< return possible_instants_[n - 1]; } -// 11.6.16 GetPossibleInstantsFor ( timeZone, dateTime ), https://tc39.es/proposal-temporal/#sec-temporal-getpossibleinstantsfor +// 11.6.15 GetPossibleInstantsFor ( timeZone, dateTime ), https://tc39.es/proposal-temporal/#sec-temporal-getpossibleinstantsfor ThrowCompletionOr> get_possible_instants_for(VM& vm, Value time_zone, PlainDateTime& date_time) { // 1. Assert: dateTime has an [[InitializedTemporalDateTime]] internal slot. @@ -703,7 +689,7 @@ ThrowCompletionOr> get_possible_instants_for(VM& vm, Valu return { move(list) }; } -// 11.6.17 TimeZoneEquals ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal-timezoneequals +// 11.6.16 TimeZoneEquals ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal-timezoneequals ThrowCompletionOr time_zone_equals(VM& vm, Object& one, Object& two) { // 1. If one and two are the same Object value, return true. diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h index 420a6ba1a9..89c36ad18f 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h @@ -41,7 +41,6 @@ String canonicalize_time_zone_name(String const& time_zone); String default_time_zone(); ThrowCompletionOr create_temporal_time_zone(VM&, String const& identifier, FunctionObject const* new_target = nullptr); ISODateTime get_iso_parts_from_epoch(VM&, Crypto::SignedBigInteger const& epoch_nanoseconds); -MarkedVector get_iana_time_zone_epoch_value(VM&, StringView time_zone_identifier, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond); i64 get_iana_time_zone_offset_nanoseconds(BigInt const& epoch_nanoseconds, String const& time_zone_identifier); BigInt* get_iana_time_zone_next_transition(VM&, BigInt const& epoch_nanoseconds, StringView time_zone_identifier); BigInt* get_iana_time_zone_previous_transition(VM&, BigInt const& epoch_nanoseconds, StringView time_zone_identifier); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.cpp index 17ab8fd163..1997ee8135 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.cpp @@ -138,7 +138,7 @@ JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::get_possible_instants_for) // 3. Set dateTime to ? ToTemporalDateTime(dateTime). auto* date_time = TRY(to_temporal_date_time(vm, vm.argument(0))); - auto possible_epoch_nanoseconds = MarkedVector { vm.heap() }; + Vector possible_epoch_nanoseconds; // 4. If timeZone.[[OffsetNanoseconds]] is not undefined, then if (time_zone->offset_nanoseconds().has_value()) { @@ -146,12 +146,12 @@ JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::get_possible_instants_for) auto epoch_nanoseconds = get_utc_epoch_nanoseconds(date_time->iso_year(), date_time->iso_month(), date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(), date_time->iso_millisecond(), date_time->iso_microsecond(), date_time->iso_nanosecond()); // b. Let possibleEpochNanoseconds be « epochNanoseconds - ℤ(timeZone.[[OffsetNanoseconds]]) ». - possible_epoch_nanoseconds.append(js_bigint(vm, epoch_nanoseconds.minus(Crypto::SignedBigInteger { *time_zone->offset_nanoseconds() }))); + possible_epoch_nanoseconds.append(epoch_nanoseconds.minus(Crypto::SignedBigInteger { *time_zone->offset_nanoseconds() })); } // 5. Else, else { - // a. Let possibleEpochNanoseconds be GetIANATimeZoneEpochValue(timeZone.[[Identifier]], dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]]). - possible_epoch_nanoseconds = get_iana_time_zone_epoch_value(vm, time_zone->identifier(), date_time->iso_year(), date_time->iso_month(), date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(), date_time->iso_millisecond(), date_time->iso_microsecond(), date_time->iso_nanosecond()); + // a. Let possibleEpochNanoseconds be GetNamedTimeZoneEpochNanoseconds(timeZone.[[Identifier]], dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]]). + possible_epoch_nanoseconds = get_named_time_zone_epoch_nanoseconds(time_zone->identifier(), date_time->iso_year(), date_time->iso_month(), date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(), date_time->iso_millisecond(), date_time->iso_microsecond(), date_time->iso_nanosecond()); } // 6. Let possibleInstants be a new empty List. @@ -160,11 +160,12 @@ JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::get_possible_instants_for) // 7. For each value epochNanoseconds in possibleEpochNanoseconds, do for (auto& epoch_nanoseconds : possible_epoch_nanoseconds) { // a. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception. - if (!is_valid_epoch_nanoseconds(*epoch_nanoseconds)) + if (!is_valid_epoch_nanoseconds(epoch_nanoseconds)) return vm.throw_completion(ErrorType::TemporalInvalidEpochNanoseconds); // b. Let instant be ! CreateTemporalInstant(epochNanoseconds). - auto* instant = MUST(create_temporal_instant(vm, *epoch_nanoseconds)); + auto* epoch_nanoseconds_bigint = js_bigint(vm, move(epoch_nanoseconds)); + auto* instant = MUST(create_temporal_instant(vm, *epoch_nanoseconds_bigint)); // c. Append instant to possibleInstants. possible_instants.append(instant);