diff --git a/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp b/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp index 2c6df2e0d22..b91284b94cc 100644 --- a/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp +++ b/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace JS::Temporal { @@ -44,6 +45,7 @@ void InstantPrototype::initialize(Realm& realm) define_native_function(realm, vm.names.toLocaleString, to_locale_string, 0, attr); define_native_function(realm, vm.names.toJSON, to_json, 0, attr); define_native_function(realm, vm.names.valueOf, value_of, 0, attr); + define_native_function(realm, vm.names.toZonedDateTimeISO, to_zoned_date_time_iso, 1, attr); } // 8.3.3 get Temporal.Instant.prototype.epochMilliseconds, https://tc39.es/proposal-temporal/#sec-get-temporal.instant.prototype.epochmilliseconds @@ -321,4 +323,18 @@ JS_DEFINE_NATIVE_FUNCTION(InstantPrototype::value_of) return vm.throw_completion(ErrorType::Convert, "Temporal.Instant", "a primitive value"); } +// 8.3.15 Temporal.Instant.prototype.toZonedDateTimeISO ( timeZone ), https://tc39.es/proposal-temporal/#sec-temporal.instant.prototype.tozoneddatetimeiso +JS_DEFINE_NATIVE_FUNCTION(InstantPrototype::to_zoned_date_time_iso) +{ + // 1. Let instant be the this value. + // 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]). + auto instant = TRY(typed_this_object(vm)); + + // 3. Set timeZone to ? ToTemporalTimeZoneIdentifier(timeZone). + auto time_zone = TRY(to_temporal_time_zone_identifier(vm, vm.argument(0))); + + // 4. Return ! CreateTemporalZonedDateTime(instant.[[EpochNanoseconds]], timeZone, "iso8601"). + return MUST(create_temporal_zoned_date_time(vm, instant->epoch_nanoseconds(), move(time_zone), "iso8601"_string)); +} + } diff --git a/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h b/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h index bdd2f57613c..c06495bf50d 100644 --- a/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h +++ b/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h @@ -35,6 +35,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_iso); }; } diff --git a/Libraries/LibJS/Runtime/Temporal/Now.cpp b/Libraries/LibJS/Runtime/Temporal/Now.cpp index a77846146b9..dce9540053c 100644 --- a/Libraries/LibJS/Runtime/Temporal/Now.cpp +++ b/Libraries/LibJS/Runtime/Temporal/Now.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace JS::Temporal { @@ -36,6 +37,7 @@ void Now::initialize(Realm& realm) define_native_function(realm, vm.names.timeZoneId, time_zone_id, 0, attr); define_native_function(realm, vm.names.instant, instant, 0, attr); define_native_function(realm, vm.names.plainDateTimeISO, plain_date_time_iso, 0, attr); + define_native_function(realm, vm.names.zonedDateTimeISO, zoned_date_time_iso, 0, attr); define_native_function(realm, vm.names.plainDateISO, plain_date_iso, 0, attr); define_native_function(realm, vm.names.plainTimeISO, plain_time_iso, 0, attr); } @@ -69,6 +71,30 @@ JS_DEFINE_NATIVE_FUNCTION(Now::plain_date_time_iso) return MUST(create_temporal_date_time(vm, iso_date_time, "iso8601"_string)); } +// 2.2.4 Temporal.Now.zonedDateTimeISO ( [ temporalTimeZoneLike ] ), https://tc39.es/proposal-temporal/#sec-temporal.now.zoneddatetimeiso +JS_DEFINE_NATIVE_FUNCTION(Now::zoned_date_time_iso) +{ + auto temporal_time_zone_like = vm.argument(0); + String time_zone; + + // 1. If temporalTimeZoneLike is undefined, then + if (temporal_time_zone_like.is_undefined()) { + // a. Let timeZone be SystemTimeZoneIdentifier(). + time_zone = system_time_zone_identifier(); + } + // 2. Else, + else { + // a. Let timeZone be ? ToTemporalTimeZoneIdentifier(temporalTimeZoneLike). + time_zone = TRY(to_temporal_time_zone_identifier(vm, temporal_time_zone_like)); + } + + // 3. Let ns be SystemUTCEpochNanoseconds(). + auto nanoseconds = system_utc_epoch_nanoseconds(vm); + + // 4. Return ! CreateTemporalZonedDateTime(ns, timeZone, "iso8601"). + return MUST(create_temporal_zoned_date_time(vm, BigInt::create(vm, move(nanoseconds)), move(time_zone), "iso8601"_string)); +} + // 2.2.5 Temporal.Now.plainDateISO ( [ temporalTimeZoneLike ] ), https://tc39.es/proposal-temporal/#sec-temporal.now.plaindateiso JS_DEFINE_NATIVE_FUNCTION(Now::plain_date_iso) { diff --git a/Libraries/LibJS/Runtime/Temporal/Now.h b/Libraries/LibJS/Runtime/Temporal/Now.h index 073a966a5a5..0fea8d993c3 100644 --- a/Libraries/LibJS/Runtime/Temporal/Now.h +++ b/Libraries/LibJS/Runtime/Temporal/Now.h @@ -27,6 +27,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(time_zone_id); JS_DECLARE_NATIVE_FUNCTION(instant); JS_DECLARE_NATIVE_FUNCTION(plain_date_time_iso); + JS_DECLARE_NATIVE_FUNCTION(zoned_date_time_iso); JS_DECLARE_NATIVE_FUNCTION(plain_date_iso); JS_DECLARE_NATIVE_FUNCTION(plain_time_iso); }; diff --git a/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp b/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp index 5f18f999565..c9530bdcc56 100644 --- a/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp +++ b/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include namespace JS::Temporal { @@ -62,6 +64,7 @@ void PlainDatePrototype::initialize(Realm& realm) define_native_function(realm, vm.names.since, since, 1, attr); define_native_function(realm, vm.names.equals, equals, 1, attr); define_native_function(realm, vm.names.toPlainDateTime, to_plain_date_time, 0, attr); + define_native_function(realm, vm.names.toZonedDateTime, to_zoned_date_time, 1, attr); define_native_function(realm, vm.names.toString, to_string, 0, attr); define_native_function(realm, vm.names.toLocaleString, to_locale_string, 0, attr); define_native_function(realm, vm.names.toJSON, to_json, 0, attr); @@ -384,6 +387,76 @@ JS_DEFINE_NATIVE_FUNCTION(PlainDatePrototype::to_plain_date_time) return TRY(create_temporal_date_time(vm, iso_date_time, temporal_date->calendar())); } +// 3.3.29 Temporal.PlainDate.prototype.toZonedDateTime ( item ), https://tc39.es/proposal-temporal/#sec-temporal.plaindate.prototype.tozoneddatetime +JS_DEFINE_NATIVE_FUNCTION(PlainDatePrototype::to_zoned_date_time) +{ + auto item = vm.argument(0); + + // 1. Let temporalDate be the this value. + // 2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]). + auto temporal_date = TRY(typed_this_object(vm)); + + String time_zone; + Value temporal_time; + + // 3. If item is an Object, then + if (item.is_object()) { + // a. Let timeZoneLike be ? Get(item, "timeZone"). + auto time_zone_like = TRY(item.as_object().get(vm.names.timeZone)); + + // b. If timeZoneLike is undefined, then + if (time_zone_like.is_undefined()) { + // i. Let timeZone be ? ToTemporalTimeZoneIdentifier(item). + time_zone = TRY(to_temporal_time_zone_identifier(vm, item)); + + // ii. Let temporalTime be undefined. + temporal_time = js_undefined(); + } + // c. Else, + else { + // i. Let timeZone be ? ToTemporalTimeZoneIdentifier(timeZoneLike). + time_zone = TRY(to_temporal_time_zone_identifier(vm, time_zone_like)); + + // ii. Let temporalTime be ? Get(item, "plainTime"). + temporal_time = TRY(item.as_object().get(vm.names.plainTime)); + } + } + // 4. Else, + else { + // a. Let timeZone be ? ToTemporalTimeZoneIdentifier(item). + time_zone = TRY(to_temporal_time_zone_identifier(vm, item)); + + // b. Let temporalTime be undefined. + temporal_time = js_undefined(); + } + + Crypto::SignedBigInteger epoch_nanoseconds; + + // 5. If temporalTime is undefined, then + if (temporal_time.is_undefined()) { + // a. Let epochNs be ? GetStartOfDay(timeZone, temporalDate.[[ISODate]]). + epoch_nanoseconds = TRY(get_start_of_day(vm, time_zone, temporal_date->iso_date())); + } + // 6. Else, + else { + // a. Set temporalTime to ? ToTemporalTime(temporalTime). + auto plain_temporal_time = TRY(to_temporal_time(vm, temporal_time)); + + // b. Let isoDateTime be CombineISODateAndTimeRecord(temporalDate.[[ISODate]], temporalTime.[[Time]]). + auto iso_date_time = combine_iso_date_and_time_record(temporal_date->iso_date(), plain_temporal_time->time()); + + // c. If ISODateTimeWithinLimits(isoDateTime) is false, throw a RangeError exception. + if (!iso_date_time_within_limits(iso_date_time)) + return vm.throw_completion(ErrorType::TemporalInvalidISODateTime); + + // d. Let epochNs be ? GetEpochNanosecondsFor(timeZone, isoDateTime, COMPATIBLE). + epoch_nanoseconds = TRY(get_epoch_nanoseconds_for(vm, time_zone, iso_date_time, Disambiguation::Compatible)); + } + + // 7. Return ! CreateTemporalZonedDateTime(epochNs, timeZone, temporalDate.[[Calendar]]). + return MUST(create_temporal_zoned_date_time(vm, BigInt::create(vm, move(epoch_nanoseconds)), move(time_zone), temporal_date->calendar())); +} + // 3.3.30 Temporal.PlainDate.prototype.toString ( [ options ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaindate.prototype.tostring JS_DEFINE_NATIVE_FUNCTION(PlainDatePrototype::to_string) { diff --git a/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.h b/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.h index d9bbbb94bc8..ca09df78348 100644 --- a/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.h +++ b/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.h @@ -49,6 +49,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(since); JS_DECLARE_NATIVE_FUNCTION(equals); JS_DECLARE_NATIVE_FUNCTION(to_plain_date_time); + JS_DECLARE_NATIVE_FUNCTION(to_zoned_date_time); JS_DECLARE_NATIVE_FUNCTION(to_string); JS_DECLARE_NATIVE_FUNCTION(to_locale_string); JS_DECLARE_NATIVE_FUNCTION(to_json); diff --git a/Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.cpp b/Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.cpp index 548824e9c44..8d21d3e742c 100644 --- a/Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.cpp +++ b/Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include namespace JS::Temporal { @@ -69,6 +71,7 @@ void PlainDateTimePrototype::initialize(Realm& realm) define_native_function(realm, vm.names.toLocaleString, to_locale_string, 0, attr); define_native_function(realm, vm.names.toJSON, to_json, 0, attr); define_native_function(realm, vm.names.valueOf, value_of, 0, attr); + define_native_function(realm, vm.names.toZonedDateTime, to_zoned_date_time, 1, attr); define_native_function(realm, vm.names.toPlainDate, to_plain_date, 0, attr); define_native_function(realm, vm.names.toPlainTime, to_plain_time, 0, attr); } @@ -558,6 +561,32 @@ JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::value_of) return vm.throw_completion(ErrorType::Convert, "Temporal.PlainDateTime", "a primitive value"); } +// 5.3.38 Temporal.PlainDateTime.prototype.toZonedDateTime ( temporalTimeZoneLike [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.tozoneddatetime +JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::to_zoned_date_time) +{ + auto temporal_time_zone_like = vm.argument(0); + auto options = vm.argument(1); + + // 1. Let dateTime be the this value. + // 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]). + auto date_time = TRY(typed_this_object(vm)); + + // 3. Let timeZone be ? ToTemporalTimeZoneIdentifier(temporalTimeZoneLike). + auto time_zone = TRY(to_temporal_time_zone_identifier(vm, temporal_time_zone_like)); + + // 4. Let resolvedOptions be ? GetOptionsObject(options). + auto resolved_options = TRY(get_options_object(vm, options)); + + // 5. Let disambiguation be ? GetTemporalDisambiguationOption(resolvedOptions). + auto disambiguation = TRY(get_temporal_disambiguation_option(vm, resolved_options)); + + // 6. Let epochNs be ? GetEpochNanosecondsFor(timeZone, dateTime.[[ISODateTime]], disambiguation). + auto epoch_nanoseconds = TRY(get_epoch_nanoseconds_for(vm, time_zone, date_time->iso_date_time(), disambiguation)); + + // 7. Return ! CreateTemporalZonedDateTime(epochNs, timeZone, dateTime.[[Calendar]]). + return MUST(create_temporal_zoned_date_time(vm, BigInt::create(vm, move(epoch_nanoseconds)), move(time_zone), date_time->calendar())); +} + // 5.3.39 Temporal.PlainDateTime.prototype.toPlainDate ( ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.toplaindate JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::to_plain_date) { diff --git a/Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.h b/Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.h index 7913a1ea1f8..409fac63a07 100644 --- a/Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.h +++ b/Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.h @@ -58,6 +58,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); JS_DECLARE_NATIVE_FUNCTION(to_plain_date); JS_DECLARE_NATIVE_FUNCTION(to_plain_time); }; diff --git a/Libraries/LibJS/Tests/builtins/Temporal/Instant/Instant.prototype.toZonedDateTimeISO.js b/Libraries/LibJS/Tests/builtins/Temporal/Instant/Instant.prototype.toZonedDateTimeISO.js new file mode 100644 index 00000000000..4bfe061be60 --- /dev/null +++ b/Libraries/LibJS/Tests/builtins/Temporal/Instant/Instant.prototype.toZonedDateTimeISO.js @@ -0,0 +1,36 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Temporal.Instant.prototype.toZonedDateTimeISO).toHaveLength(1); + }); + + test("basic functionality", () => { + const instant = new Temporal.Instant(1625614921123456789n); + const zonedDateTime = instant.toZonedDateTimeISO("UTC"); + 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.calendarId).toBe("iso8601"); + expect(zonedDateTime.timeZoneId).toBe("UTC"); + }); + + test("custom time zone object", () => { + const timeZone = "UTC"; + const instant = new Temporal.Instant(1625614921123456789n); + const zonedDateTime = instant.toZonedDateTimeISO(timeZone); + expect(zonedDateTime.timeZoneId).toBe(timeZone); + }); +}); + +describe("errors", () => { + test("this value must be a Temporal.Instant object", () => { + expect(() => { + Temporal.Instant.prototype.toZonedDateTimeISO.call("foo"); + }).toThrowWithMessage(TypeError, "Not an object of type Temporal.Instant"); + }); +}); diff --git a/Libraries/LibJS/Tests/builtins/Temporal/Now/Now.zonedDateTimeISO.js b/Libraries/LibJS/Tests/builtins/Temporal/Now/Now.zonedDateTimeISO.js new file mode 100644 index 00000000000..cc983abfbbe --- /dev/null +++ b/Libraries/LibJS/Tests/builtins/Temporal/Now/Now.zonedDateTimeISO.js @@ -0,0 +1,19 @@ +describe("correct behavior", () => { + test("length is 0", () => { + expect(Temporal.Now.zonedDateTimeISO).toHaveLength(0); + }); + + test("basic functionality", () => { + const zonedDateTime = Temporal.Now.zonedDateTimeISO(); + expect(zonedDateTime).toBeInstanceOf(Temporal.ZonedDateTime); + expect(zonedDateTime.calendarId).toBe("iso8601"); + }); + + test("with time zone", () => { + const timeZone = "UTC"; + const zonedDateTime = Temporal.Now.zonedDateTimeISO(timeZone); + expect(zonedDateTime).toBeInstanceOf(Temporal.ZonedDateTime); + expect(zonedDateTime.calendarId).toBe("iso8601"); + expect(zonedDateTime.timeZoneId).toBe(timeZone); + }); +}); diff --git a/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toZonedDateTime.js b/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toZonedDateTime.js new file mode 100644 index 00000000000..4af95d0791e --- /dev/null +++ b/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toZonedDateTime.js @@ -0,0 +1,85 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Temporal.PlainDate.prototype.toZonedDateTime).toHaveLength(1); + }); + + test("basic functionality - time zone", () => { + // 3.b. in the spec + const plainDate = new Temporal.PlainDate(2021, 7, 6); + const timeZone = "UTC"; + const zonedDateTime = plainDate.toZonedDateTime(timeZone); + expect(zonedDateTime.year).toBe(2021); + expect(zonedDateTime.month).toBe(7); + expect(zonedDateTime.day).toBe(6); + expect(zonedDateTime.hour).toBe(0); + expect(zonedDateTime.minute).toBe(0); + expect(zonedDateTime.second).toBe(0); + expect(zonedDateTime.millisecond).toBe(0); + expect(zonedDateTime.microsecond).toBe(0); + expect(zonedDateTime.nanosecond).toBe(0); + expect(zonedDateTime.calendarId).toBe(plainDate.calendarId); + expect(zonedDateTime.timeZoneId).toBe(timeZone); + }); + + test("basic functionality - time zone like object", () => { + // 3.c. in the spec + const plainDate = new Temporal.PlainDate(2021, 7, 6); + const timeZone = "UTC"; + const zonedDateTime = plainDate.toZonedDateTime(timeZone); + expect(zonedDateTime.year).toBe(2021); + expect(zonedDateTime.month).toBe(7); + expect(zonedDateTime.day).toBe(6); + expect(zonedDateTime.hour).toBe(0); + expect(zonedDateTime.minute).toBe(0); + expect(zonedDateTime.second).toBe(0); + expect(zonedDateTime.millisecond).toBe(0); + expect(zonedDateTime.microsecond).toBe(0); + expect(zonedDateTime.nanosecond).toBe(0); + expect(zonedDateTime.calendarId).toBe(plainDate.calendarId); + expect(zonedDateTime.timeZoneId).toBe(timeZone); + }); + + test("basic functionality - time zone like object and plain time", () => { + // 3.c. in the spec + const plainDate = new Temporal.PlainDate(2021, 7, 6); + const plainTime = new Temporal.PlainTime(18, 14, 47, 123, 456, 789); + const timeZone = "UTC"; + const zonedDateTime = plainDate.toZonedDateTime({ timeZone, plainTime }); + expect(zonedDateTime.year).toBe(2021); + expect(zonedDateTime.month).toBe(7); + expect(zonedDateTime.day).toBe(6); + expect(zonedDateTime.hour).toBe(18); + expect(zonedDateTime.minute).toBe(14); + expect(zonedDateTime.second).toBe(47); + expect(zonedDateTime.millisecond).toBe(123); + expect(zonedDateTime.microsecond).toBe(456); + expect(zonedDateTime.nanosecond).toBe(789); + expect(zonedDateTime.calendarId).toBe(plainDate.calendarId); + expect(zonedDateTime.timeZoneId).toBe(timeZone); + }); + + test("basic functionality - time zone identifier", () => { + // 4. in the spec + const plainDate = new Temporal.PlainDate(2021, 7, 6); + const zonedDateTime = plainDate.toZonedDateTime("UTC"); + expect(zonedDateTime.year).toBe(2021); + expect(zonedDateTime.month).toBe(7); + expect(zonedDateTime.day).toBe(6); + expect(zonedDateTime.hour).toBe(0); + expect(zonedDateTime.minute).toBe(0); + expect(zonedDateTime.second).toBe(0); + expect(zonedDateTime.millisecond).toBe(0); + expect(zonedDateTime.microsecond).toBe(0); + expect(zonedDateTime.nanosecond).toBe(0); + expect(zonedDateTime.calendarId).toBe(plainDate.calendarId); + expect(zonedDateTime.timeZoneId).toBe("UTC"); + }); +}); + +describe("errors", () => { + test("this value must be a Temporal.PlainDate object", () => { + expect(() => { + Temporal.PlainDate.prototype.toZonedDateTime.call("foo"); + }).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDate"); + }); +}); diff --git a/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.prototype.toZonedDateTime.js b/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.prototype.toZonedDateTime.js new file mode 100644 index 00000000000..45e8a83f122 --- /dev/null +++ b/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.prototype.toZonedDateTime.js @@ -0,0 +1,30 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Temporal.PlainDateTime.prototype.toZonedDateTime).toHaveLength(1); + }); + + test("basic functionality", () => { + const plainDateTime = new Temporal.PlainDateTime(2021, 7, 6, 18, 14, 47, 123, 456, 789); + const timeZone = "UTC"; + const zonedDateTime = plainDateTime.toZonedDateTime(timeZone); + expect(zonedDateTime.year).toBe(2021); + expect(zonedDateTime.month).toBe(7); + expect(zonedDateTime.day).toBe(6); + expect(zonedDateTime.hour).toBe(18); + expect(zonedDateTime.minute).toBe(14); + expect(zonedDateTime.second).toBe(47); + expect(zonedDateTime.millisecond).toBe(123); + expect(zonedDateTime.microsecond).toBe(456); + expect(zonedDateTime.nanosecond).toBe(789); + expect(zonedDateTime.calendarId).toBe(plainDateTime.calendarId); + expect(zonedDateTime.timeZoneId).toBe(timeZone); + }); +}); + +describe("errors", () => { + test("this value must be a Temporal.PlainDateTime object", () => { + expect(() => { + Temporal.PlainDateTime.prototype.toZonedDateTime.call("foo"); + }).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime"); + }); +});