diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index aadf98bc74..ded5447f85 100644 --- a/polyfill/lib/ecmascript.mjs +++ b/polyfill/lib/ecmascript.mjs @@ -2209,22 +2209,15 @@ export function GetOffsetStringFor(timeZone, instant) { // In the spec, the code below only exists as part of GetOffsetStringFor. // But in the polyfill, we re-use it to provide clearer error messages. function formatOffsetStringNanoseconds(offsetNs) { - const offsetMinutes = MathTrunc(offsetNs / 60e9); - let offsetStringMinutes = FormatOffsetTimeZoneIdentifier(offsetMinutes); - const subMinuteNanoseconds = MathAbs(offsetNs) % 60e9; - if (!subMinuteNanoseconds) return offsetStringMinutes; - - // For offsets between -1s and 0, exclusive, FormatOffsetTimeZoneIdentifier's - // return value of "+00:00" is incorrect if there are sub-minute units. - if (!offsetMinutes && offsetNs < 0) offsetStringMinutes = '-00:00'; - - const seconds = MathFloor(subMinuteNanoseconds / 1e9) % 60; - const secondString = ISODateTimePartString(seconds); - const nanoseconds = subMinuteNanoseconds % 1e9; - if (!nanoseconds) return `${offsetStringMinutes}:${secondString}`; - - let fractionString = `${nanoseconds}`.padStart(9, '0').replace(/0+$/, ''); - return `${offsetStringMinutes}:${secondString}.${fractionString}`; + const sign = offsetNs < 0 ? '-' : '+'; + const absoluteNs = MathAbs(offsetNs); + const hour = MathFloor(absoluteNs / 3600e9); + const minute = MathFloor(absoluteNs / 60e9) % 60; + const second = MathFloor(absoluteNs / 1e9) % 60; + const subSecondNs = absoluteNs % 1e9; + const precision = second === 0 && subSecondNs === 0 ? 'minute' : 'auto'; + const timeString = FormatTimeString(hour, minute, second, subSecondNs, precision); + return `${sign}${timeString}`; } export function GetPlainDateTimeFor(timeZone, instant, calendar) { @@ -2742,11 +2735,10 @@ export function GetNamedTimeZoneOffsetNanoseconds(id, epochNanoseconds) { export function FormatOffsetTimeZoneIdentifier(offsetMinutes) { const sign = offsetMinutes < 0 ? '-' : '+'; const absoluteMinutes = MathAbs(offsetMinutes); - const intHours = MathFloor(absoluteMinutes / 60); - const hh = ISODateTimePartString(intHours); - const intMinutes = absoluteMinutes % 60; - const mm = ISODateTimePartString(intMinutes); - return `${sign}${hh}:${mm}`; + const hour = MathFloor(absoluteMinutes / 60); + const minute = absoluteMinutes % 60; + const timeString = FormatTimeString(hour, minute, 0, 0, 'minute'); + return `${sign}${timeString}`; } export function FormatDateTimeUTCOffsetRounded(offsetNanoseconds) { diff --git a/spec/abstractops.html b/spec/abstractops.html index d224eae645..1b212055b6 100644 --- a/spec/abstractops.html +++ b/spec/abstractops.html @@ -715,30 +715,31 @@

FormatTimeString ( - _hour_: an integer, - _minute_: an integer, - _second_: an integer, - _subSecondNanoseconds_: an integer, - _precision_: an integer in the inclusive range 0 to 9, *"minute"*, or *"auto"* + _hour_: a non-negative integer, + _minute_: a non-negative integer, + _second_: a non-negative integer, + _subSecondNanoseconds_: a non-negative integer, + _precision_: an integer in the inclusive range 0 to 9, *"minute"*, or *"auto"*, + optional _style_: ~separated~ or ~unseparated~, ): a String

description
- The output will be formatted like HH:MM if _precision_ is *"minute"*. - Otherwise, the output will be formatted like HH:MM:SS if _precision_ is zero, or if _subSecondNanoseconds_ is zero and _precision is *"auto"*. - Otherwise, the output will be formatted like HH:MM:SS.fff where "fff" is a sequence of fractional seconds digits, truncated to _precision_ digits or (if _precision_ is *"auto"*) to the last non-zero digit. + It formats a collection of unsigned time components into a string, truncating units as necessary, and separating hours, minutes, and seconds with colons unless _style_ is ~legacy~. + The output will be formatted like HH:MM or HHMM if _precision_ is *"minute"*. + Otherwise, the output will be formatted like HH:MM:SS or HHMMSS if _precision_ is zero, or if _subSecondNanoseconds_ is zero and _precision is *"auto"*. + Otherwise, the output will be formatted like HH:MM:SS.fff or HHMMSS.fff where "fff" is a sequence of fractional seconds digits, truncated to _precision_ digits or (if _precision_ is *"auto"*) to the last non-zero digit.
+ 1. If _style_ is present and _style_ is ~unseparated~, let _separator_ be the empty String; otherwise, let _separator_ be *":"*. 1. Let _hh_ be ToZeroPaddedDecimalString(_hour_, 2). 1. Let _mm_ be ToZeroPaddedDecimalString(_minute_, 2). - 1. Let _result_ be the string-concatenation of _hh_, the code unit 0x003A (COLON), and _mm_. - 1. If _precision_ is *"minute"*, return _result_. + 1. If _precision_ is *"minute"*, return the string-concatenation of _hh_, _separator_, and _mm_. 1. Let _ss_ be ToZeroPaddedDecimalString(_second_, 2). 1. Let _subSecondsPart_ be FormatFractionalSeconds(_subSecondNanoseconds_, _precision_). - 1. Set _result_ to the string-concatenation of _result_, the code unit 0x003A (COLON), _ss_, and _subSecondsPart_. - 1. Return _result_. + 1. Return the string-concatenation of _hh_, _separator_, _mm_, _separator_, _ss_, and _subSecondsPart_.
diff --git a/spec/timezone.html b/spec/timezone.html index 033513a419..feabfd98e2 100644 --- a/spec/timezone.html +++ b/spec/timezone.html @@ -488,13 +488,10 @@

1. If _offsetMinutes_ ≥ 0, let _sign_ be the code unit 0x002B (PLUS SIGN); otherwise, let _sign_ be the code unit 0x002D (HYPHEN-MINUS). 1. Let _absoluteMinutes_ be abs(_offsetMinutes_). - 1. Let _intHours_ be floor(_absoluteMinutes_ / 60). - 1. Let _hh_ be ToZeroPaddedDecimalString(_intHours_, 2). - 1. Let _intMinutes_ be _absoluteMinutes_ modulo 60. - 1. Let _mm_ be ToZeroPaddedDecimalString(_intMinutes_, 2). - 1. If _style_ is ~unseparated~, then - 1. Return the string-concatenation of _sign_, _hh_, and _mm_. - 1. Return the string-concatenation of _sign_, _hh_, the code unit 0x003A (COLON), and _mm_. + 1. Let _hour_ be floor(_absoluteMinutes_ / 60). + 1. Let _minute_ be _absoluteMinutes_ modulo 60. + 1. Let _timeString_ be FormatTimeString(_hour_, _minute_, 0, 0, *"minute"*, _style_). + 1. Return the string-concatenation of _sign_ and _timeString_. @@ -653,20 +650,15 @@

1. Let _offsetNanoseconds_ be ? GetOffsetNanosecondsFor(_timeZone_, _instant_). - 1. Let _offsetMinutes_ be truncate(_offsetNanoseconds_ / (60 × 109)). - 1. Let _offsetString_ be FormatOffsetTimeZoneIdentifier(_offsetMinutes_, ~separate~). - 1. Let _subMinuteNanoseconds_ be abs(_offsetNanoseconds_) modulo (60 × 109). - 1. If _subMinuteNanoseconds_ = 0, then - 1. Return _offsetString_. - 1. If _offsetMinutes_ = 0 and _offsetNanoseconds_ < 0, set _offsetString_ to *"-00:00"*. - 1. Let _seconds_ be floor(_subMinuteNanoseconds_ / 109) modulo 60. - 1. Let _ss_ be ToZeroPaddedDecimalString(_seconds_, 2). - 1. Let _nanoseconds_ be _subMinuteNanoseconds_ modulo 109. - 1. If _nanoseconds_ = 0, then - 1. Return the string-concatenation of _offsetString_, the code unit 0x003A (COLON), and _ss_. - 1. Let _fractionString_ be ToZeroPaddedDecimalString(_nanoseconds_, 9). - 1. Set _fractionString_ to the longest prefix of _fractionString_ ending with a code unit other than 0x0030 (DIGIT ZERO). - 1. Return the string-concatenation of _offsetString_, the code unit 0x003A (COLON), _ss_, the code unit 0x002E (FULL STOP), and _fractionString_. + 1. If _offsetNanoseconds_ ≥ 0, let _sign_ be the code unit 0x002B (PLUS SIGN); otherwise, let _sign_ be the code unit 0x002D (HYPHEN-MINUS). + 1. Let _absoluteNanoseconds_ be abs(_offsetNanoseconds_). + 1. Let _hour_ be floor(_absoluteNanoseconds_ / (3600 × 109)). + 1. Let _minute_ be floor(_absoluteNanoseconds_ / (60 × 109)) modulo 60. + 1. Let _second_ be floor(_absoluteNanoseconds_ / 109) modulo 60. + 1. Let _subSecondNanoseconds_ be _absoluteNanoseconds_ modulo 109. + 1. If _second_ = 0 and _subSecondNanoseconds_ = 0, let _precision_ be *"minute"*; otherwise, let _precision_ be *"auto"*. + 1. Let _timeString_ be FormatTimeString(_hour_, _minute_, _second_, _subSecondNanoseconds_, _precision_). + 1. Return the string-concatenation of _sign_ and _timeString_.