在 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
)。
我正在尝试确定给定的 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
)。