LibJS: Simplify Temporal unit AOs

This is an editorial change in the Temporal spec.

See: https://github.com/tc39/proposal-temporal/commit/1b3d018
This commit is contained in:
Linus Groh 2022-06-09 22:42:42 +01:00 committed by Andreas Kling
parent b9beb2b120
commit 4c77575ec5
Notes: sideshowbarker 2024-07-17 10:21:14 +09:00
16 changed files with 347 additions and 390 deletions

View File

@ -389,8 +389,12 @@ ThrowCompletionOr<SecondsStringPrecision> to_seconds_string_precision(GlobalObje
{
auto& vm = global_object.vm();
// Let smallestUnit be ? ToSmallestTemporalUnit(normalizedOptions, « "year", "month", "week", "day", "hour" », undefined).
auto smallest_unit = TRY(to_smallest_temporal_unit(global_object, normalized_options, { "year"sv, "month"sv, "week"sv, "day"sv, "hour"sv }, {}));
// 1. Let smallestUnit be ? GetTemporalUnit(normalizedOptions, "smallestUnit", time, undefined).
auto smallest_unit = TRY(get_temporal_unit(global_object, normalized_options, vm.names.smallestUnit, UnitGroup::Time, Optional<StringView> {}));
// 2. If smallestUnit is "hour", throw a RangeError exception.
if (smallest_unit == "hour"sv)
return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, *smallest_unit, "smallestUnit"sv);
// 2. If smallestUnit is "minute", then
if (smallest_unit == "minute"sv) {
@ -462,121 +466,117 @@ ThrowCompletionOr<SecondsStringPrecision> to_seconds_string_precision(GlobalObje
return SecondsStringPrecision { .precision = digits, .unit = "nanosecond"sv, .increment = (u32)pow(10, 9 - digits) };
}
// https://tc39.es/proposal-temporal/#table-temporal-singular-and-plural-units
static HashMap<StringView, StringView> plural_to_singular_units = {
{ "years"sv, "year"sv },
{ "months"sv, "month"sv },
{ "weeks"sv, "week"sv },
{ "days"sv, "day"sv },
{ "hours"sv, "hour"sv },
{ "minutes"sv, "minute"sv },
{ "seconds"sv, "second"sv },
{ "milliseconds"sv, "millisecond"sv },
{ "microseconds"sv, "microsecond"sv },
{ "nanoseconds"sv, "nanosecond"sv }
struct TemporalUnit {
StringView singular;
StringView plural;
UnitGroup category;
};
// 13.16 ToLargestTemporalUnit ( normalizedOptions, disallowedUnits, fallback [ , autoValue ] ), https://tc39.es/proposal-temporal/#sec-temporal-tolargesttemporalunit
ThrowCompletionOr<Optional<String>> to_largest_temporal_unit(GlobalObject& global_object, Object const& normalized_options, Vector<StringView> const& disallowed_units, Optional<String> fallback, Optional<String> auto_value)
// https://tc39.es/proposal-temporal/#table-temporal-units
static Vector<TemporalUnit> temporal_units = {
{ "year"sv, "years"sv, UnitGroup::Date },
{ "month"sv, "months"sv, UnitGroup::Date },
{ "week"sv, "weeks"sv, UnitGroup::Date },
{ "day"sv, "days"sv, UnitGroup::Date },
{ "hour"sv, "hours"sv, UnitGroup::Time },
{ "minute"sv, "minutes"sv, UnitGroup::Time },
{ "second"sv, "seconds"sv, UnitGroup::Time },
{ "millisecond"sv, "milliseconds"sv, UnitGroup::Time },
{ "microsecond"sv, "microseconds"sv, UnitGroup::Time },
{ "nanosecond"sv, "nanoseconds"sv, UnitGroup::Time }
};
// 13.16 GetTemporalUnit ( normalizedOptions, key, unitGroup, default [ , extraValues ] ), https://tc39.es/proposal-temporal/#sec-temporal-gettemporalunit
ThrowCompletionOr<Optional<String>> get_temporal_unit(GlobalObject& global_object, Object const& normalized_options, PropertyKey const& key, UnitGroup unit_group, Variant<TemporalUnitRequired, Optional<StringView>> const& default_, Vector<StringView> const& extra_values)
{
auto& vm = global_object.vm();
// 1. Assert: disallowedUnits does not contain fallback.
// 2. Assert: disallowedUnits does not contain "auto".
// 3. Assert: autoValue is not present or fallback is "auto".
VERIFY(!auto_value.has_value() || fallback == "auto"sv);
// 4. Assert: autoValue is not present or disallowedUnits does not contain autoValue.
// 1. Let singularNames be a new empty List.
Vector<StringView> singular_names;
// 5. Let largestUnit be ? GetOption(normalizedOptions, "largestUnit", « String », « "auto", "year", "years", "month", "months", "week", "weeks", "day", "days", "hour", "hours", "minute", "minutes", "second", "seconds", "millisecond", "milliseconds", "microsecond", "microseconds", "nanosecond", "nanoseconds" », fallback).
auto largest_unit_value = TRY(get_option(global_object, normalized_options, vm.names.largestUnit, { OptionType::String }, { "auto"sv, "year"sv, "years"sv, "month"sv, "months"sv, "week"sv, "weeks"sv, "day"sv, "days"sv, "hour"sv, "hours"sv, "minute"sv, "minutes"sv, "second"sv, "seconds"sv, "millisecond"sv, "milliseconds"sv, "microsecond"sv, "microseconds"sv, "nanosecond"sv, "nanoseconds"sv }, fallback.has_value() ? js_string(vm, *fallback) : js_undefined()));
// 2. For each row of Table 13, except the header row, in table order, do
for (auto const& row : temporal_units) {
// a. Let unit be the value in the Singular column of the row.
auto unit = row.singular;
// OPTIMIZATION: We skip the following string-only checks for the fallback to tidy up the code a bit
if (largest_unit_value.is_undefined())
return Optional<String> {};
VERIFY(largest_unit_value.is_string());
auto largest_unit = largest_unit_value.as_string().string();
// 6. If largestUnit is "auto" and autoValue is present, then
if (largest_unit == "auto"sv && auto_value.has_value()) {
// a. Return autoValue.
return *auto_value;
// b. If the Category column of the row is date and unitGroup is date or datetime, append unit to singularNames.
if (row.category == UnitGroup::Date && (unit_group == UnitGroup::Date || unit_group == UnitGroup::DateTime))
singular_names.append(unit);
// c. Else if the Category column of the row is time and unitGroup is time or datetime, append unit to singularNames.
else if (row.category == UnitGroup::Time && (unit_group == UnitGroup::Time || unit_group == UnitGroup::DateTime))
singular_names.append(unit);
}
// 7. If largestUnit is in the Plural column of Table 12, then
if (auto singular_unit = plural_to_singular_units.get(largest_unit); singular_unit.has_value()) {
// a. Set largestUnit to the corresponding Singular value of the same row.
largest_unit = singular_unit.value();
// 3. If extraValues is present, then
if (!extra_values.is_empty()) {
// a. Set singularNames to the list-concatenation of singularNames and extraValues.
singular_names.extend(extra_values);
}
// 8. If disallowedUnits contains largestUnit, then
if (disallowed_units.contains_slow(largest_unit)) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, largest_unit, vm.names.largestUnit.as_string());
Value default_value;
// 4. If default is required, then
if (default_.has<TemporalUnitRequired>()) {
// a. Let defaultValue be undefined.
default_value = js_undefined();
}
// 5. Else,
else {
auto default_string = default_.get<Optional<StringView>>();
// a. Let defaultValue be default.
default_value = default_string.has_value() ? js_string(vm, *default_string) : js_undefined();
// b. If defaultValue is not undefined and singularNames does not contain defaultValue, then
if (default_string.has_value() && !singular_names.contains_slow(*default_string)) {
// i. Append defaultValue to singularNames.
singular_names.append(*default_string);
}
}
// 9. Return largestUnit.
return largest_unit;
// 6. Let allowedValues be a copy of singularNames.
auto allowed_values = singular_names;
// 7. For each element singularName of singularNames, do
for (auto const& singular_name : singular_names) {
for (auto const& row : temporal_units) {
// a. If singularName is listed in the Singular column of Table 13, then
if (singular_name == row.singular) {
// i. Let pluralName be the value in the Plural column of the corresponding row.
auto plural_name = row.plural;
// ii. Append pluralName to allowedValues.
allowed_values.append(plural_name);
}
}
}
// 8. NOTE: For each singular Temporal unit name that is contained within allowedValues, the corresponding plural name is also contained within it.
// 9. Let value be ? GetOption(normalizedOptions, key, « String », allowedValues, defaultValue).
auto option_value = TRY(get_option(global_object, normalized_options, key, { OptionType::String }, allowed_values, default_value));
// 10. If value is undefined and default is required, throw a RangeError exception.
if (option_value.is_undefined() && default_.has<TemporalUnitRequired>())
return vm.throw_completion<RangeError>(global_object, ErrorType::IsUndefined, String::formatted("{} option value", key.as_string()));
Optional<String> value = option_value.is_undefined()
? Optional<String> {}
: option_value.as_string().string();
// 11. If value is listed in the Plural column of Table 13, then
for (auto const& row : temporal_units) {
if (row.plural == value) {
// a. Set value to the value in the Singular column of the corresponding row.
value = row.singular;
}
}
// 12. Return value.
return value;
}
// 13.17 ToSmallestTemporalUnit ( normalizedOptions, disallowedUnits, fallback ), https://tc39.es/proposal-temporal/#sec-temporal-tosmallesttemporalunit
ThrowCompletionOr<Optional<String>> to_smallest_temporal_unit(GlobalObject& global_object, Object const& normalized_options, Vector<StringView> const& disallowed_units, Optional<String> fallback)
{
auto& vm = global_object.vm();
// 1. Assert: disallowedUnits does not contain fallback.
// 2. Let smallestUnit be ? GetOption(normalizedOptions, "smallestUnit", « String », « "year", "years", "month", "months", "week", "weeks", "day", "days", "hour", "hours", "minute", "minutes", "second", "seconds", "millisecond", "milliseconds", "microsecond", "microseconds", "nanosecond", "nanoseconds" », fallback).
auto smallest_unit_value = TRY(get_option(global_object, normalized_options, vm.names.smallestUnit, { OptionType::String }, { "year"sv, "years"sv, "month"sv, "months"sv, "week"sv, "weeks"sv, "day"sv, "days"sv, "hour"sv, "hours"sv, "minute"sv, "minutes"sv, "second"sv, "seconds"sv, "millisecond"sv, "milliseconds"sv, "microsecond"sv, "microseconds"sv, "nanosecond"sv, "nanoseconds"sv }, fallback.has_value() ? js_string(vm, *fallback) : js_undefined()));
// OPTIMIZATION: We skip the following string-only checks for the fallback to tidy up the code a bit
if (smallest_unit_value.is_undefined())
return Optional<String> {};
VERIFY(smallest_unit_value.is_string());
auto smallest_unit = smallest_unit_value.as_string().string();
// 3. If smallestUnit is in the Plural column of Table 12, then
if (auto singular_unit = plural_to_singular_units.get(smallest_unit); singular_unit.has_value()) {
// a. Set smallestUnit to the corresponding Singular value of the same row.
smallest_unit = singular_unit.value();
}
// 4. If disallowedUnits contains smallestUnit, then
if (disallowed_units.contains_slow(smallest_unit)) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, smallest_unit, vm.names.smallestUnit.as_string());
}
// 5. Return smallestUnit.
return smallest_unit;
}
// 13.18 ToTemporalDurationTotalUnit ( normalizedOptions ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaldurationtotalunit
ThrowCompletionOr<String> to_temporal_duration_total_unit(GlobalObject& global_object, Object const& normalized_options)
{
auto& vm = global_object.vm();
// 1. Let unit be ? GetOption(normalizedOptions, "unit", « String », « "year", "years", "month", "months", "week", "weeks", "day", "days", "hour", "hours", "minute", "minutes", "second", "seconds", "millisecond", "milliseconds", "microsecond", "microseconds", "nanosecond", "nanoseconds" », undefined).
auto unit_value = TRY(get_option(global_object, normalized_options, vm.names.unit, { OptionType::String }, { "year"sv, "years"sv, "month"sv, "months"sv, "week"sv, "weeks"sv, "day"sv, "days"sv, "hour"sv, "hours"sv, "minute"sv, "minutes"sv, "second"sv, "seconds"sv, "millisecond"sv, "milliseconds"sv, "microsecond"sv, "microseconds"sv, "nanosecond"sv, "nanoseconds"sv }, js_undefined()));
// 2. If unit is undefined, then
if (unit_value.is_undefined()) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::IsUndefined, "unit option value"sv);
}
auto unit = unit_value.as_string().string();
// 3. If unit is in the Plural column of Table 12, then
if (auto singular_unit = plural_to_singular_units.get(unit); singular_unit.has_value()) {
// a. Set unit to the corresponding Singular value of the same row.
unit = *singular_unit;
}
// 4. Return unit.
return unit;
}
// 13.20 ToRelativeTemporalObject ( options ), https://tc39.es/proposal-temporal/#sec-temporal-torelativetemporalobject
// 13.17 ToRelativeTemporalObject ( options ), https://tc39.es/proposal-temporal/#sec-temporal-torelativetemporalobject
ThrowCompletionOr<Value> to_relative_temporal_object(GlobalObject& global_object, Object const& options)
{
auto& vm = global_object.vm();
@ -746,95 +746,28 @@ ThrowCompletionOr<Value> to_relative_temporal_object(GlobalObject& global_object
return TRY(create_temporal_date(global_object, result.year, result.month, result.day, *calendar));
}
// 13.21 ValidateTemporalUnitRange ( largestUnit, smallestUnit ), https://tc39.es/proposal-temporal/#sec-temporal-validatetemporalunitrange
ThrowCompletionOr<void> validate_temporal_unit_range(GlobalObject& global_object, StringView largest_unit, StringView smallest_unit)
{
auto& vm = global_object.vm();
// 1. If smallestUnit is "year" and largestUnit is not "year", then
if (smallest_unit == "year"sv && largest_unit != "year"sv) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, smallest_unit, largest_unit);
}
// 2. If smallestUnit is "month" and largestUnit is not "year" or "month", then
if (smallest_unit == "month"sv && !largest_unit.is_one_of("year"sv, "month"sv)) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, smallest_unit, largest_unit);
}
// 3. If smallestUnit is "week" and largestUnit is not one of "year", "month", or "week", then
if (smallest_unit == "week"sv && !largest_unit.is_one_of("year"sv, "month"sv, "week"sv)) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, smallest_unit, largest_unit);
}
// 4. If smallestUnit is "day" and largestUnit is not one of "year", "month", "week", or "day", then
if (smallest_unit == "day"sv && !largest_unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv)) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, smallest_unit, largest_unit);
}
// 5. If smallestUnit is "hour" and largestUnit is not one of "year", "month", "week", "day", or "hour", then
if (smallest_unit == "hour"sv && !largest_unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv, "hour"sv)) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, smallest_unit, largest_unit);
}
// 6. If smallestUnit is "minute" and largestUnit is "second", "millisecond", "microsecond", or "nanosecond", then
if (smallest_unit == "minute"sv && largest_unit.is_one_of("second"sv, "millisecond"sv, "microsecond"sv, "nanosecond"sv)) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, smallest_unit, largest_unit);
}
// 7. If smallestUnit is "second" and largestUnit is "millisecond", "microsecond", or "nanosecond", then
if (smallest_unit == "second"sv && largest_unit.is_one_of("millisecond"sv, "microsecond"sv, "nanosecond"sv)) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, smallest_unit, largest_unit);
}
// 8. If smallestUnit is "millisecond" and largestUnit is "microsecond" or "nanosecond", then
if (smallest_unit == "millisecond"sv && largest_unit.is_one_of("microsecond"sv, "nanosecond"sv)) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, smallest_unit, largest_unit);
}
// 9. If smallestUnit is "microsecond" and largestUnit is "nanosecond", then
if (smallest_unit == "microsecond"sv && largest_unit == "nanosecond"sv) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, smallest_unit, largest_unit);
}
return {};
}
// 13.22 LargerOfTwoTemporalUnits ( u1, u2 ), https://tc39.es/proposal-temporal/#sec-temporal-largeroftwotemporalunits
// 13.18 LargerOfTwoTemporalUnits ( u1, u2 ), https://tc39.es/proposal-temporal/#sec-temporal-largeroftwotemporalunits
StringView larger_of_two_temporal_units(StringView unit1, StringView unit2)
{
// 1. If either u1 or u2 is "year", return "year".
if (unit1 == "year"sv || unit2 == "year"sv)
return "year"sv;
// 2. If either u1 or u2 is "month", return "month".
if (unit1 == "month"sv || unit2 == "month"sv)
return "month"sv;
// 3. If either u1 or u2 is "week", return "week".
if (unit1 == "week"sv || unit2 == "week"sv)
return "week"sv;
// 4. If either u1 or u2 is "day", return "day".
if (unit1 == "day"sv || unit2 == "day"sv)
return "day"sv;
// 5. If either u1 or u2 is "hour", return "hour".
if (unit1 == "hour"sv || unit2 == "hour"sv)
return "hour"sv;
// 6. If either u1 or u2 is "minute", return "minute".
if (unit1 == "minute"sv || unit2 == "minute"sv)
return "minute"sv;
// 7. If either u1 or u2 is "second", return "second".
if (unit1 == "second"sv || unit2 == "second"sv)
return "second"sv;
// 8. If either u1 or u2 is "millisecond", return "millisecond".
if (unit1 == "millisecond"sv || unit2 == "millisecond"sv)
return "millisecond"sv;
// 9. If either u1 or u2 is "microsecond", return "microsecond".
if (unit1 == "microsecond"sv || unit2 == "microsecond"sv)
return "microsecond"sv;
// 10. Return "nanosecond".
return "nanosecond"sv;
// 1. Assert: Both u1 and u2 are listed in the Singular column of Table 13.
// 2. For each row of Table 13, except the header row, in table order, do
for (auto const& row : temporal_units) {
// a. Let unit be the value in the Singular column of the row.
auto unit = row.singular;
// b. If SameValue(u1, unit) is true, return unit.
if (unit1 == unit)
return unit;
// c. If SameValue(u2, unit) is true, return unit.
if (unit2 == unit)
return unit;
}
VERIFY_NOT_REACHED();
}
// 13.23 MergeLargestUnitOption ( options, largestUnit ), https://tc39.es/proposal-temporal/#sec-temporal-mergelargestunitoption
// 13.19 MergeLargestUnitOption ( options, largestUnit ), https://tc39.es/proposal-temporal/#sec-temporal-mergelargestunitoption
ThrowCompletionOr<Object*> merge_largest_unit_option(GlobalObject& global_object, Object const* options, String largest_unit)
{
auto& vm = global_object.vm();
@ -867,7 +800,7 @@ ThrowCompletionOr<Object*> merge_largest_unit_option(GlobalObject& global_object
return merged;
}
// 13.24 MaximumTemporalDurationRoundingIncrement ( unit ), https://tc39.es/proposal-temporal/#sec-temporal-maximumtemporaldurationroundingincrement
// 13.20 MaximumTemporalDurationRoundingIncrement ( unit ), https://tc39.es/proposal-temporal/#sec-temporal-maximumtemporaldurationroundingincrement
Optional<u16> maximum_temporal_duration_rounding_increment(StringView unit)
{
// 1. If unit is "year", "month", "week", or "day", then
@ -895,7 +828,7 @@ Optional<u16> maximum_temporal_duration_rounding_increment(StringView unit)
return 1000;
}
// 13.25 RejectObjectWithCalendarOrTimeZone ( object ), https://tc39.es/proposal-temporal/#sec-temporal-rejectobjectwithcalendarortimezone
// 13.21 RejectObjectWithCalendarOrTimeZone ( object ), https://tc39.es/proposal-temporal/#sec-temporal-rejectobjectwithcalendarortimezone
ThrowCompletionOr<void> reject_object_with_calendar_or_time_zone(GlobalObject& global_object, Object& object)
{
auto& vm = global_object.vm();
@ -929,7 +862,7 @@ ThrowCompletionOr<void> reject_object_with_calendar_or_time_zone(GlobalObject& g
return {};
}
// 13.26 FormatSecondsStringPart ( second, millisecond, microsecond, nanosecond, precision ), https://tc39.es/proposal-temporal/#sec-temporal-formatsecondsstringpart
// 13.22 FormatSecondsStringPart ( second, millisecond, microsecond, nanosecond, precision ), https://tc39.es/proposal-temporal/#sec-temporal-formatsecondsstringpart
String format_seconds_string_part(u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, Variant<StringView, u8> const& precision)
{
// 1. Assert: second, millisecond, microsecond and nanosecond are integers.
@ -979,7 +912,7 @@ String format_seconds_string_part(u8 second, u16 millisecond, u16 microsecond, u
return String::formatted("{}.{}", seconds_string, fraction_string);
}
// 13.28 GetUnsignedRoundingMode ( roundingMode, isNegative ), https://tc39.es/proposal-temporal/#sec-temporal-getunsignedroundingmode
// 13.24 GetUnsignedRoundingMode ( roundingMode, isNegative ), https://tc39.es/proposal-temporal/#sec-temporal-getunsignedroundingmode
UnsignedRoundingMode get_unsigned_rounding_mode(StringView rounding_mode, bool is_negative)
{
// 1. If isNegative is true, return the specification type in the third column of Table 14 where the first column is roundingMode and the second column is "negative".
@ -1033,7 +966,7 @@ UnsignedRoundingMode get_unsigned_rounding_mode(StringView rounding_mode, bool i
// it uses mathematical values which can be arbitrarily (but not infinitely) large.
// Incidentally V8's Temporal implementation does the same :^)
// 13.29 ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-applyunsignedroundingmode
// 13.25 ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-applyunsignedroundingmode
double apply_unsigned_rounding_mode(double x, double r1, double r2, Optional<UnsignedRoundingMode> const& unsigned_rounding_mode)
{
// 1. If x is equal to r1, return r1.
@ -1093,7 +1026,7 @@ double apply_unsigned_rounding_mode(double x, double r1, double r2, Optional<Uns
return r2;
}
// 13.29 ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-applyunsignedroundingmode
// 13.25 ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-applyunsignedroundingmode
Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResult const& x, Crypto::SignedBigInteger const& r1, Crypto::SignedBigInteger const& r2, Optional<UnsignedRoundingMode> const& unsigned_rounding_mode, Crypto::UnsignedBigInteger const& increment)
{
// 1. If x is equal to r1, return r1.
@ -1153,7 +1086,7 @@ Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResu
return r2;
}
// 13.30 RoundNumberToIncrement ( x, increment, roundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-roundnumbertoincrement
// 13.26 RoundNumberToIncrement ( x, increment, roundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-roundnumbertoincrement
double round_number_to_increment(double x, u64 increment, StringView rounding_mode)
{
VERIFY(rounding_mode == "ceil"sv || rounding_mode == "floor"sv || rounding_mode == "trunc"sv || rounding_mode == "halfExpand"sv);
@ -1199,7 +1132,7 @@ double round_number_to_increment(double x, u64 increment, StringView rounding_mo
return rounded * static_cast<double>(increment);
}
// 13.30 RoundNumberToIncrement ( x, increment, roundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-roundnumbertoincrement
// 13.26 RoundNumberToIncrement ( x, increment, roundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-roundnumbertoincrement
Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger const& x, u64 increment, StringView rounding_mode)
{
VERIFY(rounding_mode == "ceil"sv || rounding_mode == "floor"sv || rounding_mode == "trunc"sv || rounding_mode == "halfExpand"sv);
@ -1254,7 +1187,7 @@ Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger cons
return rounded.multiplied_by(increment_big_int);
}
// 13.32 ParseISODateTime ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parseisodatetime
// 13.28 ParseISODateTime ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parseisodatetime
ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object, ParseResult const& parse_result)
{
auto& vm = global_object.vm();
@ -1401,7 +1334,7 @@ ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object,
return ISODateTime { .year = year_mv, .month = month_mv, .day = day_mv, .hour = hour_mv, .minute = minute_mv, .second = second_mv, .millisecond = millisecond_mv, .microsecond = microsecond_mv, .nanosecond = nanosecond_mv, .calendar = move(calendar_val) };
}
// 13.33 ParseTemporalInstantString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalinstantstring
// 13.29 ParseTemporalInstantString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalinstantstring
ThrowCompletionOr<TemporalInstant> parse_temporal_instant_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1433,7 +1366,7 @@ ThrowCompletionOr<TemporalInstant> parse_temporal_instant_string(GlobalObject& g
return TemporalInstant { .year = result.year, .month = result.month, .day = result.day, .hour = result.hour, .minute = result.minute, .second = result.second, .millisecond = result.millisecond, .microsecond = result.microsecond, .nanosecond = result.nanosecond, .time_zone_offset = move(offset_string) };
}
// 13.34 ParseTemporalZonedDateTimeString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalzoneddatetimestring
// 13.30 ParseTemporalZonedDateTimeString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalzoneddatetimestring
ThrowCompletionOr<TemporalZonedDateTime> parse_temporal_zoned_date_time_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1455,7 +1388,7 @@ ThrowCompletionOr<TemporalZonedDateTime> parse_temporal_zoned_date_time_string(G
return TemporalZonedDateTime { .date_time = move(result), .time_zone = move(time_zone_result) };
}
// 13.35 ParseTemporalCalendarString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalcalendarstring
// 13.31 ParseTemporalCalendarString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalcalendarstring
ThrowCompletionOr<String> parse_temporal_calendar_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1480,7 +1413,7 @@ ThrowCompletionOr<String> parse_temporal_calendar_string(GlobalObject& global_ob
return id.value();
}
// 13.36 ParseTemporalDateString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatestring
// 13.32 ParseTemporalDateString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatestring
ThrowCompletionOr<TemporalDate> parse_temporal_date_string(GlobalObject& global_object, String const& iso_string)
{
// 1. Let parts be ? ParseTemporalDateTimeString(isoString).
@ -1490,7 +1423,7 @@ ThrowCompletionOr<TemporalDate> parse_temporal_date_string(GlobalObject& global_
return TemporalDate { .year = parts.year, .month = parts.month, .day = parts.day, .calendar = move(parts.calendar) };
}
// 13.37 ParseTemporalDateTimeString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatetimestring
// 13.33 ParseTemporalDateTimeString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatetimestring
ThrowCompletionOr<ISODateTime> parse_temporal_date_time_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1510,7 +1443,7 @@ ThrowCompletionOr<ISODateTime> parse_temporal_date_time_string(GlobalObject& glo
return parse_iso_date_time(global_object, *parse_result);
}
// 13.38 ParseTemporalDurationString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldurationstring
// 13.34 ParseTemporalDurationString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldurationstring
ThrowCompletionOr<DurationRecord> parse_temporal_duration_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1650,7 +1583,7 @@ ThrowCompletionOr<DurationRecord> parse_temporal_duration_string(GlobalObject& g
return create_duration_record(global_object, years * factor, months * factor, weeks * factor, days * factor, hours * factor, floor(minutes) * factor, floor(seconds) * factor, floor(milliseconds) * factor, floor(microseconds) * factor, floor(nanoseconds) * factor);
}
// 13.39 ParseTemporalMonthDayString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalmonthdaystring
// 13.35 ParseTemporalMonthDayString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalmonthdaystring
ThrowCompletionOr<TemporalMonthDay> parse_temporal_month_day_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1682,7 +1615,7 @@ ThrowCompletionOr<TemporalMonthDay> parse_temporal_month_day_string(GlobalObject
return TemporalMonthDay { .year = year, .month = result.month, .day = result.day, .calendar = move(result.calendar) };
}
// 13.40 ParseTemporalRelativeToString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalrelativetostring
// 13.36 ParseTemporalRelativeToString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalrelativetostring
ThrowCompletionOr<TemporalZonedDateTime> parse_temporal_relative_to_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1727,7 +1660,7 @@ ThrowCompletionOr<TemporalZonedDateTime> parse_temporal_relative_to_string(Globa
return TemporalZonedDateTime { .date_time = move(result), .time_zone = { .z = z, .offset_string = move(offset_string), .name = move(time_zone) } };
}
// 13.41 ParseTemporalTimeString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimestring
// 13.37 ParseTemporalTimeString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimestring
ThrowCompletionOr<TemporalTime> parse_temporal_time_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1750,7 +1683,7 @@ ThrowCompletionOr<TemporalTime> parse_temporal_time_string(GlobalObject& global_
return TemporalTime { .hour = result.hour, .minute = result.minute, .second = result.second, .millisecond = result.millisecond, .microsecond = result.microsecond, .nanosecond = result.nanosecond, .calendar = move(result.calendar) };
}
// 13.42 ParseTemporalTimeZoneString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimezonestring
// 13.38 ParseTemporalTimeZoneString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimezonestring
ThrowCompletionOr<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1789,7 +1722,7 @@ ThrowCompletionOr<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject
return TemporalTimeZone { .z = false, .offset_string = Optional<String>(move(offset_string)), .name = Optional<String>(move(name)) };
}
// 13.43 ParseTemporalYearMonthString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalyearmonthstring
// 13.39 ParseTemporalYearMonthString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalyearmonthstring
ThrowCompletionOr<TemporalYearMonth> parse_temporal_year_month_string(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
@ -1812,7 +1745,7 @@ ThrowCompletionOr<TemporalYearMonth> parse_temporal_year_month_string(GlobalObje
return TemporalYearMonth { .year = result.year, .month = result.month, .day = result.day, .calendar = move(result.calendar) };
}
// 13.44 ToPositiveInteger ( argument ), https://tc39.es/proposal-temporal/#sec-temporal-topositiveinteger
// 13.40 ToPositiveInteger ( argument ), https://tc39.es/proposal-temporal/#sec-temporal-topositiveinteger
ThrowCompletionOr<double> to_positive_integer(GlobalObject& global_object, Value argument)
{
auto& vm = global_object.vm();
@ -1830,7 +1763,7 @@ ThrowCompletionOr<double> to_positive_integer(GlobalObject& global_object, Value
return integer;
}
// 13.47 PrepareTemporalFields ( fields, fieldNames, requiredFields ), https://tc39.es/proposal-temporal/#sec-temporal-preparetemporalfields
// 13.43 PrepareTemporalFields ( fields, fieldNames, requiredFields ), https://tc39.es/proposal-temporal/#sec-temporal-preparetemporalfields
ThrowCompletionOr<Object*> prepare_temporal_fields(GlobalObject& global_object, Object const& fields, Vector<String> const& field_names, Vector<StringView> const& required_fields)
{
auto& vm = global_object.vm();
@ -1879,7 +1812,7 @@ ThrowCompletionOr<Object*> prepare_temporal_fields(GlobalObject& global_object,
return result;
}
// 13.48 PreparePartialTemporalFields ( fields, fieldNames ), https://tc39.es/proposal-temporal/#sec-temporal-preparepartialtemporalfields
// 13.44 PreparePartialTemporalFields ( fields, fieldNames ), https://tc39.es/proposal-temporal/#sec-temporal-preparepartialtemporalfields
ThrowCompletionOr<Object*> prepare_partial_temporal_fields(GlobalObject& global_object, Object const& fields, Vector<String> const& field_names)
{
auto& vm = global_object.vm();
@ -1924,5 +1857,4 @@ ThrowCompletionOr<Object*> prepare_partial_temporal_fields(GlobalObject& global_
// 5. Return result.
return result;
}
}

View File

@ -41,6 +41,12 @@ enum class OptionType {
Number
};
enum class UnitGroup {
Date,
Time,
DateTime,
};
struct ISODateTime {
i32 year;
u8 month;
@ -115,6 +121,8 @@ struct SecondsStringPrecision {
u32 increment;
};
struct TemporalUnitRequired { };
ThrowCompletionOr<MarkedVector<Value>> iterable_to_list_of_type(GlobalObject&, Value items, Vector<OptionType> const& element_types);
ThrowCompletionOr<Object*> get_options_object(GlobalObject&, Value options);
ThrowCompletionOr<Value> get_option(GlobalObject&, Object const& options, PropertyKey const& property, Vector<OptionType> const& types, Vector<StringView> const& values, Value fallback);
@ -131,11 +139,8 @@ ThrowCompletionOr<String> to_show_offset_option(GlobalObject&, Object const& nor
ThrowCompletionOr<u64> to_temporal_rounding_increment(GlobalObject&, Object const& normalized_options, Optional<double> dividend, bool inclusive);
ThrowCompletionOr<u64> to_temporal_date_time_rounding_increment(GlobalObject&, Object const& normalized_options, StringView smallest_unit);
ThrowCompletionOr<SecondsStringPrecision> to_seconds_string_precision(GlobalObject&, Object const& normalized_options);
ThrowCompletionOr<Optional<String>> to_largest_temporal_unit(GlobalObject&, Object const& normalized_options, Vector<StringView> const& disallowed_units, Optional<String> fallback, Optional<String> auto_value = {});
ThrowCompletionOr<Optional<String>> to_smallest_temporal_unit(GlobalObject&, Object const& normalized_options, Vector<StringView> const& disallowed_units, Optional<String> fallback);
ThrowCompletionOr<String> to_temporal_duration_total_unit(GlobalObject& global_object, Object const& normalized_options);
ThrowCompletionOr<Optional<String>> get_temporal_unit(GlobalObject&, Object const& normalized_options, PropertyKey const&, UnitGroup, Variant<TemporalUnitRequired, Optional<StringView>> const& default_, Vector<StringView> const& extra_values = {});
ThrowCompletionOr<Value> to_relative_temporal_object(GlobalObject&, Object const& options);
ThrowCompletionOr<void> validate_temporal_unit_range(GlobalObject&, StringView largest_unit, StringView smallest_unit);
StringView larger_of_two_temporal_units(StringView, StringView);
ThrowCompletionOr<Object*> merge_largest_unit_option(GlobalObject&, Object const* options, String largest_unit);
Optional<u16> maximum_temporal_duration_rounding_increment(StringView unit);
@ -164,7 +169,7 @@ ThrowCompletionOr<double> to_positive_integer(GlobalObject&, Value argument);
ThrowCompletionOr<Object*> prepare_temporal_fields(GlobalObject&, Object const& fields, Vector<String> const& field_names, Vector<StringView> const& required_fields);
ThrowCompletionOr<Object*> prepare_partial_temporal_fields(GlobalObject&, Object const& fields, Vector<String> const& field_names);
// 13.45 ToIntegerThrowOnInfinity ( argument ), https://tc39.es/proposal-temporal/#sec-temporal-tointegerthrowoninfinity
// 13.41 ToIntegerThrowOnInfinity ( argument ), https://tc39.es/proposal-temporal/#sec-temporal-tointegerthrowoninfinity
template<typename... Args>
ThrowCompletionOr<double> to_integer_throw_on_infinity(GlobalObject& global_object, Value argument, ErrorType error_type, Args... args)
{
@ -183,7 +188,7 @@ ThrowCompletionOr<double> to_integer_throw_on_infinity(GlobalObject& global_obje
return integer;
}
// 13.46 ToIntegerWithoutRounding ( argument ), https://tc39.es/proposal-temporal/#sec-temporal-tointegerwithoutrounding
// 13.42 ToIntegerWithoutRounding ( argument ), https://tc39.es/proposal-temporal/#sec-temporal-tointegerwithoutrounding
template<typename... Args>
ThrowCompletionOr<double> to_integer_without_rounding(GlobalObject& global_object, Value argument, ErrorType error_type, Args... args)
{

View File

@ -205,13 +205,17 @@ JS_DEFINE_NATIVE_FUNCTION(CalendarPrototype::date_until)
// 6. Set options to ? GetOptionsObject(options).
auto const* options = TRY(get_options_object(global_object, vm.argument(2)));
// 7. Let largestUnit be ? ToLargestTemporalUnit(options, « "hour", "minute", "second", "millisecond", "microsecond", "nanosecond" », "auto", "day").
auto largest_unit = TRY(to_largest_temporal_unit(global_object, *options, { "hour"sv, "minute"sv, "second"sv, "millisecond"sv, "microsecond"sv, "nanosecond"sv }, "auto"sv, "day"sv));
// 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. Let result be DifferenceISODate(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]], largestUnit).
// 8. If largestUnit is "auto", set largestUnit to "day".
if (largest_unit == "auto")
largest_unit = "day"sv;
// 9. Let result be DifferenceISODate(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]], largestUnit).
auto result = difference_iso_date(global_object, one->iso_year(), one->iso_month(), one->iso_day(), two->iso_year(), two->iso_month(), two->iso_day(), *largest_unit);
// 9. Return ! CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0).
// 10. Return ! CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0).
return MUST(create_temporal_duration(global_object, result.years, result.months, result.weeks, result.days, 0, 0, 0, 0, 0, 0));
}

View File

@ -356,8 +356,8 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::round)
// 7. Let largestUnitPresent be true.
bool largest_unit_present = true;
// 8. Let smallestUnit be ? ToSmallestTemporalUnit(roundTo, « », undefined).
auto smallest_unit = TRY(to_smallest_temporal_unit(global_object, *round_to, {}, {}));
// 8. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", datetime, undefined).
auto smallest_unit = TRY(get_temporal_unit(global_object, *round_to, vm.names.smallestUnit, UnitGroup::DateTime, Optional<StringView> {}));
// 9. If smallestUnit is undefined, then
if (!smallest_unit.has_value()) {
@ -374,8 +374,8 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::round)
// 11. Set defaultLargestUnit to ! LargerOfTwoTemporalUnits(defaultLargestUnit, smallestUnit).
default_largest_unit = larger_of_two_temporal_units(default_largest_unit, *smallest_unit);
// 12. Let largestUnit be ? ToLargestTemporalUnit(roundTo, « », undefined).
auto largest_unit = TRY(to_largest_temporal_unit(global_object, *round_to, {}, {}));
// 12. Let largestUnit be ? GetTemporalUnit(roundTo, "largestUnit", datetime, undefined, « "auto" »).
auto largest_unit = TRY(get_temporal_unit(global_object, *round_to, vm.names.largestUnit, UnitGroup::DateTime, Optional<StringView> {}, { "auto"sv }));
// 13. If largestUnit is undefined, then
if (!largest_unit.has_value()) {
@ -397,8 +397,9 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::round)
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalMissingUnits);
}
// 16. Perform ? ValidateTemporalUnitRange(largestUnit, smallestUnit).
TRY(validate_temporal_unit_range(global_object, *largest_unit, *smallest_unit));
// 16. 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<RangeError>(global_object, ErrorType::TemporalInvalidUnitRange, *smallest_unit, *largest_unit);
// 17. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *round_to, "halfExpand"sv));
@ -473,11 +474,11 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::total)
// 6. Let relativeTo be ? ToRelativeTemporalObject(totalOf).
auto relative_to = TRY(to_relative_temporal_object(global_object, *total_of));
// 7. Let unit be ? ToTemporalDurationTotalUnit(totalOf).
auto unit = TRY(to_temporal_duration_total_unit(global_object, *total_of));
// 7. Let unit be ? GetTemporalUnit(totalOf, "unit", datetime, required).
auto unit = TRY(get_temporal_unit(global_object, *total_of, vm.names.unit, UnitGroup::DateTime, TemporalUnitRequired {}));
// 8. Let unbalanceResult be ? UnbalanceDurationRelative(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], unit, relativeTo).
auto unbalance_result = TRY(unbalance_duration_relative(global_object, duration->years(), duration->months(), duration->weeks(), duration->days(), unit, relative_to));
auto unbalance_result = TRY(unbalance_duration_relative(global_object, duration->years(), duration->months(), duration->weeks(), duration->days(), *unit, relative_to));
// 9. Let intermediate be undefined.
ZonedDateTime* intermediate = nullptr;
@ -489,10 +490,10 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::total)
}
// 11. Let balanceResult be ? BalanceDuration(unbalanceResult.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]], unit, intermediate).
auto balance_result = TRY(balance_duration(global_object, unbalance_result.days, duration->hours(), duration->minutes(), duration->seconds(), duration->milliseconds(), duration->microseconds(), Crypto::SignedBigInteger::create_from(duration->nanoseconds()), unit, intermediate));
auto balance_result = TRY(balance_duration(global_object, unbalance_result.days, duration->hours(), duration->minutes(), duration->seconds(), duration->milliseconds(), duration->microseconds(), Crypto::SignedBigInteger::create_from(duration->nanoseconds()), *unit, intermediate));
// 12. Let roundRecord be ? RoundDuration(unbalanceResult.[[Years]], unbalanceResult.[[Months]], unbalanceResult.[[Weeks]], balanceResult.[[Days]], balanceResult.[[Hours]], balanceResult.[[Minutes]], balanceResult.[[Seconds]], balanceResult.[[Milliseconds]], balanceResult.[[Microseconds]], balanceResult.[[Nanoseconds]], 1, unit, "trunc", relativeTo).
auto round_record = TRY(round_duration(global_object, unbalance_result.years, unbalance_result.months, unbalance_result.weeks, balance_result.days, balance_result.hours, balance_result.minutes, balance_result.seconds, balance_result.milliseconds, balance_result.microseconds, balance_result.nanoseconds, 1, unit, "trunc"sv, relative_to.is_object() ? &relative_to.as_object() : nullptr));
auto round_record = TRY(round_duration(global_object, unbalance_result.years, unbalance_result.months, unbalance_result.weeks, balance_result.days, balance_result.hours, balance_result.minutes, balance_result.seconds, balance_result.milliseconds, balance_result.microseconds, balance_result.nanoseconds, 1, *unit, "trunc"sv, relative_to.is_object() ? &relative_to.as_object() : nullptr));
// 13. Let roundResult be roundRecord.[[DurationRecord]].
auto& round_result = round_record.duration_record;

View File

@ -286,6 +286,8 @@ ThrowCompletionOr<String> temporal_instant_to_string(GlobalObject& global_object
// 8.5.10 DifferenceTemporalInstant ( operation, instant, other, options ), https://tc39.es/proposal-temporal/#sec-temporal-differencetemporalinstant
ThrowCompletionOr<Duration*> 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;
@ -295,42 +297,47 @@ ThrowCompletionOr<Duration*> difference_temporal_instant(GlobalObject& global_ob
// 3. Set options to ? GetOptionsObject(options).
auto const* options = TRY(get_options_object(global_object, options_value));
// 4. Let smallestUnit be ? ToSmallestTemporalUnit(options, « "year", "month", "week", "day" », "nanosecond").
auto smallest_unit = TRY(to_smallest_temporal_unit(global_object, *options, { "year"sv, "month"sv, "week"sv, "day"sv }, "nanosecond"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 defaultLargestUnit be ! LargerOfTwoTemporalUnits("second", smallestUnit).
auto default_largest_unit = larger_of_two_temporal_units("second"sv, *smallest_unit);
// 6. Let largestUnit be ? ToLargestTemporalUnit(options, « "year", "month", "week", "day" », "auto", defaultLargestUnit).
auto largest_unit = TRY(to_largest_temporal_unit(global_object, *options, { "year"sv, "month"sv, "week"sv, "day"sv }, "auto"sv, default_largest_unit));
// 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 }));
// 7. Perform ? ValidateTemporalUnitRange(largestUnit, smallestUnit).
TRY(validate_temporal_unit_range(global_object, *largest_unit, *smallest_unit));
// 7. If largestUnit is "auto", set largestUnit to defaultLargestUnit.
if (largest_unit == "auto"sv)
largest_unit = default_largest_unit;
// 8. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
// 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<RangeError>(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));
// 9. If operation is since, then
// 10. 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).
// 11. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit).
auto maximum = maximum_temporal_duration_rounding_increment(*smallest_unit);
// 11. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false).
// 12. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false).
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, *maximum, false));
// 12. Let roundedNs be ! DifferenceInstant(instant.[[Nanoseconds]], other.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode).
// 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);
// 13. Assert: The following steps cannot fail due to overflow in the Number domain because abs(roundedNs) ≤ 2 × nsMaxInstant.
// 14. Assert: The following steps cannot fail due to overflow in the Number domain because abs(roundedNs) ≤ 2 × nsMaxInstant.
// 14. Let result be ! BalanceDuration(0, 0, 0, 0, 0, 0, roundedNs, largestUnit).
// 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));
// 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]]).
// 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]]).
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));
}

View File

@ -203,8 +203,8 @@ JS_DEFINE_NATIVE_FUNCTION(InstantPrototype::round)
round_to = TRY(get_options_object(global_object, vm.argument(0)));
}
// 6. Let smallestUnit be ? ToSmallestTemporalUnit(roundTo, « "year", "month", "week", "day" », undefined).
auto smallest_unit_value = TRY(to_smallest_temporal_unit(global_object, *round_to, { "year"sv, "month"sv, "week"sv, "day"sv }, {}));
// 6. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time, required).
auto smallest_unit_value = TRY(get_temporal_unit(global_object, *round_to, vm.names.smallestUnit, UnitGroup::Time, TemporalUnitRequired {}));
// 6. If smallestUnit is undefined, throw a RangeError exception.
if (!smallest_unit_value.has_value())

View File

@ -510,20 +510,22 @@ ThrowCompletionOr<Duration*> difference_temporal_plain_date(GlobalObject& global
// 4. Set options to ? GetOptionsObject(options).
auto const* options = TRY(get_options_object(global_object, options_value));
// 5. Let disallowedUnits be « "hour", "minute", "second", "millisecond", "microsecond", "nanosecond" ».
auto disallowed_units = Vector<StringView> { "hour"sv, "minute"sv, "second"sv, "millisecond"sv, "microsecond"sv, "nanosecond"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 }));
// 6. Let smallestUnit be ? ToSmallestTemporalUnit(options, disallowedUnits, "day").
auto smallest_unit = TRY(to_smallest_temporal_unit(global_object, *options, disallowed_units, "day"sv));
// 7. Let defaultLargestUnit be ! LargerOfTwoTemporalUnits("day", smallestUnit).
// 6. Let defaultLargestUnit be ! LargerOfTwoTemporalUnits("day", smallestUnit).
auto default_largest_unit = larger_of_two_temporal_units("day"sv, *smallest_unit);
// 8. Let largestUnit be ? ToLargestTemporalUnit(options, disallowedUnits, "auto", defaultLargestUnit).
auto largest_unit = TRY(to_largest_temporal_unit(global_object, *options, disallowed_units, "auto"sv, default_largest_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 }));
// 9. Perform ? ValidateTemporalUnitRange(largestUnit, smallestUnit).
TRY(validate_temporal_unit_range(global_object, *largest_unit, *smallest_unit));
// 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<RangeError>(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));

View File

@ -409,46 +409,51 @@ ThrowCompletionOr<Duration*> difference_temporal_plain_date_time(GlobalObject& g
// 4. Set options to ? GetOptionsObject(options).
auto const* options = TRY(get_options_object(global_object, options_value));
// 5. Let smallestUnit be ? ToSmallestTemporalUnit(options, « », "nanosecond").
auto smallest_unit = TRY(to_smallest_temporal_unit(global_object, *options, {}, "nanosecond"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("day", smallestUnit).
auto default_largest_unit = larger_of_two_temporal_units("day"sv, *smallest_unit);
// 7. Let largestUnit be ? ToLargestTemporalUnit(options, « », "auto", defaultLargestUnit).
auto largest_unit = TRY(to_largest_temporal_unit(global_object, *options, {}, "auto"sv, default_largest_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. Perform ? ValidateTemporalUnitRange(largestUnit, smallestUnit).
TRY(validate_temporal_unit_range(global_object, *largest_unit, *smallest_unit));
// 8. If largestUnit is "auto", set largestUnit to defaultLargestUnit.
if (largest_unit == "auto"sv)
largest_unit = default_largest_unit;
// 9. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
// 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<RangeError>(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));
// 10. If operation is since, then
// 11. 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).
// 12. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit).
auto maximum = maximum_temporal_duration_rounding_increment(*smallest_unit);
// 12. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false).
// 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false).
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, Optional<double>(maximum), false));
// 13. 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).
// 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));
// 14. Let relativeTo be ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[Calendar]]).
// 15. 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()));
// 15. 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]].
// 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;
// 16. Let result be ? BalanceDuration(roundResult.[[Days]], roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]], roundResult.[[Nanoseconds]], largestUnit).
// 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));
// 17. 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]]).
// 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]]).
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));
}

View File

@ -545,26 +545,19 @@ JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::round)
round_to = TRY(get_options_object(global_object, vm.argument(0)));
}
// 6. Let smallestUnit be ? ToSmallestTemporalUnit(roundTo, « "year", "month", "week" », undefined).
auto smallest_unit_value = TRY(to_smallest_temporal_unit(global_object, *round_to, { "year"sv, "month"sv, "week"sv }, {}));
// 6. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time, required, « "day" »).
auto smallest_unit = TRY(get_temporal_unit(global_object, *round_to, vm.names.smallestUnit, UnitGroup::Time, TemporalUnitRequired {}, { "day"sv }));
// 7. If smallestUnit is undefined, throw a RangeError exception.
if (!smallest_unit_value.has_value())
return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, vm.names.undefined.as_string(), "smallestUnit");
// NOTE: At this point smallest_unit_value can only be a string
auto& smallest_unit = *smallest_unit_value;
// 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
// 7. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *round_to, "halfExpand"));
// 9. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(roundTo, smallestUnit).
auto rounding_increment = TRY(to_temporal_date_time_rounding_increment(global_object, *round_to, smallest_unit));
// 8. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(roundTo, smallestUnit).
auto rounding_increment = TRY(to_temporal_date_time_rounding_increment(global_object, *round_to, *smallest_unit));
// 10. Let result be ! RoundISODateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode).
auto result = round_iso_date_time(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(), rounding_increment, smallest_unit, rounding_mode);
// 9. Let result be ! RoundISODateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode).
auto result = round_iso_date_time(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(), rounding_increment, *smallest_unit, rounding_mode);
// 11. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], dateTime.[[Calendar]]).
// 10. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], dateTime.[[Calendar]]).
return TRY(create_temporal_date_time(global_object, result.year, result.month, result.day, result.hour, result.minute, result.second, result.millisecond, result.microsecond, result.nanosecond, date_time->calendar()));
}

View File

@ -622,6 +622,8 @@ DaysAndTime round_time(u8 hour, u8 minute, u8 second, u16 millisecond, u16 micro
// 4.5.14 DifferenceTemporalPlainTime ( operation, temporalTime, other, options ), https://tc39.es/proposal-temporal/#sec-temporal-differencetemporalplaintime
ThrowCompletionOr<Duration*> 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;
@ -631,40 +633,45 @@ ThrowCompletionOr<Duration*> difference_temporal_plain_time(GlobalObject& global
// 3. Set options to ? GetOptionsObject(options).
auto const* options = TRY(get_options_object(global_object, options_value));
// 4. Let smallestUnit be ? ToSmallestTemporalUnit(options, « "year", "month", "week", "day" », "nanosecond").
auto smallest_unit = TRY(to_smallest_temporal_unit(global_object, *options, { "year"sv, "month"sv, "week"sv, "day"sv }, "nanosecond"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 ? ToLargestTemporalUnit(options, « "year", "month", "week", "day" », "auto", "hour").
auto largest_unit = TRY(to_largest_temporal_unit(global_object, *options, { "year"sv, "month"sv, "week"sv, "day"sv }, "auto"sv, "hour"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. Perform ? ValidateTemporalUnitRange(largestUnit, smallestUnit).
TRY(validate_temporal_unit_range(global_object, *largest_unit, *smallest_unit));
// 6. If largestUnit is "auto", set largestUnit to "hour".
if (largest_unit == "auto"sv)
largest_unit = "hour"sv;
// 7. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
// 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<RangeError>(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));
// 8. If operation is since, then
// 9. If operation is since, then
if (operation == DifferenceOperation::Since) {
// a. Set roundingMode to ! NegateTemporalRoundingMode(roundingMode).
rounding_mode = negate_temporal_rounding_mode(rounding_mode);
}
// 9. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit).
// 10. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit).
auto maximum = maximum_temporal_duration_rounding_increment(*smallest_unit);
// 10. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false).
// 11. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false).
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, Optional<double>(maximum), false));
// 11. 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]]).
// 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]]).
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());
// 12. Set result to (? RoundDuration(0, 0, 0, 0, result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode)).[[DurationRecord]].
// 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 = TRY(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;
// 13. Set result to ? BalanceDuration(0, result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]], largestUnit).
// 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));
// 14. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]).
// 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]]).
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));
}

View File

@ -293,44 +293,37 @@ JS_DEFINE_NATIVE_FUNCTION(PlainTimePrototype::round)
round_to = TRY(get_options_object(global_object, vm.argument(0)));
}
// 6. Let smallestUnit be ? ToSmallestTemporalUnit(roundTo, « "year", "month", "week", "day" », undefined).
auto smallest_unit_value = TRY(to_smallest_temporal_unit(global_object, *round_to, { "year"sv, "month"sv, "week"sv, "day"sv }, {}));
// 6. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time, required).
auto smallest_unit = TRY(get_temporal_unit(global_object, *round_to, vm.names.smallestUnit, UnitGroup::Time, TemporalUnitRequired {}));
// 7. If smallestUnit is undefined, throw a RangeError exception.
if (!smallest_unit_value.has_value())
return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, vm.names.undefined.as_string(), "smallestUnit");
// NOTE: At this point smallest_unit_value can only be a string
auto& smallest_unit = *smallest_unit_value;
// 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
// 7. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *round_to, "halfExpand"));
double maximum;
// 9. If smallestUnit is "hour", then
// 8. If smallestUnit is "hour", then
if (smallest_unit == "hour"sv) {
// a. Let maximum be 24.
maximum = 24;
}
// 10. Else if smallestUnit is "minute" or "second", then
// 9. Else if smallestUnit is "minute" or "second", then
else if (smallest_unit == "minute"sv || smallest_unit == "second"sv) {
// a. Let maximum be 60.
maximum = 60;
}
// 11. Else,
// 10. Else,
else {
// a. Let maximum be 1000.
maximum = 1000;
}
// 12. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo, maximum, false).
// 11. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo, maximum, false).
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *round_to, maximum, false));
// 13. Let result be ! RoundTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode).
auto result = round_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(), rounding_increment, smallest_unit, rounding_mode);
// 12. Let result be ! RoundTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode).
auto result = round_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(), rounding_increment, *smallest_unit, rounding_mode);
// 14. Return ? CreateTemporalTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).
// 13. Return ? CreateTemporalTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).
return TRY(create_temporal_time(global_object, result.hour, result.minute, result.second, result.millisecond, result.microsecond, result.nanosecond));
}

View File

@ -278,66 +278,76 @@ ThrowCompletionOr<Duration*> difference_temporal_plain_year_month(GlobalObject&
// 5. Set options to ? GetOptionsObject(options).
auto const* options = TRY(get_options_object(global_object, options_value));
// 6. Let disallowedUnits be « "week", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond" ».
auto disallowed_units = Vector<StringView> { "week"sv, "day"sv, "hour"sv, "minute"sv, "second"sv, "millisecond"sv, "microsecond"sv, "nanosecond"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. Let smallestUnit be ? ToSmallestTemporalUnit(options, disallowedUnits, "month").
auto smallest_unit = TRY(to_smallest_temporal_unit(global_object, *options, disallowed_units, "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<RangeError>(global_object, ErrorType::OptionIsNotValidValue, *smallest_unit, "smallestUnit"sv);
// 8. Let largestUnit be ? ToLargestTemporalUnit(options, disallowedUnits, "auto", "year").
auto largest_unit = TRY(to_largest_temporal_unit(global_object, *options, disallowed_units, "auto"sv, "year"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. Perform ? ValidateTemporalUnitRange(largestUnit, smallestUnit).
TRY(validate_temporal_unit_range(global_object, *largest_unit, *smallest_unit));
// 9. If largestUnit is "week" or "day", throw a RangeError exception.
if (largest_unit == "week"sv || largest_unit == "day"sv)
return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, *largest_unit, "largestUnit"sv);
// 10. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
// 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<RangeError>(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));
// 11. If operation is since, then
// 13. 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).
// 14. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, undefined, false).
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, {}, false));
// 13. Let fieldNames be ? CalendarFields(calendar, « "monthCode", "year" »).
// 15. Let fieldNames be ? CalendarFields(calendar, « "monthCode", "year" »).
auto field_names = TRY(calendar_fields(global_object, calendar, { "monthCode"sv, "year"sv }));
// 14. Let otherFields be ? PrepareTemporalFields(other, fieldNames, «»).
// 16. Let otherFields be ? PrepareTemporalFields(other, fieldNames, «»).
auto* other_fields = TRY(prepare_temporal_fields(global_object, *other, field_names, {}));
// 15. Perform ! CreateDataPropertyOrThrow(otherFields, "day", 1𝔽).
// 17. Perform ! CreateDataPropertyOrThrow(otherFields, "day", 1𝔽).
MUST(other_fields->create_data_property_or_throw(vm.names.day, Value(1)));
// 16. Let otherDate be ? CalendarDateFromFields(calendar, otherFields).
// 18. Let otherDate be ? CalendarDateFromFields(calendar, otherFields).
auto* other_date = TRY(calendar_date_from_fields(global_object, calendar, *other_fields));
// 17. Let thisFields be ? PrepareTemporalFields(yearMonth, fieldNames, «»).
// 19. Let thisFields be ? PrepareTemporalFields(yearMonth, fieldNames, «»).
auto* this_fields = TRY(prepare_temporal_fields(global_object, year_month, field_names, {}));
// 18. Perform ! CreateDataPropertyOrThrow(thisFields, "day", 1𝔽).
// 20. Perform ! CreateDataPropertyOrThrow(thisFields, "day", 1𝔽).
MUST(this_fields->create_data_property_or_throw(vm.names.day, Value(1)));
// 19. Let thisDate be ? CalendarDateFromFields(calendar, thisFields).
// 21. Let thisDate be ? CalendarDateFromFields(calendar, thisFields).
auto* this_date = TRY(calendar_date_from_fields(global_object, calendar, *this_fields));
// 20. Let untilOptions be ? MergeLargestUnitOption(options, largestUnit).
// 22. Let untilOptions be ? MergeLargestUnitOption(options, largestUnit).
auto* until_options = TRY(merge_largest_unit_option(global_object, options, *largest_unit));
// 21. Let result be ? CalendarDateUntil(calendar, thisDate, otherDate, untilOptions).
// 23. 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 };
// 22. If smallestUnit is not "month" or roundingIncrement ≠ 1, then
// 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;
}
// 23. Return ! CreateTemporalDuration(sign × result.[[Years]], sign × result.[[Months]], 0, 0, 0, 0, 0, 0, 0, 0).
// 25. 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));
}

View File

@ -557,34 +557,39 @@ ThrowCompletionOr<Duration*> difference_temporal_zoned_date_time(GlobalObject& g
// 4. Set options to ? GetOptionsObject(options).
auto const* options = TRY(get_options_object(global_object, options_value));
// 5. Let smallestUnit be ? ToSmallestTemporalUnit(options, « », "nanosecond").
auto smallest_unit = TRY(to_smallest_temporal_unit(global_object, *options, {}, "nanosecond"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 ? ToLargestTemporalUnit(options, « », "auto", defaultLargestUnit).
auto largest_unit = TRY(to_largest_temporal_unit(global_object, *options, {}, "auto"sv, default_largest_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. Perform ? ValidateTemporalUnitRange(largestUnit, smallestUnit).
TRY(validate_temporal_unit_range(global_object, *largest_unit, *smallest_unit));
// 8. If largestUnit is "auto", set largestUnit to defaultLargestUnit.
if (largest_unit == "auto"sv)
largest_unit = default_largest_unit;
// 9. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
// 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<RangeError>(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));
// 10. If operation is since, then
// 11. 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).
// 12. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit).
auto maximum = maximum_temporal_duration_rounding_increment(*smallest_unit);
// 12. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false).
// 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false).
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, Optional<double>(maximum), false));
// 13. If largestUnit is not one of "year", "month", "week", or "day", then
// 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);
@ -598,25 +603,25 @@ ThrowCompletionOr<Duration*> difference_temporal_zoned_date_time(GlobalObject& g
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));
}
// 14. If ? TimeZoneEquals(zonedDateTime.[[TimeZone]], other.[[TimeZone]]) is false, then
// 15. 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<RangeError>(global_object, ErrorType::TemporalDifferentTimeZones);
}
// 15. Let untilOptions be ? MergeLargestUnitOption(options, largestUnit).
// 16. Let untilOptions be ? MergeLargestUnitOption(options, largestUnit).
auto* until_options = TRY(merge_largest_unit_option(global_object, options, *largest_unit));
// 16. Let difference be ? DifferenceZonedDateTime(zonedDateTime.[[Nanoseconds]], other.[[Nanoseconds]], zonedDateTime.[[TimeZone]], zonedDateTime.[[Calendar]], largestUnit, untilOptions).
// 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));
// 17. 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]].
// 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;
// 18. 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).
// 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));
// 19. 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]]).
// 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]]).
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));
}

View File

@ -979,69 +979,62 @@ JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::round)
round_to = TRY(get_options_object(global_object, vm.argument(0)));
}
// 6. Let smallestUnit be ? ToSmallestTemporalUnit(roundTo, « "year", "month", "week" », undefined).
auto smallest_unit_value = TRY(to_smallest_temporal_unit(global_object, *round_to, { "year"sv, "month"sv, "week"sv }, {}));
// 6. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time, required, « "day" »).
auto smallest_unit = TRY(get_temporal_unit(global_object, *round_to, vm.names.smallestUnit, UnitGroup::Time, TemporalUnitRequired {}, { "day"sv }));
// 7. If smallestUnit is undefined, throw a RangeError exception.
if (!smallest_unit_value.has_value())
return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, vm.names.undefined.as_string(), "smallestUnit");
// NOTE: At this point smallest_unit_value can only be a string
auto& smallest_unit = *smallest_unit_value;
// 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
// 7. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *round_to, "halfExpand"sv));
// 9. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(options, smallestUnit).
auto rounding_increment = TRY(to_temporal_date_time_rounding_increment(global_object, *round_to, smallest_unit));
// 8. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(options, smallestUnit).
auto rounding_increment = TRY(to_temporal_date_time_rounding_increment(global_object, *round_to, *smallest_unit));
// 10. Let timeZone be zonedDateTime.[[TimeZone]].
// 9. Let timeZone be zonedDateTime.[[TimeZone]].
auto& time_zone = zoned_date_time->time_zone();
// 11. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
// 10. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
auto* instant = MUST(create_temporal_instant(global_object, zoned_date_time->nanoseconds()));
// 12. Let calendar be zonedDateTime.[[Calendar]].
// 11. Let calendar be zonedDateTime.[[Calendar]].
auto& calendar = zoned_date_time->calendar();
// 13. Let temporalDateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
// 12. Let temporalDateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
auto* temporal_date_time = TRY(builtin_time_zone_get_plain_date_time_for(global_object, &time_zone, *instant, calendar));
// 14. Let isoCalendar be ! GetISO8601Calendar().
// 13. Let isoCalendar be ! GetISO8601Calendar().
auto* iso_calendar = get_iso8601_calendar(global_object);
// 15. Let dtStart be ? CreateTemporalDateTime(temporalDateTime.[[ISOYear]], temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], 0, 0, 0, 0, 0, 0, isoCalendar).
// 14. Let dtStart be ? CreateTemporalDateTime(temporalDateTime.[[ISOYear]], temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], 0, 0, 0, 0, 0, 0, isoCalendar).
auto* dt_start = TRY(create_temporal_date_time(global_object, temporal_date_time->iso_year(), temporal_date_time->iso_month(), temporal_date_time->iso_day(), 0, 0, 0, 0, 0, 0, *iso_calendar));
// 16. Let instantStart be ? BuiltinTimeZoneGetInstantFor(timeZone, dtStart, "compatible").
// 15. Let instantStart be ? BuiltinTimeZoneGetInstantFor(timeZone, dtStart, "compatible").
auto* instant_start = TRY(builtin_time_zone_get_instant_for(global_object, &time_zone, *dt_start, "compatible"sv));
// 17. Let startNs be instantStart.[[Nanoseconds]].
// 16. Let startNs be instantStart.[[Nanoseconds]].
auto& start_ns = instant_start->nanoseconds();
// 18. Let endNs be ? AddZonedDateTime(startNs, timeZone, zonedDateTime.[[Calendar]], 0, 0, 0, 1, 0, 0, 0, 0, 0, 0).
// 17. Let endNs be ? AddZonedDateTime(startNs, timeZone, zonedDateTime.[[Calendar]], 0, 0, 0, 1, 0, 0, 0, 0, 0, 0).
// TODO: Shouldn't `zonedDateTime.[[Calendar]]` be `calendar` for consistency?
auto* end_ns = TRY(add_zoned_date_time(global_object, start_ns, &time_zone, zoned_date_time->calendar(), 0, 0, 0, 1, 0, 0, 0, 0, 0, 0));
// 19. Let dayLengthNs be (endNs - startNs).
// 18. Let dayLengthNs be (endNs - startNs).
auto day_length_ns = end_ns->big_integer().minus(start_ns.big_integer()).to_double();
// 20. If dayLengthNs is 0, then
// 19. If dayLengthNs is 0, then
if (day_length_ns == 0) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalZonedDateTimeRoundZeroLengthDay);
}
// 21. Let roundResult be ! RoundISODateTime(temporalDateTime.[[ISOYear]], temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], temporalDateTime.[[ISOHour]], temporalDateTime.[[ISOMinute]], temporalDateTime.[[ISOSecond]], temporalDateTime.[[ISOMillisecond]], temporalDateTime.[[ISOMicrosecond]], temporalDateTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode, dayLengthNs).
auto round_result = round_iso_date_time(temporal_date_time->iso_year(), temporal_date_time->iso_month(), temporal_date_time->iso_day(), temporal_date_time->iso_hour(), temporal_date_time->iso_minute(), temporal_date_time->iso_second(), temporal_date_time->iso_millisecond(), temporal_date_time->iso_microsecond(), temporal_date_time->iso_nanosecond(), rounding_increment, smallest_unit, rounding_mode, day_length_ns);
// 20. Let roundResult be ! RoundISODateTime(temporalDateTime.[[ISOYear]], temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], temporalDateTime.[[ISOHour]], temporalDateTime.[[ISOMinute]], temporalDateTime.[[ISOSecond]], temporalDateTime.[[ISOMillisecond]], temporalDateTime.[[ISOMicrosecond]], temporalDateTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode, dayLengthNs).
auto round_result = round_iso_date_time(temporal_date_time->iso_year(), temporal_date_time->iso_month(), temporal_date_time->iso_day(), temporal_date_time->iso_hour(), temporal_date_time->iso_minute(), temporal_date_time->iso_second(), temporal_date_time->iso_millisecond(), temporal_date_time->iso_microsecond(), temporal_date_time->iso_nanosecond(), rounding_increment, *smallest_unit, rounding_mode, day_length_ns);
// 22. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
// 21. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
auto offset_nanoseconds = TRY(get_offset_nanoseconds_for(global_object, &time_zone, *instant));
// 23. Let epochNanoseconds be ? InterpretISODateTimeOffset(roundResult.[[Year]], roundResult.[[Month]], roundResult.[[Day]], roundResult.[[Hour]], roundResult.[[Minute]], roundResult.[[Second]], roundResult.[[Millisecond]], roundResult.[[Microsecond]], roundResult.[[Nanosecond]], option, offsetNanoseconds, timeZone, "compatible", "prefer", match exactly).
// 22. Let epochNanoseconds be ? InterpretISODateTimeOffset(roundResult.[[Year]], roundResult.[[Month]], roundResult.[[Day]], roundResult.[[Hour]], roundResult.[[Minute]], roundResult.[[Second]], roundResult.[[Millisecond]], roundResult.[[Microsecond]], roundResult.[[Nanosecond]], option, offsetNanoseconds, timeZone, "compatible", "prefer", match exactly).
auto* epoch_nanoseconds = TRY(interpret_iso_date_time_offset(global_object, round_result.year, round_result.month, round_result.day, round_result.hour, round_result.minute, round_result.second, round_result.millisecond, round_result.microsecond, round_result.nanosecond, OffsetBehavior::Option, offset_nanoseconds, &time_zone, "compatible"sv, "prefer"sv, MatchBehavior::MatchExactly));
// 24. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).
// 23. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).
return MUST(create_temporal_zoned_date_time(global_object, *epoch_nanoseconds, time_zone, calendar));
}

View File

@ -175,7 +175,7 @@ describe("errors", () => {
dateOne.since(dateTwo, pluralSmallestUnitOptions);
}).toThrowWithMessage(
RangeError,
`${smallestUnit} is not a valid value for option smallestUnit`
`${smallestUnit}s is not a valid value for option smallestUnit`
);
}
@ -194,7 +194,7 @@ describe("errors", () => {
dateOne.since(dateTwo, pluralLargestUnitOptions);
}).toThrowWithMessage(
RangeError,
`${largestUnit} is not a valid value for option largestUnit`
`${largestUnit}s is not a valid value for option largestUnit`
);
}
});

View File

@ -170,7 +170,7 @@ describe("errors", () => {
dateOne.until(dateTwo, pluralSmallestUnitOptions);
}).toThrowWithMessage(
RangeError,
`${smallestUnit} is not a valid value for option smallestUnit`
`${smallestUnit}s is not a valid value for option smallestUnit`
);
}
@ -189,7 +189,7 @@ describe("errors", () => {
dateOne.until(dateTwo, pluralLargestUnitOptions);
}).toThrowWithMessage(
RangeError,
`${largestUnit} is not a valid value for option largestUnit`
`${largestUnit}s is not a valid value for option largestUnit`
);
}
});