Skip to content

Automagic Time Localization

June 15, 2009

One of the most often-overlooked and easy to fix things encountered when developing a hosted software application is the management of local time. First and foremost, you should be storing timestamps in your database in UTC. I don’t care if your users are all in the same time zone now, or your app is just a local deployment, or whatever other excuse you have for storing time as local time. Always store timestamps in UTC. Do it now, and pat yourself on the back a year from now when you realize whatever reason you had for storing it as local time was irrelevant or has changed. :)

Okay, so once you’ve got your timestamps stored in UTC, you need to localize them for each individual user, which means you need their offset from UTC. For example, Eastern Standard Time, my time zone, is UTC-5. The most common thing that I’ve seen is to provide users with a massive dropdown of a bajillion time zones, and ask them to pick which one they’re in.

Maybe it’s just a pet peeve, but I hate it when sites ask me to pick my time zone. What about users who travel often? What about daylight savings time? Do I make my users go in and change their time zones when DST starts and stops? Do I write extra code to figure out if it’s DST in the user’s time zone? That’s pretty much impossible, at least in the US, because it’s not recognized in Hawaii, Arizona (except in the Navajo Nation), and some counties in middle America.

While I was building Zen, I was determined to avoid making users have to choose their time zone if I could avoid it. I realized that the client computer knows what time it is, and what time zone they’re in, so it’s pretty simple to read it with Javascript. Here’s how you can grab the client computer’s UTC offset:

new Date().getTimezoneOffset() / -60

Now, all that remains is to push that information back to the server and make sure that it’s updated often. Zen’s login form has a hidden input called timezoneOffset, which is set using jQuery when the page is displayed:

$(document).ready(function() {
  $("#timezoneOffset").val(new Date().getTimezoneOffset() / -60);
});

Now, when the form is posted, I read the UTC offset from the hidden input, and store it in the user’s record in the database. This means that each time the user logs in, their time zone information is updated to be current. This helps not only with the daylight savings time problem, but also ensures that Zen will respond to changes in the user’s computer clock. If a user travels from EST to PST, for example, and they change their computer clock, Zen will recognize the change and update the timestamps appropriately.

Then, each time I need to display a timestamp to a user, I call a method on my TimeHelper (a custom ASP.NET MVC view helper, like the built-in HtmlHelper and UrlHelper):

public TimeHelper
{
  public User User { get; private set; }

  public TimeHelper(User user)
  {
    User = user;
  }

  public DateTime GetLocalTime(DateTime utc)
  {
    DateTime local = utc.AddHours(User.TimezoneOffset);
    return new DateTime(local.Ticks, DateTimeKind.Local);
  }
}

Just another trick to keep in your bag. :)

About these ads

From → miscellaneous

13 Comments
  1. Great post, time zones have always been the bane of programming for me.

    The one problem I see is when you are trying to display times that cross the daylight savings boundaries. For example, if I want to display the time from 2/1/2009 at 11:00 UTC on 6/15/2009, the User.TimezoneOffset doesn’t account for the boundary change. The time would be incorrectly displayed as 7:00AM instead of 6:00AM.

    This does work for storing the time, but not when retrieving them for display. I have found that I have to pass the current time zone and then convert for display. I can’t just send the current offset because you can’t determine a single time zone from it.

  2. Another potential issue is if someone wants to see or enter date/time data in a different time zone. I run a site designed for promotion and discovery of dev/it pro events, and my solution (right or wrong) was to store both the timezone and the time as entered by the event owner, and display both those values, rather than make assumptions about whether the timezone of the local computer is what the user wants used.

    For something like an online event like a webcast, it would probably make more sense to display in the user’s native timezone, but for local stuff, I think using the local time along with timezone, may make more sense in some cases.

  3. @Steve: That’s true, displaying historic time is a problem with storing values with UTC. I take the stance that it’s better to always display the localized time. Zen does some time math too (to compute key performance indicators), so keeping everything in UTC eases that dramatically.

    @Andrew: I tend to think displaying the time and the user’s timezone means that your users have to think too hard. One of the primary goals of Zen is to help distributed teams work together more easily — so if some team members are in different time zones, I don’t want to have to do the time zone math in my head all the time.

  4. I understand the ease of use of not storing time zone. With this application, I wouldn’t care if times were displaying differently across the daylight savings boundaries because all times would have to change with it based on your current offset.

    I disagree that it’s always better to display the localized time because you might be traveling and want to see it in your home time zone.

  5. Fair enough…I think in the case of Zen and distributed teams, your solution may make more sense than mine.

    I do wish that working with time was easier in general. Daylight savings time rules in particular are complex, and change often. I long for a simple solution that doesn’t make my head hurt. :-)

  6. Amen to storing only UTC. Nice trick with the client side discovery. Definitely going to use that one.

    Side note, this is known as the “Money pattern”. Any time you have relative values depending on geographic or environmental factors or other variable unit sizes, always normalize to a common denominator. Physical measurements (metric vs English units), Money (currency exchange rates, etc), and time/timezones are good examples.

  7. A step further would be to have all dates sent to the client in UTC and then use Javascript to format them as local time.

    This doesn’t require the user to login to update the offset and will work instantly.

  8. .NET 3.5 introduces the TimeZoneInfo class that provides a much better way to convert a time between timezones.

    Using it, you can do something like this:
    public static DateTime GetLocalTime(DateTime utc)
    {
    return TimeZoneInfo.ConvertTime(utc, TimeZoneInfo.Local);
    }

    I’m not sure if it handles daylight saving correctly, but I bet it does.

  9. Of course, the code that I’ve posted works for fat clients, not web clients…

  10. @JP: I utilize the .NET 3.5 TimeZoneInfo class to convert times on my websites, I think it only works on Full Trust though, not 100% sure.

Trackbacks & Pingbacks

  1. Weekly Web Nuggets #69 : Code Monkey Labs
  2. Reflective Perspective - Chris Alcock » The Morning Brew #374
  3. Simplify IUserType Testing « Random Code

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: