Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.Sign up
TZInfo::AmbiguousTime: 1895-12-31 23:59:59 UTC is an ambiguous local time. (Asia/Taipei) #1
I have a Rails app that defaults time zone to "Asia/Taipei" (UTC+8). Sometimes an exception like this would be raised:
With tzinfo 0.3.37 (which Rails depends on), this exception can be reproduced in irb:
Both Asia/Taipei and Asia/Shanghai are in UTC+8 today, and have no official time zone in 1895.
This issue does not happen if I load tzinfo 1.0.1, which uses TZ Database directly from OS. If I install both tzinfo 1.0.1 and tzinfo-data gems, this issue would happen again (in this case tzinfo takes tzinfo-data instead of OS-provided TZ DB). However Rails binds version of tzinfo to >= 0.3.37, so I cannot work around this by simply upgrading tzinfo to 1.0.x.
I confirmed that such exception would happen if the local time to convert is between 1895-12-31 23:54:00 and 1895-12-31 23:59:59, and noticed that, in the original TZ Database, the following definition exists:
I want to make sure:
For Asia/Taipei, in the range you describe, there are two possible UTC times for each local time. The AmbiguousTime exception is therefore the correct result. According to the TZ data base rules, the local clock in Taipei went back 6 minutes at 15:54 UTC on 1895-12-31.
To resolve the ambiguity, you'll need to pass a block to local_to_utc to select one of the periods. For example:
You'll see a similar region of ambiguity with the Asia/Shanghai zone between 23:54:03 and 23:59:59 local time on 1927-12-31.
The reason you're not seeing the AmbiguousTime exception when using the system zoneinfo files is probably a 32-bit support issue (the earliest 32-bit UNIX timestamp being 1901-12-13 20:45:52).
It looks like you're running a version of Ruby that supports 64-bit timestamps (since you're able to instantiate a Time prior to 1901), so the issue is probably with your zoneinfo files.
Older zoneinfo files only support 32-bit timestamps. Newer files support 32-bit and 64-bit timestamps. To check which format you have available, you can run the following code (using TZInfo v1.0.1):
If the last line returns
If the last line returns
I reproduced that issue on my development env, Mac OS X 10.8.6 with Ruby 1.9.3. Here is the result, as you expected, it seems to be 32-bit-timestamps only:
If I do the same experiment on the production server (Debian Squeeze), it seems supporting 64-bit timestamp, and the AmbiguousTime behavior is the same as using tzdata-info:
OS X 10.8.4 ships TZ database version 2013c, both source code and
I surveyed for some time, and learned the following things (please correct me if I am wrong):
If I take
The version number of
If I compile
From the evidences above, I guess that: OS X 10.8.4 ships an older
Finally, I'll take the workaround you provided: choose any of the ambiguous UTC times, to mute that error in the future. Also, due to the fact that the OS-provided TZ database may not support ancient timestamp, I think I'll always take tzinfo-data in my Ruby application if ancient timestamp is vital.
By the way, I found that rails/rails#10826 is going to upgrade TZInfo to 1.0.1. I think such incorrect local-to-UTC conversion could happen, although it is not common in modern web applications.
Thank you very much!
I've just checked on an old Mac OS X 10.6 machine. It also has 32-bit zoneinfo files with
Everything you've written about the tz project looks correct to me.
I'll add something to the TZInfo documentation regarding 32-bit zoneinfo files and the issues they can cause.
One of the motivations for making TZInfo work with the system zoneinfo files was to allow it to be included in Linux distributions without duplicating all the time zone data (see Debian Bug #503591 and Red Hat Bug 729763). I think that having Rails not include a dependency on tzinfo-data is the best option - people can always install tzinfo-data or compile their own zoneinfo files if necessary.
You may like to consider using the second