Я пытаюсь определить, является ли данный time_t
значение в летнее время для данного часового пояса. Поэтому я написал что-то вроде следующего:
inline bool is_DST(time_t t) {
struct tm* ti = localtime(&t);
return ti->tm_isdst > 0;
}
Это прекрасно работает для текущих времен. Например, для текущего значения time_t возвращается true
, Для эпохи J2000 возвращается false
, Ницца.
К сожалению, вариант MSVC localtime(...)
возвращается nullptr
на отрицательном входе. Чтение документов, указанных выше, говорит мне, что после 3000 года это тоже не удастся. Так, например, (time_t)(-1)
(соответствует 1969-12-31 23:59:59) вызовет ошибку сегмента.
Это плохо. 1969 был не так давно. Стандартная практика заключается в экстраполяции UTC с допущением, что не существует високосных секунд ни до 1972 года, ни где-либо в будущем (пока не будет объявлено).*
Каковы мои варианты реализации is_DST(...)
это будет работать для диапазона дат, заданных 64-битным time_t
(± 2,9 * 1011 лет или около того) на основе вышеуказанной экстраполяции?
*Возникает вопрос, правильно ли это. Дополнительные секунды были введены в 1972 году, и экстраполяция UTC в обратном направлении означает, что вы должны предполагать, что не было дополнительных секунд (было бы). И экстраполировать UTC вперед тоже сложно, потому что вращение Земли делает непредсказуемые дополнительные секунды.
Вот библиотека, на которую ildjarn ссылается в комментариях:
https://github.com/HowardHinnant/date
Это открытый исходный код и работает на VS-2013 и позже. Вот как вы могли бы использовать его для реализации is_DST
:
#include "tz.h"#include <ctime>
bool
is_DST(std::time_t t)
{
using namespace std::chrono;
using namespace date;
return current_zone()->get_info(system_clock::from_time_t(t)).save != 0min;
}
Это будет работать на негатив time_t
, но не для всего диапазона 64 бит time_t
(что было бы +/- 292 миллиардов лет). Но он легко вернется к середине 1800-х годов, когда впервые было введено единообразное время.
На Windows вам придется либо установить Libcurl, или вручную загрузить База данных часовых поясов IANA.
Если вы хотите ответить на этот вопрос для некоторого часового пояса, отличного от текущего, компьютера, это достаточно просто:
return locate_zone("Europe/Monaco")
->get_info(system_clock::from_time_t(t)).save != 0min;
Диапазон на Windows [-27258-04-19 21:11:54.5224192, 31197-09-14 02:48:05.4775807]
, Ограничением этого диапазона является то, что это диапазон VS system_clock::time_point
(который имеет точность 100 нс и хранится как int64_t
).
Других решений пока нет …