Я играл с mktime и заметил странное и непоследовательное поведение.
Я предоставляю ему дату, которая не во время DST (летнее время), но с tm_isdst, установленным на 1, что обычно делает mktime, это изменяет tm_isdst на 0 и соответствующим образом корректирует время, сдвигая на 1 час.
Однако во временном периоде примерно в 1928..1933 годах (другого диапазона не нашел) поведение другое. Поле tm_isdst установлено в 0, но время не меняется. Это приводит к странностям при выполнении вычислений времени и т. д.
У меня есть крошечная тестовая программа, которая для заданной даты ввода печатает: исходную структуру tm, структуру tm после вызова для нее mktime, результат mktime и структуру tm, которая является результатом вызова localtime для результата mktime (должна представлять тот же момент в время как исходное).
Результат:
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)
Обратите внимание, что для 2013, 1927, 1934 годов часы меняются, а летнее время устанавливается равным 0. Но в 1929 и 1932 годах часы не меняются, а летнее время изменяется.
Что очень странно, так это то, что в tzinfo нет ничего об этом временном диапазоне — zdump для Лос-Анджелеса показывает, что самые близкие изменения приходятся на 1919 и 1942 годы.
Это на CentOS, ядро 2.6.32-358.11.1.el6.x86_64, glibc-2.12-1.107.el6.x86_64.
Дальнейшее исследование, кажется, работает, как и ожидалось (стабильно) на MacOSX. Так что для меня это выглядит как ошибка в mktime(), но, возможно, я что-то упускаю.
Программа тестового тестирования приведена ниже, а также доступна здесь
#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;
}
time_t
32- или 64-разрядной (даже если вы все еще безопасно работаете в 32-разрядном диапазоне). - person R.. GitHub STOP HELPING ICE   schedule 06.12.2013