Working with dates is one of those problems that haunt developers regularly. No matter how many years experience you have, you will still face challenges working with dates. That's partially because development languages evolve, databases evolve and us developers just have to keep up with current best practices.

In Microsoft SQL Server the DateTime data type is pretty much the standard for saving dates and/or time of day. Many developers find the concept of having one type representing both a date and a time of day to be a little frustrating. This week I ran into one such frustrating situation.

A Common Problem with Dates

We were saving a date for an instance of a Contract data model. This is a fairly basic example. Now keep in mind when you see a printed business documented the dates are usually just shown as month/day/year (or whatever your locale uses) but don't usually include time of day.

Now when you create a Date or DateTime value by only specifying the month/day/year information the time is left at 00:00:00. No problem, we're not concerned with date right?

Well the problem arises when your system is used across multiple time zones. I have a colleague who is currently living in an area using Central Daylight Time, while I am currently using Pacific Daylight Time. So my colleague opens my web app and selects a date like 8/18/2012 and saves the 'Contract' entity. The value submitted to the server was 8/18/2012 00:00:00 (GMT-5). When I save it to the database in UTC it will be 8/18/2012 05:00:00 (GMT). Now when I open that same record in my timezone it will be 8/17/2012 22:00:00 (GMT-7).

Keeping in mind we don't actually display the time of day a contract was executed on a contract, just the month/day/year, it looks like we lost a day!

The dates are theoretically correct and equivalent, but they still look wrong to the end user while using the app.

How I Handle Simple Dates Without a Time of Day

The end result I wanted was to pick on timezone that all Contract dates would be saved in and also displayed to the user and/or entered by the user. I essentially want a Date type that didn't include time of day information (and therefor didn't necessarily require conversion between time zones).

In this particular project we were using the ExtJs JavaScript library to implement the client side app. One user would select a date using an ExtJs date field drop down control and save the contract. Then someone else may come along and open the app to view that saved contract. Regardless of what timezone each of those two parties are in the viewer should see the same date on the display as was chosen by the record creator. No time of day is ever displayed during editing or viewing.

I call this MaintainLocalAsUTC, that's the name of my conversion routine that compensates for any timezone difference in the browser's date object.

Ext.util.DateTools = {
    MaintainLocalAsUTC: function (value, record) {
        if (typeof value === 'number') {
            // Interpret utc timestamp as local date
            // ex: 8/12/2012 00:00:00 UTC = 8/12/2012 00:00:00 PST (my local timezone)
            var dt = new Date();
            dt.setTime((value * 1000) + (dt.getTimezoneOffset() * 60 * 1000));
            return dt;
        } else {
            // Convert from local date to utc timestamp
            // ex: 8/12/2012 00:00:00 PST (my local timezone) = 8/12/2012 00:00:00 UTC
            return Math.round((value.getTime() / 1000) - (value.getTimezoneOffset() * 60));
        }
    }
};

ExtJs lets you specify a conversion function for any given property on a data model that will be used to read in data from the server and convert it before it is shown on the client side and vice-versa.

If the value being converted is a number, its a unix timestamp coming from my Rest Web Service and should be converted to its equivalent date plus the local timezone offset (-420 minutes for me). When it is being written back, we want to remove the local timezone offset by subtracting that offset (subtract -420, notice the double negative?).

In this fashion that date property will always show the same numeric digits for any timezone in the world. Hence the name MaintainLocalAsUTC. If you choose 8/18/2012 00:00:00 in central time, it will be saved as 8/18/2012 00:00:00 UTC, and it will show up in pacific time as 8/18/2012 00:00:00. Its always the same date!