从持续时间构造std::chrono::system_clock::time_point

Constructing std::chrono::system_clock::time_point from a duration

本文关键字:clock time point system chrono std 持续时间      更新时间:2023-10-16

我有一个数据源,它提供自一天开始(00:00:00Z(以来的时间。我想在这个输入的基础上构造一个std::chrono::time_point

为了举例说明,当前时间为2020-02-27T001:05:30.67073184。我的源代码为我提供了一个二进制编码的十进制值,精确到0.01秒。我构造intermediate值来将解析/中介与组合分离。

using Days = std::chrono::duration<int, std::ratio<86400>>;
auto hr10  = std::chrono::duration<unsigned, std::ratio<36000>> ( 0 );
auto hr1   = std::chrono::duration<unsigned, std::ratio<3600>>  ( 1 );
auto mn10  = std::chrono::duration<unsigned, std::ratio<600>>   ( 0 );
auto mn1   = std::chrono::duration<unsigned, std::ratio<60>>    ( 5 );
auto sc10  = std::chrono::duration<unsigned, std::ratio<10>>    ( 3 );
auto sc1   = std::chrono::duration<unsigned, std::ratio<1>>     ( 0 );
auto ms100 = std::chrono::duration<unsigned, std::ratio<1, 10>> ( 6 );
auto ms10  = std::chrono::duration<unsigned, std::ratio<1, 100>>( 8 );
auto t = hr10 + hr1 + mn10 + mn1 + sc10 + sc1 + ms100 + ms10;  // 393068
auto now = std::chrono::system_clock::now();
auto sinceEpoch = now.time_since_epoch();      // 1582765530687073184 ns
auto today = std::chrono::duration_cast<Days>(sinceEpoch);    // 18319 days
auto sinceDay = sinceEpoch - today;            // 3930687073184 ns
// There is logic to determine if there is a day roll-over; it is not relevant here
auto adjust = Days(0);
// Create the time_point
auto tp = std::chrono::system_clock::time_point();
std::cout << "ntnull:       " << tp.time_since_epoch().count();
tp += today;
std::cout << "nttoday:      " << tp.time_since_epoch().count();
tp += adjust;
std::cout << "ntadjust:     " << tp.time_since_epoch().count();
tp += t;
std::cout << "ntt:          " << tp.time_since_epoch().count();
std::cout << "ntall-in-one: " << decltype(tp)(today+adjust+t).time_since_epoch().count();

这将产生以下输出:

null:       0
today:      1582761600000000000
adjust:     1582761600000000000
t:          1582765530680000000
all-in-one: 36577304120000000

我不明白的是,为什么将每个duration递增地添加到time_point中会产生所需的效果,但尝试从聚合持续时间构建time_point却不会。

通过直接添加duration对象,刻度计数器溢出。

您给出了持续时间刻度计数器类型intunsigned。它们的常见类型是unsigned。因此,所有的数学运算都是在unsigned中为today+adjust+t完成的。

假设32位unsigned,则典型的最大值为2^32-1 = 4294967295。您期望得到的值是1582761600000000000,它显然更大。

只需使用unsigned long long(或足够大的固定大小整数类型(作为duration刻度计数器类型。

用于system_clock::duration(从而用于system_clock::time_point(的类型可能具有比unsigned更高的秩,并且似乎能够存储完整的数字。

在声明自己的持续时间类型时,使用64位值

问题是从Days转换时持续时间溢出。更改自定义持续时间类型以使用64位整数消除了问题:

auto hr10  = std::chrono::duration<uint64_t, std::ratio<36000>> ( std::get<0>(bcd) );
auto hr1   = std::chrono::duration<uint64_t, std::ratio<3600>>  ( std::get<1>(bcd) );
auto mn10  = std::chrono::duration<uint64_t, std::ratio<600>>   ( std::get<2>(bcd) );
auto mn1   = std::chrono::duration<uint64_t, std::ratio<60>>    ( std::get<3>(bcd) );
auto sc10  = std::chrono::duration<uint64_t, std::ratio<10>>    ( std::get<4>(bcd) );
auto sc1   = std::chrono::duration<uint64_t, std::ratio<1>>     ( std::get<5>(bcd) );
auto ms100 = std::chrono::duration<uint64_t, std::ratio<1, 10>> ( std::get<6>(bcd) );
auto ms10  = std::chrono::duration<uint64_t, std::ratio<1, 100>>( std::get<7>(bcd) );

或者,如果不需要,在添加today:之前,将t强制转换为更大的类型

auto tp = std::chrono::system_clock::time_point(
std::chrono::duration_cast::microseconds(t) + today + adjust
);

请记住,自1970年以来的纳秒数是一个很大的数字,肯定会溢出32位的数量。