Reputation: 1844
I have a data source that provides time since the start of the day (00:00:00Z). I want to construct a std::chrono::time_point
based in this input.
For the sake of example, the current time is 2020-02-27T01:05:30.687073184. My source provides me a binary-coded decimal value, to 0.01 seconds. I construct intermeditate values to separate the parsing/mediation from the combination.
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 << "\n\tnull: " << tp.time_since_epoch().count();
tp += today;
std::cout << "\n\ttoday: " << tp.time_since_epoch().count();
tp += adjust;
std::cout << "\n\tadjust: " << tp.time_since_epoch().count();
tp += t;
std::cout << "\n\tt: " << tp.time_since_epoch().count();
std::cout << "\n\tall-in-one: " << decltype(tp)(today+adjust+t).time_since_epoch().count();
This results in the following output:
null: 0
today: 1582761600000000000
adjust: 1582761600000000000
t: 1582765530680000000
all-in-one: 36577304120000000
What I don't understand is why incrementally adding each duration
to the time_point
produces the desired effect, but trying to construct the time_point
from an aggregate duration does not.
Upvotes: 0
Views: 710
Reputation: 1844
When declaring your own duration types, use 64-bit values
The problem is overflowing the duration when converting from Days
. Changing the custom duration types to use a 64-bit integer eliminates the problem:
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) );
Or, if that's undesirable, cast t
to a larger type before adding in today
:
auto tp = std::chrono::system_clock::time_point(
std::chrono::duration_cast::microseconds(t) + today + adjust
);
Remember, the number of nanoseconds since 1970 is a big number, and will certainly overflow a 32-bit quantity.
Upvotes: 1
Reputation: 22152
You are overflowing the tick counter by adding the duration
objects directly.
You gave the durations tick counter types of int
and unsigned
. The common type of these is unsigned
. Therefore all the math is done in unsigned
for today+adjust+t
.
Assuming 32bit unsigned
, the typical maximum value is 2^32-1 = 4294967295
. The value you expect to get is 1582761600000000000
, which is clearly larger.
Just use unsigned long long
(or a sufficiently large fixed-size integer type) as duration
tick counter type.
The type used for system_clock::duration
(and thus system_clock::time_point
) has probably higher rank than unsigned
and seems to be capable of storing the full number.
Upvotes: 1