Search code examples
javascriptdatetimedst

Invalid times at the start of Daylight Saving Time


Short Version

In JavaScript, can new Date(2013, 9, 20) legitimately return October 19?

Long Version

When Daylight Saving Time begins, there is a gap in local time as clocks are adjusted forward. If I construct a Date object with a time that falls within this gap, what is the expected behavior according to the ECMAScript specification?

Various browsers behave differently, as seen below. (I ran these tests on Windows 8.)

Example 1: In the Pacific Time Zone (UTC-08), the expression

new Date(2013, 2, 10, 2, 34, 56).toString() // Sun Mar 10 2013 02:34:56

gives the following results:

IE 10:      Sun Mar 10 03:34:56 PDT 2013
IE 11:      Sun Mar 10 2013 03:34:56 GMT-0700 (Pacific Daylight Time)
Chrome 29:  Sun Mar 10 2013 01:34:56 GMT-0800 (Pacific Standard Time)
Firefox 23: Sun Mar 10 2013 03:34:56 GMT-0700 (Pacific Standard Time)

Example 2: In the Brasilia Time Zone (UTC-03), the expression

new Date(2013, 9, 20, 0, 34, 56).toString() // Sun Oct 20 2013 00:34:56

gives the following results:

IE 10:      Sun Oct 20 01:34:56 UTC-0200 2013
IE 11:      Sun Oct 20 2013 01:34:56 GMT-0200 (E. South America Daylight Time)
Chrome 29:  Sat Oct 19 2013 23:34:56 GMT-0300 (E. South America Standard Time)
Firefox 23: Sat Oct 19 2013 23:34:56 GMT-0300

Based on these two examples, it seems that IE adjusts the time forward, Chrome adjusts the time backward, and Firefox can't make up its mind.

What the specification says: Based on what I could glean, new Date(yyyy, mm-1, dd, hh, mi, ss) constructs a Date with a time value of UTC(yyyy-mm-dd hh:mi:ss), where

UTC(t) = t – LocalTZA – DaylightSavingTA(t – LocalTZA)

LocalTZA is the local time zone adjustment for standard time (e.g., -08:00 in the Pacific Time Zone), and DaylightSavingTA(t) is the daylight saving time adjustment for t (e.g., 01:00 during DST, 00:00 otherwise).

It's unclear to me, though, what DaylightSavingTA should return for an argument of t = 2013-03-10 10:34:56 in the Pacific Time Zone or t = 2013-10-20 03:34:56 in the Brasilia Time Zone.


Solution

  • what is the expected behavior according to the ECMAScript specification?

    Good question! You are correct that this depends on DaylightSavingTA which is strictly undefined, however we can derive implications about DaylightSavingTA from the way it works when used in the inverse function:

    LocalTime(t) = t + LocalTZA + DaylightSavingTA(t)

    For this to convert UTC t to a local time correctly, DaylightSavingTA(hour_at_beginning_of_dst) must be 1 hour and DaylightSavingTA(hour_after_end_of_dst) must be 0.

    The same function is called in the UTC() function using a t that in that function represents a DST-adjusted time. So in the non-existent-local-hour at the start of DST, DaylightSavingTA(the-dst-adjusted-time-which-is-one-hour-ahead) is 1 hour. Consequently:

    Can new Date(2013, 9, 20) legitimately return October 19?

    Yes.

    I'm asking because I (and probably others) have written code like new Date(year, month, day) to construct a date without a time, and evidently this doesn't always work!

    Indeed! Use UTC dates for that kind of calculation—new Date(Date.UTC(2013, 9, 20)) and the getUTC* methods. In general, it's best to stick to UTC for everything except the final user-facing presentation of times.