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

Dan Nelson dnelson at allantgroup.com
Mon Nov 24 23:23:20 UTC 2003


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
-------------- next part --------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int main(int argc, char *argv[])
{
	struct tm tm;
	time_t t;

	putenv("TZ=America/Chicago");

	printf("Testing 1994-10-29 01:00:00 (DST)\n");

	memset(&t, 0, sizeof(t));
	tm.tm_year = 94; tm.tm_mon = 9; tm.tm_mday = 29; tm.tm_hour = 1; tm.tm_min = 0; tm.tm_sec = 0; 
	tm.tm_isdst = 0;
	t = mktime(&tm);
	printf("isdst=0  -> %d, isdst=%d\n", t, tm.tm_isdst);

	memset(&t, 0, sizeof(t));
	tm.tm_year = 94; tm.tm_mon = 9; tm.tm_mday = 29; tm.tm_hour = 1; tm.tm_min = 0; tm.tm_sec = 0; 
	tm.tm_isdst = -1;
	t = mktime(&tm);
	printf("isdst=-1 -> %d, isdst=%d\n", t, tm.tm_isdst);

	memset(&t, 0, sizeof(t));
	tm.tm_year = 94; tm.tm_mon = 9; tm.tm_mday = 29; tm.tm_hour = 1; tm.tm_min = 0; tm.tm_sec = 0; 
	tm.tm_isdst = 1;
	t = mktime(&tm);
	printf("isdst=1  -> %d, isdst=%d\n", t, tm.tm_isdst);

	printf("Testing 1994-10-30 01:00:00 (could be either)\n");

	memset(&t, 0, sizeof(t));
	tm.tm_year = 94; tm.tm_mon = 9; tm.tm_mday = 30; tm.tm_hour = 1; tm.tm_min = 0; tm.tm_sec = 0; 
	tm.tm_isdst = 0;
	t = mktime(&tm);
	printf("isdst=0  -> %d, isdst=%d\n", t, tm.tm_isdst);

	memset(&t, 0, sizeof(t));
	tm.tm_year = 94; tm.tm_mon = 9; tm.tm_mday = 30; tm.tm_hour = 1; tm.tm_min = 0; tm.tm_sec = 0; 
	tm.tm_isdst = -1;
	t = mktime(&tm);
	printf("isdst=-1 -> %d, isdst=%d\n", t, tm.tm_isdst);

	memset(&t, 0, sizeof(t));
	tm.tm_year = 94; tm.tm_mon = 9; tm.tm_mday = 30; tm.tm_hour = 1; tm.tm_min = 0; tm.tm_sec = 0; 
	tm.tm_isdst = 1;
	t = mktime(&tm);

	printf("isdst=1  -> %d, isdst=%d\n", t, tm.tm_isdst);

	printf("Testing 1994-11-01 01:00:00 (not DST)\n");

	memset(&t, 0, sizeof(t));
	tm.tm_year = 94; tm.tm_mon = 10; tm.tm_mday = 01; tm.tm_hour = 1; tm.tm_min = 0; tm.tm_sec = 0; 
	tm.tm_isdst = 0;
	t = mktime(&tm);
	printf("isdst=0  -> %d, isdst=%d\n", t, tm.tm_isdst);

	memset(&t, 0, sizeof(t));
	tm.tm_year = 94; tm.tm_mon = 10; tm.tm_mday = 01; tm.tm_hour = 1; tm.tm_min = 0; tm.tm_sec = 0; 
	tm.tm_isdst = -1;
	t = mktime(&tm);
	printf("isdst=-1 -> %d, isdst=%d\n", t, tm.tm_isdst);

	memset(&t, 0, sizeof(t));
	tm.tm_year = 94; tm.tm_mon = 10; tm.tm_mday = 01; tm.tm_hour = 1; tm.tm_min = 0; tm.tm_sec = 0; 
	tm.tm_isdst = 1;
	t = mktime(&tm);
	printf("isdst=1  -> %d, isdst=%d\n", t, tm.tm_isdst);

	return 0;
}


More information about the tz mailing list