|
@@ -1,6 +1,7 @@
|
|
|
/*
|
|
|
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
|
|
|
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
|
|
|
+ * Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
|
|
|
*
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
*/
|
|
@@ -1188,321 +1189,371 @@ ThrowCompletionOr<ZonedDateTime*> move_relative_zoned_date_time(VM& vm, ZonedDat
|
|
|
return MUST(create_temporal_zoned_date_time(vm, *intermediate_ns, zoned_date_time.time_zone(), zoned_date_time.calendar()));
|
|
|
}
|
|
|
|
|
|
-// 7.5.25 RoundDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, increment, unit, roundingMode [ , relativeTo ] ), https://tc39.es/proposal-temporal/#sec-temporal-roundduration
|
|
|
-ThrowCompletionOr<RoundedDuration> round_duration(VM& vm, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, u32 increment, StringView unit, StringView rounding_mode, Object* relative_to_object)
|
|
|
+// 7.5.27 RoundDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, increment, unit, roundingMode [ , plainRelativeTo [ , calendarRec [ , zonedRelativeTo [ , timeZoneRec [ , precalculatedPlainDateTime ] ] ] ] ] ), https://tc39.es/proposal-temporal/#sec-temporal-roundduration
|
|
|
+// FIXME: Support calendarRec, zonedRelativeTo, timeZoneRec, precalculatedPlainDateTime
|
|
|
+ThrowCompletionOr<RoundedDuration> round_duration(VM& vm, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, u32 increment, StringView unit, StringView rounding_mode, Object* plain_relative_to_object)
|
|
|
{
|
|
|
auto& realm = *vm.current_realm();
|
|
|
|
|
|
- Object* calendar = nullptr;
|
|
|
+ Object* calendar = nullptr; // FIXME: Should come from calendarRec
|
|
|
+
|
|
|
double fractional_seconds = 0;
|
|
|
+ double fractional_days = 0;
|
|
|
|
|
|
- // 1. If relativeTo is not present, set relativeTo to undefined.
|
|
|
- // NOTE: `relative_to_object` and `relative_to` in the various code paths below are all the same as far as the
|
|
|
- // spec is concerned, but the latter is more strictly typed for convenience.
|
|
|
- PlainDate* relative_to = nullptr;
|
|
|
+ // FIXME: 1. Assert: If either of plainRelativeTo or zonedRelativeTo are present and not undefined, calendarRec is not undefined.
|
|
|
+ // FIXME: 2. Assert: If zonedRelativeTo is present and not undefined, timeZoneRec is not undefined.
|
|
|
+
|
|
|
+ // 3. If plainRelativeTo is not present, set plainRelativeTo to undefined.
|
|
|
+ // NOTE: `plain_relative_to_object` and `plain_relative_to` in the various code paths below are all the same as far as the
|
|
|
+ // spec is concerned, but the latter is more strictly typed for convenience.
|
|
|
+ PlainDate* plain_relative_to = nullptr;
|
|
|
+
|
|
|
+ // FIXME: 4. If zonedRelativeTo is not present, set zonedRelativeTo to undefined.
|
|
|
+ ZonedDateTime* zoned_relative_to = nullptr;
|
|
|
+
|
|
|
+ // FIXME: 5. If precalculatedPlainDateTime is not present, set precalculatedPlainDateTime to undefined.
|
|
|
|
|
|
// FIXME: assuming "smallestUnit" as the option name here leads to confusing error messages in some cases:
|
|
|
// > new Temporal.Duration().total({ unit: "month" })
|
|
|
// Uncaught exception: [RangeError] month is not a valid value for option smallestUnit
|
|
|
- // 2. If unit is "year", "month", or "week", and relativeTo is undefined, then
|
|
|
- if (unit.is_one_of("year"sv, "month"sv, "week"sv) && !relative_to_object) {
|
|
|
- // a. Throw a RangeError exception.
|
|
|
- return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, unit, "smallestUnit"sv);
|
|
|
+ // 6. If unit is "year", "month", or "week", then
|
|
|
+ if (unit.is_one_of("year"sv, "month"sv, "week"sv)) {
|
|
|
+ // a. If plainRelativeTo is undefined, throw a RangeError exception.
|
|
|
+ if (!plain_relative_to_object)
|
|
|
+ return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, unit, "smallestUnit"sv);
|
|
|
+
|
|
|
+ // FIXME: b. Assert: CalendarMethodsRecordHasLookedUp(calendarRec, dateAdd) is true.
|
|
|
+ // FIXME: c. Assert: CalendarMethodsRecordHasLookedUp(calendarRec, dateUntil) is true.
|
|
|
}
|
|
|
|
|
|
- // 3. Let zonedRelativeTo be undefined.
|
|
|
- ZonedDateTime* zoned_relative_to = nullptr;
|
|
|
-
|
|
|
- // 4. If relativeTo is not undefined, then
|
|
|
- if (relative_to_object) {
|
|
|
- // a. If relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot, then
|
|
|
- if (is<ZonedDateTime>(relative_to_object)) {
|
|
|
- auto* relative_to_zoned_date_time = static_cast<ZonedDateTime*>(relative_to_object);
|
|
|
-
|
|
|
- // i. Set zonedRelativeTo to relativeTo.
|
|
|
+ // FIXME: AD-HOC, should be coming from arguments given to this function.
|
|
|
+ if (plain_relative_to_object) {
|
|
|
+ if (is<ZonedDateTime>(plain_relative_to_object)) {
|
|
|
+ auto* relative_to_zoned_date_time = static_cast<ZonedDateTime*>(plain_relative_to_object);
|
|
|
zoned_relative_to = relative_to_zoned_date_time;
|
|
|
-
|
|
|
- // ii. Set relativeTo to ? ToTemporalDate(relativeTo).
|
|
|
- relative_to = TRY(to_temporal_date(vm, relative_to_object));
|
|
|
+ plain_relative_to = TRY(to_temporal_date(vm, plain_relative_to_object));
|
|
|
+ } else {
|
|
|
+ VERIFY(is<PlainDate>(plain_relative_to_object));
|
|
|
+ plain_relative_to = verify_cast<PlainDate>(plain_relative_to_object);
|
|
|
}
|
|
|
- // b. Else,
|
|
|
- else {
|
|
|
- // i. Assert: relativeTo has an [[InitializedTemporalDate]] internal slot.
|
|
|
- VERIFY(is<PlainDate>(relative_to_object));
|
|
|
-
|
|
|
- relative_to = static_cast<PlainDate*>(relative_to_object);
|
|
|
- }
|
|
|
-
|
|
|
- // c. Let calendar be relativeTo.[[Calendar]].
|
|
|
- calendar = &relative_to->calendar();
|
|
|
+ calendar = &plain_relative_to->calendar();
|
|
|
}
|
|
|
- // 5. Else,
|
|
|
- // a. NOTE: calendar will not be used below.
|
|
|
|
|
|
- // 6. If unit is one of "year", "month", "week", or "day", then
|
|
|
+ // 7. If unit is one of "year", "month", "week", or "day", then
|
|
|
if (unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv)) {
|
|
|
- // a. Let nanoseconds be ! TotalDurationNanoseconds(0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, 0).
|
|
|
- auto nanoseconds_bigint = total_duration_nanoseconds(0, hours, minutes, seconds, milliseconds, microseconds, Crypto::SignedBigInteger { nanoseconds }, 0);
|
|
|
|
|
|
- // b. Let intermediate be undefined.
|
|
|
- ZonedDateTime* intermediate = nullptr;
|
|
|
+ // a. Let nanoseconds be TotalDurationNanoseconds(hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
|
|
|
+ // FIXME: We shouldn't be passing through 0 days and 0 offset digit
|
|
|
+ auto nanoseconds_bigint = total_duration_nanoseconds(0, hours, minutes, seconds, milliseconds, microseconds, Crypto::SignedBigInteger { nanoseconds }, 0);
|
|
|
|
|
|
- // c. If zonedRelativeTo is not undefined, then
|
|
|
+ // b. If zonedRelativeTo is not undefined, then
|
|
|
if (zoned_relative_to) {
|
|
|
- // i. Let intermediate be ? MoveRelativeZonedDateTime(zonedRelativeTo, years, months, weeks, days).
|
|
|
- intermediate = TRY(move_relative_zoned_date_time(vm, *zoned_relative_to, years, months, weeks, days));
|
|
|
- }
|
|
|
+ // i. Let intermediate be ? MoveRelativeZonedDateTime(zonedRelativeTo, calendarRec, timeZoneRec, years, months, weeks, days, precalculatedPlainDateTime).
|
|
|
+ // FIXME: Pass through calendarRecord, timeZoneRec and precalculatedPlainDateTime
|
|
|
+ auto* intermediate = TRY(move_relative_zoned_date_time(vm, *zoned_relative_to, years, months, weeks, days));
|
|
|
|
|
|
- // d. Let result be ? NanosecondsToDays(nanoseconds, intermediate).
|
|
|
- auto result = TRY(nanoseconds_to_days(vm, nanoseconds_bigint, intermediate));
|
|
|
+ // ii. Let result be ? NanosecondsToDays(nanoseconds, intermediate, timeZoneRec).
|
|
|
+ // FIXME: Pass through timeZoneRec
|
|
|
+ auto result = TRY(nanoseconds_to_days(vm, nanoseconds_bigint, intermediate));
|
|
|
|
|
|
- // e. Set days to days + result.[[Days]] + result.[[Nanoseconds]] / result.[[DayLength]].
|
|
|
- auto nanoseconds_division_result = result.nanoseconds.divided_by(Crypto::UnsignedBigInteger { result.day_length });
|
|
|
- days += result.days + nanoseconds_division_result.quotient.to_double() + nanoseconds_division_result.remainder.to_double() / result.day_length;
|
|
|
+ // iii. Let fractionalDays be days + result.[[Days]] + result.[[Nanoseconds]] / result.[[DayLength]].
|
|
|
+ auto nanoseconds_division_result = result.nanoseconds.divided_by(Crypto::UnsignedBigInteger { result.day_length });
|
|
|
+ fractional_days = days + result.days + nanoseconds_division_result.quotient.to_double() + nanoseconds_division_result.remainder.to_double() / result.day_length;
|
|
|
+ }
|
|
|
+ // c. Else,
|
|
|
+ else {
|
|
|
+ // i. Let fractionalDays be days + nanoseconds / nsPerDay.
|
|
|
+ auto nanoseconds_division_result = nanoseconds_bigint.divided_by(ns_per_day_bigint);
|
|
|
+ fractional_days = days + nanoseconds_division_result.quotient.to_double() + (nanoseconds_division_result.remainder.to_double() / ns_per_day);
|
|
|
+ }
|
|
|
|
|
|
- // f. Set hours, minutes, seconds, milliseconds, microseconds, and nanoseconds to 0.
|
|
|
+ // d. Set days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds to 0.
|
|
|
+ days = 0;
|
|
|
hours = 0;
|
|
|
minutes = 0;
|
|
|
seconds = 0;
|
|
|
milliseconds = 0;
|
|
|
microseconds = 0;
|
|
|
nanoseconds = 0;
|
|
|
+
|
|
|
+ // e. Assert: fractionalSeconds is not used below.
|
|
|
}
|
|
|
- // 7. Else,
|
|
|
+ // 8. Else,
|
|
|
else {
|
|
|
// a. Let fractionalSeconds be nanoseconds × 10^-9 + microseconds × 10^-6 + milliseconds × 10^-3 + seconds.
|
|
|
fractional_seconds = nanoseconds * 0.000000001 + microseconds * 0.000001 + milliseconds * 0.001 + seconds;
|
|
|
+
|
|
|
+ // b. Assert: fractionalDays is not used below.
|
|
|
}
|
|
|
|
|
|
- // 8. Let remainder be undefined.
|
|
|
- double remainder = 0;
|
|
|
+ // 9. Let total be unset.
|
|
|
+ double total = 0;
|
|
|
|
|
|
- // 9. If unit is "year", then
|
|
|
+ // 10. If unit is "year", then
|
|
|
if (unit == "year"sv) {
|
|
|
- VERIFY(relative_to);
|
|
|
+ VERIFY(plain_relative_to);
|
|
|
|
|
|
// a. Let yearsDuration be ! CreateTemporalDuration(years, 0, 0, 0, 0, 0, 0, 0, 0, 0).
|
|
|
auto* years_duration = MUST(create_temporal_duration(vm, years, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
- // b. Let dateAdd be ? GetMethod(calendar, "dateAdd").
|
|
|
+ // FIXME: b. Let yearsLater be ? AddDate(calendarRec, plainRelativeTo, yearsDuration).
|
|
|
auto date_add = TRY(Value(calendar).get_method(vm, vm.names.dateAdd));
|
|
|
+ auto* years_later = TRY(calendar_date_add(vm, *calendar, plain_relative_to, *years_duration, nullptr, date_add));
|
|
|
|
|
|
- // c. Let yearsLater be ? CalendarDateAdd(calendar, relativeTo, yearsDuration, undefined, dateAdd).
|
|
|
- auto* years_later = TRY(calendar_date_add(vm, *calendar, relative_to, *years_duration, nullptr, date_add));
|
|
|
-
|
|
|
- // d. Let yearsMonthsWeeks be ! CreateTemporalDuration(years, months, weeks, 0, 0, 0, 0, 0, 0, 0).
|
|
|
+ // c. Let yearsMonthsWeeks be ! CreateTemporalDuration(years, months, weeks, 0, 0, 0, 0, 0, 0, 0).
|
|
|
auto* years_months_weeks = MUST(create_temporal_duration(vm, years, months, weeks, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
- // e. Let yearsMonthsWeeksLater be ? CalendarDateAdd(calendar, relativeTo, yearsMonthsWeeks, undefined, dateAdd).
|
|
|
- auto* years_months_weeks_later = TRY(calendar_date_add(vm, *calendar, relative_to, *years_months_weeks, nullptr, date_add));
|
|
|
+ // FIXME: d. Let yearsMonthsWeeksLater be ? AddDate(calendarRec, plainRelativeTo, yearsMonthsWeeks).
|
|
|
+ auto* years_months_weeks_later = TRY(calendar_date_add(vm, *calendar, plain_relative_to, *years_months_weeks, nullptr, date_add));
|
|
|
|
|
|
- // f. Let monthsWeeksInDays be DaysUntil(yearsLater, yearsMonthsWeeksLater).
|
|
|
+ // e. Let monthsWeeksInDays be DaysUntil(yearsLater, yearsMonthsWeeksLater).
|
|
|
auto months_weeks_in_days = days_until(*years_later, *years_months_weeks_later);
|
|
|
|
|
|
- // g. Set relativeTo to yearsLater.
|
|
|
- relative_to = years_later;
|
|
|
+ // f. Set plainRelativeTo to yearsLater.
|
|
|
+ plain_relative_to = years_later;
|
|
|
|
|
|
- // h. Let days be days + monthsWeeksInDays.
|
|
|
- days += months_weeks_in_days;
|
|
|
+ // g. Set fractionalDays to fractionalDays + monthsWeeksInDays.
|
|
|
+ fractional_days = fractional_days + months_weeks_in_days;
|
|
|
|
|
|
- // i. Let wholeDaysDuration be ? CreateTemporalDuration(0, 0, 0, truncate(days), 0, 0, 0, 0, 0, 0).
|
|
|
- auto* whole_days_duration = TRY(create_temporal_duration(vm, 0, 0, 0, trunc(days), 0, 0, 0, 0, 0, 0));
|
|
|
+ // h. Let isoResult be ! AddISODate(plainRelativeTo.[[ISOYear]]. plainRelativeTo.[[ISOMonth]], plainRelativeTo.[[ISODay]], 0, 0, 0, truncate(fractionalDays), "constrain").
|
|
|
+ auto iso_result = MUST(add_iso_date(vm, plain_relative_to->iso_year(), plain_relative_to->iso_month(), plain_relative_to->iso_day(), 0, 0, 0, trunc(fractional_days), "constrain"sv));
|
|
|
|
|
|
- // j. Let wholeDaysLater be ? CalendarDateAdd(calendar, relativeTo, wholeDaysDuration, undefined, dateAdd).
|
|
|
- auto* whole_days_later = TRY(calendar_date_add(vm, *calendar, relative_to, *whole_days_duration, nullptr, date_add));
|
|
|
+ // i. Let wholeDaysLater be ? CreateTemporalDate(isoResult.[[Year]], isoResult.[[Month]], isoResult.[[Day]], calendarRec.[[Receiver]]).
|
|
|
+ // FIXME: Pass through receiver from calendarRec
|
|
|
+ auto* whole_days_later = TRY(create_temporal_date(vm, iso_result.year, iso_result.month, iso_result.day, *calendar));
|
|
|
|
|
|
- // k. Let untilOptions be OrdinaryObjectCreate(null).
|
|
|
+ // j. Let untilOptions be OrdinaryObjectCreate(null).
|
|
|
auto until_options = Object::create(realm, nullptr);
|
|
|
|
|
|
- // l. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "year").
|
|
|
+ // k. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "year").
|
|
|
MUST(until_options->create_data_property_or_throw(vm.names.largestUnit, PrimitiveString::create(vm, "year"_string)));
|
|
|
|
|
|
- // m. Let timePassed be ? CalendarDateUntil(calendar, relativeTo, wholeDaysLater, untilOptions).
|
|
|
- auto* time_passed = TRY(calendar_date_until(vm, *calendar, relative_to, whole_days_later, *until_options));
|
|
|
+ // l. Let timePassed be ? DifferenceDate(calendarRec, plainRelativeTo, wholeDaysLater, untilOptions).
|
|
|
+ // FIXME: Pass through calendarRec
|
|
|
+ auto time_passed = TRY(difference_date(vm, *calendar, *plain_relative_to, *whole_days_later, *until_options));
|
|
|
|
|
|
- // n. Let yearsPassed be timePassed.[[Years]].
|
|
|
+ // m. Let yearsPassed be timePassed.[[Years]].
|
|
|
auto years_passed = time_passed->years();
|
|
|
|
|
|
- // o. Set years to years + yearsPassed.
|
|
|
+ // n. Set years to years + yearsPassed.
|
|
|
years += years_passed;
|
|
|
|
|
|
- // p. Let oldRelativeTo be relativeTo.
|
|
|
- auto* old_relative_to = relative_to;
|
|
|
-
|
|
|
- // q. Let yearsDuration be ! CreateTemporalDuration(yearsPassed, 0, 0, 0, 0, 0, 0, 0, 0, 0).
|
|
|
+ // o. Let yearsDuration be ! CreateTemporalDuration(yearsPassed, 0, 0, 0, 0, 0, 0, 0, 0, 0).
|
|
|
years_duration = MUST(create_temporal_duration(vm, years_passed, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
- // r. Set relativeTo to ? CalendarDateAdd(calendar, relativeTo, yearsDuration, undefined, dateAdd).
|
|
|
- relative_to = TRY(calendar_date_add(vm, *calendar, relative_to, *years_duration, nullptr, date_add));
|
|
|
+ // p. Let moveResult be ? MoveRelativeDate(calendarRec, plainRelativeTo, yearsDuration).
|
|
|
+ // FIXME: Pass through calendarRec instead of date_add
|
|
|
+ auto move_result = TRY(move_relative_date(vm, *calendar, *plain_relative_to, *years_duration, date_add));
|
|
|
|
|
|
- // s. Let daysPassed be DaysUntil(oldRelativeTo, relativeTo).
|
|
|
- auto days_passed = days_until(*old_relative_to, *relative_to);
|
|
|
+ // q. Set plainRelativeTo to moveResult.[[RelativeTo]].
|
|
|
+ auto plain_relative_to = move_result.relative_to;
|
|
|
|
|
|
- // t. Set days to days - daysPassed.
|
|
|
- days -= days_passed;
|
|
|
+ // r. Let daysPassed be moveResult.[[Days]].
|
|
|
+ auto days_passed = move_result.days;
|
|
|
|
|
|
- // u. If days < 0, let sign be -1; else, let sign be 1.
|
|
|
- auto sign = days < 0 ? -1 : 1;
|
|
|
+ // s. Set fractionalDays to fractionalDays - daysPassed.
|
|
|
+ fractional_days -= days_passed;
|
|
|
|
|
|
- // v. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0, 0).
|
|
|
+ // t. If fractionalDays < 0, let sign be -1; else, let sign be 1.
|
|
|
+ auto sign = fractional_days < 0 ? -1 : 1;
|
|
|
+
|
|
|
+ // u. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0, 0).
|
|
|
auto* one_year = MUST(create_temporal_duration(vm, sign, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
- // w. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear, dateAdd).
|
|
|
- auto move_result = TRY(move_relative_date(vm, *calendar, *relative_to, *one_year, date_add));
|
|
|
+ // v. Set moveResult to ? MoveRelativeDate(calendarRec, plainRelativeTo, oneYear).
|
|
|
+ // FIXME:: pass through calendarRec
|
|
|
+ move_result = TRY(move_relative_date(vm, *calendar, *plain_relative_to, *one_year, date_add));
|
|
|
|
|
|
- // x. Let oneYearDays be moveResult.[[Days]].
|
|
|
+ // w. Let oneYearDays be moveResult.[[Days]].
|
|
|
auto one_year_days = move_result.days;
|
|
|
|
|
|
- // y. Let fractionalYears be years + days / abs(oneYearDays).
|
|
|
- auto fractional_years = years + days / fabs(one_year_days);
|
|
|
+ // x. If oneYearDays = 0, throw a RangeError exception.
|
|
|
+ if (one_year_days == 0)
|
|
|
+ return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidCalendarFunctionResult, "dateAdd", "result implying a year is zero days long");
|
|
|
+
|
|
|
+ // y. Let fractionalYears be years + fractionalDays / abs(oneYearDays).
|
|
|
+ auto fractional_years = years + fractional_days / fabs(one_year_days);
|
|
|
|
|
|
// z. Set years to RoundNumberToIncrement(fractionalYears, increment, roundingMode).
|
|
|
years = round_number_to_increment(fractional_years, increment, rounding_mode);
|
|
|
|
|
|
- // aa. Set remainder to fractionalYears - years.
|
|
|
- remainder = fractional_years - years;
|
|
|
+ // aa. Set total to fractionalYears.
|
|
|
+ total = fractional_years;
|
|
|
|
|
|
- // ab. Set months, weeks, and days to 0.
|
|
|
+ // ab. Set months and weeks to 0.
|
|
|
months = 0;
|
|
|
weeks = 0;
|
|
|
- days = 0;
|
|
|
}
|
|
|
// 10. Else if unit is "month", then
|
|
|
else if (unit == "month"sv) {
|
|
|
- VERIFY(relative_to);
|
|
|
+ VERIFY(plain_relative_to);
|
|
|
|
|
|
// a. Let yearsMonths be ! CreateTemporalDuration(years, months, 0, 0, 0, 0, 0, 0, 0, 0).
|
|
|
auto* years_months = MUST(create_temporal_duration(vm, years, months, 0, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
- // b. Let dateAdd be ? GetMethod(calendar, "dateAdd").
|
|
|
+ // FIXME: b. Let yearsMonthsLater be ? AddDate(calendarRec, plainRelativeTo, yearsMonths).
|
|
|
auto date_add = TRY(Value(calendar).get_method(vm, vm.names.dateAdd));
|
|
|
+ auto* years_months_later = TRY(calendar_date_add(vm, *calendar, plain_relative_to, *years_months, nullptr, date_add));
|
|
|
|
|
|
- // c. Let yearsMonthsLater be ? CalendarDateAdd(calendar, relativeTo, yearsMonths, undefined, dateAdd).
|
|
|
- auto* years_months_later = TRY(calendar_date_add(vm, *calendar, relative_to, *years_months, nullptr, date_add));
|
|
|
-
|
|
|
- // d. Let yearsMonthsWeeks be ! CreateTemporalDuration(years, months, weeks, 0, 0, 0, 0, 0, 0, 0).
|
|
|
+ // c. Let yearsMonthsWeeks be ! CreateTemporalDuration(years, months, weeks, 0, 0, 0, 0, 0, 0, 0).
|
|
|
auto* years_months_weeks = MUST(create_temporal_duration(vm, years, months, weeks, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
- // e. Let yearsMonthsWeeksLater be ? CalendarDateAdd(calendar, relativeTo, yearsMonthsWeeks, undefined, dateAdd).
|
|
|
- auto* years_months_weeks_later = TRY(calendar_date_add(vm, *calendar, relative_to, *years_months_weeks, nullptr, date_add));
|
|
|
+ // FIXME: d. Let yearsMonthsWeeksLater be ? AddDate(calendarRec, plainRelativeTo, yearsMonthsWeeks).
|
|
|
+ auto* years_months_weeks_later = TRY(calendar_date_add(vm, *calendar, plain_relative_to, *years_months_weeks, nullptr, date_add));
|
|
|
|
|
|
- // f. Let weeksInDays be DaysUntil(yearsMonthsLater, yearsMonthsWeeksLater).
|
|
|
+ // e. Let weeksInDays be DaysUntil(yearsMonthsLater, yearsMonthsWeeksLater).
|
|
|
auto weeks_in_days = days_until(*years_months_later, *years_months_weeks_later);
|
|
|
|
|
|
- // g. Set relativeTo to yearsMonthsLater.
|
|
|
- relative_to = years_months_later;
|
|
|
+ // f. Set plainRelativeTo to yearsMonthsLater.
|
|
|
+ plain_relative_to = years_months_later;
|
|
|
|
|
|
- // h. Let days be days + weeksInDays.
|
|
|
- days += weeks_in_days;
|
|
|
+ // g. Set fractionalDays to fractionalDays + weeksInDays.
|
|
|
+ fractional_days += weeks_in_days;
|
|
|
|
|
|
- // i. If days < 0, let sign be -1; else, let sign be 1.
|
|
|
- auto sign = days < 0 ? -1 : 1;
|
|
|
+ // h. Let isoResult be ! AddISODate(plainRelativeTo.[[ISOYear]], plainRelativeTo.[[ISOMonth]], plainRelativeTo.[[ISODay]], 0, 0, 0, truncate(fractionalDays), "constrain").
|
|
|
+ auto iso_result = MUST(add_iso_date(vm, plain_relative_to->iso_year(), plain_relative_to->iso_month(), plain_relative_to->iso_day(), 0, 0, 0, trunc(fractional_days), "constrain"sv));
|
|
|
|
|
|
- // j. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0, 0).
|
|
|
- auto* one_month = MUST(create_temporal_duration(vm, 0, sign, 0, 0, 0, 0, 0, 0, 0, 0));
|
|
|
+ // i. Let wholeDaysLater be ? CreateTemporalDate(isoResult.[[Year]], isoResult.[[Month]], isoResult.[[Day]], calendarRec.[[Receiver]]).
|
|
|
+ // FIXME: Pass through calendarRec
|
|
|
+ auto* whole_days_later = TRY(create_temporal_date(vm, iso_result.year, iso_result.month, iso_result.day, *calendar)); // FIXME: receiver
|
|
|
|
|
|
- // k. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd).
|
|
|
- auto move_result = TRY(move_relative_date(vm, *calendar, *relative_to, *one_month, date_add));
|
|
|
+ // j. Let untilOptions be OrdinaryObjectCreate(null).
|
|
|
+ auto until_options = Object::create(realm, nullptr);
|
|
|
|
|
|
- // l. Set relativeTo to moveResult.[[RelativeTo]].
|
|
|
- relative_to = move_result.relative_to.cell();
|
|
|
+ // k. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "month").
|
|
|
+ MUST(until_options->create_data_property_or_throw(vm.names.largestUnit, PrimitiveString::create(vm, "month"_string)));
|
|
|
|
|
|
- // m. Let oneMonthDays be moveResult.[[Days]].
|
|
|
- auto one_month_days = move_result.days;
|
|
|
+ // l. Let timePassed be ? DifferenceDate(calendarRec, plainRelativeTo, wholeDaysLater, untilOptions).
|
|
|
+ // FIXME: Pass through receiver from calendarRec
|
|
|
+ auto time_passed = TRY(difference_date(vm, *calendar, *plain_relative_to, *whole_days_later, *until_options));
|
|
|
|
|
|
- // n. Repeat, while abs(days) ≥ abs(oneMonthDays),
|
|
|
- while (fabs(days) >= fabs(one_month_days)) {
|
|
|
- // i. Set months to months + sign.
|
|
|
- months += sign;
|
|
|
+ // m. Let monthsPassed be timePassed.[[Months]].
|
|
|
+ auto months_passed = time_passed->months();
|
|
|
|
|
|
- // ii. Set days to days - oneMonthDays.
|
|
|
- days -= one_month_days;
|
|
|
+ // n. Set months to months + monthsPassed.
|
|
|
+ months += months_passed;
|
|
|
|
|
|
- // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd).
|
|
|
- move_result = TRY(move_relative_date(vm, *calendar, *relative_to, *one_month, date_add));
|
|
|
+ // o. Let monthsPassedDuration be ! CreateTemporalDuration(0, monthsPassed, 0, 0, 0, 0, 0, 0, 0, 0).
|
|
|
+ auto* months_passed_duration = MUST(create_temporal_duration(vm, 0, months_passed, 0, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
- // iv. Set relativeTo to moveResult.[[RelativeTo]].
|
|
|
- relative_to = move_result.relative_to.cell();
|
|
|
+ // p. Let moveResult be ? MoveRelativeDate(calendarRec, plainRelativeTo, monthsPassedDuration).
|
|
|
+ // FIXME: Pass through calendarRec
|
|
|
+ auto move_result = TRY(move_relative_date(vm, *calendar, *plain_relative_to, *months_passed_duration, date_add));
|
|
|
|
|
|
- // v. Set oneMonthDays to moveResult.[[Days]].
|
|
|
- one_month_days = move_result.days;
|
|
|
- }
|
|
|
+ // q. Set plainRelativeTo to moveResult.[[RelativeTo]].
|
|
|
+ plain_relative_to = move_result.relative_to;
|
|
|
+
|
|
|
+ // r. Let daysPassed be moveResult.[[Days]].
|
|
|
+ auto days_passed = move_result.days;
|
|
|
+
|
|
|
+ // s. Set fractionalDays to fractionalDays - daysPassed.
|
|
|
+ fractional_days -= days_passed;
|
|
|
|
|
|
- // o. Let fractionalMonths be months + days / abs(oneMonthDays).
|
|
|
- auto fractional_months = months + days / fabs(one_month_days);
|
|
|
+ // t. If fractionalDays < 0, let sign be -1; else, let sign be 1.
|
|
|
+ auto sign = fractional_days < 0 ? -1 : 1;
|
|
|
+
|
|
|
+ // u. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0, 0).
|
|
|
+ auto* one_month = MUST(create_temporal_duration(vm, 0, sign, 0, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
- // p. Set months to RoundNumberToIncrement(fractionalMonths, increment, roundingMode).
|
|
|
+ // v. Let moveResult be ? MoveRelativeDate(calendarRec, plainRelativeTo, oneMonth).
|
|
|
+ // FIXME: spec bug, this should be set.
|
|
|
+ move_result = TRY(move_relative_date(vm, *calendar, *plain_relative_to, *one_month, date_add));
|
|
|
+
|
|
|
+ // w. Let oneMonthDays be moveResult.[[Days]].
|
|
|
+ auto one_month_days = move_result.days;
|
|
|
+
|
|
|
+ // x. If oneMonthDays = 0, throw a RangeError exception.
|
|
|
+ if (one_month_days == 0)
|
|
|
+ return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidCalendarFunctionResult, "dateAdd", "result implying a month is zero days long");
|
|
|
+
|
|
|
+ // y. Let fractionalMonths be months + fractionalDays / abs(oneMonthDays).
|
|
|
+ auto fractional_months = months + fractional_days / fabs(one_month_days);
|
|
|
+
|
|
|
+ // z. Set months to RoundNumberToIncrement(fractionalMonths, increment, roundingMode).
|
|
|
months = round_number_to_increment(fractional_months, increment, rounding_mode);
|
|
|
|
|
|
- // q. Set remainder to fractionalMonths - months.
|
|
|
- remainder = fractional_months - months;
|
|
|
+ // aa. Set total to fractionalMonths.
|
|
|
+ total = fractional_months;
|
|
|
|
|
|
- // r. Set weeks and days to 0.
|
|
|
+ // ab. Set weeks to 0.
|
|
|
weeks = 0;
|
|
|
- days = 0;
|
|
|
}
|
|
|
// 11. Else if unit is "week", then
|
|
|
else if (unit == "week"sv) {
|
|
|
- VERIFY(relative_to);
|
|
|
+ VERIFY(plain_relative_to);
|
|
|
|
|
|
- // a. If days < 0, let sign be -1; else, let sign be 1.
|
|
|
- auto sign = days < 0 ? -1 : 1;
|
|
|
+ // a. Let isoResult be ! AddISODate(plainRelativeTo.[[ISOYear]], plainRelativeTo.[[ISOMonth]], plainRelativeTo.[[ISODay]], 0, 0, 0, truncate(fractionalDays), "constrain").
|
|
|
+ auto iso_result = MUST(add_iso_date(vm, plain_relative_to->iso_year(), plain_relative_to->iso_month(), plain_relative_to->iso_day(), 0, 0, 0, trunc(fractional_days), "constrain"sv));
|
|
|
|
|
|
- // b. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0).
|
|
|
- auto* one_week = MUST(create_temporal_duration(vm, 0, 0, sign, 0, 0, 0, 0, 0, 0, 0));
|
|
|
+ // b. Let wholeDaysLater be ? CreateTemporalDate(isoResult.[[Year]], isoResult.[[Month]], isoResult.[[Day]], calendarRec.[[Receiver]]).
|
|
|
+ // FIXME: Pass through receiver from calendarRec
|
|
|
+ auto* whole_days_later = TRY(create_temporal_date(vm, iso_result.year, iso_result.month, iso_result.day, *calendar));
|
|
|
+
|
|
|
+ // c. Let untilOptions be OrdinaryObjectCreate(null).
|
|
|
+ auto until_options = Object::create(realm, nullptr);
|
|
|
|
|
|
- // c. Let dateAdd be ? GetMethod(calendar, "dateAdd").
|
|
|
+ // d. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "week").
|
|
|
+ MUST(until_options->create_data_property_or_throw(vm.names.largestUnit, PrimitiveString::create(vm, "month"_string)));
|
|
|
+
|
|
|
+ // e. Let timePassed be ? DifferenceDate(calendarRec, plainRelativeTo, wholeDaysLater, untilOptions).
|
|
|
+ // FIXME: Pass through calendarRec
|
|
|
+ auto time_passed = TRY(difference_date(vm, *calendar, *plain_relative_to, *whole_days_later, *until_options));
|
|
|
+
|
|
|
+ // f. Let weeksPassed be timePassed.[[Weeks]].
|
|
|
+ auto weeks_passed = time_passed->weeks();
|
|
|
+
|
|
|
+ // g. Set weeks to weeks + weeksPassed.
|
|
|
+ weeks += weeks_passed;
|
|
|
+
|
|
|
+ // h. Let weeksPassedDuration be ! CreateTemporalDuration(0, 0, weeksPassed, 0, 0, 0, 0, 0, 0, 0).
|
|
|
+ auto* weeks_passed_duration = MUST(create_temporal_duration(vm, 0, 0, weeks_passed, 0, 0, 0, 0, 0, 0, 0));
|
|
|
+
|
|
|
+ // FIXME: i. Let moveResult be ? MoveRelativeDate(calendarRec, plainRelativeTo, weeksPassedDuration).
|
|
|
auto date_add = TRY(Value(calendar).get_method(vm, vm.names.dateAdd));
|
|
|
+ auto move_result = TRY(move_relative_date(vm, *calendar, *plain_relative_to, *weeks_passed_duration, date_add));
|
|
|
|
|
|
- // d. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneWeek, dateAdd).
|
|
|
- auto move_result = TRY(move_relative_date(vm, *calendar, *relative_to, *one_week, date_add));
|
|
|
+ // j. Set plainRelativeTo to moveResult.[[RelativeTo]].
|
|
|
+ plain_relative_to = move_result.relative_to;
|
|
|
|
|
|
- // e. Set relativeTo to moveResult.[[RelativeTo]].
|
|
|
- relative_to = move_result.relative_to.cell();
|
|
|
+ // k. Let daysPassed be moveResult.[[Days]].
|
|
|
+ auto days_passed = move_result.days;
|
|
|
|
|
|
- // f. Let oneWeekDays be moveResult.[[Days]].
|
|
|
- auto one_week_days = move_result.days;
|
|
|
+ // l. Set fractionalDays to fractionalDays - daysPassed.
|
|
|
+ fractional_days -= days_passed;
|
|
|
|
|
|
- // g. Repeat, while abs(days) ≥ abs(oneWeekDays),
|
|
|
- while (fabs(days) >= fabs(one_week_days)) {
|
|
|
- // i. Set weeks to weeks + sign.
|
|
|
- weeks += sign;
|
|
|
+ // m. If fractionalDays < 0, let sign be -1; else, let sign be 1.
|
|
|
+ auto sign = fractional_days < 0 ? -1 : 1;
|
|
|
|
|
|
- // ii. Set days to days - oneWeekDays.
|
|
|
- days -= one_week_days;
|
|
|
+ // n. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0).
|
|
|
+ auto* one_week = MUST(create_temporal_duration(vm, 0, 0, sign, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
- // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneWeek, dateAdd).
|
|
|
- move_result = TRY(move_relative_date(vm, *calendar, *relative_to, *one_week, date_add));
|
|
|
+ // o. Let moveResult be ? MoveRelativeDate(calendarRec, plainRelativeTo, oneWeek).
|
|
|
+ // FIXME: spec bug, should be set
|
|
|
+ move_result = TRY(move_relative_date(vm, *calendar, *plain_relative_to, *one_week, date_add));
|
|
|
|
|
|
- // iv. Set relativeTo to moveResult.[[RelativeTo]].
|
|
|
- relative_to = move_result.relative_to.cell();
|
|
|
+ // p. Let oneWeekDays be moveResult.[[Days]].
|
|
|
+ auto one_week_days = move_result.days;
|
|
|
|
|
|
- // v. Set oneWeekDays to moveResult.[[Days]].
|
|
|
- one_week_days = move_result.days;
|
|
|
- }
|
|
|
+ // q. If oneWeekDays = 0, throw a RangeError exception.
|
|
|
+ if (one_week_days == 0)
|
|
|
+ return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidCalendarFunctionResult, "dateAdd", "result implying a month is zero days long");
|
|
|
|
|
|
- // h. Let fractionalWeeks be weeks + days / abs(oneWeekDays).
|
|
|
- auto fractional_weeks = weeks + days / fabs(one_week_days);
|
|
|
+ // r. Let fractionalWeeks be weeks + fractionalDays / abs(oneWeekDays).
|
|
|
+ auto fractional_weeks = weeks + fractional_days / fabs(one_week_days);
|
|
|
|
|
|
- // i. Set weeks to RoundNumberToIncrement(fractionalWeeks, increment, roundingMode).
|
|
|
+ // s. Set weeks to RoundNumberToIncrement(fractionalWeeks, increment, roundingMode).
|
|
|
weeks = round_number_to_increment(fractional_weeks, increment, rounding_mode);
|
|
|
|
|
|
- // j. Set remainder to fractionalWeeks - weeks.
|
|
|
- remainder = fractional_weeks - weeks;
|
|
|
-
|
|
|
- // k. Set days to 0.
|
|
|
- days = 0;
|
|
|
+ // t. Set total to fractionalWeeks.
|
|
|
+ total = fractional_weeks;
|
|
|
}
|
|
|
// 12. Else if unit is "day", then
|
|
|
else if (unit == "day"sv) {
|
|
|
- // a. Let fractionalDays be days.
|
|
|
- auto fractional_days = days;
|
|
|
+ // a. Set days to RoundNumberToIncrement(fractionalDays, increment, roundingMode).
|
|
|
+ days = round_number_to_increment(fractional_days, increment, rounding_mode);
|
|
|
|
|
|
- // b. Set days to RoundNumberToIncrement(days, increment, roundingMode).
|
|
|
- days = round_number_to_increment(days, increment, rounding_mode);
|
|
|
-
|
|
|
- // c. Set remainder to fractionalDays - days.
|
|
|
- remainder = fractional_days - days;
|
|
|
+ // b. Set total to fractionalDays.
|
|
|
+ total = fractional_days;
|
|
|
}
|
|
|
// 13. Else if unit is "hour", then
|
|
|
else if (unit == "hour"sv) {
|
|
@@ -1512,8 +1563,8 @@ ThrowCompletionOr<RoundedDuration> round_duration(VM& vm, double years, double m
|
|
|
// b. Set hours to RoundNumberToIncrement(fractionalHours, increment, roundingMode).
|
|
|
hours = round_number_to_increment(fractional_hours, increment, rounding_mode);
|
|
|
|
|
|
- // c. Set remainder to fractionalHours - hours.
|
|
|
- remainder = fractional_hours - hours;
|
|
|
+ // c. Set total to fractionalHours.
|
|
|
+ total = fractional_hours;
|
|
|
|
|
|
// d. Set minutes, seconds, milliseconds, microseconds, and nanoseconds to 0.
|
|
|
minutes = 0;
|
|
@@ -1530,8 +1581,8 @@ ThrowCompletionOr<RoundedDuration> round_duration(VM& vm, double years, double m
|
|
|
// b. Set minutes to RoundNumberToIncrement(fractionalMinutes, increment, roundingMode).
|
|
|
minutes = round_number_to_increment(fractional_minutes, increment, rounding_mode);
|
|
|
|
|
|
- // c. Set remainder to fractionalMinutes - minutes.
|
|
|
- remainder = fractional_minutes - minutes;
|
|
|
+ // c. Set total to fractionalMinutes.
|
|
|
+ total = fractional_minutes;
|
|
|
|
|
|
// d. Set seconds, milliseconds, microseconds, and nanoseconds to 0.
|
|
|
seconds = 0;
|
|
@@ -1544,8 +1595,8 @@ ThrowCompletionOr<RoundedDuration> round_duration(VM& vm, double years, double m
|
|
|
// a. Set seconds to RoundNumberToIncrement(fractionalSeconds, increment, roundingMode).
|
|
|
seconds = round_number_to_increment(fractional_seconds, increment, rounding_mode);
|
|
|
|
|
|
- // b. Set remainder to fractionalSeconds - seconds.
|
|
|
- remainder = fractional_seconds - seconds;
|
|
|
+ // b. Set total to fractionalSeconds.
|
|
|
+ total = fractional_seconds;
|
|
|
|
|
|
// c. Set milliseconds, microseconds, and nanoseconds to 0.
|
|
|
milliseconds = 0;
|
|
@@ -1560,8 +1611,8 @@ ThrowCompletionOr<RoundedDuration> round_duration(VM& vm, double years, double m
|
|
|
// b. Set milliseconds to RoundNumberToIncrement(fractionalMilliseconds, increment, roundingMode).
|
|
|
milliseconds = round_number_to_increment(fractional_milliseconds, increment, rounding_mode);
|
|
|
|
|
|
- // c. Set remainder to fractionalMilliseconds - milliseconds.
|
|
|
- remainder = fractional_milliseconds - milliseconds;
|
|
|
+ // c. Set total to fractionalMilliseconds.
|
|
|
+ total = fractional_milliseconds;
|
|
|
|
|
|
// d. Set microseconds and nanoseconds to 0.
|
|
|
microseconds = 0;
|
|
@@ -1575,8 +1626,8 @@ ThrowCompletionOr<RoundedDuration> round_duration(VM& vm, double years, double m
|
|
|
// b. Set microseconds to RoundNumberToIncrement(fractionalMicroseconds, increment, roundingMode).
|
|
|
microseconds = round_number_to_increment(fractional_microseconds, increment, rounding_mode);
|
|
|
|
|
|
- // c. Set remainder to fractionalMicroseconds - microseconds.
|
|
|
- remainder = fractional_microseconds - microseconds;
|
|
|
+ // c. Set total to fractionalMicroseconds.
|
|
|
+ total = fractional_microseconds;
|
|
|
|
|
|
// d. Set nanoseconds to 0.
|
|
|
nanoseconds = 0;
|
|
@@ -1586,21 +1637,18 @@ ThrowCompletionOr<RoundedDuration> round_duration(VM& vm, double years, double m
|
|
|
// a. Assert: unit is "nanosecond".
|
|
|
VERIFY(unit == "nanosecond"sv);
|
|
|
|
|
|
- // b. Set remainder to nanoseconds.
|
|
|
- remainder = nanoseconds;
|
|
|
+ // b. Set total to nanoseconds.
|
|
|
+ total = nanoseconds;
|
|
|
|
|
|
// c. Set nanoseconds to RoundNumberToIncrement(nanoseconds, increment, roundingMode).
|
|
|
nanoseconds = round_number_to_increment(nanoseconds, increment, rounding_mode);
|
|
|
-
|
|
|
- // d. Set remainder to remainder - nanoseconds.
|
|
|
- remainder -= nanoseconds;
|
|
|
}
|
|
|
|
|
|
- // 19. Let duration be ? CreateDurationRecord(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
|
|
|
+ // 20. Let duration be ? CreateDurationRecord(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
|
|
|
auto duration = TRY(create_duration_record(vm, years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds));
|
|
|
|
|
|
- // 20. Return the Record { [[DurationRecord]]: duration, [[Remainder]]: remainder }.
|
|
|
- return RoundedDuration { .duration_record = duration, .remainder = remainder };
|
|
|
+ // 21. Return the Record { [[DurationRecord]]: duration, [[Total]]: total }.
|
|
|
+ return RoundedDuration { .duration_record = duration, .total = total };
|
|
|
}
|
|
|
|
|
|
// 7.5.26 AdjustRoundedDurationDays ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, increment, unit, roundingMode, relativeTo ), https://tc39.es/proposal-temporal/#sec-temporal-adjustroundeddurationdays
|