diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index a0e32d51d0..ca303e4341 100644 --- a/polyfill/lib/ecmascript.mjs +++ b/polyfill/lib/ecmascript.mjs @@ -1192,6 +1192,7 @@ export function ToTemporalDate(item, options) { export function InterpretTemporalDateTimeFields(calendar, fields, options) { let { hour, minute, second, millisecond, microsecond, nanosecond } = ToTemporalTimeRecord(fields); const overflow = ToTemporalOverflow(options); + options.overflow = overflow; // options is always an internal object, so not observable const date = CalendarDateFromFields(calendar, fields, options); const year = GetSlot(date, ISO_YEAR); const month = GetSlot(date, ISO_MONTH); @@ -1210,14 +1211,16 @@ export function InterpretTemporalDateTimeFields(calendar, fields, options) { export function ToTemporalDateTime(item, options) { let year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar; + const resolvedOptions = SnapshotOwnProperties(GetOptionsObject(options), null); + if (Type(item) === 'Object') { if (IsTemporalDateTime(item)) return item; if (IsTemporalZonedDateTime(item)) { - ToTemporalOverflow(options); // validate and ignore + ToTemporalOverflow(resolvedOptions); // validate and ignore return GetPlainDateTimeFor(GetSlot(item, TIME_ZONE), GetSlot(item, INSTANT), GetSlot(item, CALENDAR)); } if (IsTemporalDate(item)) { - ToTemporalOverflow(options); // validate and ignore + ToTemporalOverflow(resolvedOptions); // validate and ignore return CreateTemporalDateTime( GetSlot(item, ISO_YEAR), GetSlot(item, ISO_MONTH), @@ -1239,10 +1242,9 @@ export function ToTemporalDateTime(item, options) { ({ year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = InterpretTemporalDateTimeFields( calendar, fields, - options + resolvedOptions )); } else { - ToTemporalOverflow(options); // validate and ignore let z; ({ year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar, z } = ParseTemporalDateTimeString(RequireString(item))); @@ -1251,6 +1253,7 @@ export function ToTemporalDateTime(item, options) { if (!calendar) calendar = 'iso8601'; if (!IsBuiltinCalendar(calendar)) throw new RangeError(`invalid calendar identifier ${calendar}`); calendar = ASCIILowercase(calendar); + ToTemporalOverflow(resolvedOptions); // validate and ignore } return CreateTemporalDateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar); } @@ -1456,6 +1459,7 @@ export function InterpretISODateTimeOffset( export function ToTemporalZonedDateTime(item, options) { let year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, timeZone, offset, calendar; + const resolvedOptions = SnapshotOwnProperties(GetOptionsObject(options), null); let disambiguation, offsetOpt; let matchMinute = false; let offsetBehaviour = 'option'; @@ -1479,12 +1483,12 @@ export function ToTemporalZonedDateTime(item, options) { if (offset === undefined) { offsetBehaviour = 'wall'; } - disambiguation = ToTemporalDisambiguation(options); - offsetOpt = ToTemporalOffset(options, 'reject'); + disambiguation = ToTemporalDisambiguation(resolvedOptions); + offsetOpt = ToTemporalOffset(resolvedOptions, 'reject'); ({ year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = InterpretTemporalDateTimeFields( calendar, fields, - options + resolvedOptions )); } else { let tzAnnotation, z; @@ -1513,9 +1517,9 @@ export function ToTemporalZonedDateTime(item, options) { if (!IsBuiltinCalendar(calendar)) throw new RangeError(`invalid calendar identifier ${calendar}`); calendar = ASCIILowercase(calendar); matchMinute = true; // ISO strings may specify offset with less precision - disambiguation = ToTemporalDisambiguation(options); - offsetOpt = ToTemporalOffset(options, 'reject'); - ToTemporalOverflow(options); // validate and ignore + disambiguation = ToTemporalDisambiguation(resolvedOptions); + offsetOpt = ToTemporalOffset(resolvedOptions, 'reject'); + ToTemporalOverflow(resolvedOptions); // validate and ignore } let offsetNs = 0; if (offsetBehaviour === 'option') offsetNs = ParseDateTimeUTCOffset(offset); diff --git a/polyfill/lib/plaindatetime.mjs b/polyfill/lib/plaindatetime.mjs index 464af91002..e9b05497c1 100644 --- a/polyfill/lib/plaindatetime.mjs +++ b/polyfill/lib/plaindatetime.mjs @@ -153,7 +153,7 @@ export class PlainDateTime { } ES.RejectTemporalLikeObject(temporalDateTimeLike); - options = ES.GetOptionsObject(options); + const resolvedOptions = ES.SnapshotOwnProperties(ES.GetOptionsObject(options), null); const calendar = GetSlot(this, CALENDAR); const fieldNames = ES.CalendarFields(calendar, ['day', 'month', 'monthCode', 'year']); let fields = ES.PrepareTemporalFields(this, fieldNames, []); @@ -168,7 +168,7 @@ export class PlainDateTime { fields = ES.CalendarMergeFields(calendar, fields, partialDateTime); fields = ES.PrepareTemporalFields(fields, fieldNames, []); const { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = - ES.InterpretTemporalDateTimeFields(calendar, fields, options); + ES.InterpretTemporalDateTimeFields(calendar, fields, resolvedOptions); return ES.CreateTemporalDateTime( year, diff --git a/polyfill/lib/zoneddatetime.mjs b/polyfill/lib/zoneddatetime.mjs index 63d6e9f840..73af21b15d 100644 --- a/polyfill/lib/zoneddatetime.mjs +++ b/polyfill/lib/zoneddatetime.mjs @@ -180,7 +180,7 @@ export class ZonedDateTime { throw new TypeError('invalid zoned-date-time-like'); } ES.RejectTemporalLikeObject(temporalZonedDateTimeLike); - options = ES.GetOptionsObject(options); + const resolvedOptions = ES.SnapshotOwnProperties(ES.GetOptionsObject(options), null); const calendar = GetSlot(this, CALENDAR); const timeZone = GetSlot(this, TIME_ZONE); @@ -208,11 +208,11 @@ export class ZonedDateTime { fields = ES.CalendarMergeFields(calendar, fields, partialZonedDateTime); fields = ES.PrepareTemporalFields(fields, fieldNames, ['offset']); - const disambiguation = ES.ToTemporalDisambiguation(options); - const offset = ES.ToTemporalOffset(options, 'prefer'); + const disambiguation = ES.ToTemporalDisambiguation(resolvedOptions); + const offset = ES.ToTemporalOffset(resolvedOptions, 'prefer'); let { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = - ES.InterpretTemporalDateTimeFields(calendar, fields, options); + ES.InterpretTemporalDateTimeFields(calendar, fields, resolvedOptions); const newOffsetNs = ES.ParseDateTimeUTCOffset(fields.offset); const epochNanoseconds = ES.InterpretISODateTimeOffset( year, diff --git a/spec/plaindatetime.html b/spec/plaindatetime.html index 21a4791836..eaa9c80d82 100644 --- a/spec/plaindatetime.html +++ b/spec/plaindatetime.html @@ -398,7 +398,7 @@

Temporal.PlainDateTime.prototype.with ( _temporalDateTimeLike_ [ , _options_ 1. If Type(_temporalDateTimeLike_) is not Object, then 1. Throw a *TypeError* exception. 1. Perform ? RejectTemporalLikeObject(_temporalDateTimeLike_). - 1. Set _options_ to ? GetOptionsObject(_options_). + 1. Let _resolvedOptions_ be ? SnapshotOwnProperties(? GetOptionsObject(_options_), *null*). 1. Let _calendar_ be _dateTime_.[[Calendar]]. 1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »). 1. Let _fields_ be ? PrepareTemporalFields(_dateTime_, _fieldNames_, «»). @@ -412,7 +412,7 @@

Temporal.PlainDateTime.prototype.with ( _temporalDateTimeLike_ [ , _options_ 1. Let _partialDateTime_ be ? PrepareTemporalFields(_temporalDateTimeLike_, _fieldNames_, ~partial~). 1. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialDateTime_). 1. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, «»). - 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). + 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _resolvedOptions_). 1. Assert: IsValidISODate(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]]) is *true*. 1. Assert: IsValidTime(_result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]]) is *true*. 1. Return ? CreateTemporalDateTime(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]], _result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]], _calendar_). @@ -953,8 +953,11 @@

InterpretTemporalDateTimeFields ( _calendar_, _fields_, _options_ )

The abstract operation InterpretTemporalDateTimeFields interprets the date/time fields in the object _fields_ using the given _calendar_, and returns a Record with the fields according to the ISO 8601 calendar.

+ 1. Assert: _options_ is an ordinary extensible Object that is not directly observable from ECMAScript code and for which the value of the [[Prototype]] internal slot is *null* and every property is a configurable data property. 1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_). 1. Let _overflow_ be ? ToTemporalOverflow(_options_). + 1. NOTE: The following step is guaranteed to complete normally despite the *"overflow"* property existing, because of the assertion in the first step. + 1. Perform ! CreateDataPropertyOrThrow(_options_, *"overflow"*, _overflow_). 1. Let _temporalDate_ be ? CalendarDateFromFields(_calendar_, _fields_, _options_). 1. Let _timeResult_ be ? RegulateTime(_timeResult_.[[Hour]], _timeResult_.[[Minute]], _timeResult_.[[Second]], _timeResult_.[[Millisecond]], _timeResult_.[[Microsecond]], _timeResult_.[[Nanosecond]], _overflow_). 1. Return the Record { @@ -979,23 +982,23 @@

ToTemporalDateTime ( _item_ [ , _options_ ] )

1. If _options_ is not present, set _options_ to *undefined*. 1. Assert: Type(_options_) is Object or Undefined. + 1. Let _resolvedOptions_ be ? SnapshotOwnProperties(? GetOptionsObject(_options_), *null*). 1. If Type(_item_) is Object, then 1. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then 1. Return _item_. 1. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then - 1. Perform ? ToTemporalOverflow(_options_). + 1. Perform ? ToTemporalOverflow(_resolvedOptions_). 1. Let _instant_ be ! CreateTemporalInstant(_item_.[[Nanoseconds]]). 1. Return ? GetPlainDateTimeFor(_item_.[[TimeZone]], _instant_, _item_.[[Calendar]]). 1. If _item_ has an [[InitializedTemporalDate]] internal slot, then - 1. Perform ? ToTemporalOverflow(_options_). + 1. Perform ? ToTemporalOverflow(_resolvedOptions_). 1. Return ? CreateTemporalDateTime(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], 0, 0, 0, 0, 0, 0, _item_.[[Calendar]]). 1. Let _calendar_ be ? GetTemporalCalendarSlotValueWithISODefault(_item_). 1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »). 1. Append *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"nanosecond"*, and *"second"* to _fieldNames_. 1. Let _fields_ be ? PrepareTemporalFields(_item_, _fieldNames_, «»). - 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). + 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _resolvedOptions_). 1. Else, - 1. Perform ? ToTemporalOverflow(_options_). 1. If _item_ is not a String, throw a *TypeError* exception. 1. Let _result_ be ? ParseTemporalDateTimeString(_item_). 1. Assert: IsValidISODate(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]]) is *true*. @@ -1004,6 +1007,7 @@

ToTemporalDateTime ( _item_ [ , _options_ ] )

1. If _calendar_ is *undefined*, set _calendar_ to *"iso8601"*. 1. If IsBuiltinCalendar(_calendar_) is *false*, throw a *RangeError* exception. 1. Set _calendar_ to the ASCII-lowercase of _calendar_. + 1. Perform ? ToTemporalOverflow(_resolvedOptions_). 1. Return ? CreateTemporalDateTime(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]], _result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]], _calendar_).
diff --git a/spec/zoneddatetime.html b/spec/zoneddatetime.html index 54488830ff..45f74faa27 100644 --- a/spec/zoneddatetime.html +++ b/spec/zoneddatetime.html @@ -584,7 +584,7 @@

Temporal.ZonedDateTime.prototype.with ( _temporalZonedDateTimeLike_ [ , _opt 1. If Type(_temporalZonedDateTimeLike_) is not Object, then 1. Throw a *TypeError* exception. 1. Perform ? RejectTemporalLikeObject(_temporalZonedDateTimeLike_). - 1. Set _options_ to ? GetOptionsObject(_options_). + 1. Let _resolvedOptions_ be ? SnapshotOwnProperties(? GetOptionsObject(_options_), *null*). 1. Let _calendar_ be _zonedDateTime_.[[Calendar]]. 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]]. 1. Let _instant_ be ! CreateTemporalInstant(_zonedDateTime_.[[Nanoseconds]]). @@ -604,9 +604,9 @@

Temporal.ZonedDateTime.prototype.with ( _temporalZonedDateTimeLike_ [ , _opt 1. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialZonedDateTime_). 1. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, « *"offset"* »). 1. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalDisambiguation reads *"disambiguation"*, ToTemporalOffset reads *"offset"*, and InterpretTemporalDateTimeFields reads *"overflow"*). - 1. Let _disambiguation_ be ? ToTemporalDisambiguation(_options_). - 1. Let _offset_ be ? ToTemporalOffset(_options_, *"prefer"*). - 1. Let _dateTimeResult_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). + 1. Let _disambiguation_ be ? ToTemporalDisambiguation(_resolvedOptions_). + 1. Let _offset_ be ? ToTemporalOffset(_resolvedOptions_, *"prefer"*). + 1. Let _dateTimeResult_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _resolvedOptions_). 1. Let _offsetString_ be ! Get(_fields_, *"offset"*). 1. Assert: Type(_offsetString_) is String. 1. Let _newOffsetNanoseconds_ be ? ParseDateTimeUTCOffset(_offsetString_). @@ -1158,6 +1158,7 @@

1. If _options_ is not present, set _options_ to *undefined*. 1. Assert: Type(_options_) is Object or Undefined. + 1. Let _resolvedOptions_ be ? SnapshotOwnProperties(? GetOptionsObject(_options_), *null*). 1. Let _offsetBehaviour_ be ~option~. 1. Let _matchBehaviour_ be ~match exactly~. 1. If Type(_item_) is Object, then @@ -1174,9 +1175,9 @@

1. If _offsetString_ is *undefined*, then 1. Set _offsetBehaviour_ to ~wall~. 1. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalDisambiguation reads *"disambiguation"*, ToTemporalOffset reads *"offset"*, and InterpretTemporalDateTimeFields reads *"overflow"*). - 1. Let _disambiguation_ be ? ToTemporalDisambiguation(_options_). - 1. Let _offsetOption_ be ? ToTemporalOffset(_options_, *"reject"*). - 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). + 1. Let _disambiguation_ be ? ToTemporalDisambiguation(_resolvedOptions_). + 1. Let _offsetOption_ be ? ToTemporalOffset(_resolvedOptions_, *"reject"*). + 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _resolvedOptions_). 1. Else, 1. If _item_ is not a String, throw a *TypeError* exception. 1. Let _result_ be ? ParseTemporalZonedDateTimeString(_item_). @@ -1193,9 +1194,9 @@

1. If IsBuiltinCalendar(_calendar_) is *false*, throw a *RangeError* exception. 1. Set _calendar_ to the ASCII-lowercase of _calendar_. 1. Set _matchBehaviour_ to ~match minutes~. - 1. Let _disambiguation_ be ? ToTemporalDisambiguation(_options_). - 1. Let _offsetOption_ be ? ToTemporalOffset(_options_, *"reject"*). - 1. Perform ? ToTemporalOverflow(_options_). + 1. Let _disambiguation_ be ? ToTemporalDisambiguation(_resolvedOptions_). + 1. Let _offsetOption_ be ? ToTemporalOffset(_resolvedOptions_, *"reject"*). + 1. Perform ? ToTemporalOverflow(_resolvedOptions_). 1. Let _offsetNanoseconds_ be 0. 1. If _offsetBehaviour_ is ~option~, then 1. Set _offsetNanoseconds_ to ? ParseDateTimeUTCOffset(_offsetString_).