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(×tr);
/* now with daylight time */
timestr.tm_isdst = 1;
daylight = mktime(×tr);
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