From 100118a20f3b4bdaf57aa53c4b4e1b66b035f1b7 Mon Sep 17 00:00:00 2001 From: Justin Grant Date: Tue, 27 Jun 2023 20:08:26 -0700 Subject: [PATCH] Editorial: rename TimeZone "nanoseconds" slot/AOs Now that we've limited TimeZone's [[OffsetNanoseconds]] internal slot to minute precision, this commit refactors TimeZone to clarify that only minutes are allowed in that slot and related abstract operations. Changes: * Renames TimeZone's [[OffsetNanoseconds]] internal slot to [[OffsetMinutes]] * Changes ParseTimeZoneIdentifier to return an [[OffsetMinutes]] field instead of an [[OffsetNanoseconds]] field. * Changes FormatOffsetTimeZoneIdentifier to expect a minutes argument. The goal of this change is to avoid the complexity and potential confusion from a slot and AOs that deal with "nanoseconds" values that nonetheless are restricted to minutes. --- polyfill/lib/ecmascript.mjs | 18 +++++------ polyfill/lib/timezone.mjs | 14 ++++----- spec/intl.html | 2 +- spec/mainadditions.html | 12 +++---- spec/timezone.html | 62 ++++++++++++++++++------------------- 5 files changed, 53 insertions(+), 55 deletions(-) diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index 03bfe101e6..7634870be2 100644 --- a/polyfill/lib/ecmascript.mjs +++ b/polyfill/lib/ecmascript.mjs @@ -560,7 +560,7 @@ export function ParseTimeZoneIdentifier(identifier) { if (OFFSET_IDENTIFIER.test(identifier)) { // The regex limits the input to minutes precision const { offsetNanoseconds } = ParseDateTimeUTCOffset(identifier); - return { offsetNanoseconds }; + return { offsetMinutes: offsetNanoseconds / 6e10 }; } return { tzName: identifier }; } @@ -2097,8 +2097,8 @@ export function ToTemporalTimeZoneSlotValue(temporalTimeZoneLike) { const { tzName, offset, z } = ParseTemporalTimeZoneString(identifier); if (tzName) { // tzName is any valid identifier string in brackets, and could be an offset identifier - const { offsetNanoseconds } = ParseTimeZoneIdentifier(tzName); - if (offsetNanoseconds !== undefined) return FormatOffsetTimeZoneIdentifier(offsetNanoseconds); + const { offsetMinutes } = ParseTimeZoneIdentifier(tzName); + if (offsetMinutes !== undefined) return FormatOffsetTimeZoneIdentifier(offsetMinutes); const record = GetAvailableNamedTimeZoneIdentifier(tzName); if (!record) throw new RangeError(`Unrecognized time zone ${tzName}`); @@ -2110,7 +2110,7 @@ export function ToTemporalTimeZoneSlotValue(temporalTimeZoneLike) { if (hasSubMinutePrecision) { throw new RangeError(`Seconds not allowed in offset time zone: ${offset}`); } - return FormatOffsetTimeZoneIdentifier(offsetNanoseconds); + return FormatOffsetTimeZoneIdentifier(offsetNanoseconds / 6e10); } export function ToTemporalTimeZoneIdentifier(slotValue) { @@ -2180,7 +2180,7 @@ export function GetOffsetStringFor(timeZone, instant) { // But in the polyfill, we re-use it to provide clearer error messages. function formatOffsetStringNanoseconds(offsetNs) { const offsetMinutes = MathTrunc(offsetNs / 6e10); - let offsetStringMinutes = FormatOffsetTimeZoneIdentifier(offsetMinutes * 6e10); + let offsetStringMinutes = FormatOffsetTimeZoneIdentifier(offsetMinutes); const subMinuteNanoseconds = MathAbs(offsetNs) % 6e10; if (subMinuteNanoseconds === 0) return offsetStringMinutes; @@ -2741,9 +2741,9 @@ export function GetNamedTimeZoneOffsetNanoseconds(id, epochNanoseconds) { return +utc.minus(epochNanoseconds); } -export function FormatOffsetTimeZoneIdentifier(offsetNanoseconds) { - const sign = offsetNanoseconds < 0 ? '-' : '+'; - const offsetMinutes = MathAbs(offsetNanoseconds / 6e10); +export function FormatOffsetTimeZoneIdentifier(offsetMinutes) { + const sign = offsetMinutes < 0 ? '-' : '+'; + offsetMinutes = MathAbs(offsetMinutes); const hours = MathFloor(offsetMinutes / 60); const hourString = ISODateTimePartString(hours); const minutes = offsetMinutes % 60; @@ -2753,7 +2753,7 @@ export function FormatOffsetTimeZoneIdentifier(offsetNanoseconds) { export function FormatDateTimeUTCOffsetRounded(offsetNanoseconds) { offsetNanoseconds = RoundNumberToIncrement(bigInt(offsetNanoseconds), 60e9, 'halfExpand').toJSNumber(); - return FormatOffsetTimeZoneIdentifier(offsetNanoseconds); + return FormatOffsetTimeZoneIdentifier(offsetNanoseconds / 6e10); } export function GetUTCEpochNanoseconds(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond) { diff --git a/polyfill/lib/timezone.mjs b/polyfill/lib/timezone.mjs index 7c6c8a2e85..7cf62490a7 100644 --- a/polyfill/lib/timezone.mjs +++ b/polyfill/lib/timezone.mjs @@ -28,8 +28,8 @@ export class TimeZone { } let stringIdentifier = ES.ToString(identifier); const parseResult = ES.ParseTimeZoneIdentifier(identifier); - if (parseResult.offsetNanoseconds !== undefined) { - stringIdentifier = ES.FormatOffsetTimeZoneIdentifier(parseResult.offsetNanoseconds); + if (parseResult.offsetMinutes !== undefined) { + stringIdentifier = ES.FormatOffsetTimeZoneIdentifier(parseResult.offsetMinutes); } else { const record = ES.GetAvailableNamedTimeZoneIdentifier(stringIdentifier); if (!record) throw new RangeError(`Invalid time zone identifier: ${stringIdentifier}`); @@ -56,8 +56,8 @@ export class TimeZone { instant = ES.ToTemporalInstant(instant); const id = GetSlot(this, TIMEZONE_ID); - const offsetNanoseconds = ES.ParseTimeZoneIdentifier(id).offsetNanoseconds; - if (offsetNanoseconds !== undefined) return offsetNanoseconds; + const offsetMinutes = ES.ParseTimeZoneIdentifier(id).offsetMinutes; + if (offsetMinutes !== undefined) return offsetMinutes * 6e10; return ES.GetNamedTimeZoneOffsetNanoseconds(id, GetSlot(instant, EPOCHNANOSECONDS)); } @@ -85,8 +85,8 @@ export class TimeZone { const Instant = GetIntrinsic('%Temporal.Instant%'); const id = GetSlot(this, TIMEZONE_ID); - const offsetNanoseconds = ES.ParseTimeZoneIdentifier(id).offsetNanoseconds; - if (offsetNanoseconds !== undefined) { + const offsetMinutes = ES.ParseTimeZoneIdentifier(id).offsetMinutes; + if (offsetMinutes !== undefined) { const epochNs = ES.GetUTCEpochNanoseconds( GetSlot(dateTime, ISO_YEAR), GetSlot(dateTime, ISO_MONTH), @@ -99,7 +99,7 @@ export class TimeZone { GetSlot(dateTime, ISO_NANOSECOND) ); if (epochNs === null) throw new RangeError('DateTime outside of supported range'); - return [new Instant(epochNs.minus(offsetNanoseconds))]; + return [new Instant(epochNs.minus(offsetMinutes * 6e10))]; } const possibleEpochNs = ES.GetNamedTimeZoneEpochNanoseconds( diff --git a/spec/intl.html b/spec/intl.html index c89fb1f4a5..ae21ad0c1b 100644 --- a/spec/intl.html +++ b/spec/intl.html @@ -2543,7 +2543,7 @@

Temporal.ZonedDateTime.prototype.toLocaleString ( [ _locales_ [ , _options_ 1. Let _dateTimeFormat_ be ! OrdinaryCreateFromConstructor(%DateTimeFormat%, %DateTimeFormat.prototype%, « [[InitializedDateTimeFormat]], [[Locale]], [[Calendar]], [[NumberingSystem]], [[TimeZone]], [[Weekday]], [[Era]], [[Year]], [[Month]], [[Day]], [[DayPeriod]], [[Hour]], [[Minute]], [[Second]], [[FractionalSecondDigits]], [[TimeZoneName]], [[HourCycle]], [[Pattern]], [[BoundFormat]] »). 1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_zonedDateTime_.[[TimeZone]]). 1. Let _timeZoneParseResult_ be ? ParseTimeZoneIdentifier(_timeZone_). - 1. If _timeZoneParseResult_.[[OffsetNanoseconds]] is not ~empty~, throw a *RangeError* exception. + 1. If _timeZoneParseResult_.[[OffsetMinutes]] is not ~empty~, throw a *RangeError* exception. 1. Let _timeZoneIdentifierRecord_ be GetAvailableNamedTimeZoneIdentifier(_timeZone_). 1. If _timeZoneIdentifierRecord_ is ~empty~, throw a *RangeError* exception. 1. Set _timeZone_ to _timeZoneIdentifierRecord_.[[PrimaryIdentifier]]. diff --git a/spec/mainadditions.html b/spec/mainadditions.html index 40b4ff5ece..2c6a839e32 100644 --- a/spec/mainadditions.html +++ b/spec/mainadditions.html @@ -350,8 +350,8 @@

1. Let _systemTimeZoneIdentifier_ be SystemTimeZoneIdentifier(). 1. Let _parseResult_ be ! ParseTimeZoneIdentifier(_systemTimeZoneIdentifier_). - 1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*_parseResult_.[[OffsetNanoseconds]] is not ~empty~, then - 1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_)_parseResult_.[[OffsetNanoseconds]]. + 1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*_parseResult_.[[OffsetMinutes]] is not ~empty~, then + 1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_)_parseResult_.[[OffsetMinutes]] × (6 × 1010). 1. Else, 1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_systemTimeZoneIdentifier_, ℤ(ℝ(_t_) × 106)). 1. Let _offsetMs_ be truncate(_offsetNs_ / 106). @@ -385,8 +385,8 @@

1. Let _systemTimeZoneIdentifier_ be SystemTimeZoneIdentifier(). 1. Let _parseResult_ be ! ParseTimeZoneIdentifier(_systemTimeZoneIdentifier_). - 1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*_parseResult_.[[OffsetNanoseconds]] is not ~empty~, then - 1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_)_parseResult_.[[OffsetNanoseconds]]. + 1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*_parseResult_.[[OffsetMinutes]] is not ~empty~, then + 1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_)_parseResult_.[[OffsetMinutes]] × (6 × 1010). 1. Else, 1. Let _possibleInstants_ be GetNamedTimeZoneEpochNanoseconds(_systemTimeZoneIdentifier_, ℝ(YearFromTime(_t_)), ℝ(MonthFromTime(_t_)) + 1, ℝ(DateFromTime(_t_)), ℝ(HourFromTime(_t_)), ℝ(MinFromTime(_t_)), ℝ(SecFromTime(_t_)), ℝ(msFromTime(_t_)), 0, 0). 1. NOTE: The following steps ensure that when _t_ represents local time repeating multiple times at a negative time zone transition (e.g. when the daylight saving time ends or the time zone offset is decreased due to a time zone rule change) or skipped local time at a positive time zone transition (e.g. when the daylight saving time starts or the time zone offset is increased due to a time zone rule change), _t_ is interpreted using the time zone offset before the transition. @@ -436,8 +436,8 @@

1. Let _systemTimeZoneIdentifier_ be SystemTimeZoneIdentifier(). 1. Let _parseResult_ be ! ParseTimeZoneIdentifier(_systemTimeZoneIdentifier_). - 1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*_parseResult_.[[OffsetNanoseconds]] is not ~empty~, then - 1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_)_parseResult_.[[OffsetNanoseconds]]. + 1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*_parseResult_.[[OffsetMinutes]] is not ~empty~, then + 1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_)_parseResult_.[[OffsetMinutes]] × (6 × 1010). 1. Else, 1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_systemTimeZoneIdentifier_, ℤ(ℝ(_tv_) × 106)). 1. Let _offset_ be 𝔽(truncate(_offsetNs_ / 106)). diff --git a/spec/timezone.html b/spec/timezone.html index 6b81458755..8098cf9dd9 100644 --- a/spec/timezone.html +++ b/spec/timezone.html @@ -33,8 +33,8 @@

Temporal.TimeZone ( _identifier_ )

1. Throw a *TypeError* exception. 1. Set _identifier_ to ? ToString(_identifier_). 1. Let _parseResult_ be ? ParseTimeZoneIdentifier(_identifier_). - 1. If _parseResult_.[[OffsetNanoseconds]] is not ~empty~, then - 1. Set _identifier_ to FormatOffsetTimeZoneIdentifier(_parseResult_.[[OffsetNanoseconds]], ~separated~). + 1. If _parseResult_.[[OffsetMinutes]] is not ~empty~, then + 1. Set _identifier_ to FormatOffsetTimeZoneIdentifier(_parseResult_.[[OffsetMinutes]], ~separated~). 1. Else, 1. Let _timeZoneIdentifierRecord_ be GetAvailableNamedTimeZoneIdentifier(_identifier_). 1. If _timeZoneIdentifierRecord_ is ~empty~, throw a *RangeError* exception. @@ -101,7 +101,7 @@

get Temporal.TimeZone.prototype.id

1. Let _timeZone_ be the *this* value. 1. Perform ? RequireInternalSlot(_timeZone_, [[InitializedTemporalTimeZone]]). - 1. If _timeZone_.[[OffsetNanoseconds]] is not ~empty~, return FormatOffsetTimeZoneIdentifier(_timeZone_.[[OffsetNanoseconds]], ~separated~). + 1. If _timeZone_.[[OffsetMinutes]] is not ~empty~, return FormatOffsetTimeZoneIdentifier(_timeZone_.[[OffsetMinutes]], ~separated~). 1. Return _timeZone_.[[Identifier]]. @@ -115,7 +115,7 @@

Temporal.TimeZone.prototype.getOffsetNanosecondsFor ( _instant_ )

1. Let _timeZone_ be the *this* value. 1. Perform ? RequireInternalSlot(_timeZone_, [[InitializedTemporalTimeZone]]). 1. Set _instant_ to ? ToTemporalInstant(_instant_). - 1. If _timeZone_.[[OffsetNanoseconds]] is not ~empty~, return 𝔽(_timeZone_.[[OffsetNanoseconds]]). + 1. If _timeZone_.[[OffsetMinutes]] is not ~empty~, return 𝔽(_timeZone_.[[OffsetMinutes]] × (6 × 1010)). 1. Return 𝔽(GetNamedTimeZoneOffsetNanoseconds(_timeZone_.[[Identifier]], _instant_.[[Nanoseconds]])).
@@ -171,9 +171,9 @@

Temporal.TimeZone.prototype.getPossibleInstantsFor ( _dateTime_ )

1. Let _timeZone_ be the *this* value. 1. Perform ? RequireInternalSlot(_timeZone_, [[InitializedTemporalTimeZone]]). 1. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_). - 1. If _timeZone_.[[OffsetNanoseconds]] is not ~empty~, then + 1. If _timeZone_.[[OffsetMinutes]] is not ~empty~, then 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]]). - 1. Let _possibleEpochNanoseconds_ be « _epochNanoseconds_ - ℤ(_timeZone_.[[OffsetNanoseconds]]) ». + 1. Let _possibleEpochNanoseconds_ be « _epochNanoseconds_ - ℤ(_timeZone_.[[OffsetMinutes]] × (6 × 1010)) ». 1. Else, 1. Let _possibleEpochNanoseconds_ be GetNamedTimeZoneEpochNanoseconds(_timeZone_.[[Identifier]], _dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]]). 1. Let _possibleInstants_ be a new empty List. @@ -194,7 +194,7 @@

Temporal.TimeZone.prototype.getNextTransition ( _startingPoint_ )

1. Let _timeZone_ be the *this* value. 1. Perform ? RequireInternalSlot(_timeZone_, [[InitializedTemporalTimeZone]]). 1. Set _startingPoint_ to ? ToTemporalInstant(_startingPoint_). - 1. If _timeZone_.[[OffsetNanoseconds]] is not ~empty~, return *null*. + 1. If _timeZone_.[[OffsetMinutes]] is not ~empty~, return *null*. 1. Let _transition_ be GetNamedTimeZoneNextTransition(_timeZone_.[[Identifier]], _startingPoint_.[[Nanoseconds]]). 1. If _transition_ is *null*, return *null*. 1. Return ! CreateTemporalInstant(_transition_). @@ -210,7 +210,7 @@

Temporal.TimeZone.prototype.getPreviousTransition ( _startingPoint_ )

1. Let _timeZone_ be the *this* value. 1. Perform ? RequireInternalSlot(_timeZone_, [[InitializedTemporalTimeZone]]). 1. Set _startingPoint_ to ? ToTemporalInstant(_startingPoint_). - 1. If _timeZone_.[[OffsetNanoseconds]] is not ~empty~, return *null*. + 1. If _timeZone_.[[OffsetMinutes]] is not ~empty~, return *null*. 1. Let _transition_ be GetNamedTimeZonePreviousTransition(_timeZone_.[[Identifier]], _startingPoint_.[[Nanoseconds]]). 1. If _transition_ is *null*, return *null*. 1. Return ! CreateTemporalInstant(_transition_). @@ -225,7 +225,7 @@

Temporal.TimeZone.prototype.toString ( )

1. Let _timeZone_ be the *this* value. 1. Perform ? RequireInternalSlot(_timeZone_, [[InitializedTemporalTimeZone]]). - 1. If _timeZone_.[[OffsetNanoseconds]] is not ~empty~, return FormatOffsetTimeZoneIdentifier(_timeZone_.[[OffsetNanoseconds]], ~separated~). + 1. If _timeZone_.[[OffsetMinutes]] is not ~empty~, return FormatOffsetTimeZoneIdentifier(_timeZone_.[[OffsetMinutes]], ~separated~). 1. Return _timeZone_.[[Identifier]]. @@ -238,7 +238,7 @@

Temporal.TimeZone.prototype.toJSON ( )

1. Let _timeZone_ be the *this* value. 1. Perform ? RequireInternalSlot(_timeZone_, [[InitializedTemporalTimeZone]]). - 1. If _timeZone_.[[OffsetNanoseconds]] is not ~empty~, return FormatOffsetTimeZoneIdentifier(_timeZone_.[[OffsetNanoseconds]], ~separated~). + 1. If _timeZone_.[[OffsetMinutes]] is not ~empty~, return FormatOffsetTimeZoneIdentifier(_timeZone_.[[OffsetMinutes]], ~separated~). 1. Return _timeZone_.[[Identifier]]. @@ -280,12 +280,11 @@

Properties of Temporal.TimeZone Instances

- [[OffsetNanoseconds]] + [[OffsetMinutes]] - An integer for nanoseconds representing the constant offset of this time zone relative to UTC, or ~empty~ if the instance represents a named time zone. - If not ~empty~, this value must represent an integer number of minutes (i.e., [[OffsetNanoseconds]] modulo (6 × 1010) must always be 0). - If not ~empty~, this value must be in the interval from −8.64 × 1013 (exclusive) to +8.64 × 1013 (exclusive) (i.e., strictly less than 24 hours in magnitude). + An integer for minutes representing the constant offset of this time zone relative to UTC, or ~empty~ if the instance represents a named time zone. + If not ~empty~, this value must be in the interval from -1440 (exclusive) to 1440 (exclusive) (i.e., strictly less than 24 hours in magnitude). @@ -322,17 +321,17 @@

1. If _newTarget_ is not present, set _newTarget_ to %Temporal.TimeZone%. - 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.TimeZone.prototype%"*, « [[InitializedTemporalTimeZone]], [[Identifier]], [[OffsetNanoseconds]] »). + 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.TimeZone.prototype%"*, « [[InitializedTemporalTimeZone]], [[Identifier]], [[OffsetMinutes]] »). 1. Assert: _identifier_ is an available named time zone identifier or an offset time zone identifier. 1. Let _parseResult_ be ! ParseTimeZoneIdentifier(_identifier_). - 1. If _parseResult_.[[OffsetNanoseconds]] is not ~empty~, then + 1. If _parseResult_.[[OffsetMinutes]] is not ~empty~, then 1. Set _object_.[[Identifier]] to ~empty~. - 1. Set _object_.[[OffsetNanoseconds]] to _parseResult_.[[OffsetNanoseconds]]. + 1. Set _object_.[[OffsetMinutes]] to _parseResult_.[[OffsetMinutes]]. 1. Else, 1. Assert: _parseResult_.[[Name]] is not ~empty~. 1. Assert: GetAvailableNamedTimeZoneIdentifier(_identifier_).[[PrimaryIdentifier]] is _identifier_. 1. Set _object_.[[Identifier]] to _identifier_. - 1. Set _object_.[[OffsetNanoseconds]] to ~empty~. + 1. Set _object_.[[OffsetMinutes]] to ~empty~. 1. Return _object_. @@ -343,7 +342,7 @@

Although the [[Identifier]] internal slot is a String in this specification, implementations may choose to store named time zone identifiers it in any other form (for example as an enumeration or index into a List of identifier strings) as long as the String can be regenerated when needed.

- Similar flexibility exists for the storage of the [[OffsetNanoseconds]] internal slot, which can be interchangeably represented as a 12-bit signed integer or as a 6-character ±HH:MM String value. + Similar flexibility exists for the storage of the [[OffsetMinutes]] internal slot, which can be interchangeably represented as a 12-bit signed integer or as a 6-character ±HH:MM String value. ParseTimeZoneIdentifier and FormatOffsetTimeZoneIdentifier may be used to losslessly convert one representation to the other. Implementations are free to store either or both representations.

@@ -474,7 +473,7 @@

FormatOffsetTimeZoneIdentifier ( - _offsetNanoseconds_: an integer, + _offsetMinutes_: an integer, _style_: ~legacy~ or ~separated~, ): a String

@@ -487,9 +486,8 @@

- 1. If _offsetNanoseconds_ ≥ 0, let _sign_ be the code unit 0x002B (PLUS SIGN); otherwise, let _sign_ be the code unit 0x002D (HYPHEN-MINUS). - 1. Assert: _offsetNanoseconds_ modulo (6 × 1010) = 0. - 1. Let _offsetMinutes_ be abs(_offsetNanoseconds_ / (6 × 1010)). + 1. If _offsetMinutes_ ≥ 0, let _sign_ be the code unit 0x002B (PLUS SIGN); otherwise, let _sign_ be the code unit 0x002D (HYPHEN-MINUS). + 1. Set _offsetMinutes_ to abs(_offsetMinutes_). 1. Let _hours_ be floor(_offsetMinutes_ / 60). 1. Let _h_ be ToZeroPaddedDecimalString(_hours_, 2). 1. Let _minutes_ be _offsetMinutes_ modulo 60. @@ -512,7 +510,7 @@

1. Set _offsetNanoseconds_ to RoundNumberToIncrement(_offsetNanoseconds_, 6 × 1010, *"halfExpand"*). - 1. Return FormatOffsetTimeZoneIdentifier(_offsetNanoseconds_, ~separated~). + 1. Return FormatOffsetTimeZoneIdentifier(_offsetNanoseconds_ / (6 × 1010), ~separated~). @@ -558,8 +556,8 @@

1. Let _parseResult_ be ? ParseTemporalTimeZoneString(_identifier_). 1. If _parseResult_.[[Name]] is not *undefined*, then 1. Let _name_ be _parseResult_.[[Name]]. - 1. Let _offsetNanoseconds_ be ? ParseTimeZoneIdentifier(_name_).[[OffsetNanoseconds]]. - 1. If _offsetNanoseconds_ is not ~empty~, return FormatOffsetTimeZoneIdentifier(_offsetNanoseconds_, ~separated~). + 1. Let _offsetMinutes_ be ? ParseTimeZoneIdentifier(_name_).[[OffsetMinutes]]. + 1. If _offsetMinutes_ is not ~empty~, return FormatOffsetTimeZoneIdentifier(_offsetMinutes_, ~separated~). 1. Let _timeZoneIdentifierRecord_ be GetAvailableNamedTimeZoneIdentifier(_name_). 1. If _timeZoneIdentifierRecord_ is ~empty~, throw a *RangeError* exception. 1. Return _timeZoneIdentifierRecord_.[[PrimaryIdentifier]]. @@ -654,7 +652,7 @@

1. Let _offsetNanoseconds_ be ? GetOffsetNanosecondsFor(_timeZone_, _instant_). 1. Let _offsetMinutes_ be truncate(_offsetNanoseconds_ / (6 × 1010)). - 1. Let _offsetString_ be FormatOffsetTimeZoneIdentifier(_offsetMinutes_ × (6 × 1010), ~separate~). + 1. Let _offsetString_ be FormatOffsetTimeZoneIdentifier(_offsetMinutes_, ~separate~). 1. Let _subMinuteNanoseconds_ be abs(_offsetNanoseconds_) modulo (6 × 1010). 1. If _subMinuteNanoseconds_ = 0, return _offsetString_. 1. If _offsetMinutes_ = 0 and _offsetNanoseconds_ < 0, let _offsetString_ be *"-00:00"*. @@ -828,13 +826,13 @@

ParseTimeZoneIdentifier ( _identifier_: a String, - ): either a normal completion containing a Record containing [[Name]] and [[OffsetNanoseconds]] fields, or a throw completion + ): either a normal completion containing a Record containing [[Name]] and [[OffsetMinutes]] fields, or a throw completion

description
- If _identifier_ is a named time zone identifier, [[Name]] will be _identifier_ and [[OffsetNanoseconds]] will be ~empty~. - If _identifier_ is an offset time zone identifier, [[Name]] will be ~empty~ and [[OffsetNanoseconds]] will be a signed integer that is evenly divisible by 6 × 1010. + If _identifier_ is a named time zone identifier, [[Name]] will be _identifier_ and [[OffsetMinutes]] will be ~empty~. + If _identifier_ is an offset time zone identifier, [[Name]] will be ~empty~ and [[OffsetMinutes]] will be a signed integer. Otherwise, a *RangeError* will be thrown.
@@ -843,13 +841,13 @@

1. If _parseResult_ is a List of errors, throw a *RangeError* exception. 1. If _parseResult_ contains a |TimeZoneIANAName| Parse Node, then 1. Let _name_ be the source text matched by the |TimeZoneIANAName| Parse Node contained within _parseResult_. - 1. Return the Record { [[Name]]: _name_, [[OffsetNanoseconds]]: ~empty~ }. + 1. Return the Record { [[Name]]: _name_, [[OffsetMinutes]]: ~empty~ }. 1. Else, 1. Assert: _parseResult_ contains a |TimeZoneUTCOffsetName| Parse Node. 1. Let _offsetString_ be the source text matched by the |TimeZoneUTCOffsetName| Parse Node contained within _parseResult_. 1. Let _offsetNanoseconds_ be ! ParseDateTimeUTCOffset(_offsetString_). 1. Assert: _offsetNanoseconds_ modulo (6 × 1010) = 0. - 1. Return the Record { [[Name]]: ~empty~, [[OffsetNanoseconds]]: _offsetNanoseconds_ }. + 1. Return the Record { [[Name]]: ~empty~, [[OffsetMinutes]]: _offsetNanoseconds_ / (6 × 1010) }.