Saturday, March 31, 2012

Testing from the Command Line with PhantomJS

I learned about the PhantomJS project recently and thought that it would be a good fit for dygraphs.

Our current testing setup involves several steps:
  1. Start a jstd server from the command line.
  2. Visit the server in the browser that you want to test.
  3. Run the jstd command with "--tests all" set.
  4. Tear everything down.
That's not too bad, but there is enough overhead that we don't run tests as frequently as we should. Case in point: I broke one of our tests nine days ago, but didn't realize it until this morning.

With phantomjs, this process is streamlined. You can do everything from the command line:

$ ./test.sh
Ran 118 tests in 1.397s.
118 test(s) passed
0 test(s) failed:
PASS


Phantom creates a headless web browser using WebKit. You drive the browser using JavaScript, and can execute commands in the context of any web page. I'm excited that it's working so well for dygraphs. No we'll have no excuses for not running auto_tests!

Monday, March 19, 2012

Swipe and pinch now work with Dygraphs!

Check it! Swipe and pinch now work with Dygraphs!


Dan, inspired by his new iPad 3, did some weekend hacking and made pinch and zoom work in Dygraphs. This also worked on my Samsung Galaxy Nexus, although the new Chrome browser is much more responsive than the default one.

You can see this for yourself at http://dygraphs.com/tests/demo.html

Wednesday, March 14, 2012

JavaScript and Dates, What a Mess!

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.