America/Chicago zone vs mktime w/tm_isdst!=-1

Olson, Arthur David (NIH/NCI) olsona at dc37a.nci.nih.gov
Fri Nov 28 17:18:25 UTC 2003


The strange Chicago behavior occurs because for a few months back in 1936
Chicago switched to using Eastern Standard Time; mktime ended up using this
information when trying to do a DST correction.

The change below should "fix" things; it convinces mktime to work temporally
backward through time adjustments that have been used in an area when trying
to do a DST correction.
(Of course if you really did start out with a 1936 time this is the wrong
thing to do, but that's fairly unlikely.)

				--ado

------- localtime.c -------
*** /tmp/geta23340	Fri Nov 28 12:10:57 2003
--- /tmp/getb23340	Fri Nov 28 12:10:57 2003
***************
*** 5,11 ****
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.76";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
--- 5,11 ----
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.77";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
***************
*** 1503,1508 ****
--- 1503,1513 ----
  	register time_t			t;
  	register const struct state *	sp;
  	register int			samei, otheri;
+ 	register int			sameind, otherind;
+ 	register int			i;
+ 	register int			nseen;
+ 	int				seen[TZ_MAX_TYPES];
+ 	int				types[TZ_MAX_TYPES];
  	int				okay;
  
  	if (tmp->tm_isdst > 1)
***************
*** 1536,1545 ****
  	if (sp == NULL)
  		return WRONG;
  #endif /* defined ALL_STATE */
! 	for (samei = sp->typecnt - 1; samei >= 0; --samei) {
  		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
  			continue;
! 		for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
  			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
  				continue;
  			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
--- 1541,1560 ----
  	if (sp == NULL)
  		return WRONG;
  #endif /* defined ALL_STATE */
! 	for (i = 0; i < sp->typecnt; ++i)
! 		seen[i] = FALSE;
! 	nseen = 0;
! 	for (i = sp->timecnt - 1; i >= 0; --i)
! 		if (!seen[sp->types[i]]) {
! 			seen[sp->types[i]] = TRUE;
! 			types[nseen++] = sp->types[i];
! 		}
! 	for (sameind = 0; sameind < nseen; ++sameind) {
! 		samei = types[sameind];
  		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
  			continue;
! 		for (otherind = 0; otherind < nseen; ++otherind) {
! 			otheri = types[otherind];
  			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
  				continue;
  			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -


-----Original Message-----
From: tz-request at lecserver.nci.nih.gov
[mailto:tz-request at lecserver.nci.nih.gov] On Behalf Of Olson, Arthur David
(NIH/NCI)
Sent: Tuesday, November 25, 2003 7:40 AM
To: Tz (tz at elsie.nci.nih.gov)
Subject: FW: America/Chicago zone vs mktime w/tm_isdst!=-1


Dan Nelson is not on the time zone mailing list; direct replies
appropriately.

				--ado

-----Original Message-----
From: Dan Nelson [mailto:dnelson at allantgroup.com] 
Sent: Monday, November 24, 2003 6:23 PM
To: tz at lecserver.nci.nih.gov
Subject: America/Chicago zone vs mktime w/tm_isdst!=-1


Here's an interesting problem.  Usually when mktime() is called with
tm_isdst set to 0 or 1, it will interpret the original time as being either
in standard or daylight time according to tm_isdst, and update the resulting
time_t value (and the struct tm) if the DST flag was wrong.

This doesn't seem to happen with the America/Chicago zone.  I've attached a
simple program that passes three struct tm's to mktime, with three values of
tm_isdst each.  For most zones, the first and last times change depending on
what value of tm_isdst is passed in.  For America/Chicago, it looks like
tm_isdst is ignored.  Is it used correctly for the middle time (since it's
in the fall-back range).

Someone filed a FreeBSD PR against this back in June (
http://www.freebsd.org/cgi/query-pr.cgi?pr=53899 ), and I've verified the
behaviour back to FreeBSD 4.0 (which had imported tzcode1999a). 
The classictzcode.tar.gz on elsie.nci.nih.gov looks at tm_isdst in all
cases, so the change happened sometime between 1994 and 1999.  I don't know
if there are archives of tzcode sources, or I could pinpoint the exact
release.

It's not strictly a bug since POSIX basically says that any tm_isdst != -1
results in implementation-defined behaviour, but it's troublesome if the
behaviour changes from zone to zone, and the current releases of Solaris,
Tru64, AIX, and glibc(Linux) are consistent across timezones (they all
adjust the incoming struct tm based on tm_isdst).

And, a couple of POSIX/C99 links for the archives:

http://www.opengroup.org/onlinepubs/007904975/functions/mktime.html
http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_280.htm

-- 
	Dan Nelson
	dnelson at allantgroup.com




More information about the tz mailing list