FW: zdump /zoneinfo question
John Cowan
jcowan at reutershealth.com
Mon Nov 22 19:57:47 UTC 1999
John Reynolds wrote:
> My reason for asking is, how can I tell if the curent zoneinfo file is
> accurate given that governments can change the rules at any time.
> I've tried some experiments creating my own zoneinfo files then using zdump
> to display information about it but I see no way of determining the rules.
This seems as good a time as any to release the "zrd" utility: it is public
domain, and allows reading a binary timezone file. It is written in very
portable C, and does not depend on any part of the tz library except the
timezone files themselves.
I developed it in order to help me interpret timezone files from Java, rather
than redoing all of zic in Java. I hope it is helpful to you.
If the tz tribal elders wish to make this part of the regular tz distribution
(perhaps in a "contrib" directory?) I certainly have no objection. There is
no readme or man page: the command line syntax is "zrd continent/city".
-----------------cut here-------------------------------
/* zrd - a routine to dump the contents of a binary timezone file
* Define ZONEINFO to be the directory where the timezone files are,
* typically "/usr/share/zoneinfo".
* This program requires only stdio and "gmtime".
* Public domain source by John Cowan <cowan at ccil.org>
*/
# define ZONEINFO "/usr/share/zoneinfo/"
# include <stdio.h>
# include <time.h>
/* A handy routine that converts from network order
* (big-endian) 32-bit values to local order.
* It tests what local order is, and is not the most
* efficient conceivable routine, but works OK
* for this application.
*/
long my_ntohl(long s) {
long r;
char *ps;
char *pr;
long test = 0x01020304;
if ((char *)&test == "\0x01\0x02\0x03\0x04") return s;
ps = (char *) &s;
pr = (char *) &r;
pr[0] = ps[3];
pr[1] = ps[2];
pr[2] = ps[1];
pr[3] = ps[0];
return r;
}
/* The header of a timezone file.
* After the header, the following objects may be found:
* tzh_timecnt 32-bit values representing time transitions;
* tzh_timecnt 1-byte indexes into the time type table;
* the time type table, containing tzh_typecnt "struct ttinfo" elements;
* the leap-second table, containing tzh_leapcnt "struct ttleap" elements;
* tzh.isstdcnt 1-byte flags indicating if transitions are
* based on local standard time or local current ("wall") time
* tz.isgmtcnt 1-byte flags indicating if transitions are
* based on UTC or local time
*/
struct tzhead {
char tzh_magic[4]; /* magic number */
char tzh_reserved[16]; /* reserved for future use */
long tzh_ttisgmtcnt; /* coded number of trans. time flags */
long tzh_ttisstdcnt; /* coded number of trans. time flags */
long tzh_leapcnt; /* coded number of leap seconds */
long tzh_timecnt; /* coded number of transition times */
long tzh_typecnt; /* coded number of local time types */
long tzh_charcnt; /* coded number of abbr. chars */
};
/* A time type object
*/
struct ttinfo {
long tt_gmtoff; /* offset of this time type from UTC */
char tt_isdst; /* whether this is a DST time type */
char tt_abbrind; /* index into the timezone name abbreviations */
};
/* A leap second object
*/
struct ttleap {
long tt_time; /* The leap second */
long tt_seconds; /* New value of TAI - UTC - 10 */
};
char tzfilename[1024]; /* Filename of the timezone file */
FILE *tz; /* File stream for reading the file */
struct tzhead t; /* The file's header */
char tzdata[4096]; /* The rest of the file */
long tzsize; /* Size of tzdata in use */
/* Pointers to different parts of tzdata
*/
long *timep;
char *timetypep;
char *xtypep;
struct ttinfo *typep;
char *charp;
struct ttleap *leapp;
char *stdp;
char *gmtp;
main(argc, argv)
int argc;
char *argv[];
{
int i;
long gmtoff;
int gmtsign;
long clock;
struct tm *d;
char magic[5];
/* Validate command line and load header */
if (argc != 2) {
fprintf(stderr, "usage: %s continent/location\n", argv[0]);
exit(1);
}
strcpy(tzfilename, ZONEINFO);
strcat(tzfilename, argv[1]);
tz = fopen(tzfilename, "rb");
if (!tz) {
fprintf(stderr, "%s: %s unknown\n", argv[0], argv[1]);
exit(1);
}
fread(&t, sizeof(t), 1, tz);
/* Localize values in the header */
strncpy(magic, t.tzh_magic, 4);
magic[4] = 0;
t.tzh_ttisgmtcnt = my_ntohl(t.tzh_ttisgmtcnt);
t.tzh_ttisstdcnt = my_ntohl(t.tzh_ttisstdcnt);
t.tzh_leapcnt = my_ntohl(t.tzh_leapcnt);
t.tzh_typecnt = my_ntohl(t.tzh_typecnt);
t.tzh_timecnt = my_ntohl(t.tzh_timecnt);
t.tzh_charcnt = my_ntohl(t.tzh_charcnt);
/* Read the rest of the file */
tzsize = fread(&tzdata, 1, sizeof(tzdata), tz);
fclose(tz);
/* Set up pointers to various sections */
timep = (long *)tzdata;
timetypep = (char *)(timep + t.tzh_timecnt);
xtypep = timetypep + t.tzh_timecnt;
charp = xtypep + 6 * t.tzh_typecnt; /* alignment problem */
leapp = (struct ttleap *)(charp + t.tzh_charcnt);
stdp = (char *)(leapp + t.tzh_leapcnt);
gmtp = stdp + t.tzh_ttisstdcnt;
/* Check for invalid file size */
if (tzdata + tzsize != gmtp + t.tzh_ttisgmtcnt)
fprintf(stderr, "Warning: file is %ld bytes, expected %ld\n",
tzsize + sizeof(t),
(gmtp + t.tzh_ttisgmtcnt) - tzdata);
/* Print magic number */
if (magic[0])
printf("TZ magic number is \"%s\" (normally \"TZif\")\n",
magic);
/* Print transition time table */
printf("%ld transition times:\n", t.tzh_timecnt);
for (i = 0; i < t.tzh_timecnt; i++) {
clock = my_ntohl(timep[i]);
/* printf("\tat %ld use type %d\n", clock, timetypep[i]); */
d = gmtime(&clock);
printf("\tat %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d UTC (%ld) use type %d\n",
d->tm_year + 1900, d->tm_mon, d->tm_mday,
d->tm_hour, d->tm_min, d->tm_sec, clock, timetypep[i]);
}
/* Print time types table */
printf("%ld local time types:\n", t.tzh_typecnt);
for (i = 0; i < t.tzh_typecnt; i++) {
typep = (struct ttinfo *)(xtypep + i * 6);
gmtoff = my_ntohl(typep->tt_gmtoff);
if (gmtoff < 0) {
gmtsign = -1;
gmtoff = -gmtoff;
}
else if (gmtoff > 0)
gmtsign = 1;
else
gmtsign = 0;
printf("\ttype %d offset %2.2ld:%2.2ld:%2.2ld %s name (%d) %s",
i, gmtsign*(gmtoff/3600), (gmtoff%3600)/60, gmtoff%60,
typep->tt_isdst ? "isdst " : "notdst",
typep->tt_abbrind,
charp + typep->tt_abbrind);
if (i < t.tzh_ttisstdcnt)
printf(" %s", stdp[i] ? "std" : "wall");
if (i < t.tzh_ttisgmtcnt)
printf(" %s", gmtp[i] ? "gmt" : "local");
printf("\n");
}
/* Print time zone abbreviations */
printf("%ld bytes of abbreviations: [", t.tzh_charcnt);
for (i = 0; i < t.tzh_charcnt; i++)
if (charp[i])
putchar(charp[i]);
else if (i != t.tzh_charcnt - 1)
putchar('|');
printf("]\n");
/* Print leap second table */
printf("%ld leap second entries:\n", t.tzh_leapcnt);
for (i = 0; i < t.tzh_leapcnt; i++)
printf("\tat %ld, TAI - UTC = %ld seconds\n",
my_ntohl(leapp[i].tt_time),
my_ntohl(leapp[i].tt_seconds) + 10);
/* Print counts of gmt/local and std/wall flags (contents
* have already been printed)
*/
printf("%ld std/wall flags\n", t.tzh_ttisstdcnt);
printf("%ld gmt/local flags\n", t.tzh_ttisgmtcnt);
exit(0);
}
-----------------cut here-------------------------------
--
John Cowan http://www.reutershealth.com jcowan at reutershealth.com
Schlingt dreifach einen Kreis vom dies! / Schliess eurer Aug vor heiliger Schau
Den er genoss vom Honig-Tau / Und trank die Milch vom Paradies.
-- Coleridge (tr. Politzer)
More information about the tz
mailing list