We recently had a dygraphs regression where a date specified as "2012-03-13" would be displayed as "2012-03-12 20:00" when you hovered over it (or something else depending on your time zone).
The culprit wound up being surprising behavior from JavaScript's Date parser. Here's the gist of the problem, via the Chrome JavaScript Console:
> new Date("2012/03/13")
Tue Mar 13 2012 00:00:00 GMT-0400 (EDT)
> new Date("2012-03-13")
Mon Mar 12 2012 20:00:00 GMT-0400 (EDT)
So, why the discrepancy of four hours between these seemingly-identical dates? Here's another puzzler:
> new Date("2012-03-13")
Mon Mar 12 2012 20:00:00 GMT-0400 (EDT)
> new Date("2012-3-13")
Tue Mar 13 2012 00:00:00 GMT-0400 (EDT)
Why does that extra zero in the first form subtract four hours?
I've run into many issues with new Date and Date.parse while working on dygraphs over the years. This issue inspired me to put together…
The Comprehensive Cross-Browser
JavaScript Date Parsing Table
On that page, you'll see how a variety of browsers do (or don't) parse particular date strings.
Here are some rules of thumb:
- Stick to "YYYY/MM/DD" for your date strings whenever possible. It's universally supported and unambiguous. With this format, all times are local.
- Avoid using hyphenated dates ("YYYY-MM-DD") unless you know what you're doing. Only newer browsers support them.
- So long as you specify four digits years, date strings at least have a unique parse across all browsers. Some browsers may return an error, but you won't get inconsistent behavior.
- Chrome tends to be more accepting than other browsers. If a date format parses in Chrome, you shouldn't assume that it parses anywhere else.
- If a recent browser can interpret as date string as ISO-8601, it will. With this format, your date/time string is interpreted as UTC.
With the table and these rules of thumb in hand, let's take another look at those mysterious Date parses from the beginning of the post:
> new Date("2012/03/13")
Tue Mar 13 2012 00:00:00 GMT-0400 (EDT)
This parses to midnight in the local time zone. This behavior is universal across browsers.
> new Date("2012-03-13")
Mon Mar 12 2012 20:00:00 GMT-0400 (EDT)
This can be interpreted as an ISO-8601 date, and so it is (following our last rule of thumb). This means that it is parsed as UTC. But it is displayed using local time. I'm in the EDT time zone, hence the difference of four hours. This format is only supported by newer browsers (Chrome, FF4+, IE9).
> new Date("2012-3-13")
Tue Mar 13 2012 00:00:00 GMT-0400 (EDT)
This cannot be interpreted as an ISO-8601 date, since it's missing a "0" in front of the month ("3" vs. "03"). So Chrome falls back to interpreting this as a local time. At the moment, Chrome is the only browser which supports this particular gem of a format.
A final cautionary note: if you are writing a library and wish to convert date strings to millis since epoch, the built-in Date.parse method looks like just the ticket. But you'll eventually run into an issue. For reasons known only to its authors, MooTools overrides this function with an incompatible version (theirs returns a Date, not a number). What you really want is new Date(dateString).getTime().
So if you're writing a library and you get a date string from your user, what should you do with it? In dygraphs, the answer keeps getting more and more complicated.