2

I have a Rails application that, like all Rails applications, uses Ruby's TZInfo library for time-zone information. This library uses Olson-style information, but it the implementation doesn't actually parse Olson files. The definitions are in Ruby.

I want to make sure that my server and the clients are using the same time-zone data so users don't experience any surprises. Specifically, we patch the TZInfo data in Ruby much faster than new releases of the gem. Thus, I've considered and rejected the following:

  1. Using a JavaScript library that has the time-zone information built-in. The Ruby and JavaScript libraries' data will diverge.
  2. Exposing the contents of /usr/share/zoneinfo/* from my API. The Ruby and zoneinfo data will diverge.

That leaves me with two options:

  1. Rewrite or patch TZInfo to actually parse files from /usr/share/zoneinfo/*
  2. Come up with a way to serialize TZInfo's TimeZone object into JavaScript, JSON, YAML, or another useful format

It's not sufficient to simply tell the client the current time zone offset since the client needs to generate timestamps for historical (and future) dates.

James A. Rosen
  • 64,193
  • 61
  • 179
  • 261
  • One would usually just pass the zone name, such as America/Los_Angeles. How would sending the zone rules down to the client help? Which tzdb library are you using in JavaScript? – Matt Johnson-Pint Jun 07 '13 at 00:17
  • Also, you should read and understand the implications of http://stackoverflow.com/questions/16946002 – Matt Johnson-Pint Jun 07 '13 at 00:19
  • Reading this again, option 1 that you rejected is probably the right way to go. You'll just want to be sure that both the js library and ruby are using the same version of the source tzdb data. – Matt Johnson-Pint Jun 07 '13 at 00:33
  • Here is a post that I list several tzdb libraries for JavaScript. http://stackoverflow.com/a/15171030/634824 – Matt Johnson-Pint Jun 07 '13 at 00:36
  • @MattJohnson Sending the rules down to the client lets us turn `2013-03-12T22:22Z` into "12 March, 2013 4:22pm (local)" on the client-side. Without the rules, client-side rendering of localized timestamps is impossible. – James A. Rosen Jun 12 '13 at 03:54
  • @MattJohnson the problem with option 1 is that it's *impossible* for them to use the same data. The standard Ruby library doesn't consume Olson data; it has it hard-coded in Ruby. – James A. Rosen Jun 12 '13 at 03:55
  • Really? I always assumed it was sourced from Olson data and was updatable. I'll have to check that out. But could you use an alternate implementation such as the [tzinfo gem](http://tzinfo.rubyforge.org/)? – Matt Johnson-Pint Jun 12 '13 at 04:13
  • I mean the tzinfo gem itself. It "uses Olson data," but not in the sense of parsing Olson files. The data are hard-coded. Check out [New_York.rb](http://tzinfo.rubyforge.org/svn/tzinfo-data/trunk/lib/tzinfo/data/definitions/America/New_York.rb). – James A. Rosen Jun 17 '13 at 09:33

1 Answers1

3

Use a library on both the server and the client that implement the same version of the IANA time zone database. The current version (as I am writing this) is 2013c, and can be found in it's original form here.

On the server side, use the TZInfo library for ruby. It has two gems, the tzinfo gem, and the tzinfo-data gem.

If you look at the tzinfo-data docs, you will see that there is a Version property that matches the IANA version. So tzinfo-data 2013.3 shows IANA version 2013c, which is also shown in the docs on this page.

You mentioned in comments that the data was hard-coded. This isn't exactly true. It's not hard-coded, it's code-generated. When you see the ruby files with the "hard-coded" time zone data, they were actually generated using the original IANA source files. There is a custom parser that performs this operation, so that every time a new version of the IANA time zone database is released, a corresponding update to tzinfo-data can be generated and published.

On the client side, you can use any of several different libraries. Most will do the exact same thing - starting with the same IANA sources, and code-generating a file that makes sense for the web. Usually, this is a JSON file.

Let's look at one of the libraries as an example - Walltime-js.

We can see on github that they have linked to the IANA/Olson tzdb sources on github. We can make sure we're using the exact same 2013c source data by checking out the precise version from git.

  • Look at the commit history for the tzdb.
  • Find that on April 19, 2013, there's a comment indicating release 2013c.
  • Verify that the release of 2013c at IANA was April 20, 2013.
  • So we know that the commit id for 2013c is f599ad15ce.
  • (Yes, this would be easier if they used git tags, but they don't for some reason).

Ultimately, we end up code-generating the walltime-data.js file, by following their build instructions, making one minor change to ensure we have the exact same 2013c source data. The new build looks like this:

git submodule init && git submodule update
git submodule foreach 'git checkout f599ad15ce'
cake data

Now we have a walltime-data.js file that is built from TZDB 2013c. This will go down to the client and be used by walltime.js.

We also have the tzinfo-data gem for 2013c that will sit on the server and be used by tzinfo in Ruby.

So the only data that needs to transmit between them is the id of the time zone, such as America/Los_Angeles. Each library will use their own copy of the data and their own implementation, but you can trust that they are referring to the same thing.

The only thing that could make them behave differently is if there was a bug in the way that they interpret the data, either in their parser or at runtime. Such bugs should be raised to the author's attention. But the only way you could possibly avoid them is to run the exact same code and data in both places - which would mean using Node.js on the server instead of Ruby.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • This is probably the best I'll be able to do, but it fails one of the requirements: a central place for any edits we make to the timezone database. We're often able to ship patches more quickly than the official releases as governments change their timezone rules. – James A. Rosen Jun 17 '13 at 23:54
  • The source should always be from the TZDB. If you think you know something from the governments that isn't in there, please participate in [their mailing list](https://mm.icann.org/mailman/listinfo/tz). If it's checked in to the tzdb, but just not yet in the official release, you can always update from that particular commit. I showed you how to update walltime's data, but I'm sure you can also build the tzinfo-data yourself. The "central place for edits" for either should be the tzdb data. – Matt Johnson-Pint Jun 18 '13 at 00:27