Friday, October 30, 2009

Tech: Daylight Savings Time in Javascript

This is another one of those computer programming centric posts I'm doing. I spent the last day and a half trying to find a good way to handle this, and I'm somewhat happy with my solution... so I'm sharing it. I'll post code, so I'm basically saying that if you want to use it, go ahead.

Let me start though, with the situation I needed to resolve. The application I'm working on is something that allows a user to schedule recording times... kind of like TiVo, but not for general Television... the source of the video is something else. Not important. The thing to understand is that it lets a user pick a time through a web application in "local time", "server time", or "UTC".

Since the client machine doesn't know what time it is on the server without the server telling it, I pass the offset from UTC... since everyone knows what UTC is. The problem I was dealing with was when the server and client are in different timezones to begin with, and daylight savings time occurs. If the server is in a timezone before the client (for example), what ends up happening is that when I pass the client my UTC offset, and daylight savings switch happens on the server, but not on the client, the client thinks the server is one hour different from what it actually is... until the client goes through the switch too, and then everything is back to normal.

It's a pain the ass. I hate daylight savings time.

So the idea to solve this problem was to figure out whether the offset was being passed as a standard or daylight savings time, and then to figure out if the client is in the same time (daylight savings or not). If they're different, I need to adjust by one hour, but if they're the same, I can just keep doing what I normally do in the code.

On the server side, I get to use C# (C Sharp for the search engines), and there it's easy: "DateTime.Now.IsDaylightSavingTime()". Really easy... and I can just pass that to the client side in a hidden input.

Now the client side. Javascript is pretty awesome for most things... but it is lacking a simple method or property to give me a boolean response about whether the date/time I'm looking at is in daylight savings or not. I found all sorts of methods online to tell me when daylight savings would shift, but zero methods telling me if a specified Date object held a date/time in daylight savings or not. And the problem only exists for that one hour where we set the clocks back... because it means that a given time occurs twice on the same day. We have 01:30 twice... and knowing which 01:30 becomes important if you're deciding whether to start or stop a recording in that time.

I'm ashamed to admit this, but it took me a while to figure out that if you just write out the date object without using any of the Date object's "to" functions, it includes the current timezone. In my case it was showing "EDT" which of course means "Eastern Daylight Time" (On the east coast of the United States. I guess there's another EDT in Australia). I looked into this a little further to see if it might be as simple as contrasting it with "EST" (Eastern Standard Time). I found out that Internet Explorer (at least in IE 8) is not following W3C Standards for how to output that information. It's supposed to spell out "Eastern Daylight Time". The standard would make things easy... because I could just the "toTimeString" function and search for the word "daylight".

So, I had to keep looking for a solution so I could make sure it works in IE. I decided to look up the list of time zone abbreviations... and what I found lead me to believe that if the timezone abbreviation includes the letter "d", it is a daylight savings time date/time. Well... except for what the website calls a military time zone, and one of them is called "delta"... abbreviated "d".

I had my solution. I test for the browser; If it's IE, I parse out the abbreviation, make sure it's longer than one character long (just to be sure to avoid that military time zone), and make sure it contains the letter "d"; If it's any other browser, I just search the toTimeString for "daylight".

Seems kind of simple now, and I'm wondering why I didn't stumble across anything like it in my google searches. Anyway, in an attempt at getting a solution out there on the web... and in hopes that google will find the page and lead other people here, I'll include the code...

First, a simple function for determining browser...

function isIE()
{
return (navigator.userAgent.toLowerCase().indexOf("msie") > -1);
}

Second... the daylight savings time test...

function isDaylightSavingsTime(theDate)
{
var theTime = theDate.toTimeString().toLowerCase();
var isDST = false;
if (isIE()) //do the IE based code for determining whether it's daylight savings time or not...
{
if (theTime.length > 9)
{
theTime = theTime.substr(9); //trim off the time so we just have the time zone
if (theTime.length > 1 && theTime.indexOf("d") > -1)
{
isDST = true;
}
}
}
else //handle W3C compliant browsers
{
if (theTime.indexOf("daylight") > -1)
{
isDST = true;
}
}
return isDST;
}

There might be more efficient ways to do it, but it works, and it's not THAT complicated. I hope this is useful for you. And I apologize but making the indentations right for the code samples is making my headache worse... so I'm leaving them as is. I'm sure you can forgive me that.


2 comments:

hallvors said...

Good try, but this isn't really a good way to figure out whether daylight saving time applies. (It uses browser sniffing, is extremely dependant on quirks that are not specified or documented - note BTW that the Date object in JavaScript is specified by ECMA, not W3C). It doesn't work in the browser and time zone I'm in at the moment and I suspect it will fail pretty often.

While searching I found this to be probably the nicest solution so far:

http://javascript.about.com/library/bldst.htm

Kevin said...

Yeah, since making this post I've seen other ways to do it including one essentially like the one on the page you linked. It would be nice if the date object just had it built in... :)