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