Странное поведение mktime () - PullRequest
       42

Странное поведение mktime ()

1 голос
/ 29 апреля 2019

Почему mktime () конвертирует 31/03/2019 с 02:00 в 01:00 с tm.tm_isdst = 1 с часовым поясом CET?

Я думаю, что это недопустимая комбинация.

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

void reset(struct tm* tm){
    (*tm) = (const struct tm){0};

    tm->tm_sec = 0;
    tm->tm_min = 1;
    tm->tm_hour = 2;
    tm->tm_mon = 2;
    tm->tm_mday = 31;
    tm->tm_year = 2019 - 1900;
}

int main(int argc, char **argv)
{
    struct tm   tm;
    int secs;

    reset(&tm);
    printf("Before mktime\n");
        printf(" %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec);

    tm.tm_isdst = 0;
    secs = mktime(&tm);
                printf("After mktime tm.tm_isdst = 0;\n");
    printf(" %04d-%02d-%02d %02d:%02d:%02d TZ=%s , tm_isdst = %d, timestamp=%i\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tm.tm_isdst, secs);

    reset(&tm);
    tm.tm_isdst = 1;
    secs = mktime(&tm);
    printf("After mktime tm.tm_isdst = 1;\n");
    printf(" %04d-%02d-%02d %02d:%02d:%02d TZ=%s , tm_isdst = %d, timestamp=%i\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tm.tm_isdst, secs);

    reset(&tm);    
    tm.tm_isdst = -1;
    secs = mktime(&tm);
    printf("After mktime tm.tm_isdst = -1\n");
    printf(" %04d-%02d-%02d %02d:%02d:%02d TZ=%s , tm_isdst = %d, timestamp=%i\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tm.tm_isdst, secs);

    return 0;
}

Выход:

% date
Sun Mar 31 06:50:42 CEST 2019
% test_mktime
Before mktime
 2019-03-31 02:01:00
After mktime tm.tm_isdst = 0;
 2019-03-31 03:01:00 TZ=CEST , tm_isdst = 1, timestamp=1553994060
After mktime tm.tm_isdst = 1;
 2019-03-31 01:01:00 TZ=CET , tm_isdst = 0, timestamp=1553990460
After mktime tm.tm_isdst = -1
 2019-03-31 03:01:00 TZ=CEST , tm_isdst = 1, timestamp=1553994060

Ответы [ 2 ]

2 голосов
/ 29 апреля 2019
  1. 2019-03-31 02:01:00 CET (is_dst = 0, UTC + 1) не существует, но эквивалентно 2019-03-31 01:01:00 UTC (1553994060 секунд послеэпоху), что эквивалентно 2019-03-31 03:01:00 CEST (is_dst = 1, UTC + 2).
  2. 2019-03-31 02:01:00 CEST (is_dst = 1, UTC + 2) не существует, но эквивалентно 2019-03-31 00:01:00 UTC (1553990460 секунд после эпохи), что эквивалентно 2019-03-31 01:01:00 CET (is_dst = 0, UTC + 1).(Примечание: 1553994060 - 1553990460 = 3600, что составляет разницу в 1 час.)
  3. Для is_dst = -1 реализация пытается выяснить, действует ли переход на летнее время, но с 2019-03-31 02: 01: 00 одинаково недействителен как для CET, так и для CEST, он просто выбирает одно или другое.В этом случае предполагалось, что ввод был в стандартном времени 2019-03-31 02:01:00 CET (is_dst = 0, UTC + 1), который не существует, но эквивалентен 2019-03-31 01:01:00 UTC (1553994060 секунд после эпохи), что эквивалентно 2019-03-31 03:01:00 CEST (is_dst = 1, UTC + 2).
1 голос
/ 29 апреля 2019

Поскольку 02:00, 31 марта 2019 г., время перехода на летнее время изменения региона CET / CEST, время с часом 2 на эту дату не используется для отсчета времени в этой области.mktime задокументировано для нормализации данных на входе struct tm, и это вступает в действие здесь.

В частности,

  • , если отметка времени 2019-03-31 02:01:00 интерпретируется согласно стандартному времени, другими словами, как время через час после 01:01:00, тогда оно соответствует 2019-03-31 03:01:00 CEST.Вот как нормализуется struct tm, как показывает ваша программа.Возвращаемое значение соответствует этому времени.

  • , если метка времени 2019-03-31 02:01:00 интерпретируется в соответствии с летним временем, другими словами, как время один часдо 03:01:00, тогда это соответствует 2019-03-31 01:01:00 CET.Вот как нормализуется struct tm, как показывает ваша программа.Возвращаемое значение соответствует этому времени и представляет собой время на 3600 секунд раньше, чем значение, возвращенное в другом случае.

  • , если указать, что неизвестно, является ли данное времядля интерпретации, как если бы действовал DST, тогда mktime должен угадать.Для большинства времени и дат он будет выбирать в зависимости от того, действует ли DST для этой даты и времени, но здесь это не дает никакого ответа.Мне кажется разумным, что на самом деле он интерпретирует стандартное время вместо летнего времени здесь, потому что это, скорее всего, будет ожиданием программы, которая обеспечивает такой ввод.

...