[tz] localtime.c bugs
Doug Bailey
DBailey at qnx.com
Thu Jul 5 23:52:05 UTC 2012
I've started working with tzcode2012b and I've run into a couple of issues.
The first: in testing, I found that if I set a timezone like "CST6", the tzname[] array would not be initialized. Digging into it, I found that settzname[] depends on having transition rules for the zone, but a zone like "CST6" will only be created with a single type and no transitions.
To work around that one I've added the following code to initialize the tzname[] array from the ttis array before running through the types array:
+ for (i=0; i<sp->typecnt; i++) {
+ const struct ttinfo * const ttisp = &sp->ttis[i];
+ tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind];
+ }
/*
** And to get the latest zone names into tzname. . .
*/
for (i = 0; i < sp->timecnt; ++i) {
register const struct ttinfo * const ttisp =
&sp->ttis[
sp->types[i]];
The second has to do with our environment. We have an unfortunate time_t definition: an unsigned 32-bit number. The tzload code attempts to take unsigned time_t values into account, but if I'm not making a mistake understanding the way it's supposed to work, I think it has a few problems.
First, the loop over (i < sp->timecnt - 2) means that in comparing ats[i] > ats[i+1], you never compare ats[sp->timecnt-2] > ats[sp->timecnt-1]. This means that if all the transitions except the last are pre-epoch (negative number), the list doesn't get trimmed down.
Second, with that fixed, there are still problems with zones that only have pre-epoch transitions (e.g. America/Regina). In such a case, the ats[i] > ats[i+1] case never triggers, so you're left with a list of ats[] values that aren't valid -- they're negative numbers in a system with an unsigned time_t.
This is rather uglier. I've included my fix for what it's worth, but you can probably work out something better. One thing to note: I try to preserve the last pre-epoch transition, to handle situations where there's a large gap in transitions between the start of the epoch the the first post-epoch transition.
/*
** Out-of-sort ats should mean we're running on a
** signed time_t system but using a data file with
** unsigned values (or vice versa).
*/
#if 1
for (i = 0; i <= sp->timecnt - 1; ++i)
if ( (i < sp->timecnt-1 && sp->ats[i] > sp->ats[i + 1] ) ||
(i == sp->timecnt-1 && !TYPE_SIGNED(time_t) && sp->ats[i] > INT32_MAX) ) {
if (TYPE_SIGNED(time_t)) {
/*
** Ignore the end (easy).
*/
sp->timecnt = i+1;
} else {
/*
** Ignore the beginning (harder).
*/
register int j;
// keep the record right before the epoch boundary, but
// tweak it so that it starts right with the epoch
sp->ats[i] = 0;
// move everything back...
if (i > 0) {
for (j = 0; j + i < sp->timecnt; ++j) {
sp->ats[j] = sp->ats[j + i];
sp->types[j] = sp->types[j + i];
}
sp->timecnt = j;
}
}
break;
}
#else
for (i = 0; i < sp->timecnt - 2; ++i)
if (sp->ats[i] > sp->ats[i + 1]) {
++i;
if (TYPE_SIGNED(time_t)) {
/*
** Ignore the end (easy).
*/
sp->timecnt = i;
} else {
/*
** Ignore the beginning (harder).
*/
register int j;
for (j = 0; j + i < sp->timecnt; ++j) {
sp->ats[j] = sp->ats[j + i];
sp->types[j] = sp->types[j + i];
}
sp->timecnt = j;
}
break;
}
#endif
I appreciate any assistance with this.
Doug
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mm.icann.org/pipermail/tz/attachments/20120705/82a5592d/attachment.html
More information about the tz
mailing list