From 14e85b636a8168aad25447f6a5fed02ef3f8e56f Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Tue, 8 Oct 2024 09:21:18 -0700 Subject: [PATCH] Editorial: Abstract days range check into CheckISODaysRange This pattern is there because of #2729 and #2985. Abstract it into its own operation, for documentation purposes and because it can disappear after https://github.com/tc39/ecma262/issues/1087 is fixed. See: #3005 --- polyfill/lib/ecmascript.mjs | 32 +++++++++++++++----------------- spec/abstractops.html | 22 ++++++++++++++++++++++ spec/instant.html | 2 +- spec/timezone.html | 4 ++-- spec/zoneddatetime.html | 4 ++-- 5 files changed, 42 insertions(+), 22 deletions(-) diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index e55336ff8..0f697fa22 100644 --- a/polyfill/lib/ecmascript.mjs +++ b/polyfill/lib/ecmascript.mjs @@ -1301,9 +1301,7 @@ export function ToTemporalInstant(item) { microsecond, nanosecond - offsetNanoseconds ); - if (MathAbs(ISODateToEpochDays(balanced.isoDate.year, balanced.isoDate.month - 1, balanced.isoDate.day)) > 1e8) { - throw new RangeErrorCtor('date/time value is outside the supported range'); - } + CheckISODaysRange(balanced.isoDate); const epochNanoseconds = GetUTCEpochNanoseconds(balanced); ValidateEpochNanoseconds(epochNanoseconds); return new TemporalInstant(epochNanoseconds); @@ -1441,17 +1439,13 @@ export function InterpretISODateTimeOffset( 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'); - } + CheckISODaysRange(balanced.isoDate); const epochNs = GetUTCEpochNanoseconds(balanced); ValidateEpochNanoseconds(epochNs); return epochNs; } - if (MathAbs(ISODateToEpochDays(isoDate.year, isoDate.month - 1, isoDate.day)) > 1e8) { - throw new RangeErrorCtor('date/time outside of supported range'); - } + CheckISODaysRange(isoDate); const utcEpochNs = GetUTCEpochNanoseconds(dt); // "prefer" or "reject" @@ -1936,19 +1930,13 @@ export function GetPossibleEpochNanoseconds(timeZone, isoDateTime) { isoDateTime.time.microsecond, isoDateTime.time.nanosecond ); - if (MathAbs(ISODateToEpochDays(balanced.isoDate.year, balanced.isoDate.month - 1, balanced.isoDate.day)) > 1e8) { - throw new RangeErrorCtor('date/time value is outside the supported range'); - } + CheckISODaysRange(balanced.isoDate); const epochNs = GetUTCEpochNanoseconds(balanced); ValidateEpochNanoseconds(epochNs); return [epochNs]; } - if ( - MathAbs(ISODateToEpochDays(isoDateTime.isoDate.year, isoDateTime.isoDate.month - 1, isoDateTime.isoDate.day)) > 1e8 - ) { - throw new RangeErrorCtor('date/time value is outside the supported range'); - } + CheckISODaysRange(isoDateTime.isoDate); return GetNamedTimeZoneEpochNanoseconds(timeZone, isoDateTime); } @@ -2978,6 +2966,16 @@ export function ISODateToEpochDays(y, m, d) { return GetUTCEpochMilliseconds(y, m + 1, d, 0, 0, 0, 0) / DAY_MS; } +// This is needed before calling GetUTCEpochNanoseconds, because it uses MakeDay +// which is ill-defined in how it handles large year numbers. If the issue +// https://github.com/tc39/ecma262/issues/1087 is fixed, this can be removed +// with no observable changes. +function CheckISODaysRange({ year, month, day }) { + if (MathAbs(ISODateToEpochDays(year, month - 1, day)) > 1e8) { + throw new RangeErrorCtor('date/time value is outside the supported range'); + } +} + function DifferenceTime(time1, time2) { const hours = time2.hour - time1.hour; const minutes = time2.minute - time1.minute; diff --git a/spec/abstractops.html b/spec/abstractops.html index 18f091831..09ea49f1d 100644 --- a/spec/abstractops.html +++ b/spec/abstractops.html @@ -108,6 +108,28 @@

Date Equations

Note that the operation EpochTimeToMonthInYear(_t_) uses 0-based months unlike rest of Temporal since it's intended to be unified with MonthFromTime(_t_) when the above mentioned issue is fixed. + +

+ CheckISODaysRange ( + _isoDate_: an ISO Date Record, + ): either a normal completion containing ~unused~ or a throw completion +

+
+
description
+
It checks that the given date is within the range of 108 days from the epoch.
+
+ + 1. If abs(ISODateToEpochDays(_isoDate_.[[Year]], _isoDate_.[[Month]] - 1, _isoDate_.[[Day]])) > 108, then + 1. Throw a *RangeError* exception. + 1. Return ~unused~. + + + This operation is solely present to ensure that GetUTCEpochNanoseconds is not called with numbers that are too large. + It is distinct from ISODateWithinLimits, which uses GetUTCEpochNanoseconds. + This operation can be removed with no observable effect when https://github.com/tc39/ecma262/issues/1087 is fixed. + +
+

Units

diff --git a/spec/instant.html b/spec/instant.html index 6234ca34e..4def94a82 100644 --- a/spec/instant.html +++ b/spec/instant.html @@ -414,7 +414,7 @@

1. If _parsed_.[[TimeZone]].[[Z]] is *true*, let _offsetNanoseconds_ be 0; otherwise, let _offsetNanoseconds_ be ! ParseDateTimeUTCOffset(_parsed_.[[TimeZone]].[[OffsetString]]). 1. If _parsed_.[[Time]] is ~start-of-day~, let _time_ be MidnightTimeRecord(); else let _time_ be _parsed_.[[Time]]. 1. Let _balanced_ be BalanceISODateTime(_parsed_.[[Year]], _parsed_.[[Month]], _parsed_.[[Day]], _time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _time_.[[Microsecond]], _time_.[[Nanosecond]] - _offsetNanoseconds_). - 1. If abs(ISODateToEpochDays(_balanced_.[[ISODate]].[[Year]], _balanced_.[[ISODate]].[[Month]] - 1, _balanced_.[[ISODate]].[[Day]])) > 108, throw a *RangeError* exception. + 1. Perform ? CheckISODaysRange(_balanced_.[[ISODate]]). 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_balanced_). 1. If IsValidEpochNanoseconds(_epochNanoseconds_) is *false*, throw a *RangeError* exception. 1. Return ! CreateTemporalInstant(_epochNanoseconds_). diff --git a/spec/timezone.html b/spec/timezone.html index ce24655bd..db576f4a2 100644 --- a/spec/timezone.html +++ b/spec/timezone.html @@ -350,11 +350,11 @@

1. Let _parseResult_ be ! ParseTimeZoneIdentifier(_timeZone_). 1. If _parseResult_.[[OffsetMinutes]] is not ~empty~, then 1. Let _balanced_ be BalanceISODateTime(_isoDateTime_.[[ISODate]].[[Year]], _isoDateTime_.[[ISODate]].[[Month]], _isoDateTime_.[[ISODate]].[[Day]], _isoDateTime_.[[Time]].[[Hour]], _isoDateTime_.[[Time]].[[Minute]] - _parseResult_.[[OffsetMinutes]], _isoDateTime_.[[Time]].[[Second]], _isoDateTime_.[[Time]].[[Millisecond]], _isoDateTime_.[[Time]].[[Microsecond]], _isoDateTime_.[[Time]].[[Nanosecond]]). - 1. If abs(ISODateToEpochDays(_balanced_.[[ISODate]].[[Year]], _balanced_.[[ISODate]].[[Month]] - 1, _balanced_.[[ISODate]].[[Day]])) > 108, throw a *RangeError* exception. + 1. Perform ? CheckISODaysRange(_balanced_.[[ISODate]]). 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_balanced_). 1. Let _possibleEpochNanoseconds_ be « _epochNanoseconds_ ». 1. Else, - 1. If abs(ISODateToEpochDays(_isoDateTime_.[[ISODate]].[[Year]], _isoDateTime_.[[ISODate]].[[Month]] - 1, _isoDateTime_.[[ISODate]].[[Day]])) > 108, throw a *RangeError* exception. + 1. Perform ? CheckISODaysRange(_isoDateTime_.[[ISODate]]). 1. Let _possibleEpochNanoseconds_ be GetNamedTimeZoneEpochNanoseconds(_parseResult_.[[Name]], _isoDateTime_). 1. For each value _epochNanoseconds_ in _possibleEpochNanoseconds_, do 1. If IsValidEpochNanoseconds(_epochNanoseconds_) is *false*, throw a *RangeError* exception. diff --git a/spec/zoneddatetime.html b/spec/zoneddatetime.html index 8d887f5a0..ff422b259 100644 --- a/spec/zoneddatetime.html +++ b/spec/zoneddatetime.html @@ -916,13 +916,13 @@

1. Return ? GetEpochNanosecondsFor(_timeZone_, _isoDateTime_, _disambiguation_). 1. If _offsetBehaviour_ is ~exact~, or _offsetBehaviour_ is ~option~ and _offsetOption_ is ~use~, then 1. Let _balanced_ be BalanceISODateTime(_isoDate_.[[Year]], _isoDate_.[[Month]], _isoDate_.[[Day]], _time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _time_.[[Microsecond]], _time_.[[Nanosecond]] - _offsetNanoseconds_). - 1. If abs(ISODateToEpochDays(_balanced_.[[ISODate]].[[Year]], _balanced_.[[ISODate]].[[Month]] - 1, _balanced_.[[ISODate]].[[Day]])) > 108, throw a *RangeError* exception. + 1. Perform ? CheckISODaysRange(_balanced_.[[ISODate]]). 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_balanced_). 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(_isoDate_.[[Year]], _isoDate_.[[Month]] - 1, _isoDate_.[[Day]])) > 108, throw a *RangeError* exception. + 1. Perform ? CheckISODaysRange(_isoDate_). 1. Let _utcEpochNanoseconds_ be GetUTCEpochNanoseconds(_isoDateTime_). 1. Let _possibleEpochNs_ be ? GetPossibleEpochNanoseconds(_timeZone_, _isoDateTime_). 1. For each element _candidate_ of _possibleEpochNs_, do