proposed time zone package changes (Hawaii, stack overflow, et al.)

Arthur David Olson olsona at lecserver.nci.nih.gov
Wed Jan 12 16:24:53 UTC 2011


Below find proposed changes to the time zone package.
None of these changes affect current time stamps.
The executive summary:

*	Theory		Add section on scope of the database.
*	australasia	Simplification and gratuitous optimization of
			South Australia rules.
*	localtime.c	In the function tzload, if ALL_STATE is defined, 
			use allocated memory for a large structure rather
			than using the stack (based on changes suggested
			by Ted Unangst).
*	northamerica	Changes to Hawaiian time history (from an
			article by Schmitt and Cox): abandoned local mean
			time in 1986 rather than 1900; used DST during
			World War II.
*	tz-art.htm	Add DST joke from first episode of "Conan."
*	tz-link.htm	Align instructions with those in "README"
			(as suggested by Gilles Espinasse).

If no problems are found, these changes will appear in tzcode2011a.tar.gz
and tzdata2011.tar.gz on 2011-11-23.

				--ado

diff -r -c old/Theory new/Theory
*** old/Theory	Tue Oct 12 12:36:50 2010
--- new/Theory	Wed Jan 12 10:36:11 2011
***************
*** 1,4 ****
! @(#)Theory	8.5
  This file is in the public domain, so clarified as of
  2009-05-17 by Arthur David Olson.
  
--- 1,4 ----
! @(#)Theory	8.6
  This file is in the public domain, so clarified as of
  2009-05-17 by Arthur David Olson.
  
***************
*** 5,11 ****
  ----- Outline -----
  
  	Time and date functions
! 	Names of time zone regions
  	Time zone abbreviations
  	Calendrical issues
  	Time and time zones on Mars
--- 5,12 ----
  ----- Outline -----
  
  	Time and date functions
! 	Scope of the tz database
! 	Names of time zone rule files
  	Time zone abbreviations
  	Calendrical issues
  	Time and time zones on Mars
***************
*** 192,197 ****
--- 193,223 ----
  better.
  
  
+ ----- Scope of the tz database -----
+ 
+ The tz database attempts to record the history and predicted future of 
+ all computer-based clocks that track civil time.  To represent this 
+ data, the world is partitioned into regions whose clocks all agree 
+ about time stamps that occur after the somewhat-arbitrary cutoff point 
+ of the POSIX Epoch (1970-01-01 00:00:00 UTC).  For each such region, 
+ the database records all known clock transitions, and labels the region 
+ with a notable location.
+ 
+ Clock transitions before 1970 are recorded for each such location, 
+ because most POSIX-compatible systems support negative time stamps and 
+ could misbehave if data were omitted for pre-1970 transitions.
+ However, the database is not designed for and does not suffice for 
+ applications requiring accurate handling of all past times everywhere, 
+ as it would take far too much effort and guesswork to record all 
+ details of pre-1970 civil timekeeping.
+ 
+ As noted in the README file, the tz database is not authoritative 
+ (particularly not for pre-1970 time stamps), and it surely has errors.
+ Corrections are welcome and encouraged.  Users requiring authoritative 
+ data should consult national standards bodies and the references cited 
+ in the database's comments.
+ 
+ 
  ----- Names of time zone rule files -----
  
  The time zone rule file naming conventions attempt to strike a balance
diff -r -c old/australasia new/australasia
*** old/australasia	Mon Nov  1 09:18:22 2010
--- new/australasia	Wed Jan 12 11:03:44 2011
***************
*** 1,5 ****
  # <pre>
! # @(#)australasia	8.20
  # This file is in the public domain, so clarified as of
  # 2009-05-17 by Arthur David Olson.
  
--- 1,5 ----
  # <pre>
! # @(#)australasia	8.22
  # This file is in the public domain, so clarified as of
  # 2009-05-17 by Arthur David Olson.
  
***************
*** 84,97 ****
  Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	-
  Rule	AS	1972	only	-	Feb	27	2:00s	0	-
  Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	-
! Rule	AS	1986	1989	-	Mar	Sun>=15	2:00s	0	-
! Rule	AS	1990	only	-	Mar	Sun>=18	2:00s	0	-
! Rule	AS	1991	only	-	Mar	Sun>=1	2:00s	0	-
! Rule	AS	1992	only	-	Mar	Sun>=18	2:00s	0	-
! Rule	AS	1993	only	-	Mar	Sun>=1	2:00s	0	-
! Rule	AS	1994	only	-	Mar	Sun>=18	2:00s	0	-
  Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	-
! Rule	AS	2006	only	-	Apr	Sun>=1	2:00s	0	-
  Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	-
  Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	-
  Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
--- 84,96 ----
  Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	-
  Rule	AS	1972	only	-	Feb	27	2:00s	0	-
  Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	-
! Rule	AS	1986	1990	-	Mar	Sun>=15	2:00s	0	-
! Rule	AS	1991	only	-	Mar	3	2:00s	0	-
! Rule	AS	1992	only	-	Mar	22	2:00s	0	-
! Rule	AS	1993	only	-	Mar	7	2:00s	0	-
! Rule	AS	1994	only	-	Mar	20	2:00s	0	-
  Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	-
! Rule	AS	2006	only	-	Apr	2	2:00s	0	-
  Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	-
  Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	-
  Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
diff -r -c old/localtime.c new/localtime.c
*** old/localtime.c	Tue Oct 12 12:36:51 2010
--- new/localtime.c	Thu Dec 16 12:25:20 2010
***************
*** 5,11 ****
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	8.15";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
--- 5,11 ----
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	8.16";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
***************
*** 337,352 ****
  	register int			fid;
  	register int			stored;
  	register int			nread;
! 	union {
  		struct tzhead	tzhead;
  		char		buf[2 * sizeof(struct tzhead) +
  					2 * sizeof *sp +
  					4 * TZ_MAX_TIMES];
! 	} u;
  
  	sp->goback = sp->goahead = FALSE;
  	if (name == NULL && (name = TZDEFAULT) == NULL)
! 		return -1;
  	{
  		register int	doaccess;
  		/*
--- 337,362 ----
  	register int			fid;
  	register int			stored;
  	register int			nread;
! 	typedef union {
  		struct tzhead	tzhead;
  		char		buf[2 * sizeof(struct tzhead) +
  					2 * sizeof *sp +
  					4 * TZ_MAX_TIMES];
! 	} u_t;
! #ifdef ALL_STATE
! 	register u_t *			up;
  
+ 	up = (u_t *) calloc(1, sizeof *up);
+ 	if (up == NULL)
+ 		return -1;
+ #else /* !defined ALL_STATE */
+ 	u_t				u;
+ 	register u_t * const		up = &u;
+ #endif /* !defined ALL_STATE */
+ 
  	sp->goback = sp->goahead = FALSE;
  	if (name == NULL && (name = TZDEFAULT) == NULL)
! 		goto oops;
  	{
  		register int	doaccess;
  		/*
***************
*** 363,371 ****
  		doaccess = name[0] == '/';
  		if (!doaccess) {
  			if ((p = TZDIR) == NULL)
! 				return -1;
  			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
! 				return -1;
  			(void) strcpy(fullname, p);
  			(void) strcat(fullname, "/");
  			(void) strcat(fullname, name);
--- 373,381 ----
  		doaccess = name[0] == '/';
  		if (!doaccess) {
  			if ((p = TZDIR) == NULL)
! 				goto oops;
  			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
! 				goto oops;
  			(void) strcpy(fullname, p);
  			(void) strcat(fullname, "/");
  			(void) strcat(fullname, name);
***************
*** 377,400 ****
  			name = fullname;
  		}
  		if (doaccess && access(name, R_OK) != 0)
! 			return -1;
  		if ((fid = open(name, OPEN_MODE)) == -1)
! 			return -1;
  	}
! 	nread = read(fid, u.buf, sizeof u.buf);
  	if (close(fid) < 0 || nread <= 0)
! 		return -1;
  	for (stored = 4; stored <= 8; stored *= 2) {
  		int		ttisstdcnt;
  		int		ttisgmtcnt;
  
! 		ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
! 		ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
! 		sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
! 		sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
! 		sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
! 		sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
! 		p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
  		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
  			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
  			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
--- 387,410 ----
  			name = fullname;
  		}
  		if (doaccess && access(name, R_OK) != 0)
! 			goto oops;
  		if ((fid = open(name, OPEN_MODE)) == -1)
! 			goto oops;
  	}
! 	nread = read(fid, up->buf, sizeof up->buf);
  	if (close(fid) < 0 || nread <= 0)
! 		goto oops;
  	for (stored = 4; stored <= 8; stored *= 2) {
  		int		ttisstdcnt;
  		int		ttisgmtcnt;
  
! 		ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
! 		ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
! 		sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt);
! 		sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt);
! 		sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt);
! 		sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt);
! 		p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt;
  		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
  			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
  			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
***************
*** 401,408 ****
  			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
  			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
  			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
! 				return -1;
! 		if (nread - (p - u.buf) <
  			sp->timecnt * stored +		/* ats */
  			sp->timecnt +			/* types */
  			sp->typecnt * 6 +		/* ttinfos */
--- 411,418 ----
  			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
  			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
  			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
! 				goto oops;
! 		if (nread - (p - up->buf) <
  			sp->timecnt * stored +		/* ats */
  			sp->timecnt +			/* types */
  			sp->typecnt * 6 +		/* ttinfos */
***************
*** 410,416 ****
  			sp->leapcnt * (stored + 4) +	/* lsinfos */
  			ttisstdcnt +			/* ttisstds */
  			ttisgmtcnt)			/* ttisgmts */
! 				return -1;
  		for (i = 0; i < sp->timecnt; ++i) {
  			sp->ats[i] = (stored == 4) ?
  				detzcode(p) : detzcode64(p);
--- 420,426 ----
  			sp->leapcnt * (stored + 4) +	/* lsinfos */
  			ttisstdcnt +			/* ttisstds */
  			ttisgmtcnt)			/* ttisgmts */
! 				goto oops;
  		for (i = 0; i < sp->timecnt; ++i) {
  			sp->ats[i] = (stored == 4) ?
  				detzcode(p) : detzcode64(p);
***************
*** 419,425 ****
  		for (i = 0; i < sp->timecnt; ++i) {
  			sp->types[i] = (unsigned char) *p++;
  			if (sp->types[i] >= sp->typecnt)
! 				return -1;
  		}
  		for (i = 0; i < sp->typecnt; ++i) {
  			register struct ttinfo *	ttisp;
--- 429,435 ----
  		for (i = 0; i < sp->timecnt; ++i) {
  			sp->types[i] = (unsigned char) *p++;
  			if (sp->types[i] >= sp->typecnt)
! 				goto oops;
  		}
  		for (i = 0; i < sp->typecnt; ++i) {
  			register struct ttinfo *	ttisp;
***************
*** 429,439 ****
  			p += 4;
  			ttisp->tt_isdst = (unsigned char) *p++;
  			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
! 				return -1;
  			ttisp->tt_abbrind = (unsigned char) *p++;
  			if (ttisp->tt_abbrind < 0 ||
  				ttisp->tt_abbrind > sp->charcnt)
! 					return -1;
  		}
  		for (i = 0; i < sp->charcnt; ++i)
  			sp->chars[i] = *p++;
--- 439,449 ----
  			p += 4;
  			ttisp->tt_isdst = (unsigned char) *p++;
  			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
! 				goto oops;
  			ttisp->tt_abbrind = (unsigned char) *p++;
  			if (ttisp->tt_abbrind < 0 ||
  				ttisp->tt_abbrind > sp->charcnt)
! 					goto oops;
  		}
  		for (i = 0; i < sp->charcnt; ++i)
  			sp->chars[i] = *p++;
***************
*** 458,464 ****
  				ttisp->tt_ttisstd = *p++;
  				if (ttisp->tt_ttisstd != TRUE &&
  					ttisp->tt_ttisstd != FALSE)
! 						return -1;
  			}
  		}
  		for (i = 0; i < sp->typecnt; ++i) {
--- 468,474 ----
  				ttisp->tt_ttisstd = *p++;
  				if (ttisp->tt_ttisstd != TRUE &&
  					ttisp->tt_ttisstd != FALSE)
! 						goto oops;
  			}
  		}
  		for (i = 0; i < sp->typecnt; ++i) {
***************
*** 471,477 ****
  				ttisp->tt_ttisgmt = *p++;
  				if (ttisp->tt_ttisgmt != TRUE &&
  					ttisp->tt_ttisgmt != FALSE)
! 						return -1;
  			}
  		}
  		/*
--- 481,487 ----
  				ttisp->tt_ttisgmt = *p++;
  				if (ttisp->tt_ttisgmt != TRUE &&
  					ttisp->tt_ttisgmt != FALSE)
! 						goto oops;
  			}
  		}
  		/*
***************
*** 504,514 ****
  		/*
  		** If this is an old file, we're done.
  		*/
! 		if (u.tzhead.tzh_version[0] == '\0')
  			break;
! 		nread -= p - u.buf;
  		for (i = 0; i < nread; ++i)
! 			u.buf[i] = p[i];
  		/*
  		** If this is a narrow integer time_t system, we're done.
  		*/
--- 514,524 ----
  		/*
  		** If this is an old file, we're done.
  		*/
! 		if (up->tzhead.tzh_version[0] == '\0')
  			break;
! 		nread -= p - up->buf;
  		for (i = 0; i < nread; ++i)
! 			up->buf[i] = p[i];
  		/*
  		** If this is a narrow integer time_t system, we're done.
  		*/
***************
*** 516,528 ****
  			break;
  	}
  	if (doextend && nread > 2 &&
! 		u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
  		sp->typecnt + 2 <= TZ_MAX_TYPES) {
  			struct state	ts;
  			register int	result;
  
! 			u.buf[nread - 1] = '\0';
! 			result = tzparse(&u.buf[1], &ts, FALSE);
  			if (result == 0 && ts.typecnt == 2 &&
  				sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
  					for (i = 0; i < 2; ++i)
--- 526,538 ----
  			break;
  	}
  	if (doextend && nread > 2 &&
! 		up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
  		sp->typecnt + 2 <= TZ_MAX_TYPES) {
  			struct state	ts;
  			register int	result;
  
! 			up->buf[nread - 1] = '\0';
! 			result = tzparse(&up->buf[1], &ts, FALSE);
  			if (result == 0 && ts.typecnt == 2 &&
  				sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
  					for (i = 0; i < 2; ++i)
***************
*** 566,572 ****
--- 576,590 ----
  					break;
  		}
  	}
+ #ifdef ALL_STATE
+ 	(void) free((void *) up);
+ #endif /* defined ALL_STATE */
  	return 0;
+ oops:
+ #ifdef ALL_STATE
+ 	(void) free((void *) up);
+ #endif /* defined ALL_STATE */
+ 	return -1;
  }
  
  static int
diff -r -c old/northamerica new/northamerica
*** old/northamerica	Mon Nov  1 09:18:22 2010
--- new/northamerica	Thu Dec 16 16:58:32 2010
***************
*** 1,5 ****
  # <pre>
! # @(#)northamerica	8.34
  # This file is in the public domain, so clarified as of
  # 2009-05-17 by Arthur David Olson.
  
--- 1,5 ----
  # <pre>
! # @(#)northamerica	8.36
  # This file is in the public domain, so clarified as of
  # 2009-05-17 by Arthur David Olson.
  
***************
*** 471,490 ****
  #  three votes for and one against."
  
  # Hawaii
! #
! # From Arthur David Olson:
! # And then there's Hawaii.
! # DST was observed for one day in 1933;
! # standard time was changed by half an hour in 1947;
! # it's always standard as of 1986.
! #
! # From Paul Eggert:
! # Shanks says the 1933 experiment lasted for three weeks.  Go with Shanks.
! #
! Zone Pacific/Honolulu	-10:31:26 -	LMT	1900 Jan  1 12:00
! 			-10:30	-	HST	1933 Apr 30 2:00
  			-10:30	1:00	HDT	1933 May 21 2:00
! 			-10:30	US	H%sT	1947 Jun  8 2:00
  			-10:00	-	HST
  
  # Now we turn to US areas that have diverged from the consensus since 1970.
--- 471,504 ----
  #  three votes for and one against."
  
  # Hawaii
! 
! # From Arthur David Olson (2010-12-09):
! # "Hawaiian Time" by Robert C. Schmitt and Doak C. Cox appears on pages 207-225
! # of volume 26 of The Hawaian Journal of History (1992). As of 2010-12-09,
! # the article is available at
! # <a href="http://evols.library.manoa.hawaii.edu/bitstream/10524/239/2/jl26215.pdf">
! # http://evols.library.manoa.hawaii.edu/bitstream/10524/239/2/jl26215.pdf
! # </a>
! # and indicates that standard time was adopted effective noon, January
! # 13, 1896 (page 218), that in "1933, the Legislature decreed daylight
! # saving for the period between the last Sunday of each April and the
! # last Sunday of each September, but less than a month later repealed the
! # act," (page 220), that year-round daylight saving time was in effect
! # from 1942-02-09 to 1945-09-30 (page 221, with no time of day given for
! # when clocks changed) and that clocks were changed by 30 minutes
! # effective the second Sunday of June, 1947 (page 219, with no time of
! # day given for when clocks changed). A footnote for the 1933 changes
! # cites Session Laws of Hawaii 1933, "Act. 90 (approved 26 Apr. 1933)
! # and Act 163 (approved 21 May 1933)." Unless the Act was approved very
! # early on the 21st, the time for transition out of DST in 1933 below
! # is wrong.
! 
! Zone Pacific/Honolulu	-10:31:26 -	LMT	1896 Jan 13 12:00 #Schmitt&Cox
! 			-10:30	-	HST	1933 Apr 30 2:00 #Schmitt&Cox+2
  			-10:30	1:00	HDT	1933 May 21 2:00
! 			-10:30	1:00	HST	1942 Feb 09 2:00 #Schmitt&Cox+2
! 			-10:30	-	HDT	1945 Sep 30 2:00 #Schmitt&Fox+2
! 			-10:30	US	H%sT	1947 Jun  8 2:00 #Schmitt&Fox+2
  			-10:00	-	HST
  
  # Now we turn to US areas that have diverged from the consensus since 1970.
diff -r -c old/tz-art.htm new/tz-art.htm
*** old/tz-art.htm	Tue Oct 12 12:36:52 2010
--- new/tz-art.htm	Wed Jan 12 10:56:44 2011
***************
*** 9,15 ****
  <body>
  <h1>Time and the Arts</h1>
  <address>
! @(#)tz-art.htm	8.17
  </address>
  <p>
  This file is in the public domain, so clarified as of
--- 9,15 ----
  <body>
  <h1>Time and the Arts</h1>
  <address>
! @(#)tz-art.htm	8.18
  </address>
  <p>
  This file is in the public domain, so clarified as of
***************
*** 467,472 ****
--- 467,479 ----
  It is already tomorrow in Australia."
  (Charles M. Schulz, provided by Steve Summit)
  </li>
+ <li>
+ "I put myself and my staff through this crazy, huge ordeal, all because
+ I refused to go on at midnight, okay?  And so I work, you know, and
+ then I get this job at eleven, supposed to be a big deal.  Then
+ yesterday daylight [saving] time ended. Right now it's basically
+ midnight." (Conan O'Brien on the 2010-11-08 premier of "Conan.")
+ </li>
  </ul>
  </body>
  </html>
diff -r -c old/tz-link.htm new/tz-link.htm
*** old/tz-link.htm	Tue Oct 12 12:36:52 2010
--- new/tz-link.htm	Wed Jan 12 10:40:27 2011
***************
*** 18,24 ****
  <body>
  <h1>Sources for Time Zone and Daylight Saving Time Data</h1>
  <address>
! @(#)tz-link.htm	8.30
  </address>
  <p>
  This file is in the public domain, so clarified as of
--- 18,24 ----
  <body>
  <h1>Sources for Time Zone and Daylight Saving Time Data</h1>
  <address>
! @(#)tz-link.htm	8.31
  </address>
  <p>
  This file is in the public domain, so clarified as of
***************
*** 96,102 ****
  these files to a <abbr>GNU</abbr>/Linux or similar host;
  see the downloaded
  <code>README</code> file for what to do next.</p>
! <pre style="margin-left: 2em"><code><a href="http://www.gnu.org/software/wget/">wget</a> 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
  <a href="http://www.gnu.org/software/gzip/">gzip</a> -dc tzcode*.tar.gz | <a href="http://www.gnu.org/software/tar/">tar</a> -xf -
  gzip -dc tzdata*.tar.gz | tar -xf -
  </code></pre>
--- 96,104 ----
  these files to a <abbr>GNU</abbr>/Linux or similar host;
  see the downloaded
  <code>README</code> file for what to do next.</p>
! <pre style="margin-left: 2em"><code>mkdir tz
! cd tz
! <a href="http://www.gnu.org/software/wget/">wget</a> 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
  <a href="http://www.gnu.org/software/gzip/">gzip</a> -dc tzcode*.tar.gz | <a href="http://www.gnu.org/software/tar/">tar</a> -xf -
  gzip -dc tzdata*.tar.gz | tar -xf -
  </code></pre>



More information about the tz mailing list