diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index 2ec53018fb..a0d89b7f21 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -188,6 +188,7 @@ namespace JS { P(getOwnPropertyDescriptors) \ P(getOwnPropertyNames) \ P(getOwnPropertySymbols) \ + P(getPlainDateTimeFor) \ P(getPrototypeOf) \ P(getSeconds) \ P(getTime) \ diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Now.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Now.cpp index d1057f04bf..c4bd119d81 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Now.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Now.cpp @@ -196,7 +196,7 @@ PlainDateTime* system_date_time(GlobalObject& global_object, Value temporal_time auto* instant = system_instant(global_object); // 5. Return ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar). - return builtin_time_zone_get_plain_date_time_for(global_object, *time_zone, *instant, *calendar); + return builtin_time_zone_get_plain_date_time_for(global_object, time_zone, *instant, *calendar); } } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp index 9a3baeb1a9..21784cbf31 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp @@ -367,12 +367,12 @@ Object* to_temporal_time_zone(GlobalObject& global_object, Value temporal_time_z } // 11.6.11 GetOffsetNanosecondsFor ( timeZone, instant ), https://tc39.es/proposal-temporal/#sec-temporal-getoffsetnanosecondsfor -double get_offset_nanoseconds_for(GlobalObject& global_object, Object& time_zone, Instant& instant) +double get_offset_nanoseconds_for(GlobalObject& global_object, Value time_zone, Instant& instant) { auto& vm = global_object.vm(); // 1. Let getOffsetNanosecondsFor be ? GetMethod(timeZone, "getOffsetNanosecondsFor"). - auto* get_offset_nanoseconds_for = Value(&time_zone).get_method(global_object, vm.names.getOffsetNanosecondsFor); + auto* get_offset_nanoseconds_for = time_zone.get_method(global_object, vm.names.getOffsetNanosecondsFor); if (vm.exception()) return {}; @@ -381,7 +381,7 @@ double get_offset_nanoseconds_for(GlobalObject& global_object, Object& time_zone get_offset_nanoseconds_for = global_object.temporal_time_zone_prototype_get_offset_nanoseconds_for_function(); // 3. Let offsetNanoseconds be ? Call(getOffsetNanosecondsFor, timeZone, « instant »). - auto offset_nanoseconds_value = vm.call(*get_offset_nanoseconds_for, &time_zone, &instant); + auto offset_nanoseconds_value = vm.call(*get_offset_nanoseconds_for, time_zone, &instant); if (vm.exception()) return {}; @@ -416,7 +416,7 @@ Optional builtin_time_zone_get_offset_string_for(GlobalObject& global_ob auto& vm = global_object.vm(); // 1. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant). - auto offset_nanoseconds = get_offset_nanoseconds_for(global_object, time_zone, instant); + auto offset_nanoseconds = get_offset_nanoseconds_for(global_object, &time_zone, instant); if (vm.exception()) return {}; @@ -425,7 +425,7 @@ Optional builtin_time_zone_get_offset_string_for(GlobalObject& global_ob } // 11.6.13 BuiltinTimeZoneGetPlainDateTimeFor ( timeZone, instant, calendar ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetplaindatetimefor -PlainDateTime* builtin_time_zone_get_plain_date_time_for(GlobalObject& global_object, Object& time_zone, Instant& instant, Object& calendar) +PlainDateTime* builtin_time_zone_get_plain_date_time_for(GlobalObject& global_object, Value time_zone, Instant& instant, Object& calendar) { auto& vm = global_object.vm(); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h index be79fc491c..19a0b2f31a 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h @@ -46,9 +46,9 @@ i64 get_iana_time_zone_offset_nanoseconds(BigInt const& epoch_nanoseconds, Strin double parse_time_zone_offset_string(GlobalObject&, String const&); String format_time_zone_offset_string(double offset_nanoseconds); Object* to_temporal_time_zone(GlobalObject&, Value temporal_time_zone_like); -double get_offset_nanoseconds_for(GlobalObject&, Object& time_zone, Instant&); +double get_offset_nanoseconds_for(GlobalObject&, Value time_zone, Instant&); Optional builtin_time_zone_get_offset_string_for(GlobalObject&, TimeZone&, Instant&); -PlainDateTime* builtin_time_zone_get_plain_date_time_for(GlobalObject&, Object& time_zone, Instant&, Object& calendar); +PlainDateTime* builtin_time_zone_get_plain_date_time_for(GlobalObject&, Value time_zone, Instant&, Object& calendar); bool is_valid_time_zone_numeric_utc_offset_syntax(String const&); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.cpp index 5f2d9120c6..355efd9dba 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.cpp @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include @@ -28,6 +30,7 @@ void TimeZonePrototype::initialize(GlobalObject& global_object) define_native_accessor(vm.names.id, id_getter, {}, Attribute::Configurable); define_native_function(vm.names.getOffsetNanosecondsFor, get_offset_nanoseconds_for, 1, attr); define_native_function(vm.names.getOffsetStringFor, get_offset_string_for, 1, attr); + define_native_function(vm.names.getPlainDateTimeFor, get_plain_date_time_for, 1, attr); define_native_function(vm.names.toString, to_string, 0, attr); define_native_function(vm.names.toJSON, to_json, 0, attr); @@ -101,6 +104,26 @@ JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::get_offset_string_for) return js_string(vm, move(*offset_string)); } +// 11.4.6 Temporal.TimeZone.prototype.getPlainDateTimeFor ( instant [ , calendarLike ] ), https://tc39.es/proposal-temporal/#sec-temporal.timezone.prototype.getplaindatetimefor +JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::get_plain_date_time_for) +{ + // 1. Let timeZone be the this value. + auto time_zone = vm.this_value(global_object); + + // 2. Set instant to ? ToTemporalInstant(instant). + auto* instant = to_temporal_instant(global_object, vm.argument(0)); + if (vm.exception()) + return {}; + + // 3. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike). + auto* calendar = to_temporal_calendar_with_iso_default(global_object, vm.argument(1)); + if (vm.exception()) + return {}; + + // 4. Return ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar). + return builtin_time_zone_get_plain_date_time_for(global_object, time_zone, *instant, *calendar); +} + // 11.4.11 Temporal.TimeZone.prototype.toString ( ), https://tc39.es/proposal-temporal/#sec-temporal.timezone.prototype.tostring JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::to_string) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.h b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.h index e7177f4820..1a95ca42f7 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZonePrototype.h @@ -22,6 +22,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(id_getter); JS_DECLARE_NATIVE_FUNCTION(get_offset_nanoseconds_for); JS_DECLARE_NATIVE_FUNCTION(get_offset_string_for); + JS_DECLARE_NATIVE_FUNCTION(get_plain_date_time_for); JS_DECLARE_NATIVE_FUNCTION(to_string); JS_DECLARE_NATIVE_FUNCTION(to_json); }; diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/TimeZone/TimeZone.prototype.getPlainDateTimeFor.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/TimeZone/TimeZone.prototype.getPlainDateTimeFor.js new file mode 100644 index 0000000000..afe021d6a7 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/TimeZone/TimeZone.prototype.getPlainDateTimeFor.js @@ -0,0 +1,51 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Temporal.TimeZone.prototype.getPlainDateTimeFor).toHaveLength(1); + }); + + test("basic functionality", () => { + const timeZone = new Temporal.TimeZone("UTC"); + const instant = Temporal.Instant.fromEpochSeconds(123456789); + const plainDateTime = timeZone.getPlainDateTimeFor(instant); + expect(plainDateTime.year).toBe(1973); + expect(plainDateTime.month).toBe(11); + expect(plainDateTime.day).toBe(29); + expect(plainDateTime.hour).toBe(21); + expect(plainDateTime.minute).toBe(33); + expect(plainDateTime.second).toBe(9); + expect(plainDateTime.millisecond).toBe(0); + expect(plainDateTime.microsecond).toBe(0); + expect(plainDateTime.nanosecond).toBe(0); + expect(plainDateTime.calendar.id).toBe("iso8601"); + }); + + test("custom calendar", () => { + const timeZone = new Temporal.TimeZone("UTC"); + const instant = new Temporal.Instant(0n); + const calendar = new Temporal.Calendar("iso8601"); + const plainDateTime = timeZone.getPlainDateTimeFor(instant, calendar); + expect(plainDateTime.calendar).toBe(calendar); + }); + + test("non-TimeZone this value", () => { + const timeZoneLike = { + getOffsetNanosecondsFor() { + return 123; + }, + }; + const instant = new Temporal.Instant(0n); + const plainDateTime = Temporal.TimeZone.prototype.getPlainDateTimeFor.call( + timeZoneLike, + instant + ); + expect(plainDateTime.year).toBe(1970); + expect(plainDateTime.month).toBe(1); + expect(plainDateTime.day).toBe(1); + expect(plainDateTime.hour).toBe(0); + expect(plainDateTime.minute).toBe(0); + expect(plainDateTime.second).toBe(0); + expect(plainDateTime.millisecond).toBe(0); + expect(plainDateTime.microsecond).toBe(0); + expect(plainDateTime.nanosecond).toBe(123); + }); +});