LibJS: Begin implementing the relativeTo option of Duration.compare

This commit is contained in:
Timothy Flynn 2024-11-22 17:26:53 -05:00 committed by Andreas Kling
commit 0befd52725
Notes: github-actions[bot] 2024-11-23 13:47:08 +00:00
4 changed files with 55 additions and 3 deletions

View file

@ -17,6 +17,7 @@
#include <LibJS/Runtime/Temporal/Duration.h>
#include <LibJS/Runtime/Temporal/DurationConstructor.h>
#include <LibJS/Runtime/Temporal/Instant.h>
#include <LibJS/Runtime/Temporal/PlainDate.h>
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
#include <LibJS/Runtime/Temporal/TimeZone.h>
#include <LibJS/Runtime/VM.h>
@ -796,6 +797,32 @@ i8 time_duration_sign(TimeDuration const& time_duration)
return 0;
}
// 7.5.29 DateDurationDays ( dateDuration, plainRelativeTo ), https://tc39.es/proposal-temporal/#sec-temporal-datedurationdays
ThrowCompletionOr<double> date_duration_days(VM& vm, DateDuration const& date_duration, PlainDate const& plain_relative_to)
{
// 1. Let yearsMonthsWeeksDuration be ! AdjustDateDurationRecord(dateDuration, 0).
auto years_months_weeks_duration = MUST(adjust_date_duration_record(vm, date_duration, 0));
// 2. If DateDurationSign(yearsMonthsWeeksDuration) = 0, return dateDuration.[[Days]].
if (date_duration_sign(years_months_weeks_duration) == 0)
return date_duration.days;
// 3. Let later be ? CalendarDateAdd(plainRelativeTo.[[Calendar]], plainRelativeTo.[[ISODate]], yearsMonthsWeeksDuration, CONSTRAIN).
auto later = TRY(calendar_date_add(vm, plain_relative_to.calendar(), plain_relative_to.iso_date(), years_months_weeks_duration, Overflow::Constrain));
// 4. Let epochDays1 be ISODateToEpochDays(plainRelativeTo.[[ISODate]].[[Year]], plainRelativeTo.[[ISODate]].[[Month]] - 1, plainRelativeTo.[[ISODate]].[[Day]]).
auto epoch_days1 = iso_date_to_epoch_days(plain_relative_to.iso_date().year, plain_relative_to.iso_date().month - 1, plain_relative_to.iso_date().day);
// 5. Let epochDays2 be ISODateToEpochDays(later.[[Year]], later.[[Month]] - 1, later.[[Day]]).
auto epoch_days2 = iso_date_to_epoch_days(later.year, later.month - 1, later.day);
// 6. Let yearsMonthsWeeksInDays be epochDays2 - epochDays1.
auto years_months_weeks_in_days = epoch_days2 - epoch_days1;
// 7. Return dateDuration.[[Days]] + yearsMonthsWeeksInDays.
return date_duration.days + years_months_weeks_in_days;
}
// 7.5.30 RoundTimeDuration ( timeDuration, increment, unit, roundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-roundtimeduration
ThrowCompletionOr<TimeDuration> round_time_duration(VM& vm, TimeDuration const& time_duration, Crypto::UnsignedBigInteger const& increment, Unit unit, RoundingMode rounding_mode)
{

View file

@ -134,6 +134,7 @@ i8 compare_time_duration(TimeDuration const&, TimeDuration const&);
TimeDuration time_duration_from_epoch_nanoseconds_difference(TimeDuration const&, TimeDuration const&);
ThrowCompletionOr<TimeDuration> round_time_duration_to_increment(VM&, TimeDuration const&, Crypto::UnsignedBigInteger const& increment, RoundingMode);
i8 time_duration_sign(TimeDuration const&);
ThrowCompletionOr<double> date_duration_days(VM&, DateDuration const&, PlainDate const&);
ThrowCompletionOr<TimeDuration> round_time_duration(VM&, TimeDuration const&, Crypto::UnsignedBigInteger const& increment, Unit, RoundingMode);
ThrowCompletionOr<CalendarNudgeResult> nudge_to_calendar_unit(VM&, i8 sign, InternalDuration const&, TimeDuration const& dest_epoch_ns, ISODateTime const&, Optional<StringView> time_zone, StringView calendar, u64 increment, Unit, RoundingMode);
ThrowCompletionOr<DurationNudgeResult> nudge_to_zoned_time(VM&, i8 sign, InternalDuration const&, ISODateTime const&, StringView time_zone, StringView calendar, u64 increment, Unit, RoundingMode);

View file

@ -133,7 +133,7 @@ JS_DEFINE_NATIVE_FUNCTION(DurationConstructor::compare)
// 6. Let zonedRelativeTo be relativeToRecord.[[ZonedRelativeTo]].
// 7. Let plainRelativeTo be relativeToRecord.[[PlainRelativeTo]].
auto [zoned_relative_to, plain_relative_to] = relative_to_record;
auto [plain_relative_to, zoned_relative_to] = relative_to_record;
// 8. Let largestUnit1 be DefaultTemporalLargestUnit(one).
auto largest_unit1 = default_temporal_largest_unit(one);
@ -169,8 +169,12 @@ JS_DEFINE_NATIVE_FUNCTION(DurationConstructor::compare)
if (!plain_relative_to)
return vm.throw_completion<RangeError>(ErrorType::TemporalMissingStartingPoint, "calendar units");
// FIXME: b. Let days1 be ? DateDurationDays(duration1.[[Date]], plainRelativeTo).
// FIXME: c. Let days2 be ? DateDurationDays(duration2.[[Date]], plainRelativeTo).
// b. Let days1 be ? DateDurationDays(duration1.[[Date]], plainRelativeTo).
days1 = TRY(date_duration_days(vm, duration1.date, *plain_relative_to));
// c. Let days2 be ? DateDurationDays(duration2.[[Date]], plainRelativeTo).
days2 = TRY(date_duration_days(vm, duration2.date, *plain_relative_to));
}
// 14. Else,
else {

View file

@ -27,6 +27,26 @@ describe("correct behavior", () => {
const duration2 = "P2D";
checkCommonResults(duration1, duration2);
});
test("relative to plain date", () => {
const oneMonth = new Temporal.Duration(0, 1);
const thirtyDays = new Temporal.Duration(0, 0, 0, 30);
let result = Temporal.Duration.compare(oneMonth, thirtyDays, {
relativeTo: Temporal.PlainDate.from("2018-04-01"),
});
expect(result).toBe(0);
result = Temporal.Duration.compare(oneMonth, thirtyDays, {
relativeTo: Temporal.PlainDate.from("2018-03-01"),
});
expect(result).toBe(1);
result = Temporal.Duration.compare(oneMonth, thirtyDays, {
relativeTo: Temporal.PlainDate.from("2018-02-01"),
});
expect(result).toBe(-1);
});
});
describe("errors", () => {