Mktime и tm_isdst

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

Я читаю 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?

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

Ответ 1

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

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

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

Ответ 2

Вам следует избегать установки tm_isdst в -1, если это возможно. Система не всегда может определить состояние летнего времени только по дате и времени. Это неоднозначно час до и после окончания летнего времени. Например, если вы передадите mktime() 1:30 утра 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 (неизвестный статус летнего времени)

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

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

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

Ответ 3

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

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

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