thisishardtoread

code, thoughts, and learnings

github.com/arbylee

JavaScript Date, joda-time and Daylight Savings: How our users got a day older

08 May 2016

My team and I recently encountered an issue where several, but not all, of our date fields were being displayed one day off from what was stored in the database. The cause wasn’t immediately obvious and led us down the rabbit hole of dealing with Daylight Savings.

Problem

Here’s the basic layout: There are two services we’ve inherited that produced the issue: a Node.js app fronting a database and a Java app that calls the node app for data. The scenarios we encountered look something like this:

    DB      |  Java layer
09/24/1988  |  09/24/1988 #OK
09/24/1958  |  09/24/1958 #OK
01/24/1958  |  01/23/1958 #WTF

The two main causes of the problem:

  1. JavaScript Date objects always represent a moment in time (even though we’re storing Dates, not DateTimes, in the DB)

  2. We had a mismatch in date handling: the node app uses default JavaScript Dates which does not properly handle Daylight Savings, but the Java layer uses joda-time which does

The node app was pulling dates from the database and converting them from 01/24/1958 into Sat Jan 24 1958 00:00:00 GMT+1100 (AEDT) even though Daylight Savings didn’t exist back then.

The Java app would call the node app and feed that date into joda-time. With its data from IANA, jode-time reads the date and says, “Daylight Savings did not exist in 1958 for the Australian Eastern Time zone” and adjusts the time, removing the added Daylight Savings hour. However by removing that additional hour, we now have a date (calculated from UTC) that reads Jan 23 at 11pm instead of Jan 24 at midnight! Anyone born during the Daylight Savings months, before Daylight Savings existed, would have a date of birth that was one day too early.

Solution

Option 1

Stop using JavaScript Dates! In our case, the node app was actually being decommissioned, and we moved onto a new service that was properly pulling dates out of the database without conversion. If you need to be using JavaScript then you can start reading dates as strings instead of converting them into Date objects.

The ES5 spec doesn’t outline proper handling for Daylight Savings and actually encourages faulty rules (check out this blog post for a great breakdown), unlike joda-time which uses time zone information provided by IANA. There’s also wording in the ES6 spec that should result in better time zone handling as browsers transition, so we have proper Date objects to look forward to in the future. As linked above, if you want to learn more about the faultiness of JavaScript dates and the upcoming ECMA6 Date changes, I found this blog post to be a good read.

Option 2

If you can’t avoid using JavaScript Dates for some reason, then I would take a look at moment-timezone. They have builds available with timezone data imported from IANA which should provide better handling for time zones and Daylight Savings than the default Date object. Make sure you instantiate your dates with the moment.tz() syntax, not the moment() syntax though; otherwise, you’ll come across the same Daylight Savings issue.