Reputation: 400
I'm trying to parse the tzfile (Olson) format on a Unix system. In the tzfile(5) man page it states the following:
Then there are tzh_ttisstdcnt standard/wall indicators, each stored
as a one-byte value; they tell whether the transition times
associated with local time types were specified as standard time or
wall clock time, and are used when a timezone file is used in
handling POSIX-style timezone environment variables.
Finally, there are tzh_ttisgmtcnt UTC/local indicators, each stored
as a one-byte value; they tell whether the transition times
associated with local time types were specified as UTC or local time,
and are used when a timezone file is used in handling POSIX-style
timezone environment variables.
Does this mean I can ignore isstd and isgmt and still get the correct times? In spot checking, this seems to be the case but in digging around in the C source files, I see unix makes some adjustments dependant on these values.
Upvotes: 2
Views: 278
Reputation: 400
As requested above, I asked on the mailing list. The answer was to look in the code. So the relevant code is in zic.c
(zone compiler) and glib's tzfile.c
. Source code for both can be found on github at the time of this wring. The relevant code for zic.c
is
switch (lowerit(*ep)) {
case 's': /* Standard */
rp->r_todisstd = true;
rp->r_todisgmt = false;
*ep = '\0';
break;
case 'w': /* Wall */
rp->r_todisstd = false;
rp->r_todisgmt = false;
*ep = '\0';
break;
case 'g': /* Greenwich */
case 'u': /* Universal */
case 'z': /* Zulu */
rp->r_todisstd = true;
rp->r_todisgmt = true;
*ep = '\0';
break;
Which says there are 3 possible cases: isstd = true && isgmt = false
, both false and both true. So to see what is done with these flags, the relevant code in tzfile.c
is
if (trans_type->isgmt)
/* The transition time is in GMT. No correction to apply. */ ;
else if (isdst && !trans_type->isstd)
/* The type says this transition is in "local wall clock time", and
wall clock time as of the previous transition was DST. Correct
for the difference between the rule's DST offset and the user's
DST offset. */
transitions[i] += dstoff - rule_dstoff;
else
/* This transition is in "local wall clock time", and wall clock
time as of this iteration is non-DST. Correct for the
difference between the rule's standard offset and the user's
standard offset. */
transitions[i] += stdoff - rule_stdoff;
So this seems to say that if isgmt
is true we can ignore everything else. If it is false then if the previous transition was DST and the current one is not standard (i.e. case 'w' above, as it's also not gmt) apply the dst
offset (the last one found in the file). Otherwise apply the standard offset.
Which seems to mean that glibc ignores the offsets in the individual tt_types and case 's'. I looked in localtime.c
in the tz
package and it worked the same way.
I can only conclude from all this that most of the information in the tzfile isn't actually used anywhere. Some of this may be due to POSIX requirements. If anyone can expand on the details below, please do. It would be nice to have this behaviour documented somewhere on the internet besides in C source code.
Upvotes: 1