How to Elegantly Deal with Timezones

How to elegantly deal with timezones

Not that this is a recommendation, its more sharing of a paradigm, but the most agressive way I've seen of handling timezone information in a web app (which is not exclusive to ASP.NET MVC) was the following:

  • All date times on the server are UTC.
    That means using, like you said, DateTime.UtcNow.

  • Try to trust the client passing dates to the server as little as possible. For example, if you need "now", don't create a date on the client and then pass it to the server. Either create a date in your GET and pass it to the ViewModel or on POST do DateTime.UtcNow.

So far, pretty standard fare, but this is where things get 'interesting'.

  • If you have to accept a date from the client, then use javascript to make sure the data that you are posting to the server is in UTC. The client knows what timezone it is in, so it can with reasonable accuracy convert times into UTC.

  • When rendering views, they were using the HTML5 <time> element, they would never render datetimes directly in the ViewModel. It was implemented as as HtmlHelper extension, something like Html.Time(Model.when). It would render <time datetime='[utctime]' data-date-format='[datetimeformat]'></time>.

    Then they would use javascript to translate UTC time into the clients local time. The script would find all the <time> elements and use the date-format data property to format the date and populate the contents of the element.

This way they never had to keep track of, store, or manage a clients timezone. The server didn't care what timezone the client was in, nor had to do any timezone translations. It simply spit out UTC and let the client convert that into something that was reasonable. Which is easy from the browser, because it knows what timezone it is in. If the client changed his/her timezone, the web application would automatically update itself. The only thing that they stored were the datetime format string for the locale of the user.

I'm not saying it was the best approach, but it was a different one that I had not seen before. Maybe you'll glean some interesting ideas from it.

How to handle timezones?

... the only way to deal with this is to be very careful which dates I convert the timezone for, and which I leave alone, right?

In general, that's a good idea. Working with time means understanding the context of what you're working with. If you try to just set it once and forget it, you'll probably have at least one part of your app that behaves incorrectly.

In your particular use case, you describe "bookings" as being entered in an unspecified time zone. But then you say that you are storing them as UTC. If bookings are truly disassociated from any time zone, then you should not introduce UTC when working with them. Just leave them unspecified. (If you provide details about your language and DB, I can recommend specific data types.)

HOWEVER - there might be a context you're not considering. When you make a booking, is it for a specific location? If so, then the time zone of the location might be considered instead of the time zone of the user. You might use the location's time zone to convert to UTC, or you might store a "date-time-offset" combined value that is normalized to the location's time zone. Either would allow for reasonable conversions of the booking time, if that's something you need. Only you can decide whether this makes sense for your app or not.

With regard to the recorded time, that's a different context. It can certainly be in UTC, and then just converted to the time zone of whomever is viewing it.

How to deal with timezones in an event scheduling application with recurring events?

When it comes to future scheduling, especially for recurring events, you should not store values in terms of UTC. Instead, you need to store values in terms of the time zone related to that event, and you also need to store the identifier of that time zone (such as "America/Los_Angeles")

In order to conveniently order these events, you might additionally compute the UTC time for an occurrence of the event, but you should be prepared to recalculate it - as rules for time zones often change. The UTC time of the next event occurrence should be either in another column, or another table entirely.

Keep in mind that scheduling future events is a difficult problem. There are multiple pieces involved to do it properly. You should not be looking for a trivial solution. Please read some of the other posts I've written about this subject: here, and here.

How to deal with timezones between server and client?

Your problem doesn't involve timezones at all, just the fact that clients can turn their clocks or have their clock skewed considerably. For that the fix is to poll the server every once in a while for an offset fix to use in calculations.

In fact, you don't even need date objects. There is a certain universal instant in time when the auction ends. Let's say it is 1375960662823. Right now, the universal instant in time is 1375960669199, so from that we see that the auction ends in 6 seconds (1375960662823 - 1375960669199 ~ 6000 ). It will end in 6 seconds regardless if I am in Morocco or Japan. Do you understand it yet?

To generate these numbers, on the client side you can call var now = Date.now() + skewFix where skewFix is the correction that needs to applied in case client has time skew or manually set their computer to wrong time.

In PHP, you can generate it with $now = time() * 1000;

Laravel: How to deal with dates in different timezones

If you're only talking about a date, then there is no time component and thus time zones are irrelevant. For this reason, most platforms do not have a separate date-with-zone type.

You're correct that not every time zone experiences the same date at all times, and that the start of a date and the end of the date occur at different times in different time zones. However, did you notice that in the prior sentence that I had to use the word "time" to rationalize about these points? :-)

Because date and time zone don't come together without time, there's no purpose in keeping them in the same field. Instead, keep two fields in your model - one for the date, and one for the time zone. In many cases, you may even find they belong in two different models.

As a use case example, consider birthdays. Mine is 1976-08-27. That's all it is - just a date. The time zone of my birth is irrelevant, and so is the time zone I'm located in - until I want to evaluate whether it's currently my birthday (or how long until my birthday, etc.) For those operations, my current time zone is important, and so is the start time-of-day and end time-of-day of that time zone. Thus - two different fields.

How to deal with time zones in a Rails app with events

I'm working on something similar - a site with a list of events. In my situation, it's important to have the times standardized (in UTC) because we have announce and on-sale times to worry about (i.e., when the events appear on the site and when the on-sale links show up), not just displaying the event start time (which itself doesn't care what time zone it's in).

Going from a UTC time in the database to the local time for the given venue (i.e., to display the local time in the event listing) is pretty simple using something along the lines of e.start.in_time_zone("#{e.venue.time_zone}"). What I couldn't figure out was getting the local time at the point of data entry recognized as a local time needed to be converted to UTC, without having to deal with changing Time.zone.

I found something that works. Check out this post: http://steveluscher.com/archives/changing-a-times-zone-in-rails-keeping-the-same-local-representation. I added a new file (time_zone_support.rb) to my config/initializers directory. Here are the contents:

module ActiveSupport
class TimeWithZone
def zone=(new_zone = ::Time.zone)
# Reinitialize with the new zone and the local time
initialize(nil, ::Time.__send__(:get_zone, new_zone), time)
end
end
end

This allows the following in the console:

>> e.starts = Time.zone.parse("2010-09-12 10:00 am")
=> Sun, 12 Sep 2010 10:00:00 UTC +00:00
>> e.starts.zone = e.time_zone
=> "Pacific Time (US & Canada)"
>> e.starts
=> Sun, 12 Sep 2010 10:00:00 PDT -07:00
>> e.save
=> true

Hope that helps you too!



Related Topics



Leave a reply



Submit