Skip to content

Commit

Permalink
Editorial: Limit year, month, and week length calculations to nonzero
Browse files Browse the repository at this point in the history
In order to calculate the rounded value and totals in RoundDuration, when
rounding to years, months, or weeks, we need to divide by the length of
the year, month, or week in days. Throw an exception if this would
otherwise result in division by zero.

This is marked 'editorial' because division by zero with mathematical
values is an editorial error in the spec. However, the month/week
divisions didn't exist before the normative change in the previous commit,
so this would previously only have applied to years.

Closes: #2335
  • Loading branch information
ptomato committed Nov 14, 2023
1 parent ed38878 commit 8988a15
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 0 deletions.
3 changes: 3 additions & 0 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5660,6 +5660,7 @@ export function RoundDuration(
// the duration. This lets us do days-or-larger rounding using BigInt
// math which reduces precision loss.
oneYearDays = MathAbs(oneYearDays);
if (oneYearDays === 0) throw new RangeError('custom calendar reported that a year is 0 days long');
const divisor = bigInt(oneYearDays).multiply(dayLengthNs);
nanoseconds = divisor.multiply(years).plus(bigInt(days).multiply(dayLengthNs)).plus(nanoseconds);
const rounded = RoundNumberToIncrement(nanoseconds, divisor.multiply(increment).toJSNumber(), roundingMode);
Expand Down Expand Up @@ -5707,6 +5708,7 @@ export function RoundDuration(
let { days: oneMonthDays } = MoveRelativeDate(calendarRec, plainRelativeTo, oneMonth);

oneMonthDays = MathAbs(oneMonthDays);
if (oneMonthDays === 0) throw new RangeError('custom calendar reported that a month is 0 days long');
const divisor = bigInt(oneMonthDays).multiply(dayLengthNs);
nanoseconds = divisor.multiply(months).plus(bigInt(days).multiply(dayLengthNs)).plus(nanoseconds);
const rounded = RoundNumberToIncrement(nanoseconds, divisor.multiply(increment), roundingMode);
Expand Down Expand Up @@ -5744,6 +5746,7 @@ export function RoundDuration(
let { days: oneWeekDays } = MoveRelativeDate(calendarRec, plainRelativeTo, oneWeek);

oneWeekDays = MathAbs(oneWeekDays);
if (oneWeekDays === 0) throw new RangeError('custom calendar reported that a week is 0 days long');
const divisor = bigInt(oneWeekDays).multiply(dayLengthNs);
nanoseconds = divisor.multiply(weeks).plus(bigInt(days).multiply(dayLengthNs)).plus(nanoseconds);
const rounded = RoundNumberToIncrement(nanoseconds, divisor.multiply(increment), roundingMode);
Expand Down
3 changes: 3 additions & 0 deletions spec/duration.html
Original file line number Diff line number Diff line change
Expand Up @@ -1708,6 +1708,7 @@ <h1>
1. Let _oneYear_ be ! CreateTemporalDuration(_sign_, 0, 0, 0, 0, 0, 0, 0, 0, 0).
1. Set _moveResult_ to ? MoveRelativeDate(_calendarRec_, _plainRelativeTo_, _oneYear_).
1. Let _oneYearDays_ be _moveResult_.[[Days]].
1. If _oneYearDays_ = 0, throw a *RangeError* exception.
1. Let _fractionalYears_ be _years_ + _fractionalDays_ / abs(_oneYearDays_).
1. Set _years_ to RoundNumberToIncrement(_fractionalYears_, _increment_, _roundingMode_).
1. Set _total_ to _fractionalYears_.
Expand Down Expand Up @@ -1738,6 +1739,7 @@ <h1>
1. Let _oneMonth_ be ! CreateTemporalDuration(0, _sign_, 0, 0, 0, 0, 0, 0, 0, 0).
1. Let _moveResult_ be ? MoveRelativeDate(_calendarRec_, _plainRelativeTo_, _oneMonth_).
1. Let _oneMonthDays_ be _moveResult_.[[Days]].
1. If _oneMonthDays_ = 0, throw a *RangeError* exception.
1. Let _fractionalMonths_ be _months_ + _fractionalDays_ / abs(_oneMonthDays_).
1. Set _months_ to RoundNumberToIncrement(_fractionalMonths_, _increment_, _roundingMode_).
1. Set _total_ to _fractionalMonths_.
Expand All @@ -1761,6 +1763,7 @@ <h1>
1. Let _oneWeek_ be ! CreateTemporalDuration(0, 0, _sign_, 0, 0, 0, 0, 0, 0, 0).
1. Let _moveResult_ be ? MoveRelativeDate(_calendarRec_, _plainRelativeTo_, _oneWeek_).
1. Let _oneWeekDays_ be _moveResult_.[[Days]].
1. If _oneWeekDays_ = 0, throw a *RangeError* exception.
1. Let _fractionalWeeks_ be _weeks_ + _fractionalDays_ / abs(_oneWeekDays_).
1. Set _weeks_ to RoundNumberToIncrement(_fractionalWeeks_, _increment_, _roundingMode_).
1. Set _total_ to _fractionalWeeks_.
Expand Down

0 comments on commit 8988a15

Please sign in to comment.