Browse Source

Progress on Duration's round/total method updates (#3451)

* Update round and total method

* Apply review

* Cargo fmt

* validate rounding increment to u64
pull/3457/head
Kevin 1 year ago committed by GitHub
parent
commit
f551af9386
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 109
      boa_engine/src/builtins/temporal/duration/mod.rs
  2. 507
      boa_engine/src/builtins/temporal/duration/record.rs
  3. 60
      boa_engine/src/builtins/temporal/instant/mod.rs
  4. 14
      boa_engine/src/builtins/temporal/mod.rs
  5. 6
      boa_engine/src/builtins/temporal/options.rs

109
boa_engine/src/builtins/temporal/duration/mod.rs

@ -21,7 +21,7 @@ use super::{
get_temporal_rounding_increment, get_temporal_unit, TemporalUnit, TemporalUnitGroup,
},
plain_date::{self, PlainDate},
to_integer_if_integral, DateTimeValues,
to_integer_if_integral, DateTimeValues, PlainDateTime,
};
mod record;
@ -627,14 +627,14 @@ impl Duration {
// 10. Let relativeToRecord be ? ToRelativeTemporalObject(roundTo).
// 11. Let zonedRelativeTo be relativeToRecord.[[ZonedRelativeTo]].
// 12. Let plainRelativeTo be relativeToRecord.[[PlainRelativeTo]].
let (_plain_relative_to, _zoned_relative_to) =
let (plain_relative_to, zoned_relative_to) =
super::to_relative_temporal_object(&round_to, context)?;
// 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo).
let rounding_increment = get_temporal_rounding_increment(&round_to, context)?;
// 14. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
let _rounding_mode = get_option(&round_to, utf16!("roundingMode"), context)?
let rounding_mode = get_option(&round_to, utf16!("roundingMode"), context)?
.unwrap_or(RoundingMode::HalfExpand);
// 15. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", datetime, undefined).
@ -695,10 +695,109 @@ impl Duration {
// 24. If maximum is not undefined, perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, false).
if let Some(max) = maximum {
validate_temporal_rounding_increment(rounding_increment, f64::from(max), false)?;
validate_temporal_rounding_increment(rounding_increment.into(), max.into(), false)?;
}
// 25. Let hoursToDaysConversionMayOccur be false.
// 26. If duration.[[Days]] ≠ 0 and zonedRelativeTo is not undefined, set hoursToDaysConversionMayOccur to true.
// 27. Else if abs(duration.[[Hours]]) ≥ 24, set hoursToDaysConversionMayOccur to true.
let conversion_may_occur = if duration.inner.days() != 0.0 && zoned_relative_to.is_some() {
true
} else {
24f64 <= duration.inner.hours().abs()
};
// 28. If smallestUnit is "nanosecond" and roundingIncrement = 1, let roundingGranularityIsNoop be true; else let roundingGranularityIsNoop be false.
let is_noop = smallest_unit == TemporalUnit::Nanosecond && rounding_increment == 1;
// 29. If duration.[[Years]] = 0 and duration.[[Months]] = 0 and duration.[[Weeks]] = 0, let calendarUnitsPresent be false; else let calendarUnitsPresent be true.
let calendar_units_present = !(duration.inner.years() == 0f64
|| duration.inner.months() == 0f64
|| duration.inner.weeks() == 0f64);
// 30. If roundingGranularityIsNoop is true, and largestUnit is existingLargestUnit,
// and calendarUnitsPresent is false, and hoursToDaysConversionMayOccur is false,
// and abs(duration.[[Minutes]]) < 60, and abs(duration.[[Seconds]]) < 60,
// and abs(duration.[[Milliseconds]]) < 1000, and abs(duration.[[Microseconds]]) < 1000,
// and abs(duration.[[Nanoseconds]]) < 1000, then
if is_noop
&& largest_unit == existing_largest_unit
&& !calendar_units_present
&& !conversion_may_occur
&& duration.inner.is_time_within_range()
{
// a. NOTE: The above conditions mean that the operation will have no effect: the smallest unit and
// rounding increment will leave the total duration unchanged, and it can be determined without
// calling a calendar or time zone method that no balancing will take place.
// b. Return ! CreateTemporalDuration(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
}
// TODO: Complete the rest of the new `Temporal.Duration.prototype.round` impl.
// 31. Let precalculatedPlainDateTime be undefined.
// let mut precalc_datetime = None;
// 32. If roundingGranularityIsNoop is false, or largestUnit is "year", or largestUnit is "month",
// or largestUnit is "week", or largestUnit is "day", or calendarUnitsPresent is true, or duration.[[Days]] ≠ 0,
// let plainDateTimeOrRelativeToWillBeUsed be true; else let plainDateTimeOrRelativeToWillBeUsed be false.
let pdt_or_rel_will_be_used = !is_noop
|| largest_unit == TemporalUnit::Year
|| largest_unit == TemporalUnit::Month
|| largest_unit == TemporalUnit::Week
|| largest_unit == TemporalUnit::Day
|| calendar_units_present
|| duration.inner.days() != 0f64;
// 33. If zonedRelativeTo is not undefined and plainDateTimeOrRelativeToWillBeUsed is true, then
let (plain_relative_to, precalc_pdt) = if zoned_relative_to.is_some()
&& pdt_or_rel_will_be_used
{
// TODO(TimeZone): Implement GetPlainDateTimeFor
// TODO(ZonedDateTime): Implement ZonedDateTime related methods.
return Err(JsNativeError::range()
.with_message("not yet implemented.")
.into());
// a. NOTE: The above conditions mean that the corresponding Temporal.PlainDateTime or Temporal.PlainDate for zonedRelativeTo will be used in one of the operations below.
// b. Let instant be ! CreateTemporalInstant(zonedRelativeTo.[[Nanoseconds]]).
// c. Set precalculatedPlainDateTime to ? GetPlainDateTimeFor(zonedRelativeTo.[[TimeZone]], instant, zonedRelativeTo.[[Calendar]]).
// d. Set plainRelativeTo to ! CreateTemporalDate(precalculatedPlainDateTime.[[ISOYear]], precalculatedPlainDateTime.[[ISOMonth]], precalculatedPlainDateTime.[[ISODay]], zonedRelativeTo.[[Calendar]]).
} else {
// TODO: remove after ZonedDateTime is implemented
let non_zoned: (Option<PlainDate>, Option<PlainDateTime>) = (plain_relative_to, None);
non_zoned
};
// 34. Let unbalanceResult be ? UnbalanceDateDurationRelative(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], largestUnit, plainRelativeTo).
let unbalance_result = duration.inner.unbalance_duration_relative(
largest_unit,
plain_relative_to.as_ref(),
context,
)?;
// 35. Let roundRecord be ? RoundDuration(unbalanceResult.[[Years]], unbalanceResult.[[Months]],
// unbalanceResult.[[Weeks]], unbalanceResult.[[Days]], duration.[[Hours]], duration.[[Minutes]],
// duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]],
// roundingIncrement, smallestUnit, roundingMode, plainRelativeTo, zonedRelativeTo, precalculatedPlainDateTime).
let (_round_result, _) = duration.inner.round_duration(
unbalance_result,
rounding_increment.into(),
smallest_unit,
rounding_mode,
(
plain_relative_to.as_ref(),
zoned_relative_to.as_ref(),
precalc_pdt.as_ref(),
),
context,
)?;
// 36. Let roundResult be roundRecord.[[DurationRecord]].
// 37. If zonedRelativeTo is not undefined, then
// a. Set roundResult to ? AdjustRoundedDurationDays(roundResult.[[Years]], roundResult.[[Months]], roundResult.[[Weeks]], roundResult.[[Days]], roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]], roundResult.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode, zonedRelativeTo, precalculatedPlainDateTime).
// b. Let balanceResult be ? BalanceTimeDurationRelative(roundResult.[[Days]], roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]], roundResult.[[Nanoseconds]], largestUnit, zonedRelativeTo, precalculatedPlainDateTime).
// 38. Else,
// a. Let balanceResult be ? BalanceTimeDuration(roundResult.[[Days]], roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]], roundResult.[[Nanoseconds]], largestUnit).
// 39. Let result be ? BalanceDateDurationRelative(roundResult.[[Years]], roundResult.[[Months]], roundResult.[[Weeks]], balanceResult.[[Days]], largestUnit, plainRelativeTo).
// 40. Return ! CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], balanceResult.[[Hours]], balanceResult.[[Minutes]], balanceResult.[[Seconds]], balanceResult.[[Milliseconds]], balanceResult.[[Microseconds]], balanceResult.[[Nanoseconds]]).
// NOTE: Below is currently incorrect: Handling of zonedRelativeTo and precalculatedPlainDateTime is needed.
Err(JsNativeError::range()

507
boa_engine/src/builtins/temporal/duration/record.rs

@ -150,6 +150,17 @@ impl TimeDuration {
nanoseconds: f64::NAN,
}
}
/// Utility function for returning if values in a valid range.
#[inline]
pub(crate) fn is_within_range(&self) -> bool {
self.hours.abs() < 24f64
&& self.minutes.abs() < 60f64
&& self.seconds.abs() < 60f64
&& self.milliseconds.abs() < 1000f64
&& self.milliseconds.abs() < 1000f64
&& self.milliseconds.abs() < 1000f64
}
}
impl<'a> IntoIterator for &'a TimeDuration {
@ -223,6 +234,27 @@ impl DurationRecord {
}
}
/// Utility function to create a one year duration.
pub(crate) fn one_year(year_value: f64) -> Self {
Self::from_date_duration(DateDuration::new(year_value, 0f64, 0f64, 0f64))
}
/// Utility function to create a one month duration.
pub(crate) fn one_month(month_value: f64) -> Self {
Self::from_date_duration(DateDuration::new(0f64, month_value, 0f64, 0f64))
}
/// Utility function to create a one week duration.
pub(crate) fn one_week(week_value: f64) -> Self {
Self::from_date_duration(DateDuration::new(0f64, 0f64, week_value, 0f64))
}
/// Utility function to return if the Durations values are within their valid ranges.
#[inline]
pub(crate) fn is_time_within_range(&self) -> bool {
self.time.is_within_range()
}
/// Equivalent to 7.5.13 `ToTemporalPartialDurationRecord ( temporalDurationLike )`
///
/// Takes an unknown `JsObject` and attempts to create a partial duration
@ -867,14 +899,14 @@ impl DurationRecord {
Ok(())
}
/// 7.5.20 `UnbalanceDurationRelative ( years, months, weeks, days, largestUnit, relativeTo )`
/// 7.5.21 `UnbalanceDateDurationRelative ( years, months, weeks, days, largestUnit, plainRelativeTo )`
#[allow(dead_code)]
pub(crate) fn unbalance_duration_relative(
&mut self,
&self,
largest_unit: TemporalUnit,
relative_to: &JsValue,
plain_relative_to: Option<&PlainDate>,
context: &mut Context<'_>,
) -> JsResult<()> {
) -> JsResult<DateDuration> {
// 1. Let allZero be false.
// 2. If years = 0, and months = 0, and weeks = 0, and days = 0, set allZero to true.
let all_zero = self.years() == 0_f64
@ -885,115 +917,233 @@ impl DurationRecord {
// 3. If largestUnit is "year" or allZero is true, then
if largest_unit == TemporalUnit::Year || all_zero {
// a. Return ! CreateDateDurationRecord(years, months, weeks, days).
return Ok(());
return Ok(self.date());
};
// 4. Let sign be ! DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0, 0).
let sign = self.duration_sign();
// 5. Assert: sign ≠ 0.
assert!(sign != 0);
let sign = f64::from(self.duration_sign());
// 6. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0, 0).
let _one_year = Self::new(
DateDuration::new(f64::from(sign), 0.0, 0.0, 0.0),
TimeDuration::default(),
);
let one_year = Self::one_year(sign);
// 7. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0, 0).
let _one_month = Self::new(
DateDuration::new(0.0, f64::from(sign), 0.0, 0.0),
TimeDuration::default(),
);
let one_month = Self::one_month(sign);
// 9. If plainRelativeTo is not undefined, then
// a. Let calendar be plainRelativeTo.[[Calendar]].
// 10. Else,
// a. Let calendar be undefined.
// 11. If largestUnit is "month", then
if largest_unit == TemporalUnit::Month {
// a. If years = 0, return ! CreateDateDurationRecord(0, months, weeks, days).
if self.years() == 0f64 {
return Ok(DateDuration::new(
0f64,
self.months(),
self.weeks(),
self.days(),
));
}
// b. If calendar is undefined, then
let (mut plain_relative_to, calendar) =
if let Some(plain_relative_to) = plain_relative_to {
(
PlainDate::new(plain_relative_to.inner, plain_relative_to.calendar.clone()),
plain_relative_to.calendar.clone(),
)
} else {
// i. Throw a RangeError exception.
return Err(JsNativeError::range()
.with_message("Calendar cannot be undefined.")
.into());
};
// c. If calendar is an Object, then
// i. Let dateAdd be ? GetMethod(calendar, "dateAdd").
// ii. Let dateUntil be ? GetMethod(calendar, "dateUntil").
// d. Else,
// i. Let dateAdd be unused.
// ii. Let dateUntil be unused.
let mut years = self.years();
let mut months = self.months();
// e. Repeat, while years ≠ 0,
while years != 0f64 {
// i. Let newRelativeTo be ? CalendarDateAdd(calendar, plainRelativeTo, oneYear, undefined, dateAdd).
let new_relative_to = calendar::calendar_date_add(
&calendar,
&plain_relative_to,
&one_year,
&JsValue::undefined(),
context,
)?;
// ii. Let untilOptions be OrdinaryObjectCreate(null).
let until_options = JsObject::with_null_proto();
// iii. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "month").
until_options.create_data_property_or_throw(
utf16!("largestUnit"),
js_string!("month"),
context,
)?;
// iv. Let untilResult be ? CalendarDateUntil(calendar, plainRelativeTo, newRelativeTo, untilOptions, dateUntil).
let until_result = calendar::calendar_date_until(
&calendar,
&plain_relative_to,
&new_relative_to,
&until_options.into(),
context,
)?;
// v. Let oneYearMonths be untilResult.[[Months]].
let one_year_months = until_result.months();
// vi. Set plainRelativeTo to newRelativeTo.
plain_relative_to = new_relative_to;
// vii. Set years to years - sign.
years -= sign;
// viii. Set months to months + oneYearMonths.
months += one_year_months;
}
// f. Return ? CreateDateDurationRecord(0, months, weeks, days).
return Ok(DateDuration::new(years, months, self.weeks(), self.days()));
// 12. If largestUnit is "week", then
} else if largest_unit == TemporalUnit::Week {
// a. If years = 0 and months = 0, return ! CreateDateDurationRecord(0, 0, weeks, days).
if self.years() == 0f64 && self.months() == 0f64 {
return Ok(DateDuration::new(0f64, 0f64, self.weeks(), self.days()));
}
// b. If calendar is undefined, then
let (mut plain_relative_to, calendar) =
if let Some(plain_relative_to) = plain_relative_to {
(
PlainDate::new(plain_relative_to.inner, plain_relative_to.calendar.clone()),
plain_relative_to.calendar.clone(),
)
} else {
// i. Throw a RangeError exception.
return Err(JsNativeError::range()
.with_message("Calendar cannot be undefined.")
.into());
};
// c. If calendar is an Object, then
// i. Let dateAdd be ? GetMethod(calendar, "dateAdd").
// d. Else,
// i. Let dateAdd be unused.
let mut years = self.years();
let mut days = self.days();
// e. Repeat, while years ≠ 0,
while years != 0f64 {
// i. Let moveResult be ? MoveRelativeDate(calendar, plainRelativeTo, oneYear, dateAdd).
let move_result =
super::move_relative_date(&calendar, &plain_relative_to, &one_year, context)?;
// ii. Set plainRelativeTo to moveResult.[[RelativeTo]].
plain_relative_to = move_result.0;
// iii. Set days to days + moveResult.[[Days]].
days += move_result.1;
// iv. Set years to years - sign.
years -= sign;
}
let mut months = self.months();
// f. Repeat, while months ≠ 0,
while months != 0f64 {
// i. Let moveResult be ? MoveRelativeDate(calendar, plainRelativeTo, oneMonth, dateAdd).
let move_result =
super::move_relative_date(&calendar, &plain_relative_to, &one_month, context)?;
// ii. Set plainRelativeTo to moveResult.[[RelativeTo]].
plain_relative_to = move_result.0;
// iii. Set days to days + moveResult.[[Days]].
days += move_result.1;
// iv. Set months to months - sign.
months -= sign;
}
// g. Return ? CreateDateDurationRecord(0, 0, weeks, days).
return Ok(DateDuration::new(0f64, 0f64, self.weeks(), days));
}
// 13. If years = 0, and months = 0, and weeks = 0, return ! CreateDateDurationRecord(0, 0, 0, days).
if self.years() == 0f64 && self.months() == 0f64 && self.weeks() == 0f64 {
return Ok(DateDuration::new(0f64, 0f64, 0f64, self.days()));
}
// NOTE: Move 8 down to past 13 as we only use one_week after making it past 13.
// 8. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0).
let _one_week = Self::new(
DateDuration::new(0.0, 0.0, f64::from(sign), 0.0),
TimeDuration::default(),
);
// 9. If relativeTo is not undefined, then
let _calendar = if relative_to.is_undefined() {
// 10. Else
// a. Let calendar be undefined.
None
let one_week = Self::one_week(sign);
// 14. If calendar is undefined, then
let (mut plain_relative_to, calendar) = if let Some(plain_relative_to) = plain_relative_to {
(
PlainDate::new(plain_relative_to.inner, plain_relative_to.calendar.clone()),
plain_relative_to.calendar.clone(),
)
} else {
// a. Set relativeTo to ? ToTemporalDate(relativeTo).
let relative_to = to_temporal_date(
&relative_to
.as_object()
.expect("relative_to must be an object")
.clone()
.into(),
None,
context,
)?;
// a. Throw a RangeError exception.
return Err(JsNativeError::range()
.with_message("Calendar cannot be undefined.")
.into());
};
// b. Let calendar be relativeTo.[[Calendar]].
let calendar = relative_to.calendar;
// 15. If calendar is an Object, then
// a. Let dateAdd be ? GetMethod(calendar, "dateAdd").
// 16. Else,
// a. Let dateAdd be unused.
let mut years = self.years();
let mut days = self.days();
// a. Let moveResult be ? MoveRelativeDate(calendar, plainRelativeTo, oneYear, dateAdd).
while years != 0f64 {
// a. Let moveResult be ? MoveRelativeDate(calendar, plainRelativeTo, oneYear, dateAdd).
let move_result =
super::move_relative_date(&calendar, &plain_relative_to, &one_year, context)?;
// b. Set plainRelativeTo to moveResult.[[RelativeTo]].
plain_relative_to = move_result.0;
// c. Set days to days + moveResult.[[Days]].
days += move_result.1;
// d. Set years to years - sign.
years -= sign;
}
Some(calendar)
};
let mut months = self.months();
// 18. Repeat, while months ≠ 0,
while months != 0f64 {
// a. Let moveResult be ? MoveRelativeDate(calendar, plainRelativeTo, oneMonth, dateAdd).
let move_result =
super::move_relative_date(&calendar, &plain_relative_to, &one_month, context)?;
// b. Set plainRelativeTo to moveResult.[[RelativeTo]].
plain_relative_to = move_result.0;
// c. Set days to days +moveResult.[[Days]].
days += move_result.1;
// d. Set months to months - sign.
months -= sign;
}
// 11. If largestUnit is "month", then
// a. If calendar is undefined, then
// i. Throw a RangeError exception.
// b. If calendar is an Object, then
// i. Let dateAdd be ? GetMethod(calendar, "dateAdd").
// ii. Let dateUntil be ? GetMethod(calendar, "dateUntil").
// c. Else,
// i. Let dateAdd be unused.
// ii. Let dateUntil be unused.
// d. Repeat, while years ≠ 0,
// i. Let newRelativeTo be ? CalendarDateAdd(calendar, relativeTo, oneYear, undefined, dateAdd).
// ii. Let untilOptions be OrdinaryObjectCreate(null).
// iii. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "month").
// iv. Let untilResult be ? CalendarDateUntil(calendar, relativeTo, newRelativeTo, untilOptions, dateUntil).
// v. Let oneYearMonths be untilResult.[[Months]].
// vi. Set relativeTo to newRelativeTo.
// vii. Set years to years - sign.
// viii. Set months to months + oneYearMonths.
// 12. Else if largestUnit is "week", then
// a. If calendar is undefined, then
// i. Throw a RangeError exception.
// b. If calendar is an Object, then
// i. Let dateAdd be ? GetMethod(calendar, "dateAdd").
// c. Else,
// i. Let dateAdd be unused.
// d. Repeat, while years ≠ 0,
// i. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear, dateAdd).
// ii. Set relativeTo to moveResult.[[RelativeTo]].
// iii. Set days to days + moveResult.[[Days]].
// iv. Set years to years - sign.
// e. Repeat, while months ≠ 0,
// i. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd).
// ii. Set relativeTo to moveResult.[[RelativeTo]].
// iii. Set days to days + moveResult.[[Days]].
// iv. Set months to months - sign.
// 13. Else,
// a. If years ≠ 0, or months ≠ 0, or weeks ≠ zero, then
// i. If calendar is undefined, then
// 1. Throw a RangeError exception.
// ii. If calendar is an Object, then
// 1. Let dateAdd be ? GetMethod(calendar, "dateAdd").
// iii. Else,
// 1. Let dateAdd be unused.
// iv. Repeat, while years ≠ 0,
// 1. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear, dateAdd).
// 2. Set relativeTo to moveResult.[[RelativeTo]].
// 3. Set days to days + moveResult.[[Days]].
// 4. Set years to years - sign.
// v. Repeat, while months ≠ 0,
// 1. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneMonth, dateAdd).
// 2. Set relativeTo to moveResult.[[RelativeTo]].
// 3. Set days to days +moveResult.[[Days]].
// 4. Set months to months - sign.
// vi. Repeat, while weeks ≠ 0,
// 1. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneWeek, dateAdd).
// 2. Set relativeTo to moveResult.[[RelativeTo]].
// 3. Set days to days + moveResult.[[Days]].
// 4. Set weeks to weeks - sign.
// 14. Return ? CreateDateDurationRecord(years, months, weeks, days).
Err(JsNativeError::range()
.with_message("not yet implemented.")
.into())
let mut weeks = self.weeks();
// 19. Repeat, while weeks ≠ 0,
while weeks != 0f64 {
// a. Let moveResult be ? MoveRelativeDate(calendar, plainRelativeTo, oneWeek, dateAdd).
let move_result =
super::move_relative_date(&calendar, &plain_relative_to, &one_week, context)?;
// b. Set plainRelativeTo to moveResult.[[RelativeTo]].
plain_relative_to = move_result.0;
// c. Set days to days + moveResult.[[Days]].
days += move_result.1;
// d. Set weeks to weeks - sign.
weeks -= sign;
}
// 20. Return ? CreateDateDurationRecord(0, 0, 0, days).
Ok(DateDuration::new(0f64, 0f64, 0f64, days))
}
/// `BalanceDateDurationRelative`
@ -1033,11 +1183,11 @@ impl DurationRecord {
let sign = f64::from(self.duration_sign());
// 7. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0, 0).
let one_year = Self::from_date_duration(DateDuration::new(sign, 0.0, 0.0, 0.0));
let one_year = Self::one_year(sign);
// 8. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0, 0).
let one_month = Self::from_date_duration(DateDuration::new(0.0, sign, 0.0, 0.0));
let one_month = Self::one_month(sign);
// 9. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0).
let one_week = Self::from_date_duration(DateDuration::new(0.0, 0.0, sign, 0.0));
let one_week = Self::one_week(sign);
// 10. Set relativeTo to ? ToTemporalDate(relativeTo).
let mut relative_to = to_temporal_date(relative_to, None, context)?;
@ -1255,20 +1405,27 @@ impl DurationRecord {
/// Abstract Operation 7.5.26 `RoundDuration ( years, months, weeks, days, hours, minutes,
/// seconds, milliseconds, microseconds, nanoseconds, increment, unit,
/// roundingMode [ , plainRelativeTo [, zonedRelativeTo [, precalculatedDateTime]]] )`
#[allow(clippy::too_many_arguments)]
pub(crate) fn round_duration(
&mut self,
&self,
unbalance_date_duration: DateDuration,
increment: f64,
unit: TemporalUnit,
rounding_mode: RoundingMode,
plain_relative_to: Option<&PlainDate>,
zoned_relative_to: Option<&ZonedDateTime>,
_precalc_datetime: Option<&PlainDateTime>,
relative_targets: (
Option<&PlainDate>,
Option<&ZonedDateTime>,
Option<&PlainDateTime>,
),
context: &mut Context<'_>,
) -> JsResult<f64> {
) -> JsResult<(Self, f64)> {
let mut result = DurationRecord::new(unbalance_date_duration, self.time());
// 1. If plainRelativeTo is not present, set plainRelativeTo to undefined.
let plain_relative_to = relative_targets.0;
// 2. If zonedRelativeTo is not present, set zonedRelativeTo to undefined.
let zoned_relative_to = relative_targets.1;
// 3. If precalculatedPlainDateTime is not present, set precalculatedPlainDateTime to undefined.
let _precalc_pdt = relative_targets.2;
let (frac_days, frac_secs) = match unit {
// 4. If unit is "year", "month", or "week", and plainRelativeTo is undefined, then
@ -1284,7 +1441,7 @@ impl DurationRecord {
TemporalUnit::Year | TemporalUnit::Month | TemporalUnit::Week | TemporalUnit::Day => {
// a. Let nanoseconds be TotalDurationNanoseconds(hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
let nanos =
Self::from_day_and_time(0.0, self.time()).total_duration_nanoseconds(0.0);
Self::from_day_and_time(0.0, result.time()).total_duration_nanoseconds(0.0);
// b. If zonedRelativeTo is not undefined, then
// i. Let intermediate be ? MoveRelativeZonedDateTime(zonedRelativeTo, years, months, weeks, days, precalculatedPlainDateTime).
@ -1293,7 +1450,7 @@ impl DurationRecord {
// c. Else,
// i. Let fractionalDays be days + nanoseconds / nsPerDay.
let frac_days = if zoned_relative_to.is_none() {
self.days() + nanos / NS_PER_DAY as f64
result.days() + nanos / NS_PER_DAY as f64
} else {
// implementation of b: i-iii needed.
return Err(JsNativeError::range()
@ -1301,19 +1458,19 @@ impl DurationRecord {
.into());
};
// d. Set days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds to 0.
self.set_days(0.0);
self.set_time_duration(TimeDuration::default());
result.set_days(0.0);
result.set_time_duration(TimeDuration::default());
// e. Assert: fractionalSeconds is not used below.
(Some(frac_days), None)
}
// 6. Else,
_ => {
// a. Let fractionalSeconds be nanoseconds × 10-9 + microseconds × 10-6 + milliseconds × 10-3 + seconds.
let frac_secs = self.nanoseconds().mul_add(
let frac_secs = result.nanoseconds().mul_add(
1_000_000_000f64,
self.microseconds().mul_add(
result.microseconds().mul_add(
1_000_000f64,
self.milliseconds().mul_add(1_000f64, self.seconds()),
result.milliseconds().mul_add(1_000f64, result.seconds()),
),
);
@ -1335,7 +1492,7 @@ impl DurationRecord {
let calendar = &plain_relative_to.calendar;
// b. Let yearsDuration be ! CreateTemporalDuration(years, 0, 0, 0, 0, 0, 0, 0, 0, 0).
let years = DateDuration::new(self.years(), 0.0, 0.0, 0.0);
let years = DateDuration::new(result.years(), 0.0, 0.0, 0.0);
let years_duration = DurationRecord::new(years, TimeDuration::default());
// c. If calendar is an Object, then
@ -1354,7 +1511,7 @@ impl DurationRecord {
// f. Let yearsMonthsWeeks be ! CreateTemporalDuration(years, months, weeks, 0, 0, 0, 0, 0, 0, 0).
let years_months_weeks = Self::new(
DateDuration::new(self.years(), self.months(), self.weeks(), 0.0),
DateDuration::new(result.years(), result.months(), result.weeks(), 0.0),
TimeDuration::default(),
);
@ -1401,13 +1558,10 @@ impl DurationRecord {
let years_passed = time_passed.years();
// q. Set years to years + yearsPassed.
self.set_years(self.years() + years_passed);
result.set_years(result.years() + years_passed);
// r. Let yearsDuration be ! CreateTemporalDuration(yearsPassed, 0, 0, 0, 0, 0, 0, 0, 0, 0).
let years_duration = Self::new(
DateDuration::new(years_passed, 0.0, 0.0, 0.0),
TimeDuration::default(),
);
let years_duration = Self::one_year(years_passed);
// s. Let moveResult be ? MoveRelativeDate(calendar, plainRelativeTo, yearsDuration, dateAdd).
// t. Set plainRelativeTo to moveResult.[[RelativeTo]].
@ -1426,10 +1580,7 @@ impl DurationRecord {
let sign = if frac_days < 0.0 { -1 } else { 1 };
// x. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0, 0).
let one_year = Self::new(
DateDuration::new(f64::from(sign), 0.0, 0.0, 0.0),
TimeDuration::default(),
);
let one_year = Self::one_year(f64::from(sign));
// y. Set moveResult to ? MoveRelativeDate(calendar, plainRelativeTo, oneYear, dateAdd).
// z. Let oneYearDays be moveResult.[[Days]].
@ -1437,10 +1588,10 @@ impl DurationRecord {
super::move_relative_date(calendar, &plain_relative_to, &one_year, context)?;
// aa. Let fractionalYears be years + fractionalDays / abs(oneYearDays).
let frac_years = self.years() + (frac_days / one_year_days.abs());
let frac_years = result.years() + (frac_days / one_year_days.abs());
// ab. Set years to RoundNumberToIncrement(fractionalYears, increment, roundingMode).
self.set_years(round_number_to_increment(
result.set_years(round_number_to_increment(
frac_years,
increment,
rounding_mode,
@ -1448,8 +1599,8 @@ impl DurationRecord {
// ac. Set total to fractionalYears.
// ad. Set months and weeks to 0.
self.set_months(0.0);
self.set_weeks(0.0);
result.set_months(0.0);
result.set_weeks(0.0);
frac_years
}
@ -1463,10 +1614,12 @@ impl DurationRecord {
let calendar = &plain_relative_to.calendar;
// b. Let yearsMonths be ! CreateTemporalDuration(years, months, 0, 0, 0, 0, 0, 0, 0, 0).
let years_months = Self::new(
DateDuration::new(self.years(), self.months(), 0.0, 0.0),
TimeDuration::default(),
);
let years_months = Self::from_date_duration(DateDuration::new(
result.years(),
result.months(),
0.0,
0.0,
));
// c. If calendar is an Object, then
// i. Let dateAdd be ? GetMethod(calendar, "dateAdd").
@ -1483,10 +1636,12 @@ impl DurationRecord {
)?;
// f. Let yearsMonthsWeeks be ! CreateTemporalDuration(years, months, weeks, 0, 0, 0, 0, 0, 0, 0).
let years_months_weeks = Self::new(
DateDuration::new(self.years(), self.months(), self.weeks(), 0.0),
TimeDuration::default(),
);
let years_months_weeks = Self::from_date_duration(DateDuration::new(
result.years(),
result.months(),
result.weeks(),
0.0,
));
// g. Let yearsMonthsWeeksLater be ? AddDate(calendar, plainRelativeTo, yearsMonthsWeeks, undefined, dateAdd).
let years_months_weeks_later = plain_date::add_date(
@ -1511,10 +1666,7 @@ impl DurationRecord {
let sign = if frac_days < 0.0 { -1f64 } else { 1f64 };
// l. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0, 0).
let one_month = Self::new(
DateDuration::new(0.0, sign, 0.0, 0.0),
TimeDuration::default(),
);
let one_month = Self::one_month(sign);
// m. Let moveResult be ? MoveRelativeDate(calendar, plainRelativeTo, oneMonth, dateAdd).
// n. Set plainRelativeTo to moveResult.[[RelativeTo]].
@ -1525,7 +1677,7 @@ impl DurationRecord {
// p. Repeat, while abs(fractionalDays) ≥ abs(oneMonthDays),
while frac_days.abs() >= one_month_days.abs() {
// i. Set months to months + sign.
self.set_months(self.months() + sign);
result.set_months(result.months() + sign);
// ii. Set fractionalDays to fractionalDays - oneMonthDays.
frac_days -= one_month_days;
@ -1544,10 +1696,10 @@ impl DurationRecord {
}
// q. Let fractionalMonths be months + fractionalDays / abs(oneMonthDays).
let frac_months = self.months() + frac_days / one_month_days.abs();
let frac_months = result.months() + frac_days / one_month_days.abs();
// r. Set months to RoundNumberToIncrement(fractionalMonths, increment, roundingMode).
self.set_months(round_number_to_increment(
result.set_months(round_number_to_increment(
frac_months,
increment,
rounding_mode,
@ -1555,7 +1707,7 @@ impl DurationRecord {
// s. Set total to fractionalMonths.
// t. Set weeks to 0.
self.set_weeks(0.0);
result.set_weeks(0.0);
frac_months
}
// 10. Else if unit is "week", then
@ -1570,10 +1722,7 @@ impl DurationRecord {
let sign = if frac_days < 0.0 { -1f64 } else { 1f64 };
// c. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0).
let one_week = Self::new(
DateDuration::new(0.0, 0.0, sign, 0.0),
TimeDuration::default(),
);
let one_week = Self::one_week(sign);
// d. If calendar is an Object, then
// i. Let dateAdd be ? GetMethod(calendar, "dateAdd").
@ -1589,7 +1738,7 @@ impl DurationRecord {
// i. Repeat, while abs(fractionalDays) ≥ abs(oneWeekDays),
while frac_days.abs() >= one_week_days.abs() {
// i. Set weeks to weeks + sign.
self.set_weeks(self.weeks() + sign);
result.set_weeks(result.weeks() + sign);
// ii. Set fractionalDays to fractionalDays - oneWeekDays.
frac_days -= one_week_days;
@ -1609,10 +1758,10 @@ impl DurationRecord {
}
// j. Let fractionalWeeks be weeks + fractionalDays / abs(oneWeekDays).
let frac_weeks = self.weeks() + frac_days / one_week_days.abs();
let frac_weeks = result.weeks() + frac_days / one_week_days.abs();
// k. Set weeks to RoundNumberToIncrement(fractionalWeeks, increment, roundingMode).
self.set_weeks(round_number_to_increment(
result.set_weeks(round_number_to_increment(
frac_weeks,
increment,
rounding_mode,
@ -1626,7 +1775,7 @@ impl DurationRecord {
frac_days.expect("assert that fractionalDays exists for TemporalUnit::Day");
// a. Set days to RoundNumberToIncrement(fractionalDays, increment, roundingMode).
self.set_days(round_number_to_increment(
result.set_days(round_number_to_increment(
frac_days,
increment,
rounding_mode,
@ -1639,12 +1788,12 @@ impl DurationRecord {
let frac_secs =
frac_secs.expect("Assert fractionSeconds exists for Temporal::Hour");
// a. Let fractionalHours be (fractionalSeconds / 60 + minutes) / 60 + hours.
let frac_hours = (frac_secs / 60f64 + self.minutes()) / 60f64 + self.hours();
let frac_hours = (frac_secs / 60f64 + result.minutes()) / 60f64 + result.hours();
// b. Set hours to RoundNumberToIncrement(fractionalHours, increment, roundingMode).
let rounded_hours = round_number_to_increment(frac_hours, increment, rounding_mode);
// c. Set total to fractionalHours.
// d. Set minutes, seconds, milliseconds, microseconds, and nanoseconds to 0.
self.set_time_duration(TimeDuration::new(rounded_hours, 0.0, 0.0, 0.0, 0.0, 0.0));
result.set_time_duration(TimeDuration::new(rounded_hours, 0.0, 0.0, 0.0, 0.0, 0.0));
frac_hours
}
// 13. Else if unit is "minute", then
@ -1652,14 +1801,14 @@ impl DurationRecord {
let frac_secs =
frac_secs.expect("Assert fractionSeconds exists for Temporal::Hour");
// a. Let fractionalMinutes be fractionalSeconds / 60 + minutes.
let frac_minutes = frac_secs / 60f64 + self.minutes();
let frac_minutes = frac_secs / 60f64 + result.minutes();
// b. Set minutes to RoundNumberToIncrement(fractionalMinutes, increment, roundingMode).
let rounded_minutes =
round_number_to_increment(frac_minutes, increment, rounding_mode);
// c. Set total to fractionalMinutes.
// d. Set seconds, milliseconds, microseconds, and nanoseconds to 0.
self.set_time_duration(TimeDuration::new(
self.hours(),
result.set_time_duration(TimeDuration::new(
result.hours(),
rounded_minutes,
0.0,
0.0,
@ -1674,29 +1823,31 @@ impl DurationRecord {
let frac_secs =
frac_secs.expect("Assert fractionSeconds exists for Temporal::Second");
// a. Set seconds to RoundNumberToIncrement(fractionalSeconds, increment, roundingMode).
self.set_seconds(round_number_to_increment(
result.set_seconds(round_number_to_increment(
frac_secs,
increment,
rounding_mode,
));
// b. Set total to fractionalSeconds.
// c. Set milliseconds, microseconds, and nanoseconds to 0.
self.set_milliseconds(0.0);
self.set_microseconds(0.0);
self.set_nanoseconds(0.0);
result.set_milliseconds(0.0);
result.set_microseconds(0.0);
result.set_nanoseconds(0.0);
frac_secs
}
// 15. Else if unit is "millisecond", then
TemporalUnit::Millisecond => {
// a. Let fractionalMilliseconds be nanoseconds × 10-6 + microseconds × 10-3 + milliseconds.
let fraction_millis = self.nanoseconds().mul_add(
let fraction_millis = result.nanoseconds().mul_add(
1_000_000f64,
self.microseconds().mul_add(1_000f64, self.milliseconds()),
result
.microseconds()
.mul_add(1_000f64, result.milliseconds()),
);
// b. Set milliseconds to RoundNumberToIncrement(fractionalMilliseconds, increment, roundingMode).
self.set_milliseconds(round_number_to_increment(
result.set_milliseconds(round_number_to_increment(
fraction_millis,
increment,
rounding_mode,
@ -1704,17 +1855,19 @@ impl DurationRecord {
// c. Set total to fractionalMilliseconds.
// d. Set microseconds and nanoseconds to 0.
self.set_microseconds(0.0);
self.set_nanoseconds(0.0);
result.set_microseconds(0.0);
result.set_nanoseconds(0.0);
fraction_millis
}
// 16. Else if unit is "microsecond", then
TemporalUnit::Microsecond => {
// a. Let fractionalMicroseconds be nanoseconds × 10-3 + microseconds.
let frac_micros = self.nanoseconds().mul_add(1_000f64, self.microseconds());
let frac_micros = result
.nanoseconds()
.mul_add(1_000f64, result.microseconds());
// b. Set microseconds to RoundNumberToIncrement(fractionalMicroseconds, increment, roundingMode).
self.set_microseconds(round_number_to_increment(
result.set_microseconds(round_number_to_increment(
frac_micros,
increment,
rounding_mode,
@ -1722,17 +1875,17 @@ impl DurationRecord {
// c. Set total to fractionalMicroseconds.
// d. Set nanoseconds to 0.
self.set_nanoseconds(0.0);
result.set_nanoseconds(0.0);
frac_micros
}
// 17. Else,
TemporalUnit::Nanosecond => {
// a. Assert: unit is "nanosecond".
// b. Set total to nanoseconds.
let total = self.nanoseconds();
let total = result.nanoseconds();
// c. Set nanoseconds to RoundNumberToIncrement(nanoseconds, increment, roundingMode).
self.set_nanoseconds(round_number_to_increment(
self.nanoseconds(),
result.set_nanoseconds(round_number_to_increment(
result.nanoseconds(),
increment,
rounding_mode,
));
@ -1744,7 +1897,7 @@ impl DurationRecord {
// 18. Let duration be ? CreateDurationRecord(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
// 19. Return the Record { [[DurationRecord]]: duration, [[Total]]: total }.
Ok(total)
Ok((result, total))
}
/// 7.5.27 `AdjustRoundedDurationDays ( years, months, weeks, days, hours, minutes, seconds, milliseconds,

60
boa_engine/src/builtins/temporal/instant/mod.rs

@ -5,7 +5,7 @@ use crate::{
builtins::{
options::{get_option, get_options_object, RoundingMode},
temporal::{
duration::{DateDuration, TimeDuration},
duration::{DateDuration, DurationRecord, TimeDuration},
options::{
get_temporal_rounding_increment, get_temporal_unit, TemporalUnit, TemporalUnitGroup,
},
@ -381,34 +381,34 @@ impl Instant {
let maximum = match smallest_unit {
// 10. If smallestUnit is "hour"), then
// a. Let maximum be HoursPerDay.
TemporalUnit::Hour => 24,
TemporalUnit::Hour => 24u64,
// 11. Else if smallestUnit is "minute"), then
// a. Let maximum be MinutesPerHour × HoursPerDay.
TemporalUnit::Minute => 14400,
TemporalUnit::Minute => 14400u64,
// 12. Else if smallestUnit is "second"), then
// a. Let maximum be SecondsPerMinute × MinutesPerHour × HoursPerDay.
TemporalUnit::Second => 86400,
TemporalUnit::Second => 86400u64,
// 13. Else if smallestUnit is "millisecond"), then
// a. Let maximum be ℝ(msPerDay).
TemporalUnit::Millisecond => i64::from(MS_PER_DAY),
TemporalUnit::Millisecond => MS_PER_DAY as u64,
// 14. Else if smallestUnit is "microsecond"), then
// a. Let maximum be 10^3 × ℝ(msPerDay).
TemporalUnit::Microsecond => MIS_PER_DAY,
TemporalUnit::Microsecond => MIS_PER_DAY as u64,
// 15. Else,
// a. Assert: smallestUnit is "nanosecond".
// b. Let maximum be nsPerDay.
TemporalUnit::Nanosecond => NS_PER_DAY,
TemporalUnit::Nanosecond => NS_PER_DAY as u64,
// unreachable here functions as 15.a.
_ => unreachable!(),
};
// 16. Perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, true).
super::validate_temporal_rounding_increment(rounding_increment, maximum as f64, true)?;
super::validate_temporal_rounding_increment(rounding_increment.into(), maximum, true)?;
// 17. Let roundedNs be RoundTemporalInstant(instant.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode).
let rounded_ns = round_temporal_instant(
&instant.nanoseconds,
rounding_increment,
rounding_increment.into(),
smallest_unit,
rounding_mode,
)?;
@ -576,7 +576,7 @@ fn diff_instant(
largest_unit: TemporalUnit,
rounding_mode: RoundingMode,
context: &mut Context<'_>,
) -> JsResult<duration::DurationRecord> {
) -> JsResult<DurationRecord> {
// 1. Let difference be ℝ(ns2) - ℝ(ns1).
let difference = JsBigInt::sub(ns1, ns2);
// 2. Let nanoseconds be remainder(difference, 1000).
@ -591,40 +591,50 @@ fn diff_instant(
.map_err(|e| JsNativeError::typ().with_message(e.to_string()))?;
let milliseconds = JsBigInt::rem(&truncated_milli, &JsBigInt::from(1000));
// 5. Let seconds be truncate(difference / 109).
// 5. Let seconds be truncate(difference / 10^9).
let seconds = (&difference.to_f64() / 1_000_000_000_f64).trunc();
// 6. Let roundResult be ! RoundDuration(0, 0, 0, 0, 0, 0, seconds, milliseconds, microseconds, nanoseconds, roundingIncrement, smallestUnit, largestUnit, roundingMode).
let mut roundable_duration = duration::DurationRecord::new(
DateDuration::default(),
// Create TimeDuration
let mut time_duration = DurationRecord::from_day_and_time(
0f64,
TimeDuration::new(
0.0,
0.0,
0f64,
0f64,
seconds,
milliseconds.to_f64(),
microseconds.to_f64(),
nanoseconds.to_f64(),
),
);
let _total = roundable_duration.round_duration(
// 6. If smallestUnit is "nanosecond" and roundingIncrement is 1, then
if smallest_unit == TemporalUnit::Nanosecond && (rounding_increment - 1f64).abs() < f64::EPSILON
{
// a. Return ! BalanceTimeDuration(0, 0, 0, seconds, milliseconds, microseconds, nanoseconds, largestUnit).
time_duration.balance_time_duration(largest_unit, None)?;
return Ok(time_duration);
}
// 7. Let roundResult be ! RoundDuration(0, 0, 0, 0, 0, 0, seconds, milliseconds, microseconds, nanoseconds, roundingIncrement, smallestUnit, largestUnit, roundingMode).
let (mut round_result, _total) = time_duration.round_duration(
DateDuration::default(),
rounding_increment,
smallest_unit,
rounding_mode,
None,
None,
None,
(None, None, None),
context,
)?;
// 7. Assert: roundResult.[[Days]] is 0.
assert_eq!(roundable_duration.days() as i32, 0);
// 8. Assert: roundResult.[[Days]] is 0.
assert_eq!(round_result.days() as i32, 0);
// 8. Return ! BalanceTimeDuration(0, roundResult.[[Hours]], roundResult.[[Minutes]],
// 9. Return ! BalanceTimeDuration(0, roundResult.[[Hours]], roundResult.[[Minutes]],
// roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]],
// roundResult.[[Nanoseconds]], largestUnit).
roundable_duration.balance_time_duration(largest_unit, None)?;
round_result.balance_time_duration(largest_unit, None)?;
Ok(roundable_duration)
Ok(round_result)
}
/// 8.5.8 `RoundTemporalInstant ( ns, increment, unit, roundingMode )`

14
boa_engine/src/builtins/temporal/mod.rs

@ -257,8 +257,8 @@ pub(crate) fn epoch_days_to_epoch_ms(day: i32, time: i32) -> f64 {
/// 13.17 `ValidateTemporalRoundingIncrement ( increment, dividend, inclusive )`
#[inline]
pub(crate) fn validate_temporal_rounding_increment(
increment: f64,
dividend: f64,
increment: u64,
dividend: u64,
inclusive: bool,
) -> JsResult<()> {
// 1. If inclusive is true, then
@ -268,9 +268,9 @@ pub(crate) fn validate_temporal_rounding_increment(
// 2. Else,
} else {
// a. Assert: dividend > 1.
assert!(dividend > 1.0);
assert!(dividend > 1);
// b. Let maximum be dividend - 1.
dividend - 1.0
dividend - 1
};
// 3. If increment > maximum, throw a RangeError exception.
@ -280,7 +280,7 @@ pub(crate) fn validate_temporal_rounding_increment(
.into());
}
// 4. If dividend modulo increment ≠ 0, then
if dividend % increment != 0.0 {
if dividend % increment != 0 {
// a. Throw a RangeError exception.
return Err(JsNativeError::range()
.with_message("Temporal rounding increment is not valid.")
@ -555,7 +555,7 @@ pub(crate) fn get_diff_settings(
// 13. If maximum is not undefined, perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, false).
if let Some(max) = maximum {
validate_temporal_rounding_increment(rounding_increment, f64::from(max), false)?;
validate_temporal_rounding_increment(rounding_increment.into(), max.into(), false)?;
}
// 14. Return the Record { [[SmallestUnit]]: smallestUnit, [[LargestUnit]]: largestUnit, [[RoundingMode]]: roundingMode, [[RoundingIncrement]]: roundingIncrement, }.
@ -563,7 +563,7 @@ pub(crate) fn get_diff_settings(
smallest_unit,
largest_unit,
rounding_mode,
rounding_increment,
rounding_increment.into(),
))
}

6
boa_engine/src/builtins/temporal/options.rs

@ -20,7 +20,7 @@ use std::{fmt, str::FromStr};
pub(crate) fn get_temporal_rounding_increment(
options: &JsObject,
context: &mut Context<'_>,
) -> JsResult<f64> {
) -> JsResult<u32> {
// 1. Let increment be ? GetOption(normalizedOptions, "roundingIncrement", "number", undefined, 1𝔽).
let value = options.get(js_string!("roundingIncrement"), context)?;
@ -41,14 +41,14 @@ pub(crate) fn get_temporal_rounding_increment(
let integer_increment = increment.trunc();
// 4. If integerIncrement < 1 or integerIncrement > 10^9, throw a RangeError exception.
if (1.0..=1_000_000_000.0).contains(&integer_increment) {
if !(1.0..=1_000_000_000.0).contains(&integer_increment) {
return Err(JsNativeError::range()
.with_message("rounding increment was out of range.")
.into());
}
// 5. Return integerIncrement.
Ok(integer_increment)
Ok(integer_increment as u32)
}
/// Gets the `TemporalUnit` from an options object.

Loading…
Cancel
Save