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
+ 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_.