diff options
author | Linus Groh <mail@linusgroh.de> | 2021-09-09 00:27:19 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-09-09 08:52:48 +0100 |
commit | 6607d1dfb1fc19901ee9eb43f67345a8a64136e3 (patch) | |
tree | d5ea21d6f073125d62291c008c3d7dba18b444b7 /Userland | |
parent | 1c78ff1b9fbecf12d02f9435b6b5b963d7db808f (diff) | |
download | serenity-6607d1dfb1fc19901ee9eb43f67345a8a64136e3.zip |
LibJS: Implement Temporal.Instant.prototype.toZonedDateTime()
Diffstat (limited to 'Userland')
5 files changed, 116 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index 1220ec25cb..2e33ebc392 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -435,6 +435,7 @@ namespace JS { P(toTimeString) \ P(toUpperCase) \ P(toUTCString) \ + P(toZonedDateTime) \ P(trace) \ P(trim) \ P(trimEnd) \ diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Instant.h b/Userland/Libraries/LibJS/Runtime/Temporal/Instant.h index ca370d7a86..e714d6d6d7 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Instant.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Instant.h @@ -22,6 +22,7 @@ public: virtual ~Instant() override = default; [[nodiscard]] BigInt const& nanoseconds() const { return m_nanoseconds; } + [[nodiscard]] BigInt& nanoseconds() { return m_nanoseconds; } private: virtual void visit_edges(Visitor&) override; diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp index 0874738c92..e020790323 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp @@ -8,10 +8,12 @@ #include <LibCrypto/BigInt/UnsignedBigInteger.h> #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/Temporal/AbstractOperations.h> +#include <LibJS/Runtime/Temporal/Calendar.h> #include <LibJS/Runtime/Temporal/Duration.h> #include <LibJS/Runtime/Temporal/Instant.h> #include <LibJS/Runtime/Temporal/InstantPrototype.h> #include <LibJS/Runtime/Temporal/TimeZone.h> +#include <LibJS/Runtime/Temporal/ZonedDateTime.h> namespace JS::Temporal { @@ -46,6 +48,7 @@ void InstantPrototype::initialize(GlobalObject& global_object) define_native_function(vm.names.toLocaleString, to_locale_string, 0, attr); define_native_function(vm.names.toJSON, to_json, 0, attr); define_native_function(vm.names.valueOf, value_of, 0, attr); + define_native_function(vm.names.toZonedDateTime, to_zoned_date_time, 1, attr); } static Instant* typed_this(GlobalObject& global_object) @@ -509,4 +512,60 @@ JS_DEFINE_NATIVE_FUNCTION(InstantPrototype::value_of) return {}; } +// 8.3.17 Temporal.Instant.prototype.toZonedDateTime ( item ), https://tc39.es/proposal-temporal/#sec-temporal.instant.prototype.tozoneddatetime +JS_DEFINE_NATIVE_FUNCTION(InstantPrototype::to_zoned_date_time) +{ + auto item = vm.argument(0); + + // 1. Let instant be the this value. + // 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]). + auto* instant = typed_this(global_object); + if (vm.exception()) + return {}; + + // 3. If Type(item) is not Object, then + if (!item.is_object()) { + // a. Throw a TypeError exception. + vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, item); + return {}; + } + + // 4. Let calendarLike be ? Get(item, "calendar"). + auto calendar_like = item.as_object().get(vm.names.calendar); + if (vm.exception()) + return {}; + + // 5. If calendarLike is undefined, then + if (calendar_like.is_undefined()) { + // a. Throw a TypeError exception. + vm.throw_exception<TypeError>(global_object, ErrorType::TemporalMissingRequiredProperty, vm.names.calendar.as_string()); + return {}; + } + + // 6. Let calendar be ? ToTemporalCalendar(calendarLike). + auto* calendar = to_temporal_calendar(global_object, calendar_like); + if (vm.exception()) + return {}; + + // 7. Let temporalTimeZoneLike be ? Get(item, "timeZone"). + auto temporal_time_zone_like = item.as_object().get(vm.names.timeZone); + if (vm.exception()) + return {}; + + // 8. If temporalTimeZoneLike is undefined, then + if (temporal_time_zone_like.is_undefined()) { + // a. Throw a TypeError exception. + vm.throw_exception<TypeError>(global_object, ErrorType::TemporalMissingRequiredProperty, vm.names.timeZone.as_string()); + return {}; + } + + // 9. Let timeZone be ? ToTemporalTimeZone(temporalTimeZoneLike). + auto* time_zone = to_temporal_time_zone(global_object, temporal_time_zone_like); + if (vm.exception()) + return {}; + + // 10. Return ? CreateTemporalZonedDateTime(instant.[[Nanoseconds]], timeZone, calendar). + return create_temporal_zoned_date_time(global_object, instant->nanoseconds(), *time_zone, *calendar); +} + } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h b/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h index 013b40dbcf..351d665b78 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h @@ -33,6 +33,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(to_locale_string); JS_DECLARE_NATIVE_FUNCTION(to_json); JS_DECLARE_NATIVE_FUNCTION(value_of); + JS_DECLARE_NATIVE_FUNCTION(to_zoned_date_time); }; } diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Instant/Instant.prototype.toZonedDateTime.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Instant/Instant.prototype.toZonedDateTime.js new file mode 100644 index 0000000000..d01ec6841a --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Instant/Instant.prototype.toZonedDateTime.js @@ -0,0 +1,54 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Temporal.Instant.prototype.toZonedDateTime).toHaveLength(1); + }); + + test("basic functionality", () => { + const instant = new Temporal.Instant(1625614921123456789n); + const calendar = new Temporal.Calendar("iso8601"); + const timeZone = new Temporal.TimeZone("UTC"); + const zonedDateTime = instant.toZonedDateTime({ calendar, timeZone }); + expect(zonedDateTime.year).toBe(2021); + expect(zonedDateTime.month).toBe(7); + expect(zonedDateTime.day).toBe(6); + expect(zonedDateTime.hour).toBe(23); + expect(zonedDateTime.minute).toBe(42); + expect(zonedDateTime.second).toBe(1); + expect(zonedDateTime.millisecond).toBe(123); + expect(zonedDateTime.microsecond).toBe(456); + expect(zonedDateTime.nanosecond).toBe(789); + expect(zonedDateTime.calendar).toBe(calendar); + expect(zonedDateTime.timeZone).toBe(timeZone); + }); +}); + +describe("errors", () => { + test("this value must be a Temporal.Instant object", () => { + expect(() => { + Temporal.Instant.prototype.toZonedDateTime.call("foo"); + }).toThrowWithMessage(TypeError, "Not a Temporal.Instant"); + }); + + test("items argument must be an object", () => { + const instant = new Temporal.Instant(0n); + for (const value of [123, NaN, Infinity, true, false, null, undefined]) { + expect(() => { + instant.toZonedDateTime(value); + }).toThrowWithMessage(TypeError, `${value} is not an object`); + } + }); + + test("items argument must have a 'calendar' property", () => { + const instant = new Temporal.Instant(0n); + expect(() => { + instant.toZonedDateTime({}); + }).toThrowWithMessage(TypeError, "Required property calendar is missing or undefined"); + }); + + test("items argument must have a 'timeZone' property", () => { + const instant = new Temporal.Instant(0n); + expect(() => { + instant.toZonedDateTime({ calendar: {} }); + }).toThrowWithMessage(TypeError, "Required property timeZone is missing or undefined"); + }); +}); |