Функция mktime LIBC возвращает разные значения для одного и того же ввода

0

Мы знаем, что часовой пояс 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
  • 0
    Предложить: лучше использовать while(fscanf(stdin, "%d%d%d%d%d%d", ...) == 6)
  • 0
    Перед вызовом mktime(&timeinfo) используйте timeinfo.tm_isdst = -1 (DST недоступен), чтобы избежать наследования предыдущего значения. Только tm_wday и tm_yday можно оставить неинициализированными.
Показать ещё 3 комментария
Теги:
timezone
glibc
mktime

2 ответа

2
Лучший ответ

Вы начинаете с 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

Демо.

  • 0
    это может объяснить первое и второе отличия, но не объясняет второй и третий вызов. поле DST уже установлено там, как mktime устанавливает его. Кроме того, я не уверен, что верю вам в то, что mktime настроит свой ввод. Я был бы ужасно плохим дизайном.
  • 1
    @EvanDark Не стесняйтесь обращаться к документации самостоятельно, если вы мне не верите.
Показать ещё 5 комментариев
0

Проблема, вероятно, mktime не с mktime а с sscanf. Я не могу проверить его, потому что для меня работает ваш пример (ну, я не уверен, что это правильное время, но оно непротиворечиво), но очень вероятно, что scanf читает меньше чисел, чем следовало бы, и таким образом вход от предыдущего линия смешивается с текущей.

fscanf имеет проблемы с концами строк, поэтому проверьте возвращаемое значение (должно быть 6). Попробуйте прочитать строку за строкой с помощью fgets в буфер, а затем используйте sscanf.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню