From b8db0ddc708a097557e88ae9b07d6efdea250e2b Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Fri, 5 Nov 2021 01:35:37 +0000 Subject: [PATCH] LibJS: Implement Temporal.ZonedDateTime.prototype.withCalendar --- .../Temporal/ZonedDateTimePrototype.cpp | 15 +++++++ .../Runtime/Temporal/ZonedDateTimePrototype.h | 1 + .../ZonedDateTime.prototype.withCalendar.js | 43 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withCalendar.js diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp index ad47ded159..0224503483 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp @@ -67,6 +67,7 @@ void ZonedDateTimePrototype::initialize(GlobalObject& global_object) define_native_function(vm.names.withPlainTime, with_plain_time, 0, attr); define_native_function(vm.names.withPlainDate, with_plain_date, 1, attr); define_native_function(vm.names.withTimeZone, with_time_zone, 1, attr); + define_native_function(vm.names.withCalendar, with_calendar, 1, attr); define_native_function(vm.names.valueOf, value_of, 0, attr); define_native_function(vm.names.startOfDay, start_of_day, 0, attr); define_native_function(vm.names.toInstant, to_instant, 0, attr); @@ -793,6 +794,20 @@ JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::with_time_zone) return MUST(create_temporal_zoned_date_time(global_object, zoned_date_time->nanoseconds(), *time_zone, zoned_date_time->calendar())); } +// 6.3.34 Temporal.ZonedDateTime.prototype.withCalendar ( calendarLike ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.withcalendar +JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::with_calendar) +{ + // 1. Let zonedDateTime be the this value. + // 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]). + auto* zoned_date_time = TRY(typed_this_object(global_object)); + + // 3. Let calendar be ? ToTemporalCalendar(calendarLike). + auto* calendar = TRY(to_temporal_calendar(global_object, vm.argument(0))); + + // 4. Return ! CreateTemporalZonedDateTime(zonedDateTime.[[Nanoseconds]], zonedDateTime.[[TimeZone]], calendar). + return MUST(create_temporal_zoned_date_time(global_object, zoned_date_time->nanoseconds(), zoned_date_time->time_zone(), *calendar)); +} + // 6.3.44 Temporal.ZonedDateTime.prototype.valueOf ( ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.valueof JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::value_of) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.h b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.h index 416b2bb20a..208a494f77 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.h @@ -52,6 +52,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(with_plain_time); JS_DECLARE_NATIVE_FUNCTION(with_plain_date); JS_DECLARE_NATIVE_FUNCTION(with_time_zone); + JS_DECLARE_NATIVE_FUNCTION(with_calendar); JS_DECLARE_NATIVE_FUNCTION(value_of); JS_DECLARE_NATIVE_FUNCTION(start_of_day); JS_DECLARE_NATIVE_FUNCTION(to_instant); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withCalendar.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withCalendar.js new file mode 100644 index 0000000000..3361e0e15c --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withCalendar.js @@ -0,0 +1,43 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Temporal.ZonedDateTime.prototype.withCalendar).toHaveLength(1); + }); + + test("basic functionality", () => { + const object = {}; + const zonedDateTime = new Temporal.ZonedDateTime(1n, {}, object); + expect(zonedDateTime.calendar).toBe(object); + + const calendar = new Temporal.Calendar("iso8601"); + const withCalendarZonedDateTime = zonedDateTime.withCalendar(calendar); + expect(withCalendarZonedDateTime.calendar).toBe(calendar); + }); + + test("from calendar string", () => { + const object = {}; + const zonedDateTime = new Temporal.ZonedDateTime(1n, {}, object); + expect(zonedDateTime.calendar).toBe(object); + + const withCalendarZonedDateTime = zonedDateTime.withCalendar("iso8601"); + expect(withCalendarZonedDateTime.calendar).toBeInstanceOf(Temporal.Calendar); + expect(withCalendarZonedDateTime.calendar.id).toBe("iso8601"); + }); +}); + +describe("errors", () => { + test("this value must be a Temporal.ZonedDateTime object", () => { + expect(() => { + Temporal.ZonedDateTime.prototype.withCalendar.call("foo"); + }).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime"); + }); + + // FIXME: Enable this when calendar string parsing is implemented. + test.skip("from invalid calendar string", () => { + const zonedDateTime = new Temporal.ZonedDateTime(1n, {}, {}); + + // FIXME: Use "toThrowWithMessage" once this has an error message. + expect(() => { + zonedDateTime.withCalendar("iso8602foobar"); + }).toThrow(RangeError); + }); +});