mktime и tm_isdst - PullRequest
       38

mktime и tm_isdst

14 голосов
/ 19 декабря 2011

Я видел много разных взглядов, поэтому подумал спросить здесь.

Я читаю man mktime:

 (A positive or zero value for tm_isdst causes mktime() to presume initially
 that summer time (for example, Daylight Saving Time) is or is not in
 effect for the specified time, respectively.  A negative value for
 tm_isdst causes the mktime() function to attempt to divine whether summer
 time is in effect for the specified time. 

Мой вопрос заключается в том, не следует ли оставить tm_isdst как -1, чтобы позволить системе решить, является ли она dst или нет, и таким образом код становится независимым от dst?

Я что-то упустил?

Ответы [ 3 ]

10 голосов
/ 24 августа 2012

Вам следует избегать установки tm_isdst в -1, если это возможно. Система не всегда может определить состояние летнего времени только по дате и времени. Это неоднозначно час до и после окончания летнего времени. Например, если вы передаете mktime() 1:30 AM 4 ноября 2012 г., этого недостаточно для получения правильного значения time_t из mktime(). Обычно я видел mktime() предполагаемое стандартное время в случае его неоднозначности, но я не видел никакой документации, которая бы гарантировала такое поведение на всех платформах. 1:30 утра 4 ноября 2012 года с tm_isdst == 1 будет на 1 час раньше, потому что час с 1:00:00 до 1:59:59 повторяется.

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

int main()
{
    time_t daylight, standard;
    struct tm timestr;
    double diff;

    timestr.tm_year = 2012 - 1900;
    timestr.tm_mon = 11 - 1;
    timestr.tm_mday = 4;
    timestr.tm_hour = 1;
    timestr.tm_min = 30;
    timestr.tm_sec = 0;

    /* first with standard time */
    timestr.tm_isdst = 0;
    standard = mktime(&timestr);

    /* now with daylight time */
    timestr.tm_isdst = 1;
    daylight = mktime(&timestr);

    diff = difftime(standard, daylight);

    printf("Difference is %f hour(s)", diff/60.0/60.0);

    return 0;
}

Это производит:

Difference is 1.000000 hour(s)

Оба - 4 ноября 2012 года, 1:30, однако оба представляют собой два разных значения time_t с интервалом в 1 час.

mktime() по существу имеет 2 выхода:

  • time_t
  • отремонтированная структура времени

Структура времени является одновременно входом и выходом. Он изменяется mktime(), чтобы вернуть все элементы структуры в номинальные диапазоны. Например, если вы увеличиваете член tm_hour += 500, это означает увеличение времени на 500 часов. Элемент tm_hour будет изменен на значение от 00 до 23, а значения tm_day, tm_mday и т. Д. Будут соответствующим образом скорректированы. tm_isdst также является входом и выходом. Его значения следующие:

  • 1 (действующее летнее время, т.е. дневное время)
  • 0 (летнее время не действует, т.е. стандартное время)
  • -1 (неизвестный статус DST)

Таким образом, mktime () выведет 1 или 0 для tm_isdst, а не -1. ​​

-1 - это возможный ввод , но я думаю, что это означает «Неизвестно». Не думайте, что это означает «определять автоматически», потому что в общем случае mktime() не всегда может определить это автоматически.

Явное состояние DST (0 или 1) должно исходить от чего-то внешнего от программного обеспечения, например, сохранять его в файле или базе данных или запрашивать у пользователя.

4 голосов
/ 19 декабря 2011

Я считаю, что первоначальная причина в том, что некоторые часовые пояса не имеют летнего времени. Так как mktime не является асинхронно безопасным и не требует повторного входа, реализация может сохранять текущее значение летнего времени в POSIX extern char tzname [2], проиндексированном по дневному свету [0 или 1]. Это означает, что tzname [0] = "[имя STD TZ]" и tzname = "[имя TZ дневного света, например, EDT]"

Для получения дополнительной информации см. Справочную страницу tzset (). Стандарты, соответствующие mktime (), должны вести себя так, как если бы они вызывали tzset () в любом случае. Этот вид исключает использование tm_isdst, IMO.

Итог: ваша конкретная реализация и часовой пояс будут определять, будете ли вы использовать -1, 0 или 1 для tm_isdst. Не существует единого правильного способа по умолчанию для всех реализаций.

0 голосов
/ 08 апреля 2019

Я думаю, что вы действительно должны использовать -1 для поля tm_isdst, если у вас нет информации о типе времени, с которым вы имеете дело.

Например, в Калифорнии у нас все еще есть PST и PDT. Если вы анализируете дату и информация о часовом поясе присутствует, вам следует установить tm_isdst соответственно. Как упоминал Джим Макнамара, эти имена доступны в массиве tzname[] после вызова tzset().

Например, следующий код C ++ записывает PST/PDT:

int main(int argc, char * argv [])
{
    tzset();
    std::cerr << tzname[0] << "/" << tzname[1] << "\n";

    return 0;
}

Смещение в массиве tzname[] соответствует значению tm_isdst. (PST - Тихоокеанское стандартное время, tm_isdst = 0, и PDT, Тихоокеанское летнее время, tm_isdst = 1.)

Если на вашем входе нет информации о часовом поясе, тогда использование -1 - лучший выбор. Вы сталкиваетесь с проблемой только , когда дата соответствует дню и времени, когда происходит изменение. Как объясняет Рич Ян, 4 ноября 2012 года у него было временное изменение между стандартным и дневным временем, и примерно в это время gmtime() должен сделать выбор, и он не отличается от того, что вы ожидаете. При этом, это происходит только в течение 2 часов в год и среди ночи. Поэтому, если вы не работаете с критически важным типом программного обеспечения, где дата очень важна, это, вероятно, не будет иметь большого значения.

Итак, резюмируем:

  • если у вас есть часовой пояс, привязанный к дате, которую вы хотите конвертировать, используйте эту информацию, чтобы определить значение tm_isdst (при этом я не слишком уверен, как вы справитесь с этим в случае, если вы должны поддерживать все часовые пояса ... массив tzname[] отображает только текущий часовой пояс пользователя.)
  • во всех остальных случаях используйте -1
...