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
Hmmm...if a binary file has 32-bit values that are in sort and that all have their high-order bits set, it might be because it contains signed values that are all pre-epoch. It might also be because it contains unsigned values that are all post-2038--that's unlikely now, but likelier as time goes by. If we're lucky, 32-bit systems will be a thing of the past by the time it's likely. That being so, I've attached a slightly-revised version of Doug Bailey's fixes (they also appear below, with tabs mangled by Firefox/Gmail). Are there any present-day systems with unsigned 64-bit time_t's? --ado 8.17 2110 lines 8.18 2127 lines *** /tmp/,alocaltime.c 2012-07-10 15:14:38.372363200 -0400 --- /tmp/,blocaltime.c 2012-07-10 15:14:38.509371000 -0400 *************** *** 5,11 **** #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 8.17"; #endif /* !defined NOID */ #endif /* !defined lint */ --- 5,11 ---- #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 8.18"; #endif /* !defined NOID */ #endif /* !defined lint */ *************** *** 277,282 **** --- 277,287 ---- /* ** And to get the latest zone names into tzname. . . */ + for (i = 0; i < sp->typecnt; ++i) { + register const struct ttinfo * const ttisp = &sp->ttis[i]; + + tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind]; + } for (i = 0; i < sp->timecnt; ++i) { register const struct ttinfo * const ttisp = &sp->ttis[ *************** *** 489,508 **** ** signed time_t system but using a data file with ** unsigned values (or vice versa). */ ! 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]; --- 494,525 ---- ** signed time_t system but using a data file with ** unsigned values (or vice versa). */ ! for (i = 0; i < sp->timecnt; ++i) ! if ((i < sp->timecnt - 1 && ! sp->ats[i] > sp->ats[i + 1]) || ! (i == sp->timecnt - 1 && ! !TYPE_SIGNED(time_t) && ! stored == 4 && ! 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 + ** (thanks to Doug Bailey). + */ + sp->ats[i] = 0; for (j = 0; j + i < sp->timecnt; ++j) { sp->ats[j] = sp->ats[j + i]; sp->types[j] = sp->types[j + i];
On 07/10/2012 12:23 PM, Arthur David Olson wrote:
Are there any present-day systems with unsigned 64-bit time_t's?
Nothing major that I know of. However, NewOS does it that way and might be considered to be present-day. See: http://git.newos.org/?p=newos.git;a=blob;f=include/time.h
On 2012/07/10 10:16 PM, Paul Eggert wrote:
On 07/10/2012 12:23 PM, Arthur David Olson wrote:
Are there any present-day systems with unsigned 64-bit time_t's?
Nothing major that I know of. However, NewOS does it that way and might be considered to be present-day. See:
That supposedly has time_t values representing microseconds since Jan 1, 1 AD (using the Gregorian rules extrapolated back to 1 AD), although the time calculations in its libc look a little buggy, see _getLastDayOfYear() in: http://git.newos.org/?p=newos.git;a=blob;f=lib/libc/time/time.c -- -=( Ian Abbott @ MEV Ltd. E-mail: <abbotti@mev.co.uk> )=- -=( Tel: +44 (0)161 477 1898 FAX: +44 (0)161 718 3587 )=-
Are there any present-day systems with unsigned 64-bit time_t's?
Nothing major that I know of. However, NewOS does it that way and might be considered to be present-day.
That being true, I've attached a change that caters to 64-bit unsigned systems (with the usual mangled copy below); these changes are relative to the current ftpable version of localtime.c --ado 8.17 2110 lines 8.19 2126 lines *** /tmp/,alocaltime.c 2012-07-11 15:55:34.439147200 -0400 --- /tmp/,blocaltime.c 2012-07-11 15:55:34.641947500 -0400 *************** *** 5,11 **** #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 8.17"; #endif /* !defined NOID */ #endif /* !defined lint */ --- 5,11 ---- #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 8.19"; #endif /* !defined NOID */ #endif /* !defined lint */ *************** *** 277,282 **** --- 277,287 ---- /* ** And to get the latest zone names into tzname. . . */ + for (i = 0; i < sp->typecnt; ++i) { + register const struct ttinfo * const ttisp = &sp->ttis[i]; + + tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind]; + } for (i = 0; i < sp->timecnt; ++i) { register const struct ttinfo * const ttisp = &sp->ttis[ *************** *** 489,508 **** ** signed time_t system but using a data file with ** unsigned values (or vice versa). */ ! 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]; --- 494,524 ---- ** signed time_t system but using a data file with ** unsigned values (or vice versa). */ ! for (i = 0; i < sp->timecnt; ++i) ! if ((i < sp->timecnt - 1 && ! sp->ats[i] > sp->ats[i + 1]) || ! (i == sp->timecnt - 1 && !TYPE_SIGNED(time_t) && ! sp->ats[i] > ! ((stored == 4) ? INT32_MAX : INT64_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 + ** (thanks to Doug Bailey). + */ + sp->ats[i] = 0; for (j = 0; j + i < sp->timecnt; ++j) { sp->ats[j] = sp->ats[j + i]; sp->types[j] = sp->types[j + i];
participants (4)
-
Arthur David Olson -
Doug Bailey -
Ian Abbott -
Paul Eggert