Prechádzať zdrojové kódy

LibJS: Implement Temporal.TimeZone.prototype.getPreviousTransition()

Linus Groh 3 rokov pred
rodič
commit
92fdae178b

+ 1 - 0
Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h

@@ -214,6 +214,7 @@ namespace JS {
     P(getOwnPropertySymbols)                 \
     P(getPlainDateTimeFor)                   \
     P(getPossibleInstantsFor)                \
+    P(getPreviousTransition)                 \
     P(getPrototypeOf)                        \
     P(getSeconds)                            \
     P(getTime)                               \

+ 9 - 0
Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp

@@ -186,6 +186,15 @@ BigInt* get_iana_time_zone_next_transition(GlobalObject&, [[maybe_unused]] BigIn
     return nullptr;
 }
 
+// 11.6.7 GetIANATimeZonePreviousTransition ( epochNanoseconds, timeZoneIdentifier ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneprevioustransition
+BigInt* get_iana_time_zone_previous_transition(GlobalObject&, [[maybe_unused]] BigInt const& epoch_nanoseconds, [[maybe_unused]] StringView time_zone_identifier)
+{
+    // The abstract operation GetIANATimeZonePreviousTransition is an implementation-defined algorithm that returns an integer representing the number of nanoseconds since the Unix epoch in UTC that corresponds to the last time zone transition before epochNanoseconds in the IANA time zone identified by timeZoneIdentifier or null if no such transition exists.
+
+    // TODO: Implement this
+    return nullptr;
+}
+
 // https://tc39.es/proposal-temporal/#prod-TimeZoneNumericUTCOffset
 static bool parse_time_zone_numeric_utc_offset_syntax(String const& offset_string, StringView& sign, StringView& hours, Optional<StringView>& minutes, Optional<StringView>& seconds, Optional<StringView>& fraction)
 {

+ 1 - 0
Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h

@@ -42,6 +42,7 @@ ISODateTime get_iso_parts_from_epoch(BigInt const& epoch_nanoseconds);
 MarkedValueList get_iana_time_zone_epoch_value(GlobalObject&, 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(GlobalObject&, BigInt const& epoch_nanoseconds, StringView time_zone_identifier);
+BigInt* get_iana_time_zone_previous_transition(GlobalObject&, BigInt const& epoch_nanoseconds, StringView time_zone_identifier);
 ThrowCompletionOr<double> parse_time_zone_offset_string(GlobalObject&, String const&);
 String format_time_zone_offset_string(double offset_nanoseconds);
 ThrowCompletionOr<Object*> to_temporal_time_zone(GlobalObject&, Value temporal_time_zone_like);

+ 26 - 0
Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.cpp

@@ -34,6 +34,7 @@ void TimeZonePrototype::initialize(GlobalObject& global_object)
     define_native_function(vm.names.getPlainDateTimeFor, get_plain_date_time_for, 1, attr);
     define_native_function(vm.names.getPossibleInstantsFor, get_possible_instants_for, 1, attr);
     define_native_function(vm.names.getNextTransition, get_next_transition, 1, attr);
+    define_native_function(vm.names.getPreviousTransition, get_previous_transition, 1, attr);
     define_native_function(vm.names.toString, to_string, 0, attr);
     define_native_function(vm.names.toJSON, to_json, 0, attr);
 
@@ -166,6 +167,31 @@ JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::get_next_transition)
     return MUST(create_temporal_instant(global_object, *transition));
 }
 
+// 11.4.10 Temporal.TimeZone.prototype.getPreviousTransition ( startingPoint ), https://tc39.es/proposal-temporal/#sec-temporal.timezone.prototype.getprevioustransition
+JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::get_previous_transition)
+{
+    // 1. Let timeZone be the this value.
+    // 2. Perform ? RequireInternalSlot(timeZone, [[InitializedTemporalTimeZone]]).
+    auto* time_zone = TRY(typed_this_object(global_object));
+
+    // 3. Set startingPoint to ? ToTemporalInstant(startingPoint).
+    auto* starting_point = TRY(to_temporal_instant(global_object, vm.argument(0)));
+
+    // 4. If timeZone.[[OffsetNanoseconds]] is not undefined, return null.
+    if (!time_zone->offset_nanoseconds().has_value())
+        return js_null();
+
+    // 5. Let transition be ? GetIANATimeZonePreviousTransition(startingPoint.[[Nanoseconds]], timeZone.[[Identifier]]).
+    auto* transition = get_iana_time_zone_previous_transition(global_object, starting_point->nanoseconds(), time_zone->identifier());
+
+    // 6. If transition is null, return null.
+    if (!transition)
+        return js_null();
+
+    // 7. Return ! CreateTemporalInstant(transition).
+    return MUST(create_temporal_instant(global_object, *transition));
+}
+
 // 11.4.11 Temporal.TimeZone.prototype.toString ( ), https://tc39.es/proposal-temporal/#sec-temporal.timezone.prototype.tostring
 JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::to_string)
 {

+ 1 - 0
Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.h

@@ -26,6 +26,7 @@ private:
     JS_DECLARE_NATIVE_FUNCTION(get_plain_date_time_for);
     JS_DECLARE_NATIVE_FUNCTION(get_possible_instants_for);
     JS_DECLARE_NATIVE_FUNCTION(get_next_transition);
+    JS_DECLARE_NATIVE_FUNCTION(get_previous_transition);
     JS_DECLARE_NATIVE_FUNCTION(to_string);
     JS_DECLARE_NATIVE_FUNCTION(to_json);
 };

+ 25 - 0
Userland/Libraries/LibJS/Tests/builtins/Temporal/TimeZone/TimeZone.prototype.getPreviousTransition.js

@@ -0,0 +1,25 @@
+describe("correct behavior", () => {
+    test("length is 1", () => {
+        expect(Temporal.TimeZone.prototype.getPreviousTransition).toHaveLength(1);
+    });
+
+    test("basic functionality", () => {
+        const timeZone = new Temporal.TimeZone("UTC");
+        const instant = new Temporal.Instant(0n);
+        expect(timeZone.getPreviousTransition(instant)).toBeNull();
+    });
+
+    test("custom offset", () => {
+        const timeZone = new Temporal.TimeZone("+01:30");
+        const instant = new Temporal.Instant(0n);
+        expect(timeZone.getPreviousTransition(instant)).toBeNull();
+    });
+});
+
+describe("errors", () => {
+    test("this value must be a Temporal.TimeZone object", () => {
+        expect(() => {
+            Temporal.TimeZone.prototype.getPreviousTransition.call("foo");
+        }).toThrowWithMessage(TypeError, "Not an object of type Temporal.TimeZone");
+    });
+});