LibJS: Handle ZonedDateTime in the various Temporal factories

This commit is contained in:
Timothy Flynn 2024-11-25 07:24:24 -05:00 committed by Andreas Kling
parent 8c73cae2b8
commit 3e6133cc09
Notes: github-actions[bot] 2024-11-26 10:04:16 +00:00
8 changed files with 97 additions and 19 deletions

View file

@ -17,6 +17,7 @@
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
#include <LibJS/Runtime/Temporal/PlainTime.h>
#include <LibJS/Runtime/Temporal/TimeZone.h>
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/ValueInlines.h>
@ -101,11 +102,11 @@ ThrowCompletionOr<GC::Ref<Instant>> to_temporal_instant(VM& vm, Value item)
auto const& object = item.as_object();
// a. If item has an [[InitializedTemporalInstant]] or [[InitializedTemporalZonedDateTime]] internal slot, then
// FIXME: Handle ZonedDateTime.
if (is<Instant>(object)) {
// i. Return ! CreateTemporalInstant(item.[[EpochNanoseconds]]).
// i. Return ! CreateTemporalInstant(item.[[EpochNanoseconds]]).
if (is<Instant>(object))
return MUST(create_temporal_instant(vm, static_cast<Instant const&>(object).epoch_nanoseconds()));
}
if (is<ZonedDateTime>(object))
return MUST(create_temporal_instant(vm, static_cast<ZonedDateTime const&>(object).epoch_nanoseconds()));
// b. NOTE: This use of ToPrimitive allows Instant-like objects to be converted.
// c. Set item to ? ToPrimitive(item, STRING).

View file

@ -16,6 +16,8 @@
#include <LibJS/Runtime/Temporal/PlainDateConstructor.h>
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
#include <LibJS/Runtime/Temporal/PlainTime.h>
#include <LibJS/Runtime/Temporal/TimeZone.h>
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
namespace JS::Temporal {
@ -84,11 +86,22 @@ ThrowCompletionOr<GC::Ref<PlainDate>> to_temporal_date(VM& vm, Value item, Value
return MUST(create_temporal_date(vm, plain_date.iso_date(), plain_date.calendar()));
}
// FIXME: b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
// FIXME: i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
// FIXME: ii. Let resolvedOptions be ? GetOptionsObject(options).
// FIXME: iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
// FIXME: iv. Return ! CreateTemporalDate(isoDateTime.[[ISODate]], item.[[Calendar]]).
// b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
if (is<ZonedDateTime>(object)) {
auto const& zoned_date_time = static_cast<ZonedDateTime const&>(object);
// i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
auto iso_date_time = get_iso_date_time_for(zoned_date_time.time_zone(), zoned_date_time.epoch_nanoseconds()->big_integer());
// ii. Let resolvedOptions be ? GetOptionsObject(options).
auto resolved_options = TRY(get_options_object(vm, options));
// iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
TRY(get_temporal_overflow_option(vm, resolved_options));
// iv. Return ! CreateTemporalDate(isoDateTime.[[ISODate]], item.[[Calendar]]).
return MUST(create_temporal_date(vm, iso_date_time.iso_date, zoned_date_time.calendar()));
}
// c. If item has an [[InitializedTemporalDateTime]] internal slot, then
if (is<PlainDateTime>(object)) {

View file

@ -14,6 +14,8 @@
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
#include <LibJS/Runtime/Temporal/PlainDateTimeConstructor.h>
#include <LibJS/Runtime/Temporal/PlainTime.h>
#include <LibJS/Runtime/Temporal/TimeZone.h>
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
namespace JS::Temporal {
@ -102,11 +104,22 @@ ThrowCompletionOr<GC::Ref<PlainDateTime>> to_temporal_date_time(VM& vm, Value it
return MUST(create_temporal_date_time(vm, plain_date_time.iso_date_time(), plain_date_time.calendar()));
}
// FIXME: b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
// FIXME: i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
// FIXME: ii. Let resolvedOptions be ? GetOptionsObject(options).
// FIXME: iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
// FIXME: iv. Return ! CreateTemporalDateTime(isoDateTime, item.[[Calendar]]).
// b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
if (is<ZonedDateTime>(object)) {
auto const& zoned_date_time = static_cast<ZonedDateTime const&>(object);
// i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
auto iso_date_time = get_iso_date_time_for(zoned_date_time.time_zone(), zoned_date_time.epoch_nanoseconds()->big_integer());
// ii. Let resolvedOptions be ? GetOptionsObject(options).
auto resolved_options = TRY(get_options_object(vm, options));
// iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
TRY(get_temporal_overflow_option(vm, resolved_options));
// iv. Return ! CreateTemporalDateTime(isoDateTime, item.[[Calendar]]).
return MUST(create_temporal_date_time(vm, iso_date_time, zoned_date_time.calendar()));
}
// c. If item has an [[InitializedTemporalDate]] internal slot, then
if (is<PlainDate>(object)) {

View file

@ -13,6 +13,8 @@
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
#include <LibJS/Runtime/Temporal/PlainTime.h>
#include <LibJS/Runtime/Temporal/PlainTimeConstructor.h>
#include <LibJS/Runtime/Temporal/TimeZone.h>
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
#include <math.h>
namespace JS::Temporal {
@ -129,11 +131,22 @@ ThrowCompletionOr<GC::Ref<PlainTime>> to_temporal_time(VM& vm, Value item, Value
return MUST(create_temporal_time(vm, plain_date_time.iso_date_time().time));
}
// FIXME: c. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
// FIXME: i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
// FIXME: ii. Let resolvedOptions be ? GetOptionsObject(options).
// FIXME: iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
// FIXME: iv. Return ! CreateTemporalTime(isoDateTime.[[Time]]).
// c. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
if (is<ZonedDateTime>(object)) {
auto const& zoned_date_time = static_cast<ZonedDateTime const&>(object);
// i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
auto iso_date_time = get_iso_date_time_for(zoned_date_time.time_zone(), zoned_date_time.epoch_nanoseconds()->big_integer());
// ii. Let resolvedOptions be ? GetOptionsObject(options).
auto resolved_options = TRY(get_options_object(vm, options));
// iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
TRY(get_temporal_overflow_option(vm, resolved_options));
// iv. Return ! CreateTemporalTime(isoDateTime.[[Time]]).
return MUST(create_temporal_time(vm, iso_date_time.time));
}
// d. Let result be ? ToTemporalTimeRecord(item).
auto result = TRY(to_temporal_time_record(vm, object));

View file

@ -34,6 +34,11 @@ describe("correct behavior", () => {
expect(result).toBeInstanceOf(Temporal.Instant);
expect(result.epochNanoseconds).toBe(0n);
});
test("ZonedDateTime instance argument", () => {
const zonedDateTime = new Temporal.ZonedDateTime(123n, "UTC");
expect(Temporal.Instant.from(zonedDateTime).epochNanoseconds).toBe(123n);
});
});
describe("errors", () => {

View file

@ -17,6 +17,14 @@ describe("correct behavior", () => {
expect(createdPlainDate.month).toBe(7);
expect(createdPlainDate.day).toBe(26);
});
test("ZonedDateTime instance argument", () => {
const zonedDateTime = new Temporal.ZonedDateTime(1627318123456789000n, "UTC");
const createdPlainDate = Temporal.PlainDate.from(zonedDateTime);
expect(createdPlainDate.year).toBe(2021);
expect(createdPlainDate.month).toBe(7);
expect(createdPlainDate.day).toBe(26);
});
});
describe("errors", () => {

View file

@ -32,6 +32,20 @@ describe("correct behavior", () => {
expect(plainDateTime.nanosecond).toBe(0);
});
test("ZonedDateTime instance argument", () => {
const zonedDateTime = new Temporal.ZonedDateTime(1625614921000000000n, "UTC");
const plainDateTime = Temporal.PlainDateTime.from(zonedDateTime);
expect(plainDateTime.year).toBe(2021);
expect(plainDateTime.month).toBe(7);
expect(plainDateTime.day).toBe(6);
expect(plainDateTime.hour).toBe(23);
expect(plainDateTime.minute).toBe(42);
expect(plainDateTime.second).toBe(1);
expect(plainDateTime.millisecond).toBe(0);
expect(plainDateTime.microsecond).toBe(0);
expect(plainDateTime.nanosecond).toBe(0);
});
test("fields object argument", () => {
const object = {
year: 2021,

View file

@ -23,6 +23,17 @@ describe("correct behavior", () => {
expect(createdPlainTime.microsecond).toBe(0);
expect(createdPlainTime.nanosecond).toBe(0);
});
test("ZonedDateTime instance argument", () => {
const zonedDateTime = new Temporal.ZonedDateTime(1627318123456789000n, "UTC");
const createdPlainTime = Temporal.PlainTime.from(zonedDateTime);
expect(createdPlainTime.hour).toBe(16);
expect(createdPlainTime.minute).toBe(48);
expect(createdPlainTime.second).toBe(43);
expect(createdPlainTime.millisecond).toBe(456);
expect(createdPlainTime.microsecond).toBe(789);
expect(createdPlainTime.nanosecond).toBe(0);
});
});
describe("errors", () => {