Skip to content

Commit

Permalink
Normative: Make LocalTZA take 't' and 'isUTC' and drop DSTA(t). (#778)
Browse files Browse the repository at this point in the history
* Make LocalTZA take 't' and 'isUTC', Drop DSTA(t).

Currently, LocalTimezoneAdjustment is assumed to be constant across time
zone rule changes and does not take any argument. Daylight Savings Time
Adjustment does take an argument t.

DSTA(t) can 'absorb' the standard time zone offset changes
(e.g. Europe/Moscow changed the standard time zone offset multiple times
in the last decade.). However, the spec stipulates that it should only
reprsent an additional adjustment necessary when DST is in effect.

In practice, at least two implementations (Spidermonkey/Firefox and
JSC/Safari) do not follow the spec to the letter to produce results
expected by users across time zone rule changes.

This PR revises LocalTZA to accept two arguments, 't' and 'isUTC' and
drop DaylightSavingsTimeAdjustment(t). When isUTC is true, LocalTZA
interprets 't' as a time value representing UTC and gives a time zone
offset in effect at time t for the local time zone (for US ET, it'd be
4*msPerHour in summer and 5*msPerHour in winter). When isUTC is false,
't' is interpreted as local time value and gives a time zone offset in
effect at t = t_local.

It's also specified that LocalTZA(t = t_local, false) will return the offset
*before* the transition when t_local is wall time repeating multiple
times at a negative transition (e.g. fall backward) or skipped wall time
at a positive time zone transition (e.g. spring forward). This is to
get rid of an ambiguity in handling a time zone offset transition. Due
to the ambiguity, different implemenations have different behaviors and
some implementations have changed their behavior over the time.

UTC(t) and Localtime(t) are reformulated with LocalTZA(t = t_local, false) and
LocalTZA(t = t_UTC, true).

Will fix #725.

In the future, it might as well be considered to add an option to specify the
behavior to handle skipped or repeated wall time. See  [1] and [2].

[1] ICU Calendar API has skipped wall time option (https://goo.gl/h0bP26) and
repeated wall time option (https://goo.gl/Q1VX3j).

[2] Python proposal to handle skipped/repeated time:
    https://www.python.org/dev/peps/pep-0495/

* Addressed the review comments

1. Interpret skipped and repeating local time in the time zone offset
before the transition.

2. s/wall time/local time/

3. Daylight savings time => Daylight saving time.
  • Loading branch information
jungshik authored and bterlson committed Dec 29, 2017
1 parent fa82e04 commit 7e94e28
Showing 1 changed file with 15 additions and 15 deletions.
30 changes: 15 additions & 15 deletions spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -26762,19 +26762,16 @@ <h1>Week Day</h1>

<!-- es6num="20.3.1.7" -->
<emu-clause id="sec-local-time-zone-adjustment">
<h1>Local Time Zone Adjustment</h1>
<p>An implementation of ECMAScript is expected to determine the local time zone adjustment. The local time zone adjustment is a value <dfn>LocalTZA</dfn> measured in milliseconds which when added to UTC represents the local <em>standard</em> time. Daylight saving time is <em>not</em> reflected by LocalTZA.</p>
<emu-note>
<p>It is recommended that implementations use the time zone information of the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a>.</p>
</emu-note>
</emu-clause>

<!-- es6num="20.3.1.8" -->
<emu-clause id="sec-daylight-saving-time-adjustment">
<h1>Daylight Saving Time Adjustment</h1>
<p>An implementation-dependent algorithm using best available information on time zones to determine the local daylight saving time adjustment DaylightSavingTA(_t_), measured in milliseconds. An implementation of ECMAScript is expected to make its best effort to determine the local daylight saving time adjustment.</p>
<h1>LocalTimeZoneAdjustment ( _t_, _isUTC_ )</h1>
<p>LocalTimeZoneAdjustment( _t_, _isUTC_ ) is an implementation-defined algorthm that must return a number representing milliseconds suitable for adding to a Time Value. The local political rules for standard time and daylight saving time in effect at _t_ should be used to determine the result in the way specified in the following three paragraphs.</p>
<p>When _isUTC_ is true, <dfn>LocalTZA( _t_, true )</dfn> should return the offset of the local time zone from UTC measured in milliseconds at time represented by time value _t_ (UTC). When the result is added to _t_ (UTC), it should yield the local time.</p>
<p>When _isUTC_ is false, <dfn>LocalTZA( _t_, false )</dfn> should return the offset of the local time zone from UTC measured in milliseconds at local time represented by time value <dfn><emu-eqn>_t_<sub>local</sub> = _t_</emu-eqn></dfn>. When the result is subtracted from the local time <emu-eqn>_t_<sub>local</sub>, it should yield the corresponding UTC.</p>
<p>When <emu-eqn>_t_<sub>local</sub></emu-eqn> represents local time repeating multiple times at a negative time zone transition (e.g. when the daylight saving time ends or the time zone adjustment is decreased due to a time zone rule change) or skipped local time at a positive time zone transitions (e.g. when the daylight saving time starts or the time zone adjustment is increased due to a time zone rule change), <emu-eqn>_t_<sub>local</sub></emu-eqn> must be interpreted with the time zone adjustment before the transition.</p>
<p>If an implementation does not support a conversion described above or if political rules for time _t_ are not available within the implementation, the result must be 0.</p>
<emu-note>
<p>It is recommended that implementations use the time zone information of the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a>.</p>
<p>1:30 AM on November 5, 2017 in America/New_York is repeated twice (fall backward), but it must be interpreted as 1:30 AM UTC-04 instead of 1:30 AM UTC-05. LocalTZA(TimeClip(MakeDate(MakeDay(2017, 10, 5), MakeTime(1, 30, 0, 0))), false) is <emu-eqn>-4 &times; msPerHour</emu-eqn>.</p>
<p>2:30 AM on March 12, 2017 in America/New_York does not exist, but it must be interpreted as 2:30 AM UTC-05 (equivalent to 3:30 AM UTC-04). LocalTZA(TimeClip(MakeDate(MakeDay(2017, 2, 12), MakeTime(2, 30, 0, 0))), false) is <emu-eqn>-5 &times; msPerHour</emu-eqn>.</p>.
</emu-note>
</emu-clause>

Expand All @@ -26783,19 +26780,22 @@ <h1>Daylight Saving Time Adjustment</h1>
<h1>LocalTime ( _t_ )</h1>
<p>The abstract operation LocalTime with argument _t_ converts _t_ from UTC to local time by performing the following steps:</p>
<emu-alg>
1. Return _t_ + LocalTZA + DaylightSavingTA(_t_).
1. Return _t_ + LocalTZA(_t_, true).
</emu-alg>
<emu-note>
<p>Two different time values (_t_ (UTC)) are converted to the same local time <emu-eqn>t<sub>local</sub></emu-eqn> at a negative time zone transition when there are repeated times (e.g. the daylight saving time ends or the time zone adjustment is decreased.).</p>
</emu-note>
</emu-clause>

<!-- es6num="20.3.1.10" -->
<emu-clause id="sec-utc-t" aoid="UTC">
<h1>UTC ( _t_ )</h1>
<p>The abstract operation UTC with argument _t_ converts _t_ from local time to UTC. It performs the following steps:</p>
<emu-alg>
1. Return _t_ - LocalTZA - DaylightSavingTA(_t_ - LocalTZA).
1. Return _t_ - LocalTZA( _t_ , false)
</emu-alg>
<emu-note>
<p><emu-eqn>UTC(LocalTime(_t_))</emu-eqn> is not necessarily always equal to _t_.</p>
<p><emu-eqn>UTC(LocalTime(_t_))</emu-eqn> is not necessarily always equal to _t_. <emu-eqn>LocalTime(UTC(_t_<sub>local</sub>))</emu-eqn> is not necessarily always equal to <emu-eqn>_t_<sub>local</sub></emu-eqn>, either.</p>
</emu-note>
</emu-clause>

Expand Down Expand Up @@ -27969,7 +27969,7 @@ <h1>Runtime Semantics: TimeZoneString( _tv_ )</h1>
<emu-alg>
1. Assert: Type(_tv_) is Number.
1. Assert: _tv_ is not *NaN*.
1. Let _offset_ be LocalTZA + DaylightSavingTA(_tv_).
1. Let _offset_ be LocalTZA(_tv_, true).
1. If _offset_ &ge; 0, let _offsetSign_ be `"+"`; otherwise, let _offsetSign_ be `"-"`.
1. Let _offsetMin_ be the String representation of MinFromTime(abs(_offset_)), formatted as a two-digit number, padded to the left with a zero if necessary.
1. Let _offsetHour_ be the String representation of HourFromTime(abs(_offset_)), formatted as a two-digit number, padded to the left with a zero if necessary.
Expand Down

0 comments on commit 7e94e28

Please sign in to comment.