1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 22:27:35 +00:00

LibJS: Make ToRelativeTemporalObject return a RelativeTo struct

This follows a change in the spec which refactored this function and its
callers to make use of a record instead of stuffing all of the possible
return values into a single Value.

As always in temporal land, this AO remains out of date, as well of all
its callers. Update all of these callers to the new API where possible,
and use an ad-hoc function to convert this struct back to a JS::Value
for APIs that have not been updated yet.
This commit is contained in:
Shannon Booth 2024-02-18 17:53:37 +13:00 committed by Tim Flynn
parent fa692ae3f6
commit c063bf39a9
6 changed files with 101 additions and 70 deletions

View file

@ -545,8 +545,21 @@ ThrowCompletionOr<Optional<String>> get_temporal_unit(VM& vm, Object const& norm
return value;
}
// FIXME: This function is a hack to undo a RelativeTo back to the old API, which was just a Value.
// We should get rid of this once all callers have been converted to the new API.
Value relative_to_converted_to_value(RelativeTo const& relative_to)
{
if (relative_to.plain_relative_to)
return relative_to.plain_relative_to;
if (relative_to.zoned_relative_to)
return relative_to.zoned_relative_to;
return js_undefined();
}
// 13.16 ToRelativeTemporalObject ( options ), https://tc39.es/proposal-temporal/#sec-temporal-torelativetemporalobject
ThrowCompletionOr<Value> to_relative_temporal_object(VM& vm, Object const& options)
ThrowCompletionOr<RelativeTo> to_relative_temporal_object(VM& vm, Object const& options)
{
auto& realm = *vm.current_realm();
@ -558,7 +571,7 @@ ThrowCompletionOr<Value> to_relative_temporal_object(VM& vm, Object const& optio
// 3. If value is undefined, then
if (value.is_undefined()) {
// a. Return value.
return value;
return RelativeTo {};
}
// 4. Let offsetBehaviour be option.
@ -575,52 +588,77 @@ ThrowCompletionOr<Value> to_relative_temporal_object(VM& vm, Object const& optio
// 6. If Type(value) is Object, then
if (value.is_object()) {
auto& value_object = value.as_object();
// a. If value has an [[InitializedTemporalZonedDateTime]] internal slot, then
if (is<ZonedDateTime>(value_object)) {
auto& zoned_relative_to = static_cast<ZonedDateTime&>(value_object);
// a. If value has either an [[InitializedTemporalDate]] or [[InitializedTemporalZonedDateTime]] internal slot, then
if (is<PlainDate>(value_object) || is<ZonedDateTime>(value_object)) {
// i. Return value.
return value;
// i. Let timeZoneRec be ? CreateTimeZoneMethodsRecord(value.[[TimeZone]], « GET-OFFSET-NANOSECONDS-FOR, GET-POSSIBLE-INSTANTS-FOR »).
auto time_zone_record = TRY(create_time_zone_methods_record(vm, NonnullGCPtr<Object> { zoned_relative_to.time_zone() }, { { TimeZoneMethod::GetOffsetNanosecondsFor, TimeZoneMethod::GetPossibleInstantsFor } }));
// ii. Return the Record { [[PlainRelativeTo]]: undefined, [[ZonedRelativeTo]]: value, [[TimeZoneRec]]: timeZoneRec }.
return RelativeTo {
.plain_relative_to = {},
.zoned_relative_to = zoned_relative_to,
.time_zone_record = time_zone_record,
};
}
// b. If value has an [[InitializedTemporalDateTime]] internal slot, then
// b. If value has an [[InitializedTemporalDate]] internal slot, then
if (is<PlainDate>(value_object)) {
// i. Return the Record { [[PlainRelativeTo]]: value, [[ZonedRelativeTo]]: undefined, [[TimeZoneRec]]: undefined }.
return RelativeTo {
.plain_relative_to = static_cast<PlainDate&>(value_object),
.zoned_relative_to = {},
.time_zone_record = {},
};
}
// c. If value has an [[InitializedTemporalDateTime]] internal slot, then
if (is<PlainDateTime>(value_object)) {
auto& plain_date_time = static_cast<PlainDateTime&>(value_object);
// i. Return ? CreateTemporalDate(value.[[ISOYear]], value.[[ISOMonth]], value.[[ISODay]], 0, 0, 0, 0, 0, 0, value.[[Calendar]]).
return TRY(create_temporal_date(vm, plain_date_time.iso_year(), plain_date_time.iso_month(), plain_date_time.iso_day(), plain_date_time.calendar()));
// i. Let plainDate be ! CreateTemporalDate(value.[[ISOYear]], value.[[ISOMonth]], value.[[ISODay]], value.[[Calendar]]).
auto* plain_date = TRY(create_temporal_date(vm, plain_date_time.iso_year(), plain_date_time.iso_month(), plain_date_time.iso_day(), plain_date_time.calendar()));
// ii. Return the Record { [[PlainRelativeTo]]: plainDate, [[ZonedRelativeTo]]: undefined, [[TimeZoneRec]]: undefined }.
return RelativeTo {
.plain_relative_to = plain_date,
.zoned_relative_to = {},
.time_zone_record = {},
};
}
// c. Let calendar be ? GetTemporalCalendarWithISODefault(value).
// d. Let calendar be ? GetTemporalCalendarWithISODefault(value).
calendar = TRY(get_temporal_calendar_with_iso_default(vm, value_object));
// d. Let fieldNames be ? CalendarFields(calendar, « "day", "hour", "microsecond", "millisecond", "minute", "month", "monthCode", "nanosecond", "second", "year" »).
// e. Let fieldNames be ? CalendarFields(calendar, « "day", "hour", "microsecond", "millisecond", "minute", "month", "monthCode", "nanosecond", "second", "year" »).
auto field_names = TRY(calendar_fields(vm, *calendar, { "day"sv, "hour"sv, "microsecond"sv, "millisecond"sv, "minute"sv, "month"sv, "monthCode"sv, "nanosecond"sv, "second"sv, "year"sv }));
// e. Let fields be ? PrepareTemporalFields(value, fieldNames, «»).
// f. Let fields be ? PrepareTemporalFields(value, fieldNames, «»).
auto* fields = TRY(prepare_temporal_fields(vm, value_object, field_names, Vector<StringView> {}));
// f. Let dateOptions be OrdinaryObjectCreate(null).
// g. Let dateOptions be OrdinaryObjectCreate(null).
auto date_options = Object::create(realm, nullptr);
// g. Perform ! CreateDataPropertyOrThrow(dateOptions, "overflow", "constrain").
// h. Perform ! CreateDataPropertyOrThrow(dateOptions, "overflow", "constrain").
MUST(date_options->create_data_property_or_throw(vm.names.overflow, PrimitiveString::create(vm, "constrain"_string)));
// h. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, dateOptions).
// i. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, dateOptions).
result = TRY(interpret_temporal_date_time_fields(vm, *calendar, *fields, date_options));
// i. Let offsetString be ? Get(value, "offset").
// j. Let offsetString be ? Get(value, "offset").
offset_string = TRY(value_object.get(vm.names.offset));
// j. Let timeZone be ? Get(value, "timeZone").
// k. Let timeZone be ? Get(value, "timeZone").
time_zone = TRY(value_object.get(vm.names.timeZone));
// k. If timeZone is not undefined, then
// l. If timeZone is not undefined, then
if (!time_zone.is_undefined()) {
// i. Set timeZone to ? ToTemporalTimeZone(timeZone).
time_zone = TRY(to_temporal_time_zone(vm, time_zone));
}
// l. If offsetString is undefined, then
// m. If offsetString is undefined, then
if (offset_string.is_undefined()) {
// i. Set offsetBehaviour to wall.
offset_behavior = OffsetBehavior::Wall;
@ -682,7 +720,12 @@ ThrowCompletionOr<Value> to_relative_temporal_object(VM& vm, Object const& optio
// 8. If timeZone is undefined, then
if (time_zone.is_undefined()) {
// a. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
return TRY(create_temporal_date(vm, result.year, result.month, result.day, *calendar));
auto* plain_date = TRY(create_temporal_date(vm, result.year, result.month, result.day, *calendar));
return RelativeTo {
.plain_relative_to = plain_date,
.zoned_relative_to = {},
.time_zone_record = {},
};
}
double offset_ns;
@ -710,7 +753,13 @@ ThrowCompletionOr<Value> to_relative_temporal_object(VM& vm, Object const& optio
auto const* epoch_nanoseconds = TRY(interpret_iso_date_time_offset(vm, result.year, result.month, result.day, result.hour, result.minute, result.second, result.millisecond, result.microsecond, result.nanosecond, offset_behavior, offset_ns, time_zone, "compatible"sv, "reject"sv, match_behavior));
// 12. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).
return MUST(create_temporal_zoned_date_time(vm, *epoch_nanoseconds, time_zone.as_object(), *calendar));
auto time_zone_record = TRY(create_time_zone_methods_record(vm, NonnullGCPtr<Object> { time_zone.as_object() }, { { TimeZoneMethod::GetOffsetNanosecondsFor, TimeZoneMethod::GetPossibleInstantsFor } }));
auto* zoned_relative_to = MUST(create_temporal_zoned_date_time(vm, *epoch_nanoseconds, time_zone.as_object(), *calendar));
return RelativeTo {
.plain_relative_to = {},
.zoned_relative_to = zoned_relative_to,
.time_zone_record = time_zone_record,
};
}
// 13.17 LargerOfTwoTemporalUnits ( u1, u2 ), https://tc39.es/proposal-temporal/#sec-temporal-largeroftwotemporalunits

View file

@ -14,6 +14,7 @@
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Temporal/ISO8601.h>
#include <LibJS/Runtime/Temporal/TimeZoneMethods.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Temporal {
@ -148,7 +149,16 @@ ThrowCompletionOr<u64> to_temporal_rounding_increment(VM&, Object const& normali
ThrowCompletionOr<u64> to_temporal_date_time_rounding_increment(VM&, Object const& normalized_options, StringView smallest_unit);
ThrowCompletionOr<SecondsStringPrecision> to_seconds_string_precision(VM&, Object const& normalized_options);
ThrowCompletionOr<Optional<String>> get_temporal_unit(VM&, Object const& normalized_options, PropertyKey const&, UnitGroup, TemporalUnitDefault const& default_, Vector<StringView> const& extra_values = {});
ThrowCompletionOr<Value> to_relative_temporal_object(VM&, Object const& options);
struct RelativeTo {
GCPtr<PlainDate> plain_relative_to; // [[PlainRelativeTo]]
GCPtr<ZonedDateTime> zoned_relative_to; // [[ZonedRelativeTo]]
Optional<TimeZoneMethods> time_zone_record; // [[TimeZoneRec]]
};
ThrowCompletionOr<RelativeTo> to_relative_temporal_object(VM&, Object const& options);
Value relative_to_converted_to_value(RelativeTo const&);
StringView larger_of_two_temporal_units(StringView, StringView);
ThrowCompletionOr<Object*> merge_largest_unit_option(VM&, Object const& options, String largest_unit);
Optional<u16> maximum_temporal_duration_rounding_increment(StringView unit);

View file

@ -2039,11 +2039,11 @@ ThrowCompletionOr<NonnullGCPtr<Duration>> add_duration_to_or_subtract_duration_f
// 3. Set options to ? GetOptionsObject(options).
auto const* options = TRY(get_options_object(vm, options_value));
// 4. Let relativeTo be ? ToRelativeTemporalObject(options).
auto relative_to = TRY(to_relative_temporal_object(vm, *options));
// 4. Let relativeToRecord be ? ToRelativeTemporalObject(options).
auto relative_to_record = TRY(to_relative_temporal_object(vm, *options));
// 5. Let result be ? AddDuration(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]], sign × other.[[Years]], sign × other.[[Months]], sign × other.[[Weeks]], sign × other.[[Days]], sign × other.[[Hours]], sign × other.[[Minutes]], sign × other.[[Seconds]], sign × other.[[Milliseconds]], sign × other.[[Microseconds]], sign × other.[[Nanoseconds]], relativeTo).
auto result = TRY(add_duration(vm, duration.years(), duration.months(), duration.weeks(), duration.days(), duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds(), sign * other.years, sign * other.months, sign * other.weeks, sign * other.days, sign * other.hours, sign * other.minutes, sign * other.seconds, sign * other.milliseconds, sign * other.microseconds, sign * other.nanoseconds, relative_to));
auto result = TRY(add_duration(vm, duration.years(), duration.months(), duration.weeks(), duration.days(), duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds(), sign * other.years, sign * other.months, sign * other.weeks, sign * other.days, sign * other.hours, sign * other.minutes, sign * other.seconds, sign * other.milliseconds, sign * other.microseconds, sign * other.nanoseconds, relative_to_converted_to_value(relative_to_record)));
// 6. Return ! CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
return MUST(create_temporal_duration(vm, result.years, result.months, result.weeks, result.days, result.hours, result.minutes, result.seconds, result.milliseconds, result.microseconds, result.nanoseconds));

View file

@ -117,7 +117,7 @@ JS_DEFINE_NATIVE_FUNCTION(DurationConstructor::compare)
auto const* options = TRY(get_options_object(vm, vm.argument(2)));
// 4. Let relativeTo be ? ToRelativeTemporalObject(options).
auto relative_to = TRY(to_relative_temporal_object(vm, *options));
auto relative_to = relative_to_converted_to_value(TRY(to_relative_temporal_object(vm, *options)));
// 5. Let shift1 be ? CalculateOffsetShift(relativeTo, one.[[Years]], one.[[Months]], one.[[Weeks]], one.[[Days]]).
auto shift1 = TRY(calculate_offset_shift(vm, relative_to, one->years(), one->months(), one->weeks(), one->days()));

View file

@ -418,43 +418,29 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::round)
// 20. Let relativeTo be ? ToRelativeTemporalObject(roundTo).
auto relative_to = TRY(to_relative_temporal_object(vm, *round_to));
auto relative_to_value = relative_to_converted_to_value(relative_to);
// 21. Let unbalanceResult be ? UnbalanceDurationRelative(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], largestUnit, relativeTo).
auto unbalance_result = TRY(unbalance_duration_relative(vm, duration->years(), duration->months(), duration->weeks(), duration->days(), *largest_unit, relative_to));
auto unbalance_result = TRY(unbalance_duration_relative(vm, duration->years(), duration->months(), duration->weeks(), duration->days(), *largest_unit, relative_to_value));
// FIXME: AD-HOC - this function is not up to date with latest spec.
PlainDate* plain_relative_to_ptr = nullptr;
ZonedDateTime* zoned_relative_to_ptr = nullptr;
if (relative_to.is_object()) {
if (is<PlainDate>(relative_to.as_object()))
plain_relative_to_ptr = &static_cast<PlainDate&>(relative_to.as_object());
else if (is<ZonedDateTime>(relative_to.as_object()))
zoned_relative_to_ptr = &static_cast<ZonedDateTime&>(relative_to.as_object());
else
VERIFY_NOT_REACHED();
}
auto calendar_record = TRY(create_calendar_methods_record_from_relative_to(vm, plain_relative_to_ptr, zoned_relative_to_ptr, { { CalendarMethod::DateAdd, CalendarMethod::DateUntil } }));
auto calendar_record = TRY(create_calendar_methods_record_from_relative_to(vm, relative_to.plain_relative_to, relative_to.zoned_relative_to, { { CalendarMethod::DateAdd, CalendarMethod::DateUntil } }));
// 22. Let roundResult be (? RoundDuration(unbalanceResult.[[Years]], unbalanceResult.[[Months]], unbalanceResult.[[Weeks]], unbalanceResult.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode, relativeTo)).[[DurationRecord]].
auto round_result = TRY(round_duration(vm, unbalance_result.years, unbalance_result.months, unbalance_result.weeks, unbalance_result.days, duration->hours(), duration->minutes(), duration->seconds(), duration->milliseconds(), duration->microseconds(), duration->nanoseconds(), rounding_increment, *smallest_unit, rounding_mode, relative_to.is_object() ? &relative_to.as_object() : nullptr, calendar_record)).duration_record;
auto round_result = TRY(round_duration(vm, unbalance_result.years, unbalance_result.months, unbalance_result.weeks, unbalance_result.days, duration->hours(), duration->minutes(), duration->seconds(), duration->milliseconds(), duration->microseconds(), duration->nanoseconds(), rounding_increment, *smallest_unit, rounding_mode, relative_to_value.is_object() ? &relative_to_value.as_object() : nullptr, calendar_record)).duration_record;
// 23. Let adjustResult be ? AdjustRoundedDurationDays(roundResult.[[Years]], roundResult.[[Months]], roundResult.[[Weeks]], roundResult.[[Days]], roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]], roundResult.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode, relativeTo).
auto adjust_result = TRY(adjust_rounded_duration_days(vm, round_result.years, round_result.months, round_result.weeks, round_result.days, round_result.hours, round_result.minutes, round_result.seconds, round_result.milliseconds, round_result.microseconds, round_result.nanoseconds, rounding_increment, *smallest_unit, rounding_mode, relative_to.is_object() ? &relative_to.as_object() : nullptr));
auto adjust_result = TRY(adjust_rounded_duration_days(vm, round_result.years, round_result.months, round_result.weeks, round_result.days, round_result.hours, round_result.minutes, round_result.seconds, round_result.milliseconds, round_result.microseconds, round_result.nanoseconds, rounding_increment, *smallest_unit, rounding_mode, relative_to_value.is_object() ? &relative_to_value.as_object() : nullptr));
// 24. Let balanceResult be ? BalanceDurationRelative(adjustResult.[[Years]], adjustResult.[[Months]], adjustResult.[[Weeks]], adjustResult.[[Days]], largestUnit, relativeTo).
auto balance_result = TRY(balance_duration_relative(vm, adjust_result.years, adjust_result.months, adjust_result.weeks, adjust_result.days, *largest_unit, relative_to));
auto balance_result = TRY(balance_duration_relative(vm, adjust_result.years, adjust_result.months, adjust_result.weeks, adjust_result.days, *largest_unit, relative_to_value));
// 25. If Type(relativeTo) is Object and relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot, then
if (relative_to.is_object() && is<ZonedDateTime>(relative_to.as_object())) {
auto& relative_to_zoned_date_time = static_cast<ZonedDateTime&>(relative_to.as_object());
if (relative_to.zoned_relative_to) {
// a. Set relativeTo to ? MoveRelativeZonedDateTime(relativeTo, balanceResult.[[Years]], balanceResult.[[Months]], balanceResult.[[Weeks]], 0).
relative_to = TRY(move_relative_zoned_date_time(vm, relative_to_zoned_date_time, balance_result.years, balance_result.months, balance_result.weeks, 0));
relative_to_value = TRY(move_relative_zoned_date_time(vm, *relative_to.zoned_relative_to, balance_result.years, balance_result.months, balance_result.weeks, 0));
}
// 26. Let result be ? BalanceDuration(balanceResult.[[Days]], adjustResult.[[Hours]], adjustResult.[[Minutes]], adjustResult.[[Seconds]], adjustResult.[[Milliseconds]], adjustResult.[[Microseconds]], adjustResult.[[Nanoseconds]], largestUnit, relativeTo).
auto result = TRY(balance_duration(vm, balance_result.days, adjust_result.hours, adjust_result.minutes, adjust_result.seconds, adjust_result.milliseconds, adjust_result.microseconds, Crypto::SignedBigInteger { adjust_result.nanoseconds }, *largest_unit, relative_to.is_object() ? &relative_to.as_object() : nullptr));
auto result = TRY(balance_duration(vm, balance_result.days, adjust_result.hours, adjust_result.minutes, adjust_result.seconds, adjust_result.milliseconds, adjust_result.microseconds, Crypto::SignedBigInteger { adjust_result.nanoseconds }, *largest_unit, relative_to_value.is_object() ? &relative_to_value.as_object() : nullptr));
// 27. Return ! CreateTemporalDuration(balanceResult.[[Years]], balanceResult.[[Months]], balanceResult.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
return MUST(create_temporal_duration(vm, balance_result.years, balance_result.months, balance_result.weeks, result.days, result.hours, result.minutes, result.seconds, result.milliseconds, result.microseconds, result.nanoseconds));
@ -494,44 +480,30 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::total)
// 6. Let relativeTo be ? ToRelativeTemporalObject(totalOf).
auto relative_to = TRY(to_relative_temporal_object(vm, *total_of));
auto relative_to_value = relative_to_converted_to_value(relative_to);
// 7. Let unit be ? GetTemporalUnit(totalOf, "unit", datetime, required).
auto unit = TRY(get_temporal_unit(vm, *total_of, vm.names.unit, UnitGroup::DateTime, TemporalUnitRequired {}));
// 8. Let unbalanceResult be ? UnbalanceDurationRelative(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], unit, relativeTo).
auto unbalance_result = TRY(unbalance_duration_relative(vm, duration->years(), duration->months(), duration->weeks(), duration->days(), *unit, relative_to));
auto unbalance_result = TRY(unbalance_duration_relative(vm, duration->years(), duration->months(), duration->weeks(), duration->days(), *unit, relative_to_value));
// 9. Let intermediate be undefined.
ZonedDateTime* intermediate = nullptr;
// 10. If Type(relativeTo) is Object and relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot, then
if (relative_to.is_object() && is<ZonedDateTime>(relative_to.as_object())) {
auto& relative_to_zoned_date_time = static_cast<ZonedDateTime&>(relative_to.as_object());
if (relative_to.zoned_relative_to) {
// a. Set intermediate to ? MoveRelativeZonedDateTime(relativeTo, unbalanceResult.[[Years]], unbalanceResult.[[Months]], unbalanceResult.[[Weeks]], 0).
intermediate = TRY(move_relative_zoned_date_time(vm, relative_to_zoned_date_time, unbalance_result.years, unbalance_result.months, unbalance_result.weeks, 0));
intermediate = TRY(move_relative_zoned_date_time(vm, *relative_to.zoned_relative_to, unbalance_result.years, unbalance_result.months, unbalance_result.weeks, 0));
}
// 11. Let balanceResult be ? BalanceDuration(unbalanceResult.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]], unit, intermediate).
auto balance_result = TRY(balance_duration(vm, unbalance_result.days, duration->hours(), duration->minutes(), duration->seconds(), duration->milliseconds(), duration->microseconds(), Crypto::SignedBigInteger { duration->nanoseconds() }, *unit, intermediate));
// 12. Let roundRecord be ? RoundDuration(unbalanceResult.[[Years]], unbalanceResult.[[Months]], unbalanceResult.[[Weeks]], balanceResult.[[Days]], balanceResult.[[Hours]], balanceResult.[[Minutes]], balanceResult.[[Seconds]], balanceResult.[[Milliseconds]], balanceResult.[[Microseconds]], balanceResult.[[Nanoseconds]], 1, unit, "trunc", relativeTo).
// FIXME: AD-HOC - this function is not up to date with latest spec.
PlainDate* plain_relative_to_ptr = nullptr;
ZonedDateTime* zoned_relative_to_ptr = nullptr;
auto calendar_record = TRY(create_calendar_methods_record_from_relative_to(vm, relative_to.plain_relative_to, relative_to.zoned_relative_to, { { CalendarMethod::DateAdd, CalendarMethod::DateUntil } }));
if (relative_to.is_object()) {
if (is<PlainDate>(relative_to.as_object()))
plain_relative_to_ptr = &static_cast<PlainDate&>(relative_to.as_object());
else if (is<ZonedDateTime>(relative_to.as_object()))
zoned_relative_to_ptr = &static_cast<ZonedDateTime&>(relative_to.as_object());
else
VERIFY_NOT_REACHED();
}
auto calendar_record = TRY(create_calendar_methods_record_from_relative_to(vm, plain_relative_to_ptr, zoned_relative_to_ptr, { { CalendarMethod::DateAdd, CalendarMethod::DateUntil } }));
auto round_record = TRY(round_duration(vm, unbalance_result.years, unbalance_result.months, unbalance_result.weeks, balance_result.days, balance_result.hours, balance_result.minutes, balance_result.seconds, balance_result.milliseconds, balance_result.microseconds, balance_result.nanoseconds, 1, *unit, "trunc"sv, relative_to.is_object() ? &relative_to.as_object() : nullptr, calendar_record));
auto round_record = TRY(round_duration(vm, unbalance_result.years, unbalance_result.months, unbalance_result.weeks, balance_result.days, balance_result.hours, balance_result.minutes, balance_result.seconds, balance_result.milliseconds, balance_result.microseconds, balance_result.nanoseconds, 1, *unit, "trunc"sv, relative_to_value.is_object() ? &relative_to_value.as_object() : nullptr, calendar_record));
// 13. Return 𝔽(roundRecord.[[Total]]).
return Value(round_record.total);

View file

@ -98,7 +98,7 @@ describe("errors", () => {
const duration = new Temporal.Duration();
expect(() => {
Temporal.Duration.compare(duration, duration, { relativeTo: zonedDateTime });
}).toThrowWithMessage(TypeError, "null is not a function");
}).toThrowWithMessage(TypeError, "getOffsetNanosecondsFor is undefined");
});
test("UTC designator only allowed with bracketed time zone", () => {