Tag: datetime

 

Time Zones, done better

A few days ago, I signed up to HuffDuffer (love the logo, BTW). However, once I’d registered, my profile page said Huffduffing since November 1st, 2008. Which was a little weird, as when I did this it was October 31st.

So I filed a bug report and Jeremy quickly spotted the problem: the server was running in Australia, so was using an Australian timezone. That’s about 11 hours ahead, which would put my signup in to the next day. His fix was simple: force huffduffer to use GMT (see datetime configuration in the PHP manual). This isn’t a 100% correct solution, but it’s definitely the least bad approach.

But it set me wondering: can we do better? The key thing is that something somewhere has to know what time zone you’re in. That thing happens to be your browser. JavaScript Date objects have a getTimezoneOffset() method which return the minutes difference between you and GMT.

  alert(new Date().getTimezoneOffset());

Right now, when I try it, it returns zero because I’m in british winter time, which just happens to be the same as GMT. If I was in Australia, it’d return 660 (11 hours).

So we know the time on the server, and we know how far away from GMT we are. So how do we get JavaScript to format the date correctly?

Obviously, the first step is to pass the time to the browser as GMT. The normal approach to this is to use the Unix time format (number of seconds since midnight 1970). In PHP, look at gmmktime(). Perl uses gmtime(). And JavaScript has a constructor which takes milliseconds.

  new Date(0); // Thu Jan 01 1970 01:00:00 GMT+0100 (BST)

Ooops. That’s an hour ahead. But it’s actually misleading: the internal representation (the milliseconds we are passing in) doesn’t have a timezone, it’s only applied when you turn it into a human readable form. You can demonstrate this by using rhino on the command line to fool Javascript in to thinking it’s in different time zones1.

First, let’s try it in my time zone:

  % java -jar js.jar -e "print(new Date(0))"
  Thu Jan 01 1970 00:00:00 GMT-0000 (GMT)

Now let’s pretend we’re in Australia:

  % TZ=Australia/Melbourne java -jar js.jar -e 'print(new Date(0))'
  Thu Jan 01 1970 10:00:00 GMT+1000 (EST)

Which makes things really easy for us: get the server to pass the unix time, create a new Date object from it and then rewrite the textual object based on the contents.

So, if you start out with some HTML like this:

  <p>At the third stroke, it will be <span class="datetime" unixtime="1225461600">2008-10-31 14:00:00</span>.</p>

Note that we include the default (GMT) time in order to degrade gracefully.

Then you can use some JavaScript like this to automatically adjust it to the time zone of the browser.

    $("span.datetime").each(function () {
        if (!this.hasAttribute('unixtime')) {
            return;
        }
        var unixtime = this.getAttribute('unixtime');
        // Convert seconds to milliseconds
        var date = new Date(unixtime * 1000);
        $(this).text(format_date(date));
    });

I’m relying on jquery a little bit in there in order to focus on the problem, not the DOM. You can download the full source if needed (tzadjust.zip).

This is such a teeny-tiny thing overall, but it’s part of the polish to help make your site great.

1 You can change the timezone of any command this way in Unix. I have alias nydate='TZ=America/New_York date' in my shell profile so I can quickly see what the time in New York is.