Мы знаем, что часовой пояс UTC + 8 имеет некоторые изменения часов. Например, 1 января 1928 года, 00:00:00 часы были повернуты назад 0:05:52 часов до 31 декабря 1927 года, 23:54:08.
Кроме того, в 1940-1941 и 1986-1991 годах использовалось летнее время. Когда я тестирую функцию mktime
под linux с этими датами, у меня разные значения возврата. Код выглядит следующим образом:
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(int argc, char *argv[])
{
struct tm timeinfo;
memset(&timeinfo, 0, sizeof(timeinfo));
while(fscanf(stdin, "%d%d%d%d%d%d",
&timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday,
&timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec) != EOF)
{
timeinfo.tm_year -= 1900;
timeinfo.tm_mon -= 1;
fprintf(stdout, "%lld\n", mktime(&timeinfo));
}
return 0;
}
Например, тестовый ввод и вывод аналогичны тому, что тот же ввод "1940 6 2 23 59 59" и "1940 6 3 1 0 0" будет иметь другое возвращаемое значение в зависимости от вызывающей последовательности:
1940 6 2 23 59 59
-933494401
1940 6 3 1 0 0
-933490800
1940 6 3 1 0 0
-933494400
1940 6 2 23 59 59
-933498001
1940 6 2 23 59 59
-933494401
Тот же ввод 1940 6 3 1 0 0
Почему это? Почему возвращаемое значение mktime
отличается в зависимости от вызывающей последовательности?
Я прочитал некоторую версию исходного кода mktime
но не нашел никакой части кода, который может вызвать эту проблему.
Может ли кто-нибудь объяснить, почему это происходит? Большое спасибо.
Недавно добавленные случаи:
1927 12 31 23 54 8
-1325491552
1927 12 31 23 54 7
-1325491905
1927 12 31 23 54 8
-1325491904
1928 1 1 0 0 0
-1325491200
1927 12 31 23 54 8
-1325491552
Вы начинаете с timeinfo.tm_isdst
установленного в 0, который запрашивает mktime
считать время как не-DST.
mktime
затем нормализует переданную struct tm
так, чтобы поля находились в их соответствующих диапазонах; часть этого процесса будет корректировать флаг DST в зависимости от того, действовал ли DST в указанное время. (См. Документацию.) Если DST действует, он установит этот флаг в положительное значение и соответствующим образом отрегулирует другие поля struct tm
.
Позже итерации вашего цикла будут перезаписывать шесть полей, переданных вашему fscanf
, но не поле DST. Таким образом, если более ранняя итерация цикла привела к тому, что этот флаг установлен, на более поздней итерации все еще будет установлен флаг. В результате вы фактически не передаете одно и то же время в mktime
, и оно возвращает разные результаты.
С того, что вы печатаете, сценарий выглядит следующим образом:
1940 6 2 23 59 59 // tm_isdst == 0, asks mktime to consider this non-DST, and DST not in effect at this time
-933494401 // tm_isdst still 0
1940 6 3 1 0 0 // tm_isdst == 0, asks mktime to consider this non-DST, but at this time DST was in effect
-933490800 // tm_isdst now positive
1940 6 3 1 0 0 // tm_isdst > 0, asks mktime to consider this DST, and DST was actually in effect
-933494400 // tm_isdst still positive
1940 6 2 23 59 59 // tm_isdst > 0, asks mktime to consider this DST, but actually DST wasn't in effect
-933498001 // tm_isdst becomes 0
1940 6 2 23 59 59 // tm_isdst == 0, asks mktime to consider this non-DST
-933494401 // tm_isdst still 0
Демо.
Проблема, вероятно, mktime
не с mktime
а с sscanf
. Я не могу проверить его, потому что для меня работает ваш пример (ну, я не уверен, что это правильное время, но оно непротиворечиво), но очень вероятно, что scanf
читает меньше чисел, чем следовало бы, и таким образом вход от предыдущего линия смешивается с текущей.
fscanf
имеет проблемы с концами строк, поэтому проверьте возвращаемое значение (должно быть 6
). Попробуйте прочитать строку за строкой с помощью fgets
в буфер, а затем используйте sscanf
.
while(fscanf(stdin, "%d%d%d%d%d%d", ...) == 6)
mktime(&timeinfo)
используйтеtimeinfo.tm_isdst = -1
(DST недоступен), чтобы избежать наследования предыдущего значения. Толькоtm_wday
иtm_yday
можно оставить неинициализированными.