在MSVC

时间:2016-05-16 18:54:07

标签: c++ visual-c++ c++14 dst localtime

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

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

这适用于当前时间。例如,在当前time_t值上,它返回true。对于J2000纪元,它返回false。好的。

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

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

我有什么选择来实现is_DST(...),它适用于64位time_t给出的日期范围(±2.9 * 10 11 年左右)基于上述推断?

* 这是否是正确的问题。闰秒是在1972年引入的,并且向后推断UTC意味着你必须假设没有闰秒(可能已经存在)。推断UTC前进也很难,因为地球的旋转使得闰秒变得不可预测。

1 个答案:

答案 0 :(得分:2)

以下是评论中引用的库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 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)。