From ee0d5d6649b3c092aec3bd1b85b5b178a1899410 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Fri, 24 Jun 2022 00:27:29 +0100 Subject: [PATCH] LibJS: Refactor common option reading into the GetDifferenceSettings AO This is an editorial change in the Temporal spec. See: https://github.com/tc39/proposal-temporal/commit/78abbb8 --- .../Runtime/Temporal/AbstractOperations.cpp | 60 +++++++++++++++- .../Runtime/Temporal/AbstractOperations.h | 12 +++- .../LibJS/Runtime/Temporal/Instant.cpp | 50 +++----------- .../LibJS/Runtime/Temporal/PlainDate.cpp | 47 +++---------- .../LibJS/Runtime/Temporal/PlainDateTime.cpp | 53 +++------------ .../LibJS/Runtime/Temporal/PlainTime.cpp | 47 +++---------- .../LibJS/Runtime/Temporal/PlainYearMonth.cpp | 68 +++++-------------- .../LibJS/Runtime/Temporal/ZonedDateTime.cpp | 68 +++++-------------- 8 files changed, 141 insertions(+), 264 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index 3d2d2919c1..f57717f354 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -457,7 +457,7 @@ static Vector temporal_units = { }; // 13.15 GetTemporalUnit ( normalizedOptions, key, unitGroup, default [ , extraValues ] ), https://tc39.es/proposal-temporal/#sec-temporal-gettemporalunit -ThrowCompletionOr> get_temporal_unit(GlobalObject& global_object, Object const& normalized_options, PropertyKey const& key, UnitGroup unit_group, Variant> const& default_, Vector const& extra_values) +ThrowCompletionOr> get_temporal_unit(GlobalObject& global_object, Object const& normalized_options, PropertyKey const& key, UnitGroup unit_group, TemporalUnitDefault const& default_, Vector const& extra_values) { auto& vm = global_object.vm(); @@ -1838,4 +1838,62 @@ ThrowCompletionOr prepare_temporal_fields(GlobalObject& global_object, return result; } +// 13.44 GetDifferenceSettings ( operation, options, unitGroup, disallowedUnits, fallbackSmallestUnit, smallestLargestDefaultUnit ), https://tc39.es/proposal-temporal/#sec-temporal-getdifferencesettings +ThrowCompletionOr get_difference_settings(GlobalObject& global_object, DifferenceOperation operation, Value options_value, UnitGroup unit_group, Vector const& disallowed_units, TemporalUnitDefault const& fallback_smallest_unit, StringView smallest_largest_default_unit) +{ + auto& vm = global_object.vm(); + + // 1. Set options to ? GetOptionsObject(options). + auto* options = TRY(get_options_object(global_object, options_value)); + + // 2. Let smallestUnit be ? GetTemporalUnit(options, "smallestUnit", unitGroup, fallbackSmallestUnit). + auto smallest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.smallestUnit, unit_group, fallback_smallest_unit)); + + // 3. If disallowedUnits contains smallestUnit, throw a RangeError exception. + if (disallowed_units.contains_slow(*smallest_unit)) + return vm.throw_completion(global_object, ErrorType::OptionIsNotValidValue, *smallest_unit, "smallestUnit"sv); + + // 4. Let defaultLargestUnit be ! LargerOfTwoTemporalUnits(smallestLargestDefaultUnit, smallestUnit). + auto default_largest_unit = larger_of_two_temporal_units(smallest_largest_default_unit, *smallest_unit); + + // 5. Let largestUnit be ? GetTemporalUnit(options, "largestUnit", unitGroup, "auto"). + auto largest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.largestUnit, unit_group, { "auto"sv })); + + // 6. If disallowedUnits contains largestUnit, throw a RangeError exception. + if (disallowed_units.contains_slow(*largest_unit)) + return vm.throw_completion(global_object, ErrorType::OptionIsNotValidValue, *largest_unit, "largestUnit"sv); + + // 7. If largestUnit is "auto", set largestUnit to defaultLargestUnit. + if (largest_unit == "auto"sv) + largest_unit = default_largest_unit; + + // 8. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception. + if (larger_of_two_temporal_units(*largest_unit, *smallest_unit) != largest_unit) + return vm.throw_completion(global_object, ErrorType::TemporalInvalidUnitRange, *smallest_unit, *largest_unit); + + // 9. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc"). + auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "trunc"sv)); + + // 10. If operation is since, then + if (operation == DifferenceOperation::Since) { + // a. Set roundingMode to ! NegateTemporalRoundingMode(roundingMode). + rounding_mode = negate_temporal_rounding_mode(rounding_mode); + } + + // 11. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit). + auto maximum = maximum_temporal_duration_rounding_increment(*smallest_unit); + + // 12. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false). + auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, Optional { maximum }, false)); + + // 13. Return the Record { [[SmallestUnit]]: smallestUnit, [[LargestUnit]]: largestUnit, [[RoundingMode]]: roundingMode, [[RoundingIncrement]]: roundingIncrement, [[Options]]: options }. + return DifferenceSettings { + .smallest_unit = smallest_unit.release_value(), + .largest_unit = largest_unit.release_value(), + .rounding_mode = move(rounding_mode), + .rounding_increment = rounding_increment, + .options = *options, + }; +} + } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h index a7a895fd44..4f91cc0a39 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h @@ -121,11 +121,20 @@ struct SecondsStringPrecision { u32 increment; }; +struct DifferenceSettings { + String smallest_unit; + String largest_unit; + String rounding_mode; + u64 rounding_increment; + Object& options; +}; + struct TemporalUnitRequired { }; struct PrepareTemporalFieldsPartial { }; struct GetOptionRequired { }; using OptionDefault = Variant; +using TemporalUnitDefault = Variant>; ThrowCompletionOr> iterable_to_list_of_type(GlobalObject&, Value items, Vector const& element_types); ThrowCompletionOr get_options_object(GlobalObject&, Value options); @@ -141,7 +150,7 @@ ThrowCompletionOr to_show_offset_option(GlobalObject&, Object const& nor ThrowCompletionOr to_temporal_rounding_increment(GlobalObject&, Object const& normalized_options, Optional dividend, bool inclusive); ThrowCompletionOr to_temporal_date_time_rounding_increment(GlobalObject&, Object const& normalized_options, StringView smallest_unit); ThrowCompletionOr to_seconds_string_precision(GlobalObject&, Object const& normalized_options); -ThrowCompletionOr> get_temporal_unit(GlobalObject&, Object const& normalized_options, PropertyKey const&, UnitGroup, Variant> const& default_, Vector const& extra_values = {}); +ThrowCompletionOr> get_temporal_unit(GlobalObject&, Object const& normalized_options, PropertyKey const&, UnitGroup, TemporalUnitDefault const& default_, Vector const& extra_values = {}); ThrowCompletionOr to_relative_temporal_object(GlobalObject&, Object const& options); StringView larger_of_two_temporal_units(StringView, StringView); ThrowCompletionOr merge_largest_unit_option(GlobalObject&, Object const& options, String largest_unit); @@ -170,6 +179,7 @@ ThrowCompletionOr parse_temporal_time_zone_string(GlobalObject ThrowCompletionOr parse_temporal_year_month_string(GlobalObject&, String const& iso_string); ThrowCompletionOr to_positive_integer(GlobalObject&, Value argument); ThrowCompletionOr prepare_temporal_fields(GlobalObject&, Object const& fields, Vector const& field_names, Variant> const& required_fields); +ThrowCompletionOr get_difference_settings(GlobalObject&, DifferenceOperation, Value options_value, UnitGroup unit_group, Vector const& disallowed_units, TemporalUnitDefault const& fallback_smallest_unit, StringView smallest_largest_default_unit); template ThrowCompletionOr get_option(GlobalObject& global_object, Object const& options, PropertyKey const& property, OptionType type, StringView const (&values)[Size], OptionDefault const& default_) diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Instant.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Instant.cpp index 212acc1f97..35d34efc06 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Instant.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Instant.cpp @@ -280,58 +280,24 @@ ThrowCompletionOr temporal_instant_to_string(GlobalObject& global_object // 8.5.10 DifferenceTemporalInstant ( operation, instant, other, options ), https://tc39.es/proposal-temporal/#sec-temporal-differencetemporalinstant ThrowCompletionOr difference_temporal_instant(GlobalObject& global_object, DifferenceOperation operation, Instant const& instant, Value other_value, Value options_value) { - auto& vm = global_object.vm(); - // 1. If operation is since, let sign be -1. Otherwise, let sign be 1. i8 sign = operation == DifferenceOperation::Since ? -1 : 1; // 2. Set other to ? ToTemporalInstant(other). auto* other = TRY(to_temporal_instant(global_object, other_value)); - // 3. Set options to ? GetOptionsObject(options). - auto const* options = TRY(get_options_object(global_object, options_value)); + // 3. Let settings be ? GetDifferenceSettings(operation, options, time, « », "nanosecond", "second"). + auto settings = TRY(get_difference_settings(global_object, operation, options_value, UnitGroup::Time, {}, { "nanosecond"sv }, "second"sv)); - // 4. Let smallestUnit be ? GetTemporalUnit(options, "smallestUnit", time, "nanosecond"). - auto smallest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.smallestUnit, UnitGroup::Time, { "nanosecond"sv })); + // 4. Let roundedNs be ! DifferenceInstant(instant.[[Nanoseconds]], other.[[Nanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]). + auto* rounded_ns = difference_instant(global_object, instant.nanoseconds(), other->nanoseconds(), settings.rounding_increment, settings.smallest_unit, settings.rounding_mode); - // 5. Let defaultLargestUnit be ! LargerOfTwoTemporalUnits("second", smallestUnit). - auto default_largest_unit = larger_of_two_temporal_units("second"sv, *smallest_unit); + // 5. Assert: The following steps cannot fail due to overflow in the Number domain because abs(roundedNs) ≤ 2 × nsMaxInstant. - // 6. Let largestUnit be ? GetTemporalUnit(options, "largestUnit", time, "auto"). - auto largest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.largestUnit, UnitGroup::Time, { "auto"sv })); + // 6. Let result be ! BalanceDuration(0, 0, 0, 0, 0, 0, roundedNs, settings.[[LargestUnit]]). + auto result = MUST(balance_duration(global_object, 0, 0, 0, 0, 0, 0, rounded_ns->big_integer(), settings.largest_unit)); - // 7. If largestUnit is "auto", set largestUnit to defaultLargestUnit. - if (largest_unit == "auto"sv) - largest_unit = default_largest_unit; - - // 8. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception. - if (larger_of_two_temporal_units(*largest_unit, *smallest_unit) != largest_unit) - return vm.throw_completion(global_object, ErrorType::TemporalInvalidUnitRange, *smallest_unit, *largest_unit); - - // 9. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc"). - auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "trunc"sv)); - - // 10. If operation is since, then - if (operation == DifferenceOperation::Since) { - // a. Set roundingMode to ! NegateTemporalRoundingMode(roundingMode). - rounding_mode = negate_temporal_rounding_mode(rounding_mode); - } - - // 11. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit). - auto maximum = maximum_temporal_duration_rounding_increment(*smallest_unit); - - // 12. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false). - auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, *maximum, false)); - - // 13. Let roundedNs be ! DifferenceInstant(instant.[[Nanoseconds]], other.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode). - auto* rounded_ns = difference_instant(global_object, instant.nanoseconds(), other->nanoseconds(), rounding_increment, *smallest_unit, rounding_mode); - - // 14. Assert: The following steps cannot fail due to overflow in the Number domain because abs(roundedNs) ≤ 2 × nsMaxInstant. - - // 15. Let result be ! BalanceDuration(0, 0, 0, 0, 0, 0, roundedNs, largestUnit). - auto result = MUST(balance_duration(global_object, 0, 0, 0, 0, 0, 0, rounded_ns->big_integer(), *largest_unit)); - - // 16. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]). + // 7. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]). return MUST(create_temporal_duration(global_object, 0, 0, 0, 0, sign * result.hours, sign * result.minutes, sign * result.seconds, sign * result.milliseconds, sign * result.microseconds, sign * result.nanoseconds)); } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp index 8dc4227987..aee6ff126d 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp @@ -507,50 +507,21 @@ ThrowCompletionOr difference_temporal_plain_date(GlobalObject& global if (!TRY(calendar_equals(global_object, temporal_date.calendar(), other->calendar()))) return vm.throw_completion(global_object, ErrorType::TemporalDifferentCalendars); - // 4. Set options to ? GetOptionsObject(options). - auto const* options = TRY(get_options_object(global_object, options_value)); + // 4. Let settings be ? GetDifferenceSettings(operation, options, date, « », "day", "day"). + auto settings = TRY(get_difference_settings(global_object, operation, options_value, UnitGroup::Date, {}, { "day"sv }, "day"sv)); - // 5. Let smallestUnit be ? GetTemporalUnit(options, "smallestUnit", date, "day"). - auto smallest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.smallestUnit, UnitGroup::Date, { "day"sv })); + // 5. Let untilOptions be ? MergeLargestUnitOption(settings.[[Options]], settings.[[LargestUnit]]). + auto* until_options = TRY(merge_largest_unit_option(global_object, settings.options, settings.largest_unit)); - // 6. Let defaultLargestUnit be ! LargerOfTwoTemporalUnits("day", smallestUnit). - auto default_largest_unit = larger_of_two_temporal_units("day"sv, *smallest_unit); - - // 7. Let largestUnit be ? GetTemporalUnit(options, "largestUnit", date, "auto"). - auto largest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.largestUnit, UnitGroup::Date, { "auto"sv })); - - // 8. If largestUnit is "auto", set largestUnit to defaultLargestUnit. - if (largest_unit == "auto"sv) - largest_unit = default_largest_unit; - - // 9. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception. - if (larger_of_two_temporal_units(*largest_unit, *smallest_unit) != largest_unit) - return vm.throw_completion(global_object, ErrorType::TemporalInvalidUnitRange, *smallest_unit, *largest_unit); - - // 10. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc"). - auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "trunc"sv)); - - // 11. If operation is since, then - if (operation == DifferenceOperation::Since) { - // a. Set roundingMode to ! NegateTemporalRoundingMode(roundingMode). - rounding_mode = negate_temporal_rounding_mode(rounding_mode); - } - - // 12. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, undefined, false). - auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, {}, false)); - - // 13. Let untilOptions be ? MergeLargestUnitOption(options, largestUnit). - auto* until_options = TRY(merge_largest_unit_option(global_object, *options, largest_unit.release_value())); - - // 14. Let result be ? CalendarDateUntil(temporalDate.[[Calendar]], temporalDate, other, untilOptions). + // 6. Let result be ? CalendarDateUntil(temporalDate.[[Calendar]], temporalDate, other, untilOptions). auto* duration = TRY(calendar_date_until(global_object, temporal_date.calendar(), &temporal_date, other, *until_options)); auto result = DurationRecord { duration->years(), duration->months(), duration->weeks(), duration->days(), 0, 0, 0, 0, 0, 0 }; - // 15. If smallestUnit is not "day" or roundingIncrement ≠ 1, then - if (*smallest_unit != "day"sv || rounding_increment != 1) { - // a. Set result to (? RoundDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0, roundingIncrement, smallestUnit, roundingMode, temporalDate)).[[DurationRecord]]. - result = TRY(round_duration(global_object, result.years, result.months, result.weeks, result.days, 0, 0, 0, 0, 0, 0, rounding_increment, *smallest_unit, rounding_mode, &temporal_date)).duration_record; + // 7. If settings.[[SmallestUnit]] is not "day" or settings.[[RoundingIncrement]] ≠ 1, then + if (settings.smallest_unit != "day"sv || settings.rounding_increment != 1) { + // a. Set result to (? RoundDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0, settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]], temporalDate)).[[DurationRecord]]. + result = TRY(round_duration(global_object, result.years, result.months, result.weeks, result.days, 0, 0, 0, 0, 0, 0, settings.rounding_increment, settings.smallest_unit, settings.rounding_mode, &temporal_date)).duration_record; } // 16. Return ! CreateTemporalDuration(sign × result.[[Years]], sign × result.[[Months]], sign × result.[[Weeks]], sign × result.[[Days]], 0, 0, 0, 0, 0, 0). diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp index c737954727..b59a5b4a73 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp @@ -409,54 +409,23 @@ ThrowCompletionOr difference_temporal_plain_date_time(GlobalObject& g if (!TRY(calendar_equals(global_object, date_time.calendar(), other->calendar()))) return vm.throw_completion(global_object, ErrorType::TemporalDifferentCalendars); - // 4. Set options to ? GetOptionsObject(options). - auto const* options = TRY(get_options_object(global_object, options_value)); + // 4. Let settings be ? GetDifferenceSettings(operation, options, datetime, « », "nanosecond", "day"). + auto settings = TRY(get_difference_settings(global_object, operation, options_value, UnitGroup::DateTime, {}, { "nanosecond"sv }, "day"sv)); - // 5. Let smallestUnit be ? GetTemporalUnit(options, "smallestUnit", datetime, "nanosecond"). - auto smallest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.smallestUnit, UnitGroup::DateTime, { "nanosecond"sv })); + // 5. Let diff be ? DifferenceISODateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], other.[[ISOYear]], other.[[ISOMonth]], other.[[ISODay]], other.[[ISOHour]], other.[[ISOMinute]], other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]], other.[[ISONanosecond]], dateTime.[[Calendar]], settings.[[LargestUnit]], settings.[[Options]]). + auto diff = TRY(difference_iso_date_time(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(), other->iso_year(), other->iso_month(), other->iso_day(), other->iso_hour(), other->iso_minute(), other->iso_second(), other->iso_millisecond(), other->iso_microsecond(), other->iso_nanosecond(), date_time.calendar(), settings.largest_unit, settings.options)); - // 6. Let defaultLargestUnit be ! LargerOfTwoTemporalUnits("day", smallestUnit). - auto default_largest_unit = larger_of_two_temporal_units("day"sv, *smallest_unit); - - // 7. Let largestUnit be ? GetTemporalUnit(options, "largestUnit", datetime, "auto"). - auto largest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.largestUnit, UnitGroup::DateTime, { "auto"sv })); - - // 8. If largestUnit is "auto", set largestUnit to defaultLargestUnit. - if (largest_unit == "auto"sv) - largest_unit = default_largest_unit; - - // 9. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception. - if (larger_of_two_temporal_units(*largest_unit, *smallest_unit) != largest_unit) - return vm.throw_completion(global_object, ErrorType::TemporalInvalidUnitRange, *smallest_unit, *largest_unit); - - // 10. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc"). - auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "trunc"sv)); - - // 11. If operation is since, then - if (operation == DifferenceOperation::Since) { - // a. Set roundingMode to ! NegateTemporalRoundingMode(roundingMode). - rounding_mode = negate_temporal_rounding_mode(rounding_mode); - } - - // 12. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit). - auto maximum = maximum_temporal_duration_rounding_increment(*smallest_unit); - - // 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false). - auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, Optional(maximum), false)); - - // 14. Let diff be ? DifferenceISODateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], other.[[ISOYear]], other.[[ISOMonth]], other.[[ISODay]], other.[[ISOHour]], other.[[ISOMinute]], other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]], other.[[ISONanosecond]], dateTime.[[Calendar]], largestUnit, options). - auto diff = TRY(difference_iso_date_time(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(), other->iso_year(), other->iso_month(), other->iso_day(), other->iso_hour(), other->iso_minute(), other->iso_second(), other->iso_millisecond(), other->iso_microsecond(), other->iso_nanosecond(), date_time.calendar(), *largest_unit, *options)); - - // 15. Let relativeTo be ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[Calendar]]). + // 6. Let relativeTo be ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[Calendar]]). auto* relative_to = MUST(create_temporal_date(global_object, date_time.iso_year(), date_time.iso_month(), date_time.iso_day(), date_time.calendar())); - // 16. Let roundResult be (? RoundDuration(diff.[[Years]], diff.[[Months]], diff.[[Weeks]], diff.[[Days]], diff.[[Hours]], diff.[[Minutes]], diff.[[Seconds]], diff.[[Milliseconds]], diff.[[Microseconds]], diff.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode, relativeTo)).[[DurationRecord]]. - auto round_result = TRY(round_duration(global_object, diff.years, diff.months, diff.weeks, diff.days, diff.hours, diff.minutes, diff.seconds, diff.milliseconds, diff.microseconds, diff.nanoseconds, rounding_increment, *smallest_unit, rounding_mode, relative_to)).duration_record; + // 7. Let roundResult be (? RoundDuration(diff.[[Years]], diff.[[Months]], diff.[[Weeks]], diff.[[Days]], diff.[[Hours]], diff.[[Minutes]], diff.[[Seconds]], diff.[[Milliseconds]], diff.[[Microseconds]], diff.[[Nanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]], relativeTo)).[[DurationRecord]]. + auto round_result = TRY(round_duration(global_object, diff.years, diff.months, diff.weeks, diff.days, diff.hours, diff.minutes, diff.seconds, diff.milliseconds, diff.microseconds, diff.nanoseconds, settings.rounding_increment, settings.smallest_unit, settings.rounding_mode, relative_to)).duration_record; - // 17. Let result be ? BalanceDuration(roundResult.[[Days]], roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]], roundResult.[[Nanoseconds]], largestUnit). - auto result = MUST(balance_duration(global_object, round_result.days, round_result.hours, round_result.minutes, round_result.seconds, round_result.milliseconds, round_result.microseconds, Crypto::SignedBigInteger::create_from((i64)round_result.nanoseconds), *largest_unit)); + // 8. Let result be ? BalanceDuration(roundResult.[[Days]], roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]], roundResult.[[Nanoseconds]], settings.[[LargestUnit]]). + // FIXME: Narrowing conversion from 'double' to 'i64' + auto result = MUST(balance_duration(global_object, round_result.days, round_result.hours, round_result.minutes, round_result.seconds, round_result.milliseconds, round_result.microseconds, Crypto::SignedBigInteger::create_from((i64)round_result.nanoseconds), settings.largest_unit)); - // 18. Return ! CreateTemporalDuration(sign × roundResult.[[Years]], sign × roundResult.[[Months]], sign × roundResult.[[Weeks]], sign × result.[[Days]], sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]). + // 9. Return ! CreateTemporalDuration(sign × roundResult.[[Years]], sign × roundResult.[[Months]], sign × roundResult.[[Weeks]], sign × result.[[Days]], sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]). return MUST(create_temporal_duration(global_object, sign * round_result.years, sign * round_result.months, sign * round_result.weeks, sign * result.days, sign * result.hours, sign * result.minutes, sign * result.seconds, sign * result.milliseconds, sign * result.microseconds, sign * result.nanoseconds)); } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp index e6e8d8a852..c2eaf2771e 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp @@ -579,56 +579,25 @@ DaysAndTime round_time(u8 hour, u8 minute, u8 second, u16 millisecond, u16 micro // 4.5.13 DifferenceTemporalPlainTime ( operation, temporalTime, other, options ), https://tc39.es/proposal-temporal/#sec-temporal-differencetemporalplaintime ThrowCompletionOr difference_temporal_plain_time(GlobalObject& global_object, DifferenceOperation operation, PlainTime const& temporal_time, Value other_value, Value options_value) { - auto& vm = global_object.vm(); - // 1. If operation is since, let sign be -1. Otherwise, let sign be 1. i8 sign = operation == DifferenceOperation::Since ? -1 : 1; // 2. Set other to ? ToTemporalTime(other). auto* other = TRY(to_temporal_time(global_object, other_value)); - // 3. Set options to ? GetOptionsObject(options). - auto const* options = TRY(get_options_object(global_object, options_value)); + // 3. Let settings be ? GetDifferenceSettings(operation, options, time, « », "nanosecond", "hour"). + auto settings = TRY(get_difference_settings(global_object, operation, options_value, UnitGroup::Time, {}, { "nanosecond"sv }, "hour"sv)); - // 4. Let smallestUnit be ? GetTemporalUnit(options, "smallestUnit", time, "nanosecond"). - auto smallest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.smallestUnit, UnitGroup::Time, { "nanosecond"sv })); - - // 5. Let largestUnit be ? GetTemporalUnit(options, "largestUnit", time, "auto"). - auto largest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.largestUnit, UnitGroup::Time, { "auto"sv })); - - // 6. If largestUnit is "auto", set largestUnit to "hour". - if (largest_unit == "auto"sv) - largest_unit = "hour"sv; - - // 7. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception. - if (larger_of_two_temporal_units(*largest_unit, *smallest_unit) != largest_unit) - return vm.throw_completion(global_object, ErrorType::TemporalInvalidUnitRange, *smallest_unit, *largest_unit); - - // 8. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc"). - auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "trunc"sv)); - - // 9. If operation is since, then - if (operation == DifferenceOperation::Since) { - // a. Set roundingMode to ! NegateTemporalRoundingMode(roundingMode). - rounding_mode = negate_temporal_rounding_mode(rounding_mode); - } - - // 10. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit). - auto maximum = maximum_temporal_duration_rounding_increment(*smallest_unit); - - // 11. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false). - auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, Optional(maximum), false)); - - // 12. Let result be ! DifferenceTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], other.[[ISOHour]], other.[[ISOMinute]], other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]], other.[[ISONanosecond]]). + // 4. Let result be ! DifferenceTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], other.[[ISOHour]], other.[[ISOMinute]], other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]], other.[[ISONanosecond]]). auto result = difference_time(temporal_time.iso_hour(), temporal_time.iso_minute(), temporal_time.iso_second(), temporal_time.iso_millisecond(), temporal_time.iso_microsecond(), temporal_time.iso_nanosecond(), other->iso_hour(), other->iso_minute(), other->iso_second(), other->iso_millisecond(), other->iso_microsecond(), other->iso_nanosecond()); - // 13. Set result to (! RoundDuration(0, 0, 0, 0, result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode)).[[DurationRecord]]. - auto rounded_result = MUST(round_duration(global_object, 0, 0, 0, 0, result.hours, result.minutes, result.seconds, result.milliseconds, result.microseconds, result.nanoseconds, rounding_increment, *smallest_unit, rounding_mode)).duration_record; + // 5. Set result to (! RoundDuration(0, 0, 0, 0, result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]])).[[DurationRecord]]. + auto rounded_result = MUST(round_duration(global_object, 0, 0, 0, 0, result.hours, result.minutes, result.seconds, result.milliseconds, result.microseconds, result.nanoseconds, settings.rounding_increment, settings.smallest_unit, settings.rounding_mode)).duration_record; - // 14. Set result to ! BalanceDuration(0, result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]], largestUnit). - result = MUST(balance_duration(global_object, 0, rounded_result.hours, rounded_result.minutes, rounded_result.seconds, rounded_result.milliseconds, rounded_result.microseconds, Crypto::SignedBigInteger { (i32)rounded_result.nanoseconds }, *largest_unit)); + // 6. Set result to ! BalanceDuration(0, result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]], settings.[[LargestUnit]]). + result = MUST(balance_duration(global_object, 0, rounded_result.hours, rounded_result.minutes, rounded_result.seconds, rounded_result.milliseconds, rounded_result.microseconds, Crypto::SignedBigInteger { (i32)rounded_result.nanoseconds }, settings.largest_unit)); - // 15. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]). + // 7. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]). return MUST(create_temporal_duration(global_object, 0, 0, 0, 0, sign * result.hours, sign * result.minutes, sign * result.seconds, sign * result.milliseconds, sign * result.microseconds, sign * result.nanoseconds)); } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp index 6771c46fd9..af182edf29 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp @@ -264,79 +264,45 @@ ThrowCompletionOr difference_temporal_plain_year_month(GlobalObject& if (!TRY(calendar_equals(global_object, calendar, other->calendar()))) return vm.throw_completion(global_object, ErrorType::TemporalDifferentCalendars); - // 5. Set options to ? GetOptionsObject(options). - auto const* options = TRY(get_options_object(global_object, options_value)); + // 5. Let settings be ? GetDifferenceSettings(operation, options, date, « "week", "day" », "month", "year"). + auto settings = TRY(get_difference_settings(global_object, operation, options_value, UnitGroup::Date, { "week"sv, "day"sv }, { "month"sv }, "year"sv)); - // 6. Let smallestUnit be ? GetTemporalUnit(options, "smallestUnit", date, "month"). - auto smallest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.smallestUnit, UnitGroup::Date, { "month"sv })); - - // 7. If smallestUnit is "week" or "day", throw a RangeError exception. - if (smallest_unit == "week"sv || smallest_unit == "day"sv) - return vm.throw_completion(global_object, ErrorType::OptionIsNotValidValue, *smallest_unit, "smallestUnit"sv); - - // 8. Let largestUnit be ? GetTemporalUnit(options, "largestUnit", date, "auto"). - auto largest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.largestUnit, UnitGroup::Date, { "auto"sv })); - - // 9. If largestUnit is "week" or "day", throw a RangeError exception. - if (largest_unit == "week"sv || largest_unit == "day"sv) - return vm.throw_completion(global_object, ErrorType::OptionIsNotValidValue, *largest_unit, "largestUnit"sv); - - // 10. If largestUnit is "auto", set largestUnit to "year". - if (largest_unit == "auto"sv) - largest_unit = "year"sv; - - // 11. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception. - if (larger_of_two_temporal_units(*largest_unit, *smallest_unit) != largest_unit) - return vm.throw_completion(global_object, ErrorType::TemporalInvalidUnitRange, *smallest_unit, *largest_unit); - - // 12. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc"). - auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "trunc"sv)); - - // 13. If operation is since, then - if (operation == DifferenceOperation::Since) { - // a. Set roundingMode to ! NegateTemporalRoundingMode(roundingMode). - rounding_mode = negate_temporal_rounding_mode(rounding_mode); - } - - // 14. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, undefined, false). - auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, {}, false)); - - // 15. Let fieldNames be ? CalendarFields(calendar, « "monthCode", "year" »). + // 6. Let fieldNames be ? CalendarFields(calendar, « "monthCode", "year" »). auto field_names = TRY(calendar_fields(global_object, calendar, { "monthCode"sv, "year"sv })); - // 16. Let otherFields be ? PrepareTemporalFields(other, fieldNames, «»). + // 7. Let otherFields be ? PrepareTemporalFields(other, fieldNames, «»). auto* other_fields = TRY(prepare_temporal_fields(global_object, *other, field_names, Vector {})); - // 17. Perform ! CreateDataPropertyOrThrow(otherFields, "day", 1𝔽). + // 8. Perform ! CreateDataPropertyOrThrow(otherFields, "day", 1𝔽). MUST(other_fields->create_data_property_or_throw(vm.names.day, Value(1))); - // 18. Let otherDate be ? CalendarDateFromFields(calendar, otherFields). + // 9. Let otherDate be ? CalendarDateFromFields(calendar, otherFields). auto* other_date = TRY(calendar_date_from_fields(global_object, calendar, *other_fields)); - // 19. Let thisFields be ? PrepareTemporalFields(yearMonth, fieldNames, «»). + // 10. Let thisFields be ? PrepareTemporalFields(yearMonth, fieldNames, «»). auto* this_fields = TRY(prepare_temporal_fields(global_object, year_month, field_names, Vector {})); - // 20. Perform ! CreateDataPropertyOrThrow(thisFields, "day", 1𝔽). + // 11. Perform ! CreateDataPropertyOrThrow(thisFields, "day", 1𝔽). MUST(this_fields->create_data_property_or_throw(vm.names.day, Value(1))); - // 21. Let thisDate be ? CalendarDateFromFields(calendar, thisFields). + // 12. Let thisDate be ? CalendarDateFromFields(calendar, thisFields). auto* this_date = TRY(calendar_date_from_fields(global_object, calendar, *this_fields)); - // 22. Let untilOptions be ? MergeLargestUnitOption(options, largestUnit). - auto* until_options = TRY(merge_largest_unit_option(global_object, *options, *largest_unit)); + // 13. Let untilOptions be ? MergeLargestUnitOption(settings.[[Options]], settings.[[LargestUnit]]). + auto* until_options = TRY(merge_largest_unit_option(global_object, settings.options, settings.largest_unit)); - // 23. Let result be ? CalendarDateUntil(calendar, thisDate, otherDate, untilOptions). + // 14. Let result be ? CalendarDateUntil(calendar, thisDate, otherDate, untilOptions). auto* duration = TRY(calendar_date_until(global_object, calendar, this_date, other_date, *until_options)); auto result = DurationRecord { duration->years(), duration->months(), 0, 0, 0, 0, 0, 0, 0, 0 }; - // 24. If smallestUnit is not "month" or roundingIncrement ≠ 1, then - if (smallest_unit != "month"sv || rounding_increment != 1) { - // a. Set result to (? RoundDuration(result.[[Years]], result.[[Months]], 0, 0, 0, 0, 0, 0, 0, 0, roundingIncrement, smallestUnit, roundingMode, thisDate)).[[DurationRecord]]. - result = TRY(round_duration(global_object, result.years, result.months, 0, 0, 0, 0, 0, 0, 0, 0, rounding_increment, *smallest_unit, rounding_mode, this_date)).duration_record; + // 15. If settings.[[SmallestUnit]] is not "month" or settings.[[RoundingIncrement]] ≠ 1, then + if (settings.smallest_unit != "month"sv || settings.rounding_increment != 1) { + // a. Set result to (? RoundDuration(result.[[Years]], result.[[Months]], 0, 0, 0, 0, 0, 0, 0, 0, settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]], thisDate)).[[DurationRecord]]. + result = TRY(round_duration(global_object, result.years, result.months, 0, 0, 0, 0, 0, 0, 0, 0, settings.rounding_increment, settings.smallest_unit, settings.rounding_mode, this_date)).duration_record; } - // 25. Return ! CreateTemporalDuration(sign × result.[[Years]], sign × result.[[Months]], 0, 0, 0, 0, 0, 0, 0, 0). + // 16. Return ! CreateTemporalDuration(sign × result.[[Years]], sign × result.[[Months]], 0, 0, 0, 0, 0, 0, 0, 0). return MUST(create_temporal_duration(global_object, sign * result.years, sign * result.months, 0, 0, 0, 0, 0, 0, 0, 0)); } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp index 6195394bda..c86f76c7e8 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp @@ -568,74 +568,42 @@ ThrowCompletionOr difference_temporal_zoned_date_time(GlobalObject& g return vm.throw_completion(global_object, ErrorType::TemporalDifferentCalendars); } - // 4. Set options to ? GetOptionsObject(options). - auto const* options = TRY(get_options_object(global_object, options_value)); + // 4. Let settings be ? GetDifferenceSettings(operation, options, datetime, « », "nanosecond", "hour"). + auto settings = TRY(get_difference_settings(global_object, operation, options_value, UnitGroup::DateTime, {}, { "nanosecond"sv }, "hour"sv)); - // 5. Let smallestUnit be ? GetTemporalUnit(options, "smallestUnit", datetime, "nanosecond"). - auto smallest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.smallestUnit, UnitGroup::DateTime, { "nanosecond"sv })); - - // 6. Let defaultLargestUnit be ! LargerOfTwoTemporalUnits("hour", smallestUnit). - auto default_largest_unit = larger_of_two_temporal_units("hour"sv, *smallest_unit); - - // 7. Let largestUnit be ? GetTemporalUnit(options, "largestUnit", datetime, "auto"). - auto largest_unit = TRY(get_temporal_unit(global_object, *options, vm.names.largestUnit, UnitGroup::DateTime, { "auto"sv })); - - // 8. If largestUnit is "auto", set largestUnit to defaultLargestUnit. - if (largest_unit == "auto"sv) - largest_unit = default_largest_unit; - - // 9. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception. - if (larger_of_two_temporal_units(*largest_unit, *smallest_unit) != largest_unit) - return vm.throw_completion(global_object, ErrorType::TemporalInvalidUnitRange, *smallest_unit, *largest_unit); - - // 10. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc"). - auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "trunc"sv)); - - // 11. If operation is since, then - if (operation == DifferenceOperation::Since) { - // a. Set roundingMode to ! NegateTemporalRoundingMode(roundingMode). - rounding_mode = negate_temporal_rounding_mode(rounding_mode); - } - - // 12. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit). - auto maximum = maximum_temporal_duration_rounding_increment(*smallest_unit); - - // 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false). - auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, Optional(maximum), false)); - - // 14. If largestUnit is not one of "year", "month", "week", or "day", then - if (!largest_unit->is_one_of("year"sv, "month"sv, "week"sv, "day"sv)) { - // a. Let differenceNs be ! DifferenceInstant(zonedDateTime.[[Nanoseconds]], other.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode). - auto* difference_ns = difference_instant(global_object, zoned_date_time.nanoseconds(), other->nanoseconds(), rounding_increment, *smallest_unit, rounding_mode); + // 5. If settings.[[LargestUnit]] is not one of "year", "month", "week", or "day", then + if (!settings.largest_unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv)) { + // a. Let differenceNs be ! DifferenceInstant(zonedDateTime.[[Nanoseconds]], other.[[Nanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]). + auto* difference_ns = difference_instant(global_object, zoned_date_time.nanoseconds(), other->nanoseconds(), settings.rounding_increment, settings.smallest_unit, settings.rounding_mode); // b. Assert: The following steps cannot fail due to overflow in the Number domain because abs(differenceNs) ≤ 2 × nsMaxInstant. - // c. Let balanceResult be ! BalanceDuration(0, 0, 0, 0, 0, 0, differenceNs, largestUnit). - auto balance_result = MUST(balance_duration(global_object, 0, 0, 0, 0, 0, 0, difference_ns->big_integer(), *largest_unit)); + // c. Let balanceResult be ! BalanceDuration(0, 0, 0, 0, 0, 0, differenceNs, settings.[[LargestUnit]]). + auto balance_result = MUST(balance_duration(global_object, 0, 0, 0, 0, 0, 0, difference_ns->big_integer(), settings.largest_unit)); // d. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × balanceResult.[[Hours]], sign × balanceResult.[[Minutes]], sign × balanceResult.[[Seconds]], sign × balanceResult.[[Milliseconds]], sign × balanceResult.[[Microseconds]], sign × balanceResult.[[Nanoseconds]]). return MUST(create_temporal_duration(global_object, 0, 0, 0, 0, sign * balance_result.hours, sign * balance_result.minutes, sign * balance_result.seconds, sign * balance_result.milliseconds, sign * balance_result.microseconds, sign * balance_result.nanoseconds)); } - // 15. If ? TimeZoneEquals(zonedDateTime.[[TimeZone]], other.[[TimeZone]]) is false, then + // 6. If ? TimeZoneEquals(zonedDateTime.[[TimeZone]], other.[[TimeZone]]) is false, then if (!TRY(time_zone_equals(global_object, zoned_date_time.time_zone(), other->time_zone()))) { // a. Throw a RangeError exception. return vm.throw_completion(global_object, ErrorType::TemporalDifferentTimeZones); } - // 16. Let untilOptions be ? MergeLargestUnitOption(options, largestUnit). - auto* until_options = TRY(merge_largest_unit_option(global_object, *options, *largest_unit)); + // 7. Let untilOptions be ? MergeLargestUnitOption(settings.[[Options]], settings.[[LargestUnit]]). + auto* until_options = TRY(merge_largest_unit_option(global_object, settings.options, settings.largest_unit)); - // 17. Let difference be ? DifferenceZonedDateTime(zonedDateTime.[[Nanoseconds]], other.[[Nanoseconds]], zonedDateTime.[[TimeZone]], zonedDateTime.[[Calendar]], largestUnit, untilOptions). - auto difference = TRY(difference_zoned_date_time(global_object, zoned_date_time.nanoseconds(), other->nanoseconds(), zoned_date_time.time_zone(), zoned_date_time.calendar(), *largest_unit, *until_options)); + // 8. Let difference be ? DifferenceZonedDateTime(zonedDateTime.[[Nanoseconds]], other.[[Nanoseconds]], zonedDateTime.[[TimeZone]], zonedDateTime.[[Calendar]], settings.[[LargestUnit]], untilOptions). + auto difference = TRY(difference_zoned_date_time(global_object, zoned_date_time.nanoseconds(), other->nanoseconds(), zoned_date_time.time_zone(), zoned_date_time.calendar(), settings.largest_unit, *until_options)); - // 18. Let roundResult be (? RoundDuration(difference.[[Years]], difference.[[Months]], difference.[[Weeks]], difference.[[Days]], difference.[[Hours]], difference.[[Minutes]], difference.[[Seconds]], difference.[[Milliseconds]], difference.[[Microseconds]], difference.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode, zonedDateTime)).[[DurationRecord]]. - auto round_result = TRY(round_duration(global_object, difference.years, difference.months, difference.weeks, difference.days, difference.hours, difference.minutes, difference.seconds, difference.milliseconds, difference.microseconds, difference.nanoseconds, rounding_increment, *smallest_unit, rounding_mode, &zoned_date_time)).duration_record; + // 9. Let roundResult be (? RoundDuration(difference.[[Years]], difference.[[Months]], difference.[[Weeks]], difference.[[Days]], difference.[[Hours]], difference.[[Minutes]], difference.[[Seconds]], difference.[[Milliseconds]], difference.[[Microseconds]], difference.[[Nanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]], zonedDateTime)).[[DurationRecord]]. + auto round_result = TRY(round_duration(global_object, difference.years, difference.months, difference.weeks, difference.days, difference.hours, difference.minutes, difference.seconds, difference.milliseconds, difference.microseconds, difference.nanoseconds, settings.rounding_increment, settings.smallest_unit, settings.rounding_mode, &zoned_date_time)).duration_record; - // 19. Let result 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, zonedDateTime). - auto result = TRY(adjust_rounded_duration_days(global_object, 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, &zoned_date_time)); + // 10. Let result be ? AdjustRoundedDurationDays(roundResult.[[Years]], roundResult.[[Months]], roundResult.[[Weeks]], roundResult.[[Days]], roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]], roundResult.[[Nanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]], zonedDateTime). + auto result = TRY(adjust_rounded_duration_days(global_object, 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, settings.rounding_increment, settings.smallest_unit, settings.rounding_mode, &zoned_date_time)); - // 20. Return ! CreateTemporalDuration(sign × result.[[Years]], sign × result.[[Months]], sign × result.[[Weeks]], sign × result.[[Days]], sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]). + // 11. Return ! CreateTemporalDuration(sign × result.[[Years]], sign × result.[[Months]], sign × result.[[Weeks]], sign × result.[[Days]], sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]). return MUST(create_temporal_duration(global_object, sign * result.years, sign * result.months, sign * result.weeks, sign * result.days, sign * result.hours, sign * result.minutes, sign * result.seconds, sign * result.milliseconds, sign * result.microseconds, sign * result.nanoseconds)); }