从编译时已知的日历日期创建`std :: chrono :: time_point`

问题描述 投票:2回答:2

This答案显示如何将字符串解析为std::chrono::time_point,如下所示:

std::tm tm = {};
std::stringstream ss("Jan 9 2014 12:35:34");
ss >> std::get_time(&tm, "%b %d %Y %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));

如果我想从(公历)日历日期创建一个std::chrono::time_point,其日年,月份和日期在编译时是已知的,有没有比上面建议的字符串解析它更简单的方法?

c++ c++14 chrono
2个回答
3
投票

是的,你可以在编译时完成整个计算,使用constexpr system_clock::time_point创建一个Howard Hinnant's date/time library

#include "date/date.h"
#include <chrono>

int
main()
{
    using namespace date;
    using namespace std::chrono;
    constexpr system_clock::time_point tp = sys_days{January/9/2014} + 12h + 35min + 34s;
    static_assert(tp == system_clock::time_point{1389270934s}, "");
}

这假设日期/时间是UTC。如果不是,则必须手动添加/减去UTC偏移量才能实现。随着时区规则随着政治家的一时兴起而改变,制作constexpr的希望渺茫。当误解被揭露时,甚至历史时区规则也会更新。

此程序还将通过删除#include "date/date.h"using namespace date;移植到C ++ 20。同样使用Howard Hinnant's date/time library需要C ++ 14 constexpr肌肉。 C ++ 11 constexpr还不够(但你可以在运行时完成它,放弃constexprstatic_assert)。


2
投票

如果您有c ++ 20,或者将使用Howard Hinnant日期/时间库,那么Howard Hannant的答案会更好,因为它会为您提供constexpr time_point。

但是,如果还没有c ++ 20并且想要避免添加更多外部库,那么这个答案仍然有用。

您可以在初始化程序中单独设置std::tm的成员,以避免解析字符串。

// 9th January, 2014
#define DAY 9
#define MONTH 1
#define YEAR 2014

std::tm tm = { .tm_sec  = 0,
               .tm_min  = 0,
               .tm_hour = 0,
               .tm_mday = (DAY),
               .tm_mon  = (MONTH) - 1,
               .tm_year = (YEAR) - 1900,
             };
tm.tm_isdst = -1; // Use DST value from local time zone
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));

由于gcc对C ++代码中非平凡指定的初始值设定项的限制,因此只能在那里对零字段进行初始化,如果想要在编译日期的午夜,则可以省略。

值得注意的是,mktime会将tm解释为当地时间,而不是GMT或UTC。如果tm_isdst未设置为-1,则它将是本地标准时间,即使夏令时(夏令时)将在指定时间内在本地时区使用。

std::tm生成UTC时间点,与您的示例共享的问题,在其他问题中得到解决,例如Easy way to convert a struct tm (expressed in UTC) to time_t type

© www.soinside.com 2019 - 2024. All rights reserved.