The midnightless midnight

If the line below is executed in a JavaScript console, what will be the value of hour?

var hour = new Date(2015, 9, 18, 0).getHours();

The intuitive answer is zero, and it is right in most situations. Yet, in regions under the America/Sao_Paulo time zone, daylight saving time will start at October 18, 2015 at 0:00, so all clocks will advance to 1 AM once they pass through 11:59:59 PM. In other words, in half of Brazil, October 18, 2015 has no midnight. What the line above means, then?

If you test it with Google Chrome, hour will be 1. The browser will somehow assume that you need the first millisecond of the day:

At first I thought it was not correct but now it makes sense to me.[1] In fact, I would never think about it anyway if other browsers followed this behavior. Yet, in Firefox we get a different result:

As a corollary, the date above does not yield October 2015, 18 at all:

While not perfect, this is not an absurd behavior neither. SpiderMonkey considers new Date(2015, 9, 18, 0) as the moment that comens one hour before October 18 at 1 AM. However, this difference of behavior is breaking our tests[2] and causing some bugs (e.g. AUI-1893).

To solve them, we check whether the date's day of month is the expected one; if no, we calculate the DST shift and manually add it to the expected values. It is not elegant, but works. After all, it is rarely easy to deal with time zones, daylight saving time and browser exceptions; handling all of them at once will hardly be succinct.

Since this issue will probably not affect a sizeable number of users, I have no hope to see it solved, but now we know the problem. Once we glimpse the night misteries, we know that strange bug may be caused by the midnightless midnight smiley

[1] This makes sense IMHO because the ECMAScript Language Specification requires the Date constructor to separately build the amount of days in the date and the amount of milliseconds in the day (cf. step 9 at section 15.9.3.1 from ECMA-262). Since the amount of milliseconds in the day will be zero, it is natural to the date to point to the first millisecond from the day. Also, this behavior will ensure the equality new Date(2015, 9, 18).getDate() === 18, which strikes me as very important (and other browsers do not comply with).

[2] The tests break because PhantomJS also follows the Firefox approach.

Blogs
Great post, Mr. Adam! Very detailed and technically rich.