mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:27:35 +00:00
LibJS: Implement Temporal.Now.plainDate()
...and ten required AOs we didn't have yet: - BalanceISODate - BalanceISODateTime - BalanceISOYearMonth - BalanceTime - BuiltinTimeZoneGetPlainDateTimeFor - GetISOPartsFromEpoch - GetOffsetNanosecondsFor - ParseTemporalTimeZone - SystemDateTime - ToTemporalTimeZone
This commit is contained in:
parent
5512ff79f0
commit
c303bbde54
18 changed files with 507 additions and 1 deletions
|
@ -5,8 +5,13 @@
|
|||
*/
|
||||
|
||||
#include <AK/DateTimeLexer.h>
|
||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Date.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
|
||||
|
||||
|
@ -59,6 +64,26 @@ String default_time_zone()
|
|||
return "UTC";
|
||||
}
|
||||
|
||||
// 11.6.1 ParseTemporalTimeZone ( string ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimezone
|
||||
String parse_temporal_time_zone(GlobalObject& global_object, String const& string)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Assert: Type(string) is String.
|
||||
|
||||
// 2. Let result be ? ParseTemporalTimeZoneString(string).
|
||||
auto result = parse_temporal_time_zone_string(global_object, string);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 3. If result.[[Z]] is not undefined, return "UTC".
|
||||
if (result->z)
|
||||
return "UTC";
|
||||
|
||||
// 4. Return result.[[Name]].
|
||||
return *result->name;
|
||||
}
|
||||
|
||||
// 11.6.2 CreateTemporalTimeZone ( identifier [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaltimezone
|
||||
TimeZone* create_temporal_time_zone(GlobalObject& global_object, String const& identifier, FunctionObject* new_target)
|
||||
{
|
||||
|
@ -92,6 +117,48 @@ TimeZone* create_temporal_time_zone(GlobalObject& global_object, String const& i
|
|||
return object;
|
||||
}
|
||||
|
||||
// 11.6.3 GetISOPartsFromEpoch ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-getisopartsfromepoch
|
||||
Optional<ISODateTime> get_iso_parts_from_epoch(BigInt const& epoch_nanoseconds)
|
||||
{
|
||||
// 1. Let remainderNs be epochNanoseconds modulo 10^6.
|
||||
auto remainder_ns_bigint = epoch_nanoseconds.big_integer().divided_by(Crypto::UnsignedBigInteger { 1'000'000 }).remainder;
|
||||
auto remainder_ns = remainder_ns_bigint.to_base(10).to_int<i64>().value();
|
||||
|
||||
// 2. Let epochMilliseconds be (epochNanoseconds − remainderNs) / 10^6.
|
||||
auto epoch_milliseconds_bigint = epoch_nanoseconds.big_integer().minus(remainder_ns_bigint).divided_by(Crypto::UnsignedBigInteger { 1'000'000 }).quotient;
|
||||
auto epoch_milliseconds = (double)epoch_milliseconds_bigint.to_base(10).to_int<i64>().value();
|
||||
|
||||
// 3. Let year be ! YearFromTime(epochMilliseconds).
|
||||
auto year = year_from_time(epoch_milliseconds);
|
||||
|
||||
// 4. Let month be ! MonthFromTime(epochMilliseconds) + 1.
|
||||
auto month = static_cast<u8>(month_from_time(epoch_milliseconds) + 1);
|
||||
|
||||
// 5. Let day be ! DateFromTime(epochMilliseconds).
|
||||
auto day = date_from_time(epoch_milliseconds);
|
||||
|
||||
// 6. Let hour be ! HourFromTime(epochMilliseconds).
|
||||
auto hour = hour_from_time(epoch_milliseconds);
|
||||
|
||||
// 7. Let minute be ! MinFromTime(epochMilliseconds).
|
||||
auto minute = min_from_time(epoch_milliseconds);
|
||||
|
||||
// 8. Let second be ! SecFromTime(epochMilliseconds).
|
||||
auto second = sec_from_time(epoch_milliseconds);
|
||||
|
||||
// 9. Let millisecond be ! msFromTime(epochMilliseconds).
|
||||
auto millisecond = ms_from_time(epoch_milliseconds);
|
||||
|
||||
// 10. Let microsecond be floor(remainderNs / 1000) modulo 1000.
|
||||
auto microsecond = static_cast<u16>((remainder_ns / 1000) % 1000);
|
||||
|
||||
// 11. Let nanosecond be remainderNs modulo 1000.
|
||||
auto nanosecond = static_cast<u16>(remainder_ns % 1000);
|
||||
|
||||
// 12. Return the new Record { [[Year]]: year, [[Month]]: month, [[Day]]: day, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond }.
|
||||
return ISODateTime { .year = year, .month = month, .day = day, .hour = hour, .minute = minute, .second = second, .millisecond = millisecond, .microsecond = microsecond, .nanosecond = nanosecond };
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -252,4 +319,115 @@ String format_time_zone_offset_string(double offset_nanoseconds)
|
|||
return builder.to_string();
|
||||
}
|
||||
|
||||
// 11.6.10 ToTemporalTimeZone ( temporalTimeZoneLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaltimezone
|
||||
Object* to_temporal_time_zone(GlobalObject& global_object, Value temporal_time_zone_like)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. If Type(temporalTimeZoneLike) is Object, then
|
||||
if (temporal_time_zone_like.is_object()) {
|
||||
// TODO:
|
||||
// a. If temporalTimeZoneLike has an [[InitializedTemporalZonedDateTime]] internal slot, then
|
||||
// i. Return temporalTimeZoneLike.[[TimeZone]].
|
||||
|
||||
// b. If ? HasProperty(temporalTimeZoneLike, "timeZone") is false, return temporalTimeZoneLike.
|
||||
auto has_property = temporal_time_zone_like.as_object().has_property(vm.names.timeZone);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (!has_property)
|
||||
return &temporal_time_zone_like.as_object();
|
||||
|
||||
// c. Set temporalTimeZoneLike to ? Get(temporalTimeZoneLike, "timeZone").
|
||||
temporal_time_zone_like = temporal_time_zone_like.as_object().get(vm.names.timeZone);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// d. If Type(temporalTimeZoneLike) is Object and ? HasProperty(temporalTimeZoneLike, "timeZone") is false, return temporalTimeZoneLike.
|
||||
if (temporal_time_zone_like.is_object()) {
|
||||
has_property = temporal_time_zone_like.as_object().has_property(vm.names.timeZone);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (!has_property)
|
||||
return &temporal_time_zone_like.as_object();
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Let identifier be ? ToString(temporalTimeZoneLike).
|
||||
auto identifier = temporal_time_zone_like.to_string(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 3. Let result be ? ParseTemporalTimeZone(identifier).
|
||||
auto result = parse_temporal_time_zone(global_object, identifier);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 4. Return ? CreateTemporalTimeZone(result).
|
||||
return create_temporal_time_zone(global_object, result);
|
||||
}
|
||||
|
||||
// 11.6.11 GetOffsetNanosecondsFor ( timeZone, instant ), https://tc39.es/proposal-temporal/#sec-temporal-getoffsetnanosecondsfor
|
||||
double get_offset_nanoseconds_for(GlobalObject& global_object, Object& time_zone, Instant& instant)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Let getOffsetNanosecondsFor be ? GetMethod(timeZone, "getOffsetNanosecondsFor").
|
||||
auto* get_offset_nanoseconds_for = Value(&time_zone).get_method(global_object, vm.names.getOffsetNanosecondsFor);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 2. If getOffsetNanosecondsFor is undefined, set getOffsetNanosecondsFor to %Temporal.TimeZone.prototype.getOffsetNanosecondsFor%.
|
||||
if (!get_offset_nanoseconds_for)
|
||||
get_offset_nanoseconds_for = global_object.temporal_time_zone_prototype_get_offset_nanoseconds_for_function();
|
||||
|
||||
// 3. Let offsetNanoseconds be ? Call(getOffsetNanosecondsFor, timeZone, « instant »).
|
||||
auto offset_nanoseconds_value = vm.call(*get_offset_nanoseconds_for, &time_zone, &instant);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 4. If Type(offsetNanoseconds) is not Number, throw a TypeError exception.
|
||||
if (!offset_nanoseconds_value.is_number()) {
|
||||
vm.throw_exception<TypeError>(global_object, ErrorType::IsNotA, "Offset nanoseconds value", "number");
|
||||
return {};
|
||||
}
|
||||
|
||||
// 5. If ! IsIntegralNumber(offsetNanoseconds) is false, throw a RangeError exception.
|
||||
if (!offset_nanoseconds_value.is_integral_number()) {
|
||||
vm.throw_exception<TypeError>(global_object, ErrorType::IsNotA, "Offset nanoseconds value", "integral number");
|
||||
return {};
|
||||
}
|
||||
|
||||
// 6. Set offsetNanoseconds to ℝ(offsetNanoseconds).
|
||||
auto offset_nanoseconds = offset_nanoseconds_value.as_double();
|
||||
|
||||
// 7. If abs(offsetNanoseconds) > 86400 × 10^9, throw a RangeError exception.
|
||||
if (fabs(offset_nanoseconds) > 86400000000000.0) {
|
||||
vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidOffsetNanosecondsValue);
|
||||
return {};
|
||||
}
|
||||
|
||||
// 8. Return offsetNanoseconds.
|
||||
return offset_nanoseconds;
|
||||
}
|
||||
|
||||
// 11.6.13 BuiltinTimeZoneGetPlainDateTimeFor ( timeZone, instant, calendar ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetplaindatetimefor
|
||||
PlainDateTime* builtin_time_zone_get_plain_date_time_for(GlobalObject& global_object, Object& time_zone, Instant& instant, Object& calendar)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
|
||||
auto offset_nanoseconds = get_offset_nanoseconds_for(global_object, time_zone, instant);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 2. Let result be ! GetISOPartsFromEpoch(instant.[[Nanoseconds]]).
|
||||
auto result = get_iso_parts_from_epoch(instant.nanoseconds());
|
||||
|
||||
// 3. Set result to ! BalanceISODateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]] + offsetNanoseconds).
|
||||
result = balance_iso_date_time(result->year, result->month, result->day, result->hour, result->minute, result->second, result->millisecond, result->microsecond, result->nanosecond + offset_nanoseconds);
|
||||
|
||||
// 4. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], calendar).
|
||||
return create_temporal_date_time(global_object, result->year, result->month, result->day, result->hour, result->minute, result->second, result->millisecond, result->microsecond, result->nanosecond, calendar);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue