在 MSVC 中为负的 `time_t` 获取夏令时

Getting DST for negative `time_t` in MSVC

我正在尝试确定给定的 time_t 值是否在给定时区的 DST 中。所以我写了如下内容:

inline bool is_DST(time_t t) {
    struct tm* ti = localtime(&t);
    return ti->tm_isdst > 0;
}

这对现在的时代来说非常有用。例如,在当前 time_t 值上它 returns true。对于 J2000 纪元,它 returns false。不错

不幸的是,localtime(...) returns nullptr 的 MSVC 变体在负输入上。阅读上面链接的文档告诉我它也会在 3000 年后失败。因此,例如 (time_t)(-1)(对应于 1969-12-31 23:59:59)将导致段错误。

这很糟糕。 1969 年并不是很久以前。标准做法是在假设 1972 年之前或未来任何地方(直到宣布)都没有闰秒的情况下推断 UTC。*

我有哪些选择来实现 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 的整个范围(即 +/- 2920 亿年)。但它很容易回到 1800 年代中期首次引入统一时间时。

在 Windows 上,您必须安装 libcurl, or manually download the IANA timezone database

如果您想回答计算机当前时区以外的某个时区的问题,这很简单:

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(精度为100ns,存储为int64_t)。