Time zone confusion and implementation hints
guy at alum.mit.edu
Thu Jul 1 21:53:36 UTC 2010
On Jul 1, 2010, at 12:22 PM, Yves Goergen wrote:
> I'm currently implementing an API for the tz database that should look
> like .NET's TimeZoneInfo class to replace that in my application. The
> API includes:
> * Convert a date and time from UTC to a time zone
> * Convert a date and time from a time zone to UTC
> * Return the base UTC offset of a time zone for a date and time
> * Return the save offset of a time zone for a date and time
> * Determine whether a date and time is ambiguous in a time zone
> * Determine whether a date and time is invalid in a time zone
> It will come with a code generator that "compiles" the text files into
> C# code so that there's no need to deploy additional files with the
> application. The API's internal data structures are very similar to the
> tz database records, these are already coded.
> Currently I'm stuck because of the flexibility of the tz rules. These
> can define transition times either in local, standard or universal time.
> Additionally, the caller of my API passes a date and time that is either
> local or universal. All this needs to be matched correctly. The right
> rule needs to be selected and there can be ambiguous or invalid times
> all along the way. It's not only hard to implement, it's also hard to
> describe, it's very confusing not to have a common base [zone] you can
> hold on to.
> I have now read about any manpage and code file from the tzcode
> distribution, starting with zic.c and going backwards in the list. I
> think the file localtime.c does the actual conversion but it's hard to
> read because it contains only few comments and uses short all-lowercase
> global variable names. I couldn't follow it to its core where the magic
Note that the localtime.c code reads in the compiled time zone files and uses those; those files are much simpler than the rule files - they have an array of "transition times", all of which are represented as UTC, that refer to items that have:
offset from GMT;
indication of whether DST/summer time is in effect;
reference to the time zone abbreviation (e.g., EST vs. EDT for US/Canada Eastern Standard Time vs. Eastern Daylight Time);
for the local time state that comes into effect at that transition time, so, for any given UTC time, it just has to find the earliest transition time >= the given time and use the local time state that comes into effect at that transition time to convert the UTC time to local time.
The flexibility of the tz rules are handled in zic.c - it's the compiler that translates the text files with rules into the compiled time zone files.
As for "the caller of my API passes a date and time that is either local or universal", note that localtime() takes a universal-time argument (seconds since January 1, 1970, 00:00:00 UTC) and mktime() takes a local-time argument (year, month, day, hours, minutes, seconds), so you might want to look at those to see how they find the right transition time.
I would *STRONGLY* suggest that your compiler duplicate the work that zic does, and compile the text files into code that just has universal-time transition times and, for each transition time, data, or a reference to data, giving the time zone offset (and any other information your APIs need, such as "is this daylight savings/summer time?" and "what's the time zone abbreviation?").
More information about the tz