Monthly Archives: April 2009

JavaScript date parsing woes

I just corrected an interesting bug in a web application’s client-side JavaScript code.

How come, most of the time, the string ‘2009-02-01’ gets parsed into a Date object with the correct February 1st, 2009 value, but sometimes results in March 1st, 2009?

This particular piece of code builds a financial periods menu by extracting dates out of some HTML returned by an AJAX request. Here’s what the function looks like – it may not be the best way to construct a date from a string in the form yyyy-mm-dd, but it works:
function makeDateFromIsoString(isoString)
{
if (isoString == null)
return null;
var date = new Date();
date.setFullYear(isoString.substr(0, 4));
date.setMonth(isoString.substr(5, 2) - 1);
date.setDate(isoString.substr(8, 2));
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
return date;
}

That is, it works most of the time, but not at the end of some months, as I discovered.

Take yesterday, for instance – March 31st, 2009 – and let’s look at what makeDateFromIsoString(‘2009-02-01’) returned:

  • var date = new Date() created a new Date object, containing the current date and time: March 31st, 2009.
  • date.setFullYear(isoString.substr(0, 4)) changed the year of the data object to  ‘2009‘, so its value stayed the same.
  • date.setMonth(isoString.substr(5, 2) – 1) changed the month of the date object to  ‘02‘ (minus one, because months in JavaScript are zero-based,) so its value became February 31st, 2009. Of course, February 31st doesn’t exists, so because the real date three days after February 28th, 2009 is March 3rd, 2009, the date object now contained that value.
  • So by the the time the code was done with date.setDate(isoString.substr(8, 2)), the date value had become March 1st, 2009.

And this is how February became March, but only during the three last days of March. Interesting twist, isn’t it?

The fix was simple: call setDate() before setMonth().

Viva la Firebug for helping me nail this one down.

Update: In the end, I just replaced the whole function body with this: return new Date(isoString.replace(‘-‘, ‘/’, ‘g’)). Much simpler, and not subject to the above subtle, but interesting nevertheless, bug.

Share