Skip to content

Commit

Permalink
Editorial: refactor offset string formatting
Browse files Browse the repository at this point in the history
Simplify offset formatting by using FormatTimeString instead of bespoke
formatting logic. This commit completes the time-formatting refactor that
#2629 started.
  • Loading branch information
justingrant committed Jul 19, 2023
1 parent 890327c commit 30b2304
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 54 deletions.
34 changes: 13 additions & 21 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
25 changes: 13 additions & 12 deletions spec/abstractops.html
Original file line number Diff line number Diff line change
Expand Up @@ -715,30 +715,31 @@ <h1>
<emu-clause id="sec-temporal-formattimestring" type="abstract operation">
<h1>
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
</h1>
<dl class="header">
<dt>description</dt>
<dd>
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 ~unseparated~.
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.
</dd>
</dl>
<emu-alg>
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_.
</emu-alg>
</emu-clause>

Expand Down
34 changes: 13 additions & 21 deletions spec/timezone.html
Original file line number Diff line number Diff line change
Expand Up @@ -488,13 +488,10 @@ <h1>
<emu-alg>
1. If _offsetMinutes_ &ge; 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_.
</emu-alg>
</emu-clause>

Expand Down Expand Up @@ -653,20 +650,15 @@ <h1>
</dl>
<emu-alg>
1. Let _offsetNanoseconds_ be ? GetOffsetNanosecondsFor(_timeZone_, _instant_).
1. Let _offsetMinutes_ be truncate(_offsetNanoseconds_ / (60 × 10<sup>9</sup>)).
1. Let _offsetString_ be FormatOffsetTimeZoneIdentifier(_offsetMinutes_, ~separate~).
1. Let _subMinuteNanoseconds_ be abs(_offsetNanoseconds_) modulo (60 × 10<sup>9</sup>).
1. If _subMinuteNanoseconds_ = 0, then
1. Return _offsetString_.
1. If _offsetMinutes_ = 0 and _offsetNanoseconds_ &lt; 0, set _offsetString_ to *"-00:00"*.
1. Let _seconds_ be floor(_subMinuteNanoseconds_ / 10<sup>9</sup>) modulo 60.
1. Let _ss_ be ToZeroPaddedDecimalString(_seconds_, 2).
1. Let _nanoseconds_ be _subMinuteNanoseconds_ modulo 10<sup>9</sup>.
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_ &ge; 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 × 10<sup>9</sup>)).
1. Let _minute_ be floor(_absoluteNanoseconds_ / (60 × 10<sup>9</sup>)) modulo 60.
1. Let _second_ be floor(_absoluteNanoseconds_ / 10<sup>9</sup>) modulo 60.
1. Let _subSecondNanoseconds_ be _absoluteNanoseconds_ modulo 10<sup>9</sup>.
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_.
</emu-alg>
</emu-clause>

Expand Down

0 comments on commit 30b2304

Please sign in to comment.