This is a requirement that can hardly be considered common. Most applications are not forced to deal with more than one timezone: intranet applications, nationwide deployments (most European Countries enjoy this great invention that is Central European Time), even air navigation systems place everything in UTC.
We recently deployed Koliseo on App Engine. This is still a work in progress, where some features have raised interesting questions: what happens when a friend tells you to meet on Friday at 17:15? How do you store this in the database?
I love the way computers measure time: milliseconds since 1970. Holy cow. No leap years, no arbitrary seconds-in-a-minute conversion, no Daylight Saving Time and it doesn't matter where you are. Give me a number that I can sort and compare. Computers do not have problems with dates. Humans do.
Then, the only problem is parsing and formatting these dates.
Parse date
Ye olde way of providing time information says that you should put a test field, label it "when" and let the user do his thing. Suppose that he introduces 25 Oct 2010 at 00:00
, sitting comfortably in his nice office in Madrid (GMT + 1, where DST applies).
- What the user means:
25 Oct 2010 at 00:00
in NiceAndWarmOffice@Madrid - What the server understood:
25 Oct 2010 at 00:00
in local server time. For App Engine this is UTC, which means one or two hours less, depending on the season.
The user wanted to express Oct 25 00:00 (Madrid time), but the server understood Oct 24 23:00 (Madrid time). This is the value that will get stored in the database.
You need to ask for a timezone to parse dates. A default timezone can be automatically guessed using javascript (it comes in small and jumbo sizes), but it is nice practice to let the user modify the timezone later, just in case.
Following this example, any Performance must specify where at the same time as when if we want to be able to parse the introduced timestamp.
The code to parse is quite straightforward thanks to Saint Joda Time:
DateTimeZone dtz = DateTimeZone.forID(timezoneID); DateTimeFormatter formatter = DateTimeFormat .forPattern("yyyy-MM-dd HH:mm") // replace with your favorite format string .withZone(dtz) ; Date date = formatter.parseDateTime(dateAsString).toDate();
Format date
How do you want to display dates to the user?
- Relative units: This is the best way to display unambiguous dates ("ten minutes ago", "one week ago", etc). This is done in moment.js or through hoops and loops in Joda Time.
- User time: This is usually not interesting, since a date is associated to something happening (in Koliseo, a performance) and is usually meaningful inside their own context and timezone.
- Original timezone: This is the most common case. Example: tell me that the show is scheduled at 17:30 (local time of the show, in this case Madrid), not browser time (Helsinki or whatever).
To format dates in the original timezone you can use the same snippet of code just replacing formatter.parse() with format().
Javascript code
Whenever you send or receive a Date from the server, the typical JSON serialization uses "milliseconds from 1970", which can be a problem. This value cannot be used as is because the timezone information is missing. 17:35 in Madrid will be deserialized as 16:35 if I am browsing from London, which is wrong.
Twitter solves this by serializing dates as text, then you can parse and separate the parts to display (day, month, year, weekday). To test your javascript code, just add -Duser.timezone=UTC
to your server launch script and play a little with your application. If you do not see any date mismatch, everything is good.