tc39 / proposal-temporal

Provides standard objects and functions for working with dates and times.
https://tc39.es/proposal-temporal/docs/
Other
3.29k stars 149 forks source link

ZonedDateTime's `startOfDay` and `hoursInDay` when the same date starts twice due to offset transition #2938

Open fabon-f opened 5 days ago

fabon-f commented 5 days ago

zdump -v -c 2010,2011 America/St_Johns:

...
America/St_Johns  Sun Nov  7 02:30:59 2010 UT = Sun Nov  7 00:00:59 2010 NDT isdst=1 gmtoff=-9000
America/St_Johns  Sun Nov  7 02:31:00 2010 UT = Sat Nov  6 23:01:00 2010 NST isdst=0 gmtoff=-12600
...

In this time zone, the moment when 2010-11-06 ends and 2010-11-07 starts occurred twice (before and after the offset transition).

  1. 2010-11-06: 24 hours (00:00:00-23:59:59.999, in offset -02:30)
  2. 2010-11-07: 1 minute (00:00:00-00:00:59.999, in offset -02:30)
  3. offset transition
  4. 2010-11-06 again: 59 minutes (23:01:00-23:59:59.999, in offset -03:30)
  5. 2010-11-07 again: 24 hours (00:00:00-23:59:59.999, in offset -03:30)

According to tz database, America/Goose_Bay before 2010, America/Moncton before 2006, Pacific/Guam and Pacific/Saipan in 1969, America/Phoenix in 1944 follows same pattern (offset transition backwards from 00:00:59 to 23:01:00). Also Antarctica/Casey changed offset backwards in March 2010 (from 01:59:59 to 23:00:00), which causes same situation.

current behavior is below:

const zdt1 = Temporal.ZonedDateTime.from('2010-11-06T00:00:00-02:30[America/St_Johns]')
zdt1.hoursInDay // 24
const zdt2 = Temporal.ZonedDateTime.from('2010-11-07T23:00:00-03:30[America/St_Johns]')
zdt2.hoursInDay // 25
zdt2.startOfDay() // 2010-11-07T00:00:00-02:30[America/St_Johns], first midnight

In my opinion, unlike #2910 this behavior is appropriate and not a spec bug, because startOfDay method returns 'the earliest valid local clock time during the current calendar day' correctly ('the current calendar day' isn't continuous though), and hoursInDay property behaves consistently (25 hours in the day when DST ends, which is same to common cases). But I'm not sure I'm correct.

Also even if it's not a spec bug, it is the corner case the developer using these API should consider, so it would be great to document it (as a Pacific/Apia case in hoursInDay docs).

PS. Offset transitions in Alaska in 1867 due to the purchase of Alaska from Russia (west to east of the international date line, opposite to Pacific/Apia in 2011) is a corner case too, but it's historical events and would not so critical.

Temporal.ZonedDateTime.from('1867-10-19T01:00:00+12:13:22[America/Adak]').hoursInDay // 48
ptomato commented 2 days ago

Thanks for finding this. I agree, it seems like the value we are already returning is reasonable. You could make a case for the other possible return value, but I expect this is just one of those situations where either choice will make some people happy and some people unhappy.

I think a good resolution of this issue would be to mention it in the docs, as you suggest. Also it would be good to write test262 coverage for one of these cases.