diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index d0b7f3cb3..387d6552e 100644 --- a/polyfill/lib/ecmascript.mjs +++ b/polyfill/lib/ecmascript.mjs @@ -1541,6 +1541,43 @@ export function InterpretISODateTimeOffset( return GetEpochNanosecondsFor(timeZone, dt, disambiguation); } + // The caller wants the offset to always win ('use') OR the caller is OK + // with the offset winning ('prefer' or 'reject') as long as it's valid + // for this timezone and date/time. + if (offsetBehaviour === 'exact' || offsetOpt === 'use') { + // Calculate the instant for the input's date/time and offset + const balanced = BalanceISODateTime( + year, + month, + day, + time.hour, + time.minute, + time.second, + time.millisecond, + time.microsecond, + time.nanosecond - offsetNs + ); + if (MathAbs(ISODateToEpochDays(balanced.year, balanced.month - 1, balanced.day)) > 1e8) { + throw new RangeErrorCtor('date/time outside of supported range'); + } + const epochNs = GetUTCEpochNanoseconds( + balanced.year, + balanced.month, + balanced.day, + balanced.hour, + balanced.minute, + balanced.second, + balanced.millisecond, + balanced.microsecond, + balanced.nanosecond + ); + ValidateEpochNanoseconds(epochNs); + return epochNs; + } + + if (MathAbs(ISODateToEpochDays(year, month - 1, day)) > 1e8) { + throw new RangeErrorCtor('date/time outside of supported range'); + } const utcEpochNs = GetUTCEpochNanoseconds( year, month, @@ -1553,16 +1590,6 @@ export function InterpretISODateTimeOffset( time.nanosecond ); - // The caller wants the offset to always win ('use') OR the caller is OK - // with the offset winning ('prefer' or 'reject') as long as it's valid - // for this timezone and date/time. - if (offsetBehaviour === 'exact' || offsetOpt === 'use') { - // Calculate the instant for the input's date/time and offset - const epochNs = utcEpochNs.subtract(offsetNs); - ValidateEpochNanoseconds(epochNs); - return epochNs; - } - // "prefer" or "reject" const possibleEpochNs = GetPossibleEpochNanoseconds(timeZone, dt); for (let index = 0; index < possibleEpochNs.length; index++) { diff --git a/spec/zoneddatetime.html b/spec/zoneddatetime.html index c97b494ad..fd302b9fd 100644 --- a/spec/zoneddatetime.html +++ b/spec/zoneddatetime.html @@ -921,13 +921,16 @@

1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_isoDate_, _time_). 1. If _offsetBehaviour_ is ~wall~, or _offsetBehaviour_ is ~option~ and _offsetOption_ is ~ignore~, then 1. Return ? GetEpochNanosecondsFor(_timeZone_, _isoDateTime_, _disambiguation_). - 1. Let _utcEpochNanoseconds_ be GetUTCEpochNanoseconds(_year_, _month_, _day_, _time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _time_.[[Microsecond]], _time_.[[Nanosecond]]). 1. If _offsetBehaviour_ is ~exact~, or _offsetBehaviour_ is ~option~ and _offsetOption_ is ~use~, then - 1. Let _epochNanoseconds_ be _utcEpochNanoseconds_ - ℤ(_offsetNanoseconds_). + 1. Let _balanced_ be BalanceISODateTime(_year_, _month_, _day_, _time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _time_.[[Microsecond]], _time_.[[Nanosecond]] - _offsetNanoseconds_). + 1. If abs(ISODateToEpochDays(_balanced_.[[Year]], _balanced_.[[Month]] - 1, _balanced_.[[Day]])) > 108, throw a *RangeError* exception. + 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_balanced_.[[Year]], _balanced_.[[Month]], _balanced_.[[Day]], _balanced_.[[Hour]], _balanced_.[[Minute]], _balanced_.[[Second]], _balanced_.[[Millisecond]], _balanced_.[[Microsecond]], _balanced_.[[Nanosecond]]). 1. If IsValidEpochNanoseconds(_epochNanoseconds_) is *false*, throw a *RangeError* exception. 1. Return _epochNanoseconds_. 1. Assert: _offsetBehaviour_ is ~option~. 1. Assert: _offsetOption_ is ~prefer~ or ~reject~. + 1. If abs(ISODateToEpochDays(_year_, _month_ - 1, _day_)) > 108, throw a *RangeError* exception. + 1. Let _utcEpochNanoseconds_ be GetUTCEpochNanoseconds(_year_, _month_, _day_, _time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _time_.[[Microsecond]], _time_.[[Nanosecond]]). 1. Let _possibleEpochNs_ be ? GetPossibleEpochNanoseconds(_timeZone_, _isoDateTime_). 1. For each element _candidate_ of _possibleEpochNs_, do 1. Let _candidateOffset_ be _utcEpochNanoseconds_ - _candidate_.