mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 23:17:45 +00:00
LibJS: Allow string as parameter in Temporal's round() / total()
This is a normative change in the Temporal spec.
See: 1f0c586
This commit is contained in:
parent
93ee922027
commit
d0c29c9735
9 changed files with 199 additions and 89 deletions
|
@ -288,92 +288,107 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::abs)
|
|||
return TRY(create_temporal_duration(global_object, fabs(duration->years()), fabs(duration->months()), fabs(duration->weeks()), fabs(duration->days()), fabs(duration->hours()), fabs(duration->minutes()), fabs(duration->seconds()), fabs(duration->milliseconds()), fabs(duration->microseconds()), fabs(duration->nanoseconds())));
|
||||
}
|
||||
|
||||
// 7.3.21 Temporal.Duration.prototype.total ( options ), https://tc39.es/proposal-temporal/#sec-temporal.duration.prototype.total
|
||||
// 7.3.21 Temporal.Duration.prototype.total ( totalOf ), https://tc39.es/proposal-temporal/#sec-temporal.duration.prototype.total
|
||||
JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::total)
|
||||
{
|
||||
// 1. Let duration be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
|
||||
auto* duration = TRY(typed_this_object(global_object));
|
||||
|
||||
// 3. If options is undefined, throw a TypeError exception.
|
||||
// 3. If totalOf is undefined, throw a TypeError exception.
|
||||
if (vm.argument(0).is_undefined())
|
||||
return vm.throw_completion<TypeError>(global_object, ErrorType::TemporalMissingOptionsObject);
|
||||
|
||||
// 4. Set options to ? GetOptionsObject(options).
|
||||
auto* options = TRY(get_options_object(global_object, vm.argument(0)));
|
||||
Object* total_of;
|
||||
|
||||
// 5. Let relativeTo be ? ToRelativeTemporalObject(options).
|
||||
auto relative_to = TRY(to_relative_temporal_object(global_object, *options));
|
||||
// 4. If Type(totalOf) is String, then
|
||||
if (vm.argument(0).is_string()) {
|
||||
// a. Let paramString be totalOf.
|
||||
|
||||
// 6. Let unit be ? ToTemporalDurationTotalUnit(options).
|
||||
auto unit = TRY(to_temporal_duration_total_unit(global_object, *options));
|
||||
// b. Set totalOf to ! OrdinaryObjectCreate(null).
|
||||
total_of = Object::create(global_object, nullptr);
|
||||
|
||||
// 7. Let unbalanceResult be ? UnbalanceDurationRelative(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], unit, relativeTo).
|
||||
// c. Perform ! CreateDataPropertyOrThrow(totalOf, "unit", paramString).
|
||||
MUST(total_of->create_data_property_or_throw(vm.names.unit, vm.argument(0)));
|
||||
}
|
||||
// 5. Else,
|
||||
else {
|
||||
// a. Set totalOf to ? GetOptionsObject(totalOf).
|
||||
total_of = TRY(get_options_object(global_object, vm.argument(0)));
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
// 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));
|
||||
|
||||
// 8. Let intermediate be undefined.
|
||||
// 9. Let intermediate be undefined.
|
||||
ZonedDateTime* intermediate = nullptr;
|
||||
|
||||
// 9. If relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot, then
|
||||
// 10. If relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot, then
|
||||
if (relative_to.is_object() && is<ZonedDateTime>(relative_to.as_object())) {
|
||||
// a. Set intermediate to ? MoveRelativeZonedDateTime(relativeTo, unbalanceResult.[[Years]], unbalanceResult.[[Months]], unbalanceResult.[[Weeks]], 0).
|
||||
intermediate = TRY(move_relative_zoned_date_time(global_object, static_cast<ZonedDateTime&>(relative_to.as_object()), unbalance_result.years, unbalance_result.months, unbalance_result.weeks, 0));
|
||||
}
|
||||
|
||||
// 10. Let balanceResult be ? BalanceDuration(unbalanceResult.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]], unit, intermediate).
|
||||
// 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(), *js_bigint(vm, Crypto::SignedBigInteger::create_from(duration->nanoseconds())), unit, intermediate));
|
||||
|
||||
// 11. Let roundResult 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).
|
||||
// 12. Let roundResult 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_result = 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));
|
||||
|
||||
double whole;
|
||||
|
||||
// 12. If unit is "year", then
|
||||
// 13. If unit is "year", then
|
||||
if (unit == "year"sv) {
|
||||
// a. Let whole be roundResult.[[Years]].
|
||||
whole = round_result.years;
|
||||
}
|
||||
// 13. Else if unit is "month", then
|
||||
// 14. Else if unit is "month", then
|
||||
else if (unit == "month"sv) {
|
||||
// a. Let whole be roundResult.[[Months]].
|
||||
whole = round_result.months;
|
||||
}
|
||||
// 14. Else if unit is "week", then
|
||||
// 15. Else if unit is "week", then
|
||||
else if (unit == "week"sv) {
|
||||
// a. Let whole be roundResult.[[Weeks]].
|
||||
whole = round_result.weeks;
|
||||
}
|
||||
// 15. Else if unit is "day", then
|
||||
// 16. Else if unit is "day", then
|
||||
else if (unit == "day"sv) {
|
||||
// a. Let whole be roundResult.[[Days]].
|
||||
whole = round_result.days;
|
||||
}
|
||||
// 16. Else if unit is "hour", then
|
||||
// 17. Else if unit is "hour", then
|
||||
else if (unit == "hour"sv) {
|
||||
// a. Let whole be roundResult.[[Hours]].
|
||||
whole = round_result.hours;
|
||||
}
|
||||
// 17. Else if unit is "minute", then
|
||||
// 18. Else if unit is "minute", then
|
||||
else if (unit == "minute"sv) {
|
||||
// a. Let whole be roundResult.[[Minutes]].
|
||||
whole = round_result.minutes;
|
||||
}
|
||||
// 18. Else if unit is "second", then
|
||||
// 19. Else if unit is "second", then
|
||||
else if (unit == "second"sv) {
|
||||
// a. Let whole be roundResult.[[Seconds]].
|
||||
whole = round_result.seconds;
|
||||
}
|
||||
// 19. Else if unit is "millisecond", then
|
||||
// 20. Else if unit is "millisecond", then
|
||||
else if (unit == "millisecond"sv) {
|
||||
// a. Let whole be roundResult.[[Milliseconds]].
|
||||
whole = round_result.milliseconds;
|
||||
}
|
||||
// 20. Else if unit is "microsecond", then
|
||||
// 21. Else if unit is "microsecond", then
|
||||
else if (unit == "microsecond"sv) {
|
||||
// a. Let whole be roundResult.[[Microseconds]].
|
||||
whole = round_result.microseconds;
|
||||
}
|
||||
// 21. Else,
|
||||
// 22. Else,
|
||||
else {
|
||||
// a. Assert: unit is "nanosecond".
|
||||
VERIFY(unit == "nanosecond"sv);
|
||||
|
@ -382,7 +397,7 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::total)
|
|||
whole = round_result.nanoseconds;
|
||||
}
|
||||
|
||||
// 22. Return whole + roundResult.[[Remainder]].
|
||||
// 23. Return whole + roundResult.[[Remainder]].
|
||||
return whole + round_result.remainder;
|
||||
}
|
||||
|
||||
|
|
|
@ -243,24 +243,40 @@ JS_DEFINE_NATIVE_FUNCTION(InstantPrototype::since)
|
|||
return TRY(create_temporal_duration(global_object, 0, 0, 0, 0, result.hours, result.minutes, result.seconds, result.milliseconds, result.microseconds, result.nanoseconds));
|
||||
}
|
||||
|
||||
// 8.3.11 Temporal.Instant.prototype.round ( options ), https://tc39.es/proposal-temporal/#sec-temporal.instant.prototype.round
|
||||
// 8.3.11 Temporal.Instant.prototype.round ( roundTo ), https://tc39.es/proposal-temporal/#sec-temporal.instant.prototype.round
|
||||
JS_DEFINE_NATIVE_FUNCTION(InstantPrototype::round)
|
||||
{
|
||||
// 1. Let instant be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
|
||||
auto* instant = TRY(typed_this_object(global_object));
|
||||
|
||||
// 3. If options is undefined, then
|
||||
// 3. If roundTo is undefined, then
|
||||
if (vm.argument(0).is_undefined()) {
|
||||
// a. Throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(global_object, ErrorType::TemporalMissingOptionsObject);
|
||||
}
|
||||
|
||||
// 4. Set options to ? GetOptionsObject(options).
|
||||
auto* options = TRY(get_options_object(global_object, vm.argument(0)));
|
||||
Object* round_to;
|
||||
|
||||
// 5. Let smallestUnit be ? ToSmallestTemporalUnit(options, « "year", "month", "week", "day" », undefined).
|
||||
auto smallest_unit_value = TRY(to_smallest_temporal_unit(global_object, *options, { "year"sv, "month"sv, "week"sv, "day"sv }, {}));
|
||||
// 4. If Type(roundTo) is String, then
|
||||
if (vm.argument(0).is_string()) {
|
||||
// a. Let paramString be roundTo.
|
||||
|
||||
// b. Set roundTo to ! OrdinaryObjectCreate(null).
|
||||
round_to = Object::create(global_object, nullptr);
|
||||
|
||||
// FIXME: "_smallestUnit_" is a spec bug, see https://github.com/tc39/proposal-temporal/pull/1931
|
||||
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "_smallestUnit_", paramString).
|
||||
MUST(round_to->create_data_property_or_throw(vm.names.smallestUnit, vm.argument(0)));
|
||||
}
|
||||
// 5. Else,
|
||||
else {
|
||||
// a. Set roundTo to ? GetOptionsObject(roundTo).
|
||||
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. If smallestUnit is undefined, throw a RangeError exception.
|
||||
if (!smallest_unit_value.has_value())
|
||||
|
@ -269,8 +285,8 @@ JS_DEFINE_NATIVE_FUNCTION(InstantPrototype::round)
|
|||
// At this point smallest_unit_value can only be a string
|
||||
auto& smallest_unit = *smallest_unit_value;
|
||||
|
||||
// 7. Let roundingMode be ? ToTemporalRoundingMode(options, "halfExpand").
|
||||
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "halfExpand"));
|
||||
// 7. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
|
||||
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *round_to, "halfExpand"));
|
||||
|
||||
double maximum;
|
||||
// 8. If smallestUnit is "hour", then
|
||||
|
@ -306,8 +322,8 @@ JS_DEFINE_NATIVE_FUNCTION(InstantPrototype::round)
|
|||
maximum = 86400000000000;
|
||||
}
|
||||
|
||||
// 14. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, true).
|
||||
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, maximum, true));
|
||||
// 14. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo, maximum, true).
|
||||
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *round_to, maximum, true));
|
||||
|
||||
// 15. Let roundedNs be ! RoundTemporalInstant(instant.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode).
|
||||
auto* rounded_ns = round_temporal_instant(global_object, instant->nanoseconds(), rounding_increment, smallest_unit, rounding_mode);
|
||||
|
|
|
@ -506,42 +506,58 @@ JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::subtract)
|
|||
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()));
|
||||
}
|
||||
|
||||
// 5.3.30 Temporal.PlainDateTime.prototype.round ( options ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.round
|
||||
// 5.3.30 Temporal.PlainDateTime.prototype.round ( roundTo ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.round
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::round)
|
||||
{
|
||||
// 1. Let dateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
|
||||
auto* date_time = TRY(typed_this_object(global_object));
|
||||
|
||||
// 3. If options is undefined, then
|
||||
// 3. If roundTo is undefined, then
|
||||
if (vm.argument(0).is_undefined()) {
|
||||
// a. Throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(global_object, ErrorType::TemporalMissingOptionsObject);
|
||||
}
|
||||
|
||||
// 4. Set options to ? GetOptionsObject(options).
|
||||
auto* options = TRY(get_options_object(global_object, vm.argument(0)));
|
||||
Object* round_to;
|
||||
|
||||
// 5. Let smallestUnit be ? ToSmallestTemporalUnit(options, « "year", "month", "week" », undefined).
|
||||
auto smallest_unit_value = TRY(to_smallest_temporal_unit(global_object, *options, { "year"sv, "month"sv, "week"sv }, {}));
|
||||
// 4. If Type(roundTo) is String, then
|
||||
if (vm.argument(0).is_string()) {
|
||||
// a. Let paramString be roundTo.
|
||||
|
||||
// 6. If smallestUnit is undefined, throw a RangeError exception.
|
||||
// b. Set roundTo to ! OrdinaryObjectCreate(null).
|
||||
round_to = Object::create(global_object, nullptr);
|
||||
|
||||
// FIXME: "_smallestUnit_" is a spec bug, see https://github.com/tc39/proposal-temporal/pull/1931
|
||||
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "_smallestUnit_", paramString).
|
||||
MUST(round_to->create_data_property_or_throw(vm.names.smallestUnit, vm.argument(0)));
|
||||
}
|
||||
// 5. Else,
|
||||
else {
|
||||
// a. Set roundTo to ? GetOptionsObject(roundTo).
|
||||
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 }, {}));
|
||||
|
||||
// 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;
|
||||
|
||||
// 7. Let roundingMode be ? ToTemporalRoundingMode(options, "halfExpand").
|
||||
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "halfExpand"));
|
||||
// 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
|
||||
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *round_to, "halfExpand"));
|
||||
|
||||
// 8. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(options, smallestUnit).
|
||||
auto rounding_increment = TRY(to_temporal_date_time_rounding_increment(global_object, *options, smallest_unit));
|
||||
// 9. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(roundTo, smallestUnit).
|
||||
auto rounding_increment = TRY(to_temporal_date_time_rounding_increment(global_object, *round_to, smallest_unit));
|
||||
|
||||
// 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).
|
||||
// 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);
|
||||
|
||||
// 10. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], dateTime.[[Calendar]]).
|
||||
// 11. 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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -250,60 +250,76 @@ JS_DEFINE_NATIVE_FUNCTION(PlainTimePrototype::with)
|
|||
return TRY(create_temporal_time(global_object, result.hour, result.minute, result.second, result.millisecond, result.microsecond, result.nanosecond));
|
||||
}
|
||||
|
||||
// 4.3.15 Temporal.PlainTime.prototype.round ( options ), https://tc39.es/proposal-temporal/#sec-temporal.plaintime.prototype.round
|
||||
// 4.3.15 Temporal.PlainTime.prototype.round ( roundTo ), https://tc39.es/proposal-temporal/#sec-temporal.plaintime.prototype.round
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainTimePrototype::round)
|
||||
{
|
||||
// 1. Let temporalTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
|
||||
auto* temporal_time = TRY(typed_this_object(global_object));
|
||||
|
||||
// 3. If options is undefined, then
|
||||
// 3. If roundTo is undefined, then
|
||||
if (vm.argument(0).is_undefined()) {
|
||||
// a. Throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(global_object, ErrorType::TemporalMissingOptionsObject);
|
||||
}
|
||||
|
||||
// 4. Set options to ? GetOptionsObject(options).
|
||||
auto* options = TRY(get_options_object(global_object, vm.argument(0)));
|
||||
Object* round_to;
|
||||
|
||||
// 5. Let smallestUnit be ? ToSmallestTemporalUnit(options, « "year", "month", "week", "day" », undefined).
|
||||
auto smallest_unit_value = TRY(to_smallest_temporal_unit(global_object, *options, { "year"sv, "month"sv, "week"sv, "day"sv }, {}));
|
||||
// 4. If Type(roundTo) is String, then
|
||||
if (vm.argument(0).is_string()) {
|
||||
// a. Let paramString be roundTo.
|
||||
|
||||
// 6. If smallestUnit is undefined, throw a RangeError exception.
|
||||
// b. Set roundTo to ! OrdinaryObjectCreate(null).
|
||||
round_to = Object::create(global_object, nullptr);
|
||||
|
||||
// FIXME: "_smallestUnit_" is a spec bug, see https://github.com/tc39/proposal-temporal/pull/1931
|
||||
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "_smallestUnit_", paramString).
|
||||
MUST(round_to->create_data_property_or_throw(vm.names.smallestUnit, vm.argument(0)));
|
||||
}
|
||||
// 5. Else,
|
||||
else {
|
||||
// a. Set roundTo to ? GetOptionsObject(roundTo).
|
||||
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 }, {}));
|
||||
|
||||
// 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;
|
||||
|
||||
// 7. Let roundingMode be ? ToTemporalRoundingMode(options, "halfExpand").
|
||||
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "halfExpand"));
|
||||
// 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
|
||||
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *round_to, "halfExpand"));
|
||||
|
||||
double maximum;
|
||||
|
||||
// 8. If smallestUnit is "hour", then
|
||||
// 9. If smallestUnit is "hour", then
|
||||
if (smallest_unit == "hour"sv) {
|
||||
// a. Let maximum be 24.
|
||||
maximum = 24;
|
||||
}
|
||||
// 9. Else if smallestUnit is "minute" or "second", then
|
||||
// 10. 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;
|
||||
}
|
||||
// 10. Else,
|
||||
// 11. Else,
|
||||
else {
|
||||
// a. Let maximum be 1000.
|
||||
maximum = 1000;
|
||||
}
|
||||
|
||||
// 11. Let roundingIncrement be ? ToTemporalRoundingIncrement(options, maximum, false).
|
||||
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *options, maximum, false));
|
||||
// 12. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo, maximum, false).
|
||||
auto rounding_increment = TRY(to_temporal_rounding_increment(global_object, *round_to, maximum, false));
|
||||
|
||||
// 12. Let result be ! RoundTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode).
|
||||
// 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);
|
||||
|
||||
// 13. Return ? CreateTemporalTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).
|
||||
// 14. 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));
|
||||
}
|
||||
|
||||
|
|
|
@ -942,85 +942,101 @@ JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::subtract)
|
|||
return MUST(create_temporal_zoned_date_time(global_object, *epoch_nanoseconds, time_zone, calendar));
|
||||
}
|
||||
|
||||
// 6.3.39 Temporal.ZonedDateTime.prototype.round ( options ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.round
|
||||
// 6.3.39 Temporal.ZonedDateTime.prototype.round ( roundTo ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.round
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::round)
|
||||
{
|
||||
// 1. Let zonedDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
|
||||
auto* zoned_date_time = TRY(typed_this_object(global_object));
|
||||
|
||||
// 3. If options is undefined, then
|
||||
// 3. If roundTo is undefined, then
|
||||
if (vm.argument(0).is_undefined()) {
|
||||
// a. Throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(global_object, ErrorType::TemporalMissingOptionsObject);
|
||||
}
|
||||
|
||||
// 4. Set options to ? GetOptionsObject(options).
|
||||
auto* options = TRY(get_options_object(global_object, vm.argument(0)));
|
||||
Object* round_to;
|
||||
|
||||
// 5. Let smallestUnit be ? ToSmallestTemporalUnit(options, « "year", "month", "week" », undefined).
|
||||
auto smallest_unit_value = TRY(to_smallest_temporal_unit(global_object, *options, { "year"sv, "month"sv, "week"sv }, {}));
|
||||
// 4. If Type(roundTo) is String, then
|
||||
if (vm.argument(0).is_string()) {
|
||||
// a. Let paramString be roundTo.
|
||||
|
||||
// 6. If smallestUnit is undefined, throw a RangeError exception.
|
||||
// b. Set roundTo to ! OrdinaryObjectCreate(null).
|
||||
round_to = Object::create(global_object, nullptr);
|
||||
|
||||
// FIXME: "_smallestUnit_" is a spec bug, see https://github.com/tc39/proposal-temporal/pull/1931
|
||||
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "_smallestUnit_", paramString).
|
||||
MUST(round_to->create_data_property_or_throw(vm.names.smallestUnit, vm.argument(0)));
|
||||
}
|
||||
// 5. Else,
|
||||
else {
|
||||
// a. Set roundTo to ? GetOptionsObject(roundTo).
|
||||
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 }, {}));
|
||||
|
||||
// 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;
|
||||
|
||||
// 7. Let roundingMode be ? ToTemporalRoundingMode(options, "halfExpand").
|
||||
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *options, "halfExpand"sv));
|
||||
// 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
|
||||
auto rounding_mode = TRY(to_temporal_rounding_mode(global_object, *round_to, "halfExpand"sv));
|
||||
|
||||
// 8. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(options, smallestUnit).
|
||||
auto rounding_increment = TRY(to_temporal_date_time_rounding_increment(global_object, *options, smallest_unit));
|
||||
// 9. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(options, smallestUnit).
|
||||
auto rounding_increment = TRY(to_temporal_date_time_rounding_increment(global_object, *round_to, smallest_unit));
|
||||
|
||||
// 9. Let timeZone be zonedDateTime.[[TimeZone]].
|
||||
// 10. Let timeZone be zonedDateTime.[[TimeZone]].
|
||||
auto& time_zone = zoned_date_time->time_zone();
|
||||
|
||||
// 10. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
|
||||
// 11. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
|
||||
auto* instant = MUST(create_temporal_instant(global_object, zoned_date_time->nanoseconds()));
|
||||
|
||||
// 11. Let calendar be zonedDateTime.[[Calendar]].
|
||||
// 12. Let calendar be zonedDateTime.[[Calendar]].
|
||||
auto& calendar = zoned_date_time->calendar();
|
||||
|
||||
// 12. Let temporalDateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
|
||||
// 13. 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));
|
||||
|
||||
// 13. Let isoCalendar be ! GetISO8601Calendar().
|
||||
// 14. Let isoCalendar be ! GetISO8601Calendar().
|
||||
auto* iso_calendar = get_iso8601_calendar(global_object);
|
||||
|
||||
// 14. Let dtStart be ? CreateTemporalDateTime(temporalDateTime.[[ISOYear]], temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], 0, 0, 0, 0, 0, 0, isoCalendar).
|
||||
// 15. 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));
|
||||
|
||||
// 15. Let instantStart be ? BuiltinTimeZoneGetInstantFor(timeZone, dtStart, "compatible").
|
||||
// 16. 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));
|
||||
|
||||
// 16. Let startNs be instantStart.[[Nanoseconds]].
|
||||
// 17. Let startNs be instantStart.[[Nanoseconds]].
|
||||
auto& start_ns = instant_start->nanoseconds();
|
||||
|
||||
// 17. Let endNs be ? AddZonedDateTime(startNs, timeZone, zonedDateTime.[[Calendar]], 0, 0, 0, 1, 0, 0, 0, 0, 0, 0).
|
||||
// 18. 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));
|
||||
|
||||
// 18. Let dayLengthNs be ℝ(endNs − startNs).
|
||||
// 19. Let dayLengthNs be ℝ(endNs − startNs).
|
||||
auto day_length_ns = end_ns->big_integer().minus(start_ns.big_integer()).to_double();
|
||||
|
||||
// 19. If dayLengthNs is 0, then
|
||||
// 20. If dayLengthNs is 0, then
|
||||
if (day_length_ns == 0) {
|
||||
// a. Throw a RangeError exception.
|
||||
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalZonedDateTimeRoundZeroLengthDay);
|
||||
}
|
||||
|
||||
// 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).
|
||||
// 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);
|
||||
|
||||
// 21. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
|
||||
// 22. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
|
||||
auto offset_nanoseconds = TRY(get_offset_nanoseconds_for(global_object, &time_zone, *instant));
|
||||
|
||||
// 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).
|
||||
// 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).
|
||||
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));
|
||||
|
||||
// 23. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).
|
||||
// 24. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).
|
||||
return MUST(create_temporal_zoned_date_time(global_object, *epoch_nanoseconds, time_zone, calendar));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue