Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relax error checking requiring exclusive end in NudgeToCalendarUnit #2924

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3853,28 +3853,28 @@ function NudgeToCalendarUnit(

// Round the smallestUnit within the epoch-nanosecond span
if (
(sign === 1 && (startEpochNs.gt(destEpochNs) || destEpochNs.geq(endEpochNs))) ||
(sign === -1 && (endEpochNs.geq(destEpochNs) || destEpochNs.gt(startEpochNs)))
(sign === 1 && (startEpochNs.gt(destEpochNs) || destEpochNs.gt(endEpochNs))) ||
(sign === -1 && (endEpochNs.gt(destEpochNs) || destEpochNs.gt(startEpochNs))) ||
endEpochNs.equals(startEpochNs)
) {
throw new RangeError(`custom calendar reported a ${unit} that is 0 days long`);
}
if (endEpochNs.equals(startEpochNs)) {
throw new Error('assertion failed: startEpochNs ≠ endEpochNs');
}
const numerator = TimeDuration.fromEpochNsDiff(destEpochNs, startEpochNs);
const denominator = TimeDuration.fromEpochNsDiff(endEpochNs, startEpochNs);
const unsignedRoundingMode = GetUnsignedRoundingMode(roundingMode, sign < 0 ? 'negative' : 'positive');
const cmp = numerator.add(numerator).abs().subtract(denominator.abs()).sign();
const even = (MathAbs(r1) / increment) % 2 === 0;
const roundedUnit = numerator.isZero()
? MathAbs(r1)
: ApplyUnsignedRoundingMode(MathAbs(r1), MathAbs(r2), cmp, even, unsignedRoundingMode);
: !numerator.cmp(denominator) // equal?
? MathAbs(r2)
: ApplyUnsignedRoundingMode(MathAbs(r1), MathAbs(r2), cmp, even, unsignedRoundingMode);

// Trick to minimize rounding error, due to the lack of fma() in JS
const fakeNumerator = new TimeDuration(denominator.totalNs.times(r1).add(numerator.totalNs.times(increment * sign)));
const total = fakeNumerator.fdiv(denominator.totalNs);
if (MathAbs(total) < MathAbs(r1) || MathAbs(total) >= MathAbs(r2)) {
throw new Error('assertion failed: r1 ≤ total < r2');
if (MathAbs(total) < MathAbs(r1) || MathAbs(total) > MathAbs(r2)) {
throw new Error('assertion failed: r1 ≤ total r2');
}

// Determine whether expanded or contracted
Expand Down
19 changes: 11 additions & 8 deletions spec/duration.html
Original file line number Diff line number Diff line change
Expand Up @@ -1878,20 +1878,23 @@ <h1>
1. Let _endInstant_ be ? GetInstantFor(_timeZoneRec_, _endDateTime_, *"compatible"*).
1. Let _endEpochNs_ be _endInstant_.[[Nanoseconds]].
1. If _sign_ is 1, then
1. If _startEpochNs_ &gt; _destEpochNs_ or _destEpochNs_ _endEpochNs_, throw a *RangeError* exception.
1. Assert: _startEpochNs_ ≤ _destEpochNs_ &lt; _endEpochNs_.
1. If _startEpochNs_ &gt; _destEpochNs_ or _destEpochNs_ &gt; _endEpochNs_, throw a *RangeError* exception.
1. Assert: _startEpochNs_ ≤ _destEpochNs_ _endEpochNs_.
1. Else,
1. If _endEpochNs_ _destEpochNs_ or _destEpochNs_ &gt; _startEpochNs_, throw a *RangeError* exception.
1. Assert: _endEpochNs_ &lt; _destEpochNs_ ≤ _startEpochNs_.
1. Assert: _startEpochNs_ ≠ _endEpochNs_.
1. If _endEpochNs_ &gt; _destEpochNs_ or _destEpochNs_ &gt; _startEpochNs_, throw a *RangeError* exception.
1. Assert: _endEpochNs_ _destEpochNs_ ≤ _startEpochNs_.
1. If _endEpochNs_ = _startEpochNs_, throw a *RangeError* exception.
1. Let _progress_ be (_destEpochNs_ - _startEpochNs_) / (_endEpochNs_ - _startEpochNs_).
1. Let _total_ be _r1_ + _progress_ × _increment_ × _sign_.
1. NOTE: The above two steps cannot be implemented directly using floating-point arithmetic. This division can be implemented as if constructing Normalized Time Duration Records for the denominator and numerator of _total_ and performing one division operation with a floating-point result.
1. Assert: 0 ≤ _progress_ &lt; 1.
1. Assert: 0 ≤ _progress_ 1.
1. If _sign_ &lt; 0, let _isNegative_ be ~negative~; else let _isNegative_ be ~positive~.
1. Let _unsignedRoundingMode_ be GetUnsignedRoundingMode(_roundingMode_, _isNegative_).
1. Assert: abs(_r1_) ≤ abs(_total_) &lt; abs(_r2_).
1. Let _roundedUnit_ be ApplyUnsignedRoundingMode(abs(_total_), abs(_r1_), abs(_r2_), _unsignedRoundingMode_).
1. If _progress_ = 1, then
1. Let _roundedUnit_ be abs(_r2_).
1. Else,
1. Assert: abs(_r1_) ≤ abs(_total_) &lt; abs(_r2_).
1. Let _roundedUnit_ be ApplyUnsignedRoundingMode(abs(_total_), abs(_r1_), abs(_r2_), _unsignedRoundingMode_).
1. If _roundedUnit_ is abs(_r2_), then
1. Let _didExpandCalendarUnit_ be *true*.
1. Let _resultDuration_ be _endDuration_.
Expand Down
Loading