mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 17:27:35 +00:00
LibJS: Implement Temporal.TimeZone.prototype.getPossibleInstantsFor()
This commit is contained in:
parent
82792a6815
commit
5fde02184d
6 changed files with 92 additions and 0 deletions
|
@ -212,6 +212,7 @@ namespace JS {
|
|||
P(getOwnPropertyNames) \
|
||||
P(getOwnPropertySymbols) \
|
||||
P(getPlainDateTimeFor) \
|
||||
P(getPossibleInstantsFor) \
|
||||
P(getPrototypeOf) \
|
||||
P(getSeconds) \
|
||||
P(getTime) \
|
||||
|
|
|
@ -154,6 +154,20 @@ ISODateTime get_iso_parts_from_epoch(BigInt const& epoch_nanoseconds)
|
|||
return { .year = year, .month = month, .day = day, .hour = hour, .minute = minute, .second = second, .millisecond = millisecond, .microsecond = microsecond, .nanosecond = nanosecond };
|
||||
}
|
||||
|
||||
// 11.6.4 GetIANATimeZoneEpochValue ( timeZoneIdentifier, year, month, day, hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneepochvalue
|
||||
MarkedValueList get_iana_time_zone_epoch_value(GlobalObject& global_object, StringView time_zone_identifier, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond)
|
||||
{
|
||||
// The abstract operation GetIANATimeZoneEpochValue is an implementation-defined algorithm that returns a List of integers. Each integer in the List represents a number of nanoseconds since the Unix epoch in UTC that may correspond to the given calendar date and wall-clock time in the IANA time zone identified by timeZoneIdentifier.
|
||||
// When the input represents a local time repeating multiple times at a negative time zone transition (e.g. when the daylight saving time ends or the time zone offset is decreased due to a time zone rule change), the returned List will have more than one element. When the input represents a skipped local time at a positive time zone transition (e.g. when the daylight saving time starts or the time zone offset is increased due to a time zone rule change), the returned List will be empty. Otherwise, the returned List will have one element.
|
||||
|
||||
VERIFY(time_zone_identifier == "UTC"sv);
|
||||
// FIXME: MarkedValueList<T> for T != Value would still be nice.
|
||||
auto& vm = global_object.vm();
|
||||
auto list = MarkedValueList { vm.heap() };
|
||||
list.append(get_epoch_from_iso_parts(global_object, year, month, day, hour, minute, second, millisecond, microsecond, nanosecond));
|
||||
return list;
|
||||
}
|
||||
|
||||
// 11.6.5 GetIANATimeZoneOffsetNanoseconds ( epochNanoseconds, timeZoneIdentifier ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneoffsetnanoseconds
|
||||
i64 get_iana_time_zone_offset_nanoseconds([[maybe_unused]] BigInt const& epoch_nanoseconds, [[maybe_unused]] String const& time_zone_identifier)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibJS/Runtime/MarkedValueList.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||
|
||||
|
@ -38,6 +39,7 @@ String default_time_zone();
|
|||
ThrowCompletionOr<String> parse_temporal_time_zone(GlobalObject&, String const&);
|
||||
ThrowCompletionOr<TimeZone*> create_temporal_time_zone(GlobalObject&, String const& identifier, FunctionObject const* new_target = nullptr);
|
||||
ISODateTime get_iso_parts_from_epoch(BigInt const& epoch_nanoseconds);
|
||||
MarkedValueList get_iana_time_zone_epoch_value(GlobalObject&, StringView time_zone_identifier, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond);
|
||||
i64 get_iana_time_zone_offset_nanoseconds(BigInt const& epoch_nanoseconds, String const& time_zone_identifier);
|
||||
ThrowCompletionOr<double> parse_time_zone_offset_string(GlobalObject&, String const&);
|
||||
String format_time_zone_offset_string(double offset_nanoseconds);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||
|
@ -31,6 +32,7 @@ void TimeZonePrototype::initialize(GlobalObject& global_object)
|
|||
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.getPossibleInstantsFor, get_possible_instants_for, 1, attr);
|
||||
define_native_function(vm.names.toString, to_string, 0, attr);
|
||||
define_native_function(vm.names.toJSON, to_json, 0, attr);
|
||||
|
||||
|
@ -97,6 +99,47 @@ JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::get_plain_date_time_for)
|
|||
return TRY(builtin_time_zone_get_plain_date_time_for(global_object, time_zone, *instant, *calendar));
|
||||
}
|
||||
|
||||
// 11.4.8 Temporal.TimeZone.prototype.getPossibleInstantsFor ( dateTime ), https://tc39.es/proposal-temporal/#sec-temporal.timezone.prototype.getpossibleinstantsfor
|
||||
JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::get_possible_instants_for)
|
||||
{
|
||||
// 1. Let timeZone be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(timeZone, [[InitializedTemporalTimezone]]).
|
||||
auto* time_zone = TRY(typed_this_object(global_object));
|
||||
|
||||
// 3. Set dateTime to ? ToTemporalDateTime(dateTime).
|
||||
auto* date_time = TRY(to_temporal_date_time(global_object, vm.argument(0)));
|
||||
|
||||
// 4. If timeZone.[[OffsetNanoseconds]] is not undefined, then
|
||||
if (time_zone->offset_nanoseconds().has_value()) {
|
||||
// a. Let epochNanoseconds be ! GetEpochFromISOParts(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]]).
|
||||
auto* epoch_nanoseconds = get_epoch_from_iso_parts(global_object, date_time->iso_year(), date_time->iso_month(), date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(), date_time->iso_millisecond(), date_time->iso_microsecond(), date_time->iso_nanosecond());
|
||||
|
||||
// b. Let instant be ! CreateTemporalInstant(ℤ(epochNanoseconds − timeZone.[[OffsetNanoseconds]])).
|
||||
auto* instant = MUST(create_temporal_instant(global_object, *js_bigint(vm, epoch_nanoseconds->big_integer().minus(Crypto::SignedBigInteger::create_from(*time_zone->offset_nanoseconds())))));
|
||||
|
||||
// c. Return ! CreateArrayFromList(« instant »).
|
||||
return Array::create_from(global_object, { instant });
|
||||
}
|
||||
|
||||
// 5. Let possibleEpochNanoseconds be ? GetIANATimeZoneEpochValue(timeZone.[[Identifier]], dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]]).
|
||||
auto possible_epoch_nanoseconds = get_iana_time_zone_epoch_value(global_object, time_zone->identifier(), date_time->iso_year(), date_time->iso_month(), date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(), date_time->iso_millisecond(), date_time->iso_microsecond(), date_time->iso_nanosecond());
|
||||
|
||||
// 6. Let possibleInstants be a new empty List.
|
||||
auto possible_instants = MarkedValueList { vm.heap() };
|
||||
|
||||
// 7. For each value epochNanoseconds in possibleEpochNanoseconds, do
|
||||
for (auto& epoch_nanoseconds : possible_epoch_nanoseconds) {
|
||||
// a. Let instant be ! CreateTemporalInstant(epochNanoseconds).
|
||||
auto* instant = MUST(create_temporal_instant(global_object, epoch_nanoseconds.as_bigint()));
|
||||
|
||||
// b. Append instant to possibleInstants.
|
||||
possible_instants.append(instant);
|
||||
}
|
||||
|
||||
// 8. Return ! CreateArrayFromList(possibleInstants).
|
||||
return Array::create_from(global_object, possible_instants);
|
||||
}
|
||||
|
||||
// 11.4.11 Temporal.TimeZone.prototype.toString ( ), https://tc39.es/proposal-temporal/#sec-temporal.timezone.prototype.tostring
|
||||
JS_DEFINE_NATIVE_FUNCTION(TimeZonePrototype::to_string)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ private:
|
|||
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(get_possible_instants_for);
|
||||
JS_DECLARE_NATIVE_FUNCTION(to_string);
|
||||
JS_DECLARE_NATIVE_FUNCTION(to_json);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 1", () => {
|
||||
expect(Temporal.TimeZone.prototype.getPossibleInstantsFor).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const timeZone = new Temporal.TimeZone("UTC");
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 6, 18, 14, 47);
|
||||
const possibleInstants = timeZone.getPossibleInstantsFor(plainDateTime);
|
||||
expect(possibleInstants).toBeInstanceOf(Array);
|
||||
expect(possibleInstants).toHaveLength(1);
|
||||
expect(possibleInstants[0].epochNanoseconds).toBe(1625595287000000000n);
|
||||
});
|
||||
|
||||
test("custom offset", () => {
|
||||
const timeZone = new Temporal.TimeZone("+01:30");
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 6, 18, 14, 47);
|
||||
const possibleInstants = timeZone.getPossibleInstantsFor(plainDateTime);
|
||||
expect(possibleInstants).toBeInstanceOf(Array);
|
||||
expect(possibleInstants).toHaveLength(1);
|
||||
expect(possibleInstants[0].epochNanoseconds).toBe(1625589887000000000n);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.TimeZone object", () => {
|
||||
expect(() => {
|
||||
Temporal.TimeZone.prototype.getPossibleInstantsFor.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.TimeZone");
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue