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

时间:2018-09-08 20:04:08

标签: c++ c++14 chrono

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,该日历日期的年,月,日是编译时已知的,那么还有什么比从字符串中解析为更简单的方法了:以上建议?

3 个答案:

答案 0 :(得分:4)

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

#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来做到这一点。)

答案 1 :(得分:3)

如果您使用的是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

答案 2 :(得分:0)

这适用于C ++ 11及更高版本:

#include <chrono>

std::chrono::system_clock::time_point
createDateTime(int year,
               int month,
               int day,
               int hour,
               int minute,
               int second) // these are UTC values
{
    tm timeinfo1 = tm();
    timeinfo1.tm_year = year - 1900;
    timeinfo1.tm_mon = month - 1;
    timeinfo1.tm_mday = day;
    timeinfo1.tm_hour = hour;
    timeinfo1.tm_min = minute;
    timeinfo1.tm_sec = second;
    tm timeinfo = timeinfo1;
    time_t tt = toUTC(timeinfo);
    return std::chrono::system_clock::from_time_t(tt);
}

time_t toUTC(std::tm& timeinfo)
{
#ifdef _WIN32
    std::time_t tt = _mkgmtime(&timeinfo);
#else
    time_t tt = timegm(&timeinfo);
#endif
    return tt;
}

取自ApprovalTests/utilities/DateUtils.cpp