mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:57:35 +00:00
LibJS: Implement TODO()'d parts of balance_duration()
Massive :yakstack:, so I understand why it was skipped in the first place :^)
This commit is contained in:
parent
17fd08d752
commit
d49bbb1da3
11 changed files with 320 additions and 6 deletions
|
@ -533,6 +533,35 @@ String larger_of_two_temporal_units(StringView unit1, StringView unit2)
|
|||
return "nanosecond"sv;
|
||||
}
|
||||
|
||||
// 13.24 MergeLargestUnitOption ( options, largestUnit ), https://tc39.es/proposal-temporal/#sec-temporal-mergelargestunitoption
|
||||
ThrowCompletionOr<Object*> merge_largest_unit_option(GlobalObject& global_object, Object& options, String largest_unit)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Let merged be ! OrdinaryObjectCreate(%Object.prototype%).
|
||||
auto* merged = Object::create(global_object, global_object.object_prototype());
|
||||
|
||||
// 2. Let keys be ? EnumerableOwnPropertyNames(options, key).
|
||||
auto keys = TRY(options.enumerable_own_property_names(Object::PropertyKind::Key));
|
||||
|
||||
// 3. For each element nextKey of keys, do
|
||||
for (auto& key : keys) {
|
||||
auto next_key = PropertyKey::from_value(global_object, key);
|
||||
|
||||
// a. Let propValue be ? Get(options, nextKey).
|
||||
auto prop_value = TRY(options.get(next_key));
|
||||
|
||||
// b. Perform ! CreateDataPropertyOrThrow(merged, nextKey, propValue).
|
||||
MUST(merged->create_data_property_or_throw(next_key, prop_value));
|
||||
}
|
||||
|
||||
// 4. Perform ! CreateDataPropertyOrThrow(merged, "largestUnit", largestUnit).
|
||||
MUST(merged->create_data_property_or_throw(vm.names.largestUnit, js_string(vm, move(largest_unit))));
|
||||
|
||||
// 5. Return merged.
|
||||
return merged;
|
||||
}
|
||||
|
||||
// 13.25 MaximumTemporalDurationRoundingIncrement ( unit ), https://tc39.es/proposal-temporal/#sec-temporal-maximumtemporaldurationroundingincrement
|
||||
Optional<u16> maximum_temporal_duration_rounding_increment(StringView unit)
|
||||
{
|
||||
|
|
|
@ -99,6 +99,7 @@ ThrowCompletionOr<String> to_largest_temporal_unit(GlobalObject&, Object const&
|
|||
ThrowCompletionOr<Optional<String>> to_smallest_temporal_unit(GlobalObject&, Object const& normalized_options, Vector<StringView> const& disallowed_units, Optional<String> fallback);
|
||||
ThrowCompletionOr<void> validate_temporal_unit_range(GlobalObject&, StringView largest_unit, StringView smallest_unit);
|
||||
String larger_of_two_temporal_units(StringView, StringView);
|
||||
ThrowCompletionOr<Object*> merge_largest_unit_option(GlobalObject&, Object& options, String largest_unit);
|
||||
Optional<u16> maximum_temporal_duration_rounding_increment(StringView unit);
|
||||
ThrowCompletionOr<void> reject_temporal_calendar_type(GlobalObject&, Object&);
|
||||
String format_seconds_string_part(u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, Variant<StringView, u8> const& precision);
|
||||
|
|
|
@ -159,6 +159,29 @@ ThrowCompletionOr<PlainDate*> calendar_date_add(GlobalObject& global_object, Obj
|
|||
return static_cast<PlainDate*>(added_date_object);
|
||||
}
|
||||
|
||||
// 12.1.8 CalendarDateUntil ( calendar, one, two, options [ , dateUntil ] ), https://tc39.es/proposal-temporal/#sec-temporal-calendardateuntil
|
||||
ThrowCompletionOr<Duration*> calendar_date_until(GlobalObject& global_object, Object& calendar, PlainDate& one, PlainDate& two, Object& options, FunctionObject* date_until)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Assert: Type(calendar) is Object.
|
||||
|
||||
// 2. If dateUntil is not present, set dateUntil to ? GetMethod(calendar, "dateUntil").
|
||||
if (!date_until)
|
||||
date_until = TRY(Value(&calendar).get_method(global_object, vm.names.dateUntil));
|
||||
|
||||
// 3. Let duration be ? Call(dateUntil, calendar, « one, two, options »).
|
||||
auto duration = TRY(call(global_object, date_until ?: js_undefined(), &calendar, &one, &two, &options));
|
||||
|
||||
// 4. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
|
||||
auto* duration_object = TRY(duration.to_object(global_object));
|
||||
if (!is<Duration>(duration_object))
|
||||
return vm.throw_completion<TypeError>(global_object, ErrorType::NotAnObjectOfType, "Temporal.Duration");
|
||||
|
||||
// 5. Return duration.
|
||||
return static_cast<Duration*>(duration_object);
|
||||
}
|
||||
|
||||
// 12.1.9 CalendarYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendaryear
|
||||
ThrowCompletionOr<double> calendar_year(GlobalObject& global_object, Object& calendar, Object& date_like)
|
||||
{
|
||||
|
|
|
@ -37,6 +37,7 @@ Calendar* get_iso8601_calendar(GlobalObject&);
|
|||
ThrowCompletionOr<Vector<String>> calendar_fields(GlobalObject&, Object& calendar, Vector<StringView> const& field_names);
|
||||
ThrowCompletionOr<Object*> calendar_merge_fields(GlobalObject&, Object& calendar, Object& fields, Object& additional_fields);
|
||||
ThrowCompletionOr<PlainDate*> calendar_date_add(GlobalObject&, Object& calendar, PlainDate&, Duration&, Object* options, FunctionObject* date_add = nullptr);
|
||||
ThrowCompletionOr<Duration*> calendar_date_until(GlobalObject&, Object& calendar, PlainDate& one, PlainDate& two, Object& options, FunctionObject* date_until = nullptr);
|
||||
ThrowCompletionOr<double> calendar_year(GlobalObject&, Object& calendar, Object& date_like);
|
||||
ThrowCompletionOr<double> calendar_month(GlobalObject&, Object& calendar, Object& date_like);
|
||||
ThrowCompletionOr<String> calendar_month_code(GlobalObject&, Object& calendar, Object& date_like);
|
||||
|
|
|
@ -294,16 +294,19 @@ BigInt* total_duration_nanoseconds(GlobalObject& global_object, double days, dou
|
|||
ThrowCompletionOr<BalancedDuration> balance_duration(GlobalObject& global_object, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, BigInt const& nanoseconds, String const& largest_unit, Object* relative_to)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. If relativeTo is not present, set relativeTo to undefined.
|
||||
|
||||
Crypto::SignedBigInteger total_nanoseconds;
|
||||
// 2. If Type(relativeTo) is Object and relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot, then
|
||||
if (relative_to && is<ZonedDateTime>(*relative_to)) {
|
||||
auto& relative_to_zoned_date_time = static_cast<ZonedDateTime&>(*relative_to);
|
||||
|
||||
// a. Let endNs be ? AddZonedDateTime(relativeTo.[[Nanoseconds]], relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
|
||||
TODO();
|
||||
if (auto* exception = vm.exception())
|
||||
return throw_completion(exception->value());
|
||||
auto* end_ns = TRY(add_zoned_date_time(global_object, relative_to_zoned_date_time.nanoseconds(), &relative_to_zoned_date_time.time_zone(), relative_to_zoned_date_time.calendar(), 0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds.big_integer().to_double()));
|
||||
|
||||
// b. Set nanoseconds to endNs − relativeTo.[[Nanoseconds]].
|
||||
total_nanoseconds = end_ns->big_integer().minus(relative_to_zoned_date_time.nanoseconds().big_integer());
|
||||
}
|
||||
// 3. Else,
|
||||
else {
|
||||
|
@ -314,13 +317,13 @@ ThrowCompletionOr<BalancedDuration> balance_duration(GlobalObject& global_object
|
|||
// 4. If largestUnit is one of "year", "month", "week", or "day", then
|
||||
if (largest_unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv)) {
|
||||
// a. Let result be ? NanosecondsToDays(nanoseconds, relativeTo).
|
||||
TODO();
|
||||
if (auto* exception = vm.exception())
|
||||
return throw_completion(exception->value());
|
||||
auto result = TRY(nanoseconds_to_days(global_object, *js_bigint(vm, total_nanoseconds), relative_to ?: js_undefined()));
|
||||
|
||||
// b. Set days to result.[[Days]].
|
||||
days = result.days;
|
||||
|
||||
// c. Set nanoseconds to result.[[Nanoseconds]].
|
||||
total_nanoseconds = result.nanoseconds.cell()->big_integer();
|
||||
}
|
||||
// 5. Else,
|
||||
else {
|
||||
|
|
|
@ -333,4 +333,58 @@ ThrowCompletionOr<TemporalPlainDateTime> add_date_time(GlobalObject& global_obje
|
|||
return TemporalPlainDateTime { .year = added_date->iso_year(), .month = added_date->iso_month(), .day = added_date->iso_day(), .hour = time_result.hour, .minute = time_result.minute, .second = time_result.second, .millisecond = time_result.millisecond, .microsecond = time_result.microsecond, .nanosecond = time_result.nanosecond };
|
||||
}
|
||||
|
||||
// 5.5.11 DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2, calendar, largestUnit [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal-differenceisodatetime
|
||||
ThrowCompletionOr<TemporalDuration> difference_iso_date_time(GlobalObject& global_object, i32 year1, u8 month1, u8 day1, u8 hour1, u8 minute1, u8 second1, u16 millisecond1, u16 microsecond1, u16 nanosecond1, i32 year2, u8 month2, u8 day2, u8 hour2, u8 minute2, u8 second2, u16 millisecond2, u16 microsecond2, u16 nanosecond2, Object& calendar, StringView largest_unit, Object* options)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Assert: y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, and ns2 are integers.
|
||||
|
||||
// 2. If options is not present, set options to ! OrdinaryObjectCreate(null).
|
||||
if (!options)
|
||||
options = Object::create(global_object, nullptr);
|
||||
|
||||
// 3. Let timeDifference be ! DifferenceTime(h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2).
|
||||
auto time_difference = difference_time(hour1, minute1, second1, millisecond1, microsecond1, nanosecond1, hour2, minute2, second2, millisecond2, microsecond2, nanosecond2);
|
||||
|
||||
// 4. Let timeSign be ! DurationSign(0, 0, 0, timeDifference.[[Days]], timeDifference.[[Hours]], timeDifference.[[Minutes]], timeDifference.[[Seconds]], timeDifference.[[Milliseconds]], timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]]).
|
||||
auto time_sign = duration_sign(0, 0, 0, time_difference.days, time_difference.hours, time_difference.minutes, time_difference.seconds, time_difference.milliseconds, time_difference.microseconds, time_difference.nanoseconds);
|
||||
|
||||
// 5. Let dateSign be ! CompareISODate(y2, mon2, d2, y1, mon1, d1).
|
||||
auto date_sign = compare_iso_date(year2, month2, day2, year1, month1, day1);
|
||||
|
||||
// 6. Let balanceResult be ! BalanceISODate(y1, mon1, d1 + timeDifference.[[Days]]).
|
||||
auto balance_result = balance_iso_date(year1, month1, day1 + time_difference.days);
|
||||
|
||||
// 7. If timeSign is -dateSign, then
|
||||
if (time_sign == -date_sign) {
|
||||
// a. Set balanceResult to ! BalanceISODate(balanceResult.[[Year]], balanceResult.[[Month]], balanceResult.[[Day]] - timeSign).
|
||||
balance_result = balance_iso_date(balance_result.year, balance_result.month, balance_result.day - time_sign);
|
||||
|
||||
// b. Set timeDifference to ? BalanceDuration(-timeSign, timeDifference.[[Hours]], timeDifference.[[Minutes]], timeDifference.[[Seconds]], timeDifference.[[Milliseconds]], timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]], largestUnit).
|
||||
time_difference = TRY(balance_duration(global_object, -time_sign, time_difference.hours, time_difference.minutes, time_difference.seconds, time_difference.milliseconds, time_difference.microseconds, *js_bigint(vm, { (i32)time_difference.nanoseconds }), largest_unit));
|
||||
}
|
||||
|
||||
// 8. Let date1 be ? CreateTemporalDate(balanceResult.[[Year]], balanceResult.[[Month]], balanceResult.[[Day]], calendar).
|
||||
auto* date1 = TRY(create_temporal_date(global_object, balance_result.year, balance_result.month, balance_result.day, calendar));
|
||||
|
||||
// 9. Let date2 be ? CreateTemporalDate(y2, mon2, d2, calendar).
|
||||
auto* date2 = TRY(create_temporal_date(global_object, year2, month2, day2, calendar));
|
||||
|
||||
// 10. Let dateLargestUnit be ! LargerOfTwoTemporalUnits("day", largestUnit).
|
||||
auto date_largest_unit = larger_of_two_temporal_units("day"sv, largest_unit);
|
||||
|
||||
// 11. Let untilOptions be ? MergeLargestUnitOption(options, dateLargestUnit).
|
||||
auto* until_options = TRY(merge_largest_unit_option(global_object, *options, move(date_largest_unit)));
|
||||
|
||||
// 12. Let dateDifference be ? CalendarDateUntil(calendar, date1, date2, untilOptions).
|
||||
auto* date_difference = TRY(calendar_date_until(global_object, calendar, *date1, *date2, *until_options));
|
||||
|
||||
// 13. Let balanceResult be ? BalanceDuration(dateDifference.[[Days]], timeDifference.[[Hours]], timeDifference.[[Minutes]], timeDifference.[[Seconds]], timeDifference.[[Milliseconds]], timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]], largestUnit).
|
||||
auto balance_result_ = TRY(balance_duration(global_object, date_difference->days(), time_difference.hours, time_difference.minutes, time_difference.seconds, time_difference.milliseconds, time_difference.microseconds, *js_bigint(vm, { (i32)time_difference.nanoseconds }), largest_unit));
|
||||
|
||||
// 14. Return the Record { [[Years]]: dateDifference.[[Years]], [[Months]]: dateDifference.[[Months]], [[Weeks]]: dateDifference.[[Weeks]], [[Days]]: balanceResult.[[Days]], [[Hours]]: balanceResult.[[Hours]], [[Minutes]]: balanceResult.[[Minutes]], [[Seconds]]: balanceResult.[[Seconds]], [[Milliseconds]]: balanceResult.[[Milliseconds]], [[Microseconds]]: balanceResult.[[Microseconds]], [[Nanoseconds]]: balanceResult.[[Nanoseconds]] }.
|
||||
return TemporalDuration { .years = date_difference->years(), .months = date_difference->months(), .weeks = date_difference->weeks(), .days = balance_result_.days, .hours = balance_result_.hours, .minutes = balance_result_.minutes, .seconds = balance_result_.seconds, .milliseconds = balance_result_.milliseconds, .microseconds = balance_result_.microseconds, .nanoseconds = balance_result_.nanoseconds };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <LibJS/Runtime/Completion.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
|
@ -71,5 +72,6 @@ ThrowCompletionOr<PlainDateTime*> create_temporal_date_time(GlobalObject&, i32 i
|
|||
ThrowCompletionOr<String> temporal_date_time_to_string(GlobalObject&, i32 iso_year, u8 iso_month, u8 iso_day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, Value calendar, Variant<StringView, u8> const& precision, StringView show_calendar);
|
||||
i8 compare_iso_date_time(i32 year1, u8 month1, u8 day1, u8 hour1, u8 minute1, u8 second1, u16 millisecond1, u16 microsecond1, u16 nanosecond1, i32 year2, u8 month2, u8 day2, u8 hour2, u8 minute2, u8 second2, u16 millisecond2, u16 microsecond2, u16 nanosecond2);
|
||||
ThrowCompletionOr<TemporalPlainDateTime> add_date_time(GlobalObject&, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, Object& calendar, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, Object* options);
|
||||
ThrowCompletionOr<TemporalDuration> difference_iso_date_time(GlobalObject&, i32 year1, u8 month1, u8 day1, u8 hour1, u8 minute1, u8 second1, u16 millisecond1, u16 microsecond1, u16 nanosecond1, i32 year2, u8 month2, u8 day2, u8 hour2, u8 minute2, u8 second2, u16 millisecond2, u16 microsecond2, u16 nanosecond2, Object& calendar, StringView largest_unit, Object* options = nullptr);
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||
|
@ -38,6 +39,39 @@ void PlainTime::visit_edges(Visitor& visitor)
|
|||
visitor.visit(&m_calendar);
|
||||
}
|
||||
|
||||
// 4.5.1 DifferenceTime ( h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2 ), https://tc39.es/proposal-temporal/#sec-temporal-differencetime
|
||||
BalancedDuration difference_time(u8 hour1, u8 minute1, u8 second1, u16 millisecond1, u16 microsecond1, u16 nanosecond1, u8 hour2, u8 minute2, u8 second2, u16 millisecond2, u16 microsecond2, u16 nanosecond2)
|
||||
{
|
||||
// Assert: h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, and ns2 are integers.
|
||||
|
||||
// 2. Let hours be h2 − h1.
|
||||
auto hours = hour2 - hour1;
|
||||
|
||||
// 3. Let minutes be min2 − min1.
|
||||
auto minutes = minute2 - minute1;
|
||||
|
||||
// 4. Let seconds be s2 − s1.
|
||||
auto seconds = second2 - second1;
|
||||
|
||||
// 5. Let milliseconds be ms2 − ms1.
|
||||
auto milliseconds = millisecond2 - millisecond1;
|
||||
|
||||
// 6. Let microseconds be mus2 − mus1.
|
||||
auto microseconds = microsecond2 - microsecond1;
|
||||
|
||||
// 7. Let nanoseconds be ns2 − ns1.
|
||||
auto nanoseconds = nanosecond2 - nanosecond1;
|
||||
|
||||
// 8. Let sign be ! DurationSign(0, 0, 0, 0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
|
||||
auto sign = duration_sign(0, 0, 0, 0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
|
||||
|
||||
// 9. Let bt be ! BalanceTime(hours × sign, minutes × sign, seconds × sign, milliseconds × sign, microseconds × sign, nanoseconds × sign).
|
||||
auto bt = balance_time(hours * sign, minutes * sign, seconds * sign, milliseconds * sign, microseconds * sign, nanoseconds * sign);
|
||||
|
||||
// 10. Return the Record { [[Days]]: bt.[[Days]] × sign, [[Hours]]: bt.[[Hour]] × sign, [[Minutes]]: bt.[[Minute]] × sign, [[Seconds]]: bt.[[Second]] × sign, [[Milliseconds]]: bt.[[Millisecond]] × sign, [[Microseconds]]: bt.[[Microsecond]] × sign, [[Nanoseconds]]: bt.[[Nanosecond]] × sign }.
|
||||
return BalancedDuration { .days = static_cast<double>(bt.days * sign), .hours = static_cast<double>(bt.hour * sign), .minutes = static_cast<double>(bt.minute * sign), .seconds = static_cast<double>(bt.second * sign), .milliseconds = static_cast<double>(bt.millisecond * sign), .microseconds = static_cast<double>(bt.microsecond * sign), .nanoseconds = static_cast<double>(bt.nanosecond * sign) };
|
||||
}
|
||||
|
||||
// 4.5.2 ToTemporalTime ( item [ , overflow ] ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaltime
|
||||
ThrowCompletionOr<PlainTime*> to_temporal_time(GlobalObject& global_object, Value item, Optional<StringView> overflow)
|
||||
{
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <AK/Optional.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
@ -92,6 +93,7 @@ auto temporal_time_like_properties = [](VM& vm) {
|
|||
};
|
||||
};
|
||||
|
||||
BalancedDuration difference_time(u8 hour1, u8 minute1, u8 second1, u16 millisecond1, u16 microsecond1, u16 nanosecond1, u8 hour2, u8 minute2, u8 second2, u16 millisecond2, u16 microsecond2, u16 nanosecond2);
|
||||
ThrowCompletionOr<PlainTime*> to_temporal_time(GlobalObject&, Value item, Optional<StringView> overflow = {});
|
||||
ThrowCompletionOr<PartialUnregulatedTemporalTime> to_partial_time(GlobalObject&, Object& temporal_time_like);
|
||||
ThrowCompletionOr<TemporalTime> regulate_time(GlobalObject&, double hour, double minute, double second, double millisecond, double microsecond, double nanosecond, StringView overflow);
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTimeConstructor.h>
|
||||
|
||||
|
@ -54,4 +59,155 @@ ThrowCompletionOr<ZonedDateTime*> create_temporal_zoned_date_time(GlobalObject&
|
|||
return object;
|
||||
}
|
||||
|
||||
// 6.5.5 AddZonedDateTime ( epochNanoseconds, timeZone, calendar, years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal-addzoneddatetime
|
||||
ThrowCompletionOr<BigInt*> add_zoned_date_time(GlobalObject& global_object, BigInt const& epoch_nanoseconds, Value time_zone, Object& calendar, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, Object* options)
|
||||
{
|
||||
// 1. If options is not present, set options to ! OrdinaryObjectCreate(null).
|
||||
if (!options)
|
||||
options = Object::create(global_object, nullptr);
|
||||
|
||||
// 2. If all of years, months, weeks, and days are 0, then
|
||||
if (years == 0 && months == 0 && weeks == 0 && days == 0) {
|
||||
// a. Return ! AddInstant(epochNanoseconds, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
|
||||
return MUST(add_instant(global_object, epoch_nanoseconds, hours, minutes, seconds, milliseconds, microseconds, nanoseconds));
|
||||
}
|
||||
|
||||
// 3. Let instant be ! CreateTemporalInstant(epochNanoseconds).
|
||||
auto* instant = MUST(create_temporal_instant(global_object, epoch_nanoseconds));
|
||||
|
||||
// 4. Let temporalDateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
|
||||
auto* temporal_date_time = TRY(builtin_time_zone_get_plain_date_time_for(global_object, time_zone, *instant, calendar));
|
||||
|
||||
// 5. Let datePart be ? CreateTemporalDate(temporalDateTime.[[ISOYear]], temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], calendar).
|
||||
auto* date_part = TRY(create_temporal_date(global_object, temporal_date_time->iso_year(), temporal_date_time->iso_month(), temporal_date_time->iso_day(), calendar));
|
||||
|
||||
// 6. Let dateDuration be ? CreateTemporalDuration(years, months, weeks, days, 0, 0, 0, 0, 0, 0).
|
||||
auto* date_duration = TRY(create_temporal_duration(global_object, years, months, weeks, days, 0, 0, 0, 0, 0, 0));
|
||||
|
||||
// 7. Let addedDate be ? CalendarDateAdd(calendar, datePart, dateDuration, options).
|
||||
auto* added_date = TRY(calendar_date_add(global_object, calendar, *date_part, *date_duration, options));
|
||||
|
||||
// 8. Let intermediateDateTime be ? CreateTemporalDateTime(addedDate.[[ISOYear]], addedDate.[[ISOMonth]], addedDate.[[ISODay]], temporalDateTime.[[ISOHour]], temporalDateTime.[[ISOMinute]], temporalDateTime.[[ISOSecond]], temporalDateTime.[[ISOMillisecond]], temporalDateTime.[[ISOMicrosecond]], temporalDateTime.[[ISONanosecond]], calendar).
|
||||
auto* intermediate_date_time = TRY(create_temporal_date_time(global_object, added_date->iso_year(), added_date->iso_month(), added_date->iso_day(), temporal_date_time->iso_hour(), temporal_date_time->iso_minute(), temporal_date_time->iso_second(), temporal_date_time->iso_millisecond(), temporal_date_time->iso_microsecond(), temporal_date_time->iso_nanosecond(), calendar));
|
||||
|
||||
// 9. Let intermediateInstant be ? BuiltinTimeZoneGetInstantFor(timeZone, intermediateDateTime, "compatible").
|
||||
auto* intermediate_instant = TRY(builtin_time_zone_get_instant_for(global_object, time_zone, *intermediate_date_time, "compatible"sv));
|
||||
|
||||
// 10. Return ! AddInstant(intermediateInstant.[[Nanoseconds]], hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
|
||||
return MUST(add_instant(global_object, intermediate_instant->nanoseconds(), hours, minutes, seconds, milliseconds, microseconds, nanoseconds));
|
||||
}
|
||||
|
||||
// 6.5.7 NanosecondsToDays ( nanoseconds, relativeTo ), https://tc39.es/proposal-temporal/#sec-temporal-nanosecondstodays
|
||||
ThrowCompletionOr<NanosecondsToDaysResult> nanoseconds_to_days(GlobalObject& global_object, BigInt const& nanoseconds_bigint, Value relative_to_value)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Assert: Type(nanoseconds) is BigInt.
|
||||
|
||||
// 2. Set nanoseconds to ℝ(nanoseconds).
|
||||
auto nanoseconds = nanoseconds_bigint.big_integer();
|
||||
|
||||
// 3. Let sign be ! ℝ(Sign(𝔽(nanoseconds))).
|
||||
i8 sign;
|
||||
if (nanoseconds == Crypto::UnsignedBigInteger { 0 })
|
||||
sign = 0;
|
||||
else if (nanoseconds.is_negative())
|
||||
sign = -1;
|
||||
else
|
||||
sign = 1;
|
||||
|
||||
// 4. Let dayLengthNs be 8.64 × 10^13.
|
||||
auto day_length_ns = "86400000000000"_sbigint;
|
||||
|
||||
// 5. If sign is 0, then
|
||||
if (sign == 0) {
|
||||
// a. Return the Record { [[Days]]: 0, [[Nanoseconds]]: 0, [[DayLength]]: dayLengthNs }.
|
||||
return NanosecondsToDaysResult { .days = 0, .nanoseconds = make_handle(js_bigint(vm, { 0 })), .day_length = day_length_ns.to_double() };
|
||||
}
|
||||
|
||||
// 6. If Type(relativeTo) is not Object or relativeTo does not have an [[InitializedTemporalZonedDateTime]] internal slot, then
|
||||
if (!relative_to_value.is_object() || !is<ZonedDateTime>(relative_to_value.as_object())) {
|
||||
// a. Return the Record { [[Days]]: the integral part of nanoseconds / dayLengthNs, [[Nanoseconds]]: (abs(nanoseconds) modulo dayLengthNs) × sign, [[DayLength]]: dayLengthNs }.
|
||||
return NanosecondsToDaysResult {
|
||||
.days = nanoseconds.divided_by(day_length_ns).quotient.to_double(),
|
||||
.nanoseconds = make_handle(js_bigint(vm, Crypto::SignedBigInteger { nanoseconds.unsigned_value() }.divided_by(day_length_ns).remainder.multiplied_by(Crypto::SignedBigInteger { sign }))),
|
||||
.day_length = day_length_ns.to_double()
|
||||
};
|
||||
}
|
||||
|
||||
auto& relative_to = static_cast<ZonedDateTime&>(relative_to_value.as_object());
|
||||
|
||||
// 7. Let startNs be ℝ(relativeTo.[[Nanoseconds]]).
|
||||
auto& start_ns = relative_to.nanoseconds().big_integer();
|
||||
|
||||
// 8. Let startInstant be ! CreateTemporalInstant(ℤ(startNs)).
|
||||
auto* start_instant = MUST(create_temporal_instant(global_object, *js_bigint(vm, start_ns)));
|
||||
|
||||
// 9. Let startDateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(relativeTo.[[TimeZone]], startInstant, relativeTo.[[Calendar]]).
|
||||
auto* start_date_time = TRY(builtin_time_zone_get_plain_date_time_for(global_object, &relative_to.time_zone(), *start_instant, relative_to.calendar()));
|
||||
|
||||
// 10. Let endNs be startNs + nanoseconds.
|
||||
auto end_ns = start_ns.plus(nanoseconds);
|
||||
|
||||
// 11. Let endInstant be ! CreateTemporalInstant(ℤ(endNs)).
|
||||
auto* end_instant = MUST(create_temporal_instant(global_object, *js_bigint(vm, end_ns)));
|
||||
|
||||
// 12. Let endDateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(relativeTo.[[TimeZone]], endInstant, relativeTo.[[Calendar]]).
|
||||
auto* end_date_time = TRY(builtin_time_zone_get_plain_date_time_for(global_object, &relative_to.time_zone(), *end_instant, relative_to.calendar()));
|
||||
|
||||
// 13. Let dateDifference be ? DifferenceISODateTime(startDateTime.[[ISOYear]], startDateTime.[[ISOMonth]], startDateTime.[[ISODay]], startDateTime.[[ISOHour]], startDateTime.[[ISOMinute]], startDateTime.[[ISOSecond]], startDateTime.[[ISOMillisecond]], startDateTime.[[ISOMicrosecond]], startDateTime.[[ISONanosecond]], endDateTime.[[ISOYear]], endDateTime.[[ISOMonth]], endDateTime.[[ISODay]], endDateTime.[[ISOHour]], endDateTime.[[ISOMinute]], endDateTime.[[ISOSecond]], endDateTime.[[ISOMillisecond]], endDateTime.[[ISOMicrosecond]], endDateTime.[[ISONanosecond]], relativeTo.[[Calendar]], "day").
|
||||
auto date_difference = TRY(difference_iso_date_time(global_object, start_date_time->iso_year(), start_date_time->iso_month(), start_date_time->iso_day(), start_date_time->iso_hour(), start_date_time->iso_minute(), start_date_time->iso_second(), start_date_time->iso_millisecond(), start_date_time->iso_microsecond(), start_date_time->iso_nanosecond(), end_date_time->iso_year(), end_date_time->iso_month(), end_date_time->iso_day(), end_date_time->iso_hour(), end_date_time->iso_minute(), end_date_time->iso_second(), end_date_time->iso_millisecond(), end_date_time->iso_microsecond(), end_date_time->iso_nanosecond(), relative_to.calendar(), "day"sv));
|
||||
|
||||
// 14. Let days be dateDifference.[[Days]].
|
||||
auto days = date_difference.days;
|
||||
|
||||
// 15. Let intermediateNs be ℝ(? AddZonedDateTime(ℤ(startNs), relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0, 0, 0, 0)).
|
||||
auto intermediate_ns = TRY(add_zoned_date_time(global_object, *js_bigint(vm, start_ns), &relative_to.time_zone(), relative_to.calendar(), 0, 0, 0, days, 0, 0, 0, 0, 0, 0))->big_integer();
|
||||
|
||||
// 16. If sign is 1, then
|
||||
if (sign == 1) {
|
||||
// a. Repeat, while days > 0 and intermediateNs > endNs,
|
||||
while (days > 0 && intermediate_ns > end_ns) {
|
||||
// i. Set days to days − 1.
|
||||
days--;
|
||||
|
||||
// ii. Set intermediateNs to ℝ(? AddZonedDateTime(ℤ(startNs), relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0, 0, 0, 0)).
|
||||
intermediate_ns = TRY(add_zoned_date_time(global_object, *js_bigint(vm, start_ns), &relative_to.time_zone(), relative_to.calendar(), 0, 0, 0, days, 0, 0, 0, 0, 0, 0))->big_integer();
|
||||
}
|
||||
}
|
||||
|
||||
// 17. Set nanoseconds to endNs − intermediateNs.
|
||||
nanoseconds = end_ns.minus(intermediate_ns);
|
||||
|
||||
// 18. Let done be false.
|
||||
// 19. Repeat, while done is false,
|
||||
while (true) {
|
||||
// a. Let oneDayFartherNs be ℝ(? AddZonedDateTime(ℤ(intermediateNs), relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, sign, 0, 0, 0, 0, 0, 0)).
|
||||
auto one_day_farther_ns = TRY(add_zoned_date_time(global_object, *js_bigint(vm, intermediate_ns), &relative_to.time_zone(), relative_to.calendar(), 0, 0, 0, sign, 0, 0, 0, 0, 0, 0))->big_integer();
|
||||
|
||||
// b. Set dayLengthNs to oneDayFartherNs − intermediateNs.
|
||||
day_length_ns = one_day_farther_ns.minus(intermediate_ns);
|
||||
|
||||
// c. If (nanoseconds − dayLengthNs) × sign ≥ 0, then
|
||||
if (nanoseconds.minus(day_length_ns).multiplied_by(Crypto::SignedBigInteger { sign }) >= "0"_sbigint) {
|
||||
// i. Set nanoseconds to nanoseconds − dayLengthNs.
|
||||
nanoseconds = nanoseconds.minus(day_length_ns);
|
||||
|
||||
// ii. Set intermediateNs to oneDayFartherNs.
|
||||
intermediate_ns = move(one_day_farther_ns);
|
||||
|
||||
// iii. Set days to days + sign.
|
||||
days += sign;
|
||||
}
|
||||
// d. Else,
|
||||
else {
|
||||
// i. Set done to true.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 20. Return the Record { [[Days]]: days, [[Nanoseconds]]: nanoseconds, [[DayLength]]: abs(dayLengthNs) }.
|
||||
return NanosecondsToDaysResult { .days = days, .nanoseconds = make_handle(js_bigint(vm, move(nanoseconds))), .day_length = fabs(day_length_ns.to_double()) };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Heap/Handle.h>
|
||||
#include <LibJS/Runtime/BigInt.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
|
@ -33,6 +34,14 @@ private:
|
|||
Object& m_calendar; // [[Calendar]]
|
||||
};
|
||||
|
||||
struct NanosecondsToDaysResult {
|
||||
double days;
|
||||
Handle<BigInt> nanoseconds;
|
||||
double day_length;
|
||||
};
|
||||
|
||||
ThrowCompletionOr<ZonedDateTime*> create_temporal_zoned_date_time(GlobalObject&, BigInt const& epoch_nanoseconds, Object& time_zone, Object& calendar, FunctionObject const* new_target = nullptr);
|
||||
ThrowCompletionOr<BigInt*> add_zoned_date_time(GlobalObject&, BigInt const& epoch_nanoseconds, Value time_zone, Object& calendar, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, Object* options = nullptr);
|
||||
ThrowCompletionOr<NanosecondsToDaysResult> nanoseconds_to_days(GlobalObject&, BigInt const& nanoseconds, Value relative_to);
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue