I played with mktime and I noticed strange and inconsistent behavior.
I give it a date that is absent during daylight saving time (DST), but with tm_isdst set to 1, which usually mktime makes tm_isdst change to 0 and adjusts the time accordingly, shifting by 1 hour.
However, in a period of time, approximately in 1928. 1933 (could not find another range), the behavior is different. The tm_isdst field is set to 0, but the time does not change. This leads to weirdness when doing time calculations, etc.
I have a tiny test program that prints for a given input date: the original struct tm, struct tm after calling mktime on it, the result of mktime and struct tm, which is the result of calling localtime on the result mktime (should represent the same point in time as source).
Output:
2013-01-01 12:00:00 (off=0, dst=1) -> 2013-01-01 11:00:00 (off=-28800, dst=0) -> 1357066800 -> 2013-01-01 11:00:00 (off=-28800, dst=0) 1927-01-01 12:00:00 (off=0, dst=1) -> 1927-01-01 11:00:00 (off=-28800, dst=0) -> -1356930000 -> 1927-01-01 11:00:00 (off=-28800, dst=0) 1929-01-01 12:00:00 (off=0, dst=1) -> 1929-01-01 12:00:00 (off=-28800, dst=0) -> -1293768000 -> 1929-01-01 12:00:00 (off=-28800, dst=0) 1932-01-01 12:00:00 (off=0, dst=1) -> 1932-01-01 12:00:00 (off=-28800, dst=0) -> -1199160000 -> 1932-01-01 12:00:00 (off=-28800, dst=0) 1934-01-01 12:00:00 (off=0, dst=1) -> 1934-01-01 11:00:00 (off=-28800, dst=0) -> -1136005200 -> 1934-01-01 11:00:00 (off=-28800, dst=0)
See that for many years 2013, 1927, 1934, the hour has changed, and dst is set to 0. But in 1929 and 1932 the hour has not changed, but there is dst.
What is super strange is that tzinfo has nothing about this time range - zdump for Los Angeles shows that the closest changes occurred in 1919 and 1942.
This is in CentOS, kernel 2.6.32-358.11.1.el6.x86_64, glibc-2.12-1.107.el6.x86_64.
Further research seems to work as expected (sequentially) on MacOSX. So it looks like an error in mktime () for me, but maybe I missed something.
The test program below and is also available here.
#include <time.h> #include <stdio.h> #include <string.h> #include <stdlib.h> char* printtm(struct tm tm) { static char buf[100]; sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d (off=%ld, dst=%d)", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_gmtoff, tm.tm_isdst); return buf; } void test(int y, int m, int d, int hh, int mm, int ss, int isdst) { // Prepare tm structs struct tm tm, tm2; memset(&tm, 0, sizeof(tm)); memset(&tm2, 0, sizeof(tm)); tm.tm_year = y - 1900; tm.tm_mon = m - 1; tm.tm_mday = d; tm.tm_hour = hh; tm.tm_min = mm; tm.tm_sec = ss; tm.tm_isdst = isdst; // Convert tm -> t -> tm and print printf("%s -> ", printtm(tm)); time_t t = mktime(&tm); printf("%s -> ", printtm(tm)); printf("%12ld -> ", t); localtime_r(&t, &tm2); printf("%s\n", printtm(tm)); } int main() { setenv("TZ", ":America/Los_Angeles", 1); tzset(); test(2013,07,01, 12,0,0, 1); test(2013,01,01, 12,0,0, 1); test(1927,01,01, 12,0,0, 1); test(1929,01,01, 12,0,0, 1); test(1932,01,01, 12,0,0, 1); test(1934,01,01, 12,0,0, 1); return 0; }