Tips, Thoughts, and Gotchas Working with JavaScript Dates

This post is being written in conjunction with a piece of work dealing with JavaScript dates.

Draft last updated: 21 February 2018

Things to remember about JavaScript Dates:

JSON.stringify() in JavaScript will serialize a date to UTC.

Month numbers start at 0 (zero) in JavaScript, not 1 (one).

So, January is represented by 0, through to December being represented by 11.

You need to remember this when using the Date.getMonth() method;

And when creating a new Date() object with a constructor overload – e.g. var today = new Date(2018, 1, 21) to create a date representing 21 February 2018.

A JavaScript Date object is internally represented as the number of milliseconds since 1970-01-01 00:00:00 UTC;

But the object itself uses the local timezone of the system running it – e.g. In Melbourne, Australia it returns a date/time of UTC+1000 during Australian Easter Standard Time and UTC+1000 during Australian Easter Daylight Time (during daylight savings).

If you try to manually calculate the current UTC time and set a Date object to that date/time, then the value of date and time is the same as UTC, however, the Date object still returns the local system timezone.

The JavaScript Date.getTimezoneOffset() is non-intuitive and returns the opposite of the UTC timezone offset sign.

For example: If the local timezone is UTC+1100 then getTimezoneOffset() returns “-660” (that minus 660 minutes).

Why?

The definition of the method is: “The getTimezoneOffset() method returns the time zone difference, in minutes, from UTC to current locale (host system settings).”

In other words: it subtracts the local timezone offset (including the offset sign) from UTC.

We want to pass a date from the front-end to a server-side API that records the date in the database.

I’ve seen the following:

A JavaScript Date variable representing the current local date and time is created:

var localNow = new Date();

We want to JavaScript Date variable representing a ‘StartDate’, and we want to assign the current UTC date/time to it:

var startDate = new GetUTCDate(localNow);

See below for the GetUTCDate() function.

We need to serialize startDate to JSON so send it over the wire to the API.

The problems with this are:

‘startDate’ may have a value that represents the UTC equivalent of ‘localNow’ but the actual ‘startDate’ JavaScript object still retains the local timezone offset.

The JSON.stringify() method used to serialize a JavaScript object to JSON converts Date values to their UTC equivalent time (remember the internal representation of a Date object is an offset representing a UTC time);

So what ends up happening is the ‘startDate’ value represented in the JSON is actually the UTC time plus or minus the local timezone offset.

For example:

If the current local time is 21 February 2018 at 10:00am, then ‘the startDate’ JavaScript object has the value: “2018-02-21 10:00:00.00000 UTC+1100”

But the string/value for returned by JSON.stringify(startDate) is: “2018-02-20 23:00:00.00000 UTC” (11 hours earlier).

If you want to store just a date (no time component) in a database, you cannot perform any locale conversions if it is stored as UTC.

Why? Let’s assume you want to convert the UTC date to the date in Timezone UTC+1100 AEDT (Melbourne, Australia). There are actually 2 dates this can convert to. To understand, look at it from the point of view of the local time we want to convert to:

In Melbourne, for any local time from midnight to 10:59:59am the equivalent UTC time is the day before (e.g. if the local date is 21 February, then UTC date is 20 February);

However, for the remainder of the day – 11:00am to 23:59:50pm – the UTC date is the same as the local date (i.e. both dates are 21 February).

Think about how you want to handle dates that are timezone neutral. That is a date that remains the same regardless of where in the world you are. For example, a date of birth usually does not care about where in the world the person is born, nor the timezone.