> (Interesting note, UTC only matches the time in Greenwich during standard time. When it is DST there, Greenwich and UTC are not identical.)
Time is really really hard, and I don't claim to understand it, but going lightly with basic facts is a bad idea.
First, GMT != UTC. UTC observes leap seconds, GMT don't. That doesn't matter, right up until when it suddently does matter.
Second, it's grossly confusing to talk about "Greenwich time", i.e. the time at the location, when you don't mean GMT. Neither UTC nor GMT observes DST, Britain, in which Greenwich is located, does.
The International Earth Rotation and Reference Systems Service (IERS) announces the insertion of a leap second whenever the difference between UTC and UT1 approaches 0.6 s, to keep the difference between UTC and UT1 from exceeding 0.9 s.
I can't stress enough how important it is to get dates, times and timezones correct in your code to avoid embarrassment or worse. Just yesterday, just when we thought we'd ironed out all the timezone issues in our production code, our system rejected a bunch of customer data thinking the current time was actually an hour ahead of what it was. It turns out to be a bug in the Oracle JDBC driver that happens when connections are kept open while DST flips the clocks back but it goes to show that you can never be too careful when dealing with times and timezones.
And don't forget the Zune time bug which caused a bit of embarrassment for Microsoft last year/beginning of this year. It's hard to test every boundary and edge condition, especially if you are relying on black box testing to catch bugs.
Fun story regarding the UTC abbreviation: English speakers wanted it to be CUT (coordinated universal time), while French speakers wanted TUC (temps universel coordonné). They compromised on UTC.
His suggestion that storing datetimes in UTC may be a problem is only half-correct. If you have access to an accurate historical record of rules for a given zone, then you _can_ always store UTC.
On Unixen, this data is typically stored somewhere like /usr/share/zoneinfo, and is called the zoneinfo or Olson database (Arthur David Olson is the original creator and maintainer of this database).
Using this database, you will always get the right conversion, even for datetimes that predate recent shift in DST rules.
OTOH, if you're on a crippled system that assumes the most recent rules extend indefinitely back in time, then storing data in UTC only will be problematic.
Correct handling of dates and times in the general case (i.e, arbitrary time zones and arbitrary dates in the past, including calendar and time zone changes) is one of those things that I have tentatively filed under "too complicated for me to hope to get right", along with "correct handling of Unicode"[0] and "concurrency with fully shared mutable state"[1].
In practice, my rule is that if you can avoid dealing with the full complexity of date/time, such as by working in absolute time as much as possible and explicitly restricting the allowed date range, then do so; anywhere you have to work with dates/times as non-opaque values, always prefer library functions that explicitly say they conceptually do what you want, not ones that provide low level operations that let you do what you want, probably, at least in your own locale, for now. If your platform provides only a broken date/time implementation, use a third-party library.
Fun anecdote time! When an international group pushed for a standardized, absolute time, the English and French both wanted it to be named in their own language, "coordinated universal time" vs. "temps universel coordonné". The compromise of UTC provided an "acronym" that, by design, didn't make sense to anyone, which I think is somewhat telling about the whole issue. The blog post here gives a good overview of fundamental difficulties, though doesn't really convey the true horror of the subject; I often suspect that a full and complete description of the proper handling for date/times can be found only in an appendix of the Necronomicon, serving as a final deathblow to any last scraps of the reader's sanity.
[0] cf. Michael Kaplan's MSDN blog for a glimpse at all the ways Unicode can go wrong. See how many entries you can read successively until starting to doubt whether written communication was ever actually a good idea! I think my personal record is 14 or so.
[1] cf. anyone who's ever tried. I don't think I need to justify this one.
Storing as localtime+timezone is asking for bugs since most people shift timezone twice a year. That makes testing a real problem.
Store times internally as UTC (time_t epoch is a good representation, or the DateTime object of your preference), convert as needed at the boundaries of your app for display/persistent storage purposes.
I think the article was trying to point out that it is not possible to use UTC for everything. If for example you store in your database an event to occur in the distant future (e.g. opening ceremony of the 2016 Olympics) in UTC, then the time that that represents can change as rules about timezones, leap seconds and daylight savings change.
Also there is the possibility that you actually want to store the timezone information at write-time, rather than assuming a timezone at read-time. For example if you have multiple records storing event times (say the working hours of all your global employees) then storing them only using UTC, you will not be able to retrieve the actual time in the timezone of each event individually. You can only assume a global timezone to apply to all events.
When storing localtime+timezone, do as the article recommends. Store the timezone, not the offset from UTC. Store "New York time" not EST or EDT.
There are two UTC times corresponding to each moment from 00:00->01:00 25th Oct 2009 "London Time". There are no UTC times corresponding to 01:00->02:00 29th March 2009 "London Time".
> Also there is the possibility that you actually want to store the timezone information at write-time, rather than assuming a timezone at read-time.
Whether a given time should be displayed in the viewer's localtime or another time is a display issue (I may want to switch between seeing my plane arrival time in localtime of the destination and localtime of my body clock). I don't think it should affect the internal storage format as without help from a strong type system (or some strong coding conventions) coders will intermingle the two types and miss errors in testing either due to geographical proximity or lack of testing over daylight savings boundaries.
[All the above saud, the problem of changing DST parameters and future event times is problematic. I think it depends on what you want to be doing with such a time. Note that you'd have the opposite bug if you were storing pre-calculated sunrise time in various locales, so it's an issue of the semantic meaning of the timestamp.]
I've dealt with this quite a bit, and you're right- it's difficult to deal with the conceptual impedance mismatch between the concept of a time, and its discrete meaning in persistent storage.
I wrote a blog post about a month ago that talks about some issues surrounding the concept of "all-day" events which, by definition, are conceptually ambiguous.
I've had more traumatic code errors due to times than I care to admit.
The bottom line: Learn from Unix. Store everything in epoch time (even if you're in Windows.) Do all your math in that. Showing local time is for display _only_. You won't ever regret it. (Well, hardly ever.)
And don't store birthdays of anyone older (currently) than 39. I had a bug where I was enforcing epoch time for birthdates (Why? Long story) It worked when I (born in 1976) tested it, but it totally exploded when my more senior (in years) comrade tested it.
Every programmer working with dates should read http://naggum.no/lugm-time.html - "A Long Painful history of time". And also the Dave Olson paper referenced therein.
Great article. The author suggests saving time in two formats, (1) UTC and (2) local date-time with a geographical time zone. The app would then pick the right one to use depending on context.
BTW, let me take the opportunity to praise the Joda Time library for JVM languages. First time I've ever seen date and time primitives implemented well. It can be used for the scheme suggested in the article.
> (2) local date-time with a geographical time zone.
Note that timezones aren't just geographical. In London, you'll be in timezone GMT (+0000) for half the year and timezone BST (+0100) for half the year.
If you think instead that you're in a single timezone, then you need to know that your "timezone" isn't linear, it contained 00:00->01:00 twice on 25th October 2009 this year (when the clocks go back).
So "what was the UTC time for 00:30 on 25th October 2009 in London" isn't a question with a well-defined (or unique) answer.
> Note that timezones aren't just geographical. In London, you'll be in timezone GMT (+0000) for half the year and timezone BST (+0100) for half the year.
You're comparing apples and oranges. There are two different concepts here: 1) the name of a UTC offset for a given period of time in a given region i.e. BST. 2) the geographic area that has a set of rules about when to change the UTC offset.
In the US, we call #1 "Central Standard Time or Central Daylight Time" and #2 "Central Time". #1 means "UTC -6", and #2 means "convert UTC according to whatever the current rule is".
The author's point is to store local time + concept #2.
EDIT: ok, I see what you mean. If the user types in "send me a reminder at 12:30 Oct 25 London time, you don't know whether they're talking about pre-DST, or post-DST. Interesting.
Thanks, I didn't know that! With regard to the non-geographical "timezone" concept, is that what the time zone ID string concept "Europe/London" aims to solve (along with historical and assumed future rules specifying time changes)? I always wondered why those were used.
So, if I asked you to meet me for coffee at 5:00 PM EST, and I showed up when my watch said 5:00, I would be an hour early, b/c we're in DST right now.
I though that was interesting, b/c I will put EST in an email to people in another timezone, just thinking it means "Eastern Time Zone" or something like that.
> .. UTC (also known as Greenwich Mean Time)...
> (Interesting note, UTC only matches the time in Greenwich during standard time. When it is DST there, Greenwich and UTC are not identical.)
Time is really really hard, and I don't claim to understand it, but going lightly with basic facts is a bad idea.
First, GMT != UTC. UTC observes leap seconds, GMT don't. That doesn't matter, right up until when it suddently does matter.
Second, it's grossly confusing to talk about "Greenwich time", i.e. the time at the location, when you don't mean GMT. Neither UTC nor GMT observes DST, Britain, in which Greenwich is located, does.