Does zic currently compile time zone abbreviations correctly?
John B. Morrow
jmorrow at sendwordnow.com
Fri Jul 27 16:18:58 UTC 2007
This response and program was very helpful. Apparently I was missing the level of indirection that converted the type in the ttinfo into an abbrind to look up the abbreviation. For some time zones, that was fine and for others it wasn't. Now that I've added that additional level in, my program seems to be working correctly.
Thank you for your quick response.
John Morrow
-----Original Message-----
From: Olson, Arthur David (NIH/NCI) [E] [mailto:olsona at dc37a.nci.nih.gov]
Sent: Friday, July 27, 2007 11:29 AM
To: tz at elsie.nci.nih.gov
Cc: John B. Morrow
Subject: RE: Does zic currently compile time zone abbreviations correctly?
The typescript below seems to indicate that there's nothing amiss with Europe/London; do you get different results if you run "tzhead"?
--ado
Script started on Fri 27 Jul 2007 11:24:37 AM EDT
lecserver$ cat tzhead.c
#include "private.h"
struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
char tzh_version[1]; /* '\0' or '2' as of 2005 */
char tzh_reserved[15]; /* reserved--must be zero */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
char tzh_timecnt[4]; /* coded number of transition times */
char tzh_typecnt[4]; /* coded number of local time types */
char tzh_charcnt[4]; /* coded number of abbr. chars */
};
static char * progname;
static long long
detzcode64(codep)
const char * const codep;
{
register long long result;
register int i;
result = (codep[0] & 0x80) ? ~0L : 0L;
for (i = 0; i < 8; ++i)
result = result * 256 + (codep[i] & 0xff);
return result;
}
static long long
detzcode(codep)
const char * const codep;
{
register long result;
register int i;
result = (codep[0] & 0x80) ? ~0L : 0L;
for (i = 0; i < 4; ++i)
result = (result << 8) | (codep[i] & 0xff);
return result;
}
static void
wild2exit(cp, dp)
{
(void) fprintf(stderr, "%s: wild result %s %s\n", progname, cp, dp);
exit(1);
}
static void
handle(filename)
char * filename;
{
FILE * fp;
struct tzhead tzh;
long long ll;
char c;
int i;
int pass;
long ttisgmtcnt;
long ttisstdcnt;
long leapcnt;
long timecnt;
long typecnt;
long charcnt;
char buf[8];
struct tm tm;
fp = fopen(filename, "r");
if (fp == NULL)
wild2exit("result opening", filename);
for (pass = 1; pass <= 2; ++pass) {
if (fread(&tzh, sizeof tzh, 1, fp) != 1)
wild2exit("result reading", filename);
(void) printf("%s\tversion\t", filename);
c = tzh.tzh_version[0];
if (isascii(c) && isprint(c))
(void) putchar(c);
else (void) printf("\\%o", c);
(void) putchar('\n');
ttisgmtcnt = detzcode(tzh.tzh_ttisgmtcnt);
ttisstdcnt = detzcode(tzh.tzh_ttisstdcnt);
leapcnt = detzcode(tzh.tzh_leapcnt);
timecnt = detzcode(tzh.tzh_timecnt);
typecnt = detzcode(tzh.tzh_typecnt);
charcnt = detzcode(tzh.tzh_charcnt);
(void) printf("%s\tttisgmtcnt\t%ld\n", filename, ttisgmtcnt);
(void) printf("%s\tttisstdcnt\t%ld\n", filename, ttisstdcnt);
(void) printf("%s\tleapcnt\t%ld\n", filename, leapcnt);
(void) printf("%s\ttimecnt\t%ld\n", filename, timecnt);
(void) printf("%s\ttypecnt\t%ld\n", filename, typecnt);
(void) printf("%s\tcharcnt\t%ld\n", filename, charcnt);
for (i = 0; i < timecnt; ++i) {
if (fread(buf, pass * 4, 1, fp) != 1)
wild2exit("result reading", filename);
ll = (pass == 1) ? detzcode(buf) : detzcode64(buf);
{
time_t l;
l = ll;
tm = *gmtime(&l);
}
(void) printf("%s\ttime[%d]\t%lld\t%s",
filename, i, ll, asctime(&tm));
}
for (i = 0; i < timecnt; ++i) {
if (fread(buf, 1, 1, fp) != 1)
wild2exit("result reading", filename);
(void) printf("%s\ttype[%d]\t%d\n",
filename, i, buf[0]);
}
for (i = 0; i < typecnt; ++i) {
long l;
if (fread(buf, 4, 1, fp) != 1)
wild2exit("result reading", filename);
l = detzcode(buf);
(void) printf("%s\ttype[%d].offset\t%ld\n",
filename, i, l);
if (fread(buf, 1, 1, fp) != 1)
wild2exit("result reading", filename);
(void) printf("%s\ttype[%d].isdst\t%ld\n",
filename, i, buf[0]);
if (fread(buf, 1, 1, fp) != 1)
wild2exit("result reading", filename);
(void) printf("%s\ttype[%d].abbrind\t%ld\n",
filename, i, buf[0]);
}
for (i = 0; i < charcnt; ++i) {
if (fread(buf, 1, 1, fp) != 1)
wild2exit("result reading", filename);
(void) printf("%s\tabbr[%d]\t", filename, i);
if (isascii(buf[0]) && isprint(buf[0]))
(void) printf("%c", buf[0]);
else if (buf[0] == '\0')
(void) printf("\\0");
else (void) printf("\%03o", buf[0]);
(void) printf("\n");
}
for (i = 0; i < ttisstdcnt; ++i) {
if (fread(buf, 1, 1, fp) != 1)
wild2exit("result reading", filename);
(void) printf("%s\tisstd[%d]\t%d\n",
filename, i, buf[0]);
}
for (i = 0; i < ttisgmtcnt; ++i) {
if (fread(buf, 1, 1, fp) != 1)
wild2exit("result reading", filename);
(void) printf("%s\tisgmt[%d]\t%d\n",
filename, i, buf[0]);
}
if (tzh.tzh_version[0] != '2')
break;
}
if (fclose(fp) != 0) {
(void) fprintf(stderr, "%s: wild result closing %s\n",
progname, filename);
exit(1);
}
}
int
main(argc, argv)
int argc;
char * argv[];
{
int i;
progname = argv[0];
for (i = 1; i < argc; ++i)
handle(argv[i]);
exit(0);
}
lecserver$ make tzhead
cc -DTZDIR=\"/usr/local/etc/zoneinfo\" tzhead.c -o tzhead
lecserver$ tzhead tmp/etc/zoneinfo/Europe/London | grep abbr
tmp/etc/zoneinfo/Europe/London type[0].abbrind 0
tmp/etc/zoneinfo/Europe/London type[1].abbrind 4
tmp/etc/zoneinfo/Europe/London type[2].abbrind 8
tmp/etc/zoneinfo/Europe/London type[3].abbrind 0
tmp/etc/zoneinfo/Europe/London type[4].abbrind 0
tmp/etc/zoneinfo/Europe/London type[5].abbrind 4
tmp/etc/zoneinfo/Europe/London type[6].abbrind 4
tmp/etc/zoneinfo/Europe/London abbr[0] B
tmp/etc/zoneinfo/Europe/London abbr[1] S
tmp/etc/zoneinfo/Europe/London abbr[2] T
tmp/etc/zoneinfo/Europe/London abbr[3] \0
tmp/etc/zoneinfo/Europe/London abbr[4] G
tmp/etc/zoneinfo/Europe/London abbr[5] M
tmp/etc/zoneinfo/Europe/London abbr[6] T
tmp/etc/zoneinfo/Europe/London abbr[7] \0
tmp/etc/zoneinfo/Europe/London abbr[8] B
tmp/etc/zoneinfo/Europe/London abbr[9] D
tmp/etc/zoneinfo/Europe/London abbr[10] S
tmp/etc/zoneinfo/Europe/London abbr[11] T
tmp/etc/zoneinfo/Europe/London abbr[12] \0
tmp/etc/zoneinfo/Europe/London type[0].abbrind 0
tmp/etc/zoneinfo/Europe/London type[1].abbrind 4
tmp/etc/zoneinfo/Europe/London type[2].abbrind 8
tmp/etc/zoneinfo/Europe/London type[3].abbrind 12
tmp/etc/zoneinfo/Europe/London type[4].abbrind 4
tmp/etc/zoneinfo/Europe/London type[5].abbrind 4
tmp/etc/zoneinfo/Europe/London type[6].abbrind 8
tmp/etc/zoneinfo/Europe/London type[7].abbrind 8
tmp/etc/zoneinfo/Europe/London abbr[0] L
tmp/etc/zoneinfo/Europe/London abbr[1] M
tmp/etc/zoneinfo/Europe/London abbr[2] T
tmp/etc/zoneinfo/Europe/London abbr[3] \0
tmp/etc/zoneinfo/Europe/London abbr[4] B
tmp/etc/zoneinfo/Europe/London abbr[5] S
tmp/etc/zoneinfo/Europe/London abbr[6] T
tmp/etc/zoneinfo/Europe/London abbr[7] \0
tmp/etc/zoneinfo/Europe/London abbr[8] G
tmp/etc/zoneinfo/Europe/London abbr[9] M
tmp/etc/zoneinfo/Europe/London abbr[10] T
tmp/etc/zoneinfo/Europe/London abbr[11] \0
tmp/etc/zoneinfo/Europe/London abbr[12] B
tmp/etc/zoneinfo/Europe/London abbr[13] D
tmp/etc/zoneinfo/Europe/London abbr[14] S
tmp/etc/zoneinfo/Europe/London abbr[15] T
tmp/etc/zoneinfo/Europe/London abbr[16] \0
lecserver$ exit
script done on Fri 27 Jul 2007 11:25:04 AM EDT
From: John B. Morrow [mailto:jmorrow at sendwordnow.com]
Sent: Friday, July 27, 2007 2:29 AM
To: tz at lecserver.nci.nih.gov
Subject: Does zic currently compile time zone abbreviations correctly?
In the process of extracting time zone information from the zoneinfo database, I noticed that the abbreviation pointer break for quite a few time zones including Europe/London, Asia/Dubai, and quite a few others. The problem seems to be in the compiled time zone files so I spent some time looking at zic. What seems to be happening is that zic uses some criteria to determine of the abbreviation (and other info for types) is used and won't write it if it thinks it isn't needed. The problem is that it doesn't adjust the indexes (tt_abbrind) that reference those abbreviations, so they'll point to bad data or empty strings. My quick (and admittedly heavy handed fix) was to force zic to write all of the abbreviations, whether they are necessary or not. If this really is a problem, it should probably be fixed at some point. Please note that the data in our fairly recently updated Linux server has abbreviations that don't seem to work.
If I'm missing something or there is some other way more correct way to reference the abbreviations, please let me know. I'm using tt_abbrind as per the tzfile man page and the tzcode2007f.tar.gz sources.
John Morrow
More information about the tz
mailing list