Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert a double to time point using std chrono library

I have a double value that represents an epoch time but added the accuracy of a micro second. So a number like this:

double time_us=1628517578.547;
std::chrono::time_point time(time_us);

The above code doesn't;t work as I am getting the following error:

 no instance of constructor "time_point" matches the argument list  

I need to do this conversion to get the millisecond of the day (number of Milliseconds that passed from the last night).

I plan to use the following code to get the required millisecond:

double sysTOH=time.hour*3600+time.min*60+time.sec+time.usec*1e-6;

What is the best way to achieve this?

like image 407
mans Avatar asked Oct 24 '25 09:10

mans


1 Answers

std::chrono:: is a lot to write everywhere, so I'm going to assume:

using namespace std::chrono;

time_point is not a concrete type, it is a class template:

template<class Clock, class Duration = typename Clock::duration> class time_point;

This means that you have to supply at least the first template parameter, and in your case, it is best to supply the second as well.

Your input, time_ms, has type double, and represents a count of seconds. So start by creating a type that matches that description:

using ds = duration<double>;

ds is a duration with a rep of double and a period of ratio<1>.

Now it is handy to use a little of C++20 <chrono>. Don't worry, if you don't have C++20, there is a free, open-source, header-only preview of it that works with C++11/14/17.

sys_time<ds> time{ds{time_ms}};

sys_time is a type alias supplied by "date/date.h" for the type:

time_point<system_clock, duration<double>>

I.e. a time_point based on system_clock using your custom duration type ds (double-based seconds).

One first converts the raw double to double-based seconds, and then to a time_point based on those seconds.

Next, it is best to convert to an integral-based time_point to find the time since midnight. Your questions uses microseconds and milliseconds somewhat interchangeably. So I am going to assume milliseconds for everything. Change to microseconds if you need to.

auto tp = round<milliseconds>(time);

This takes the double-based time_point and converts it to an integral-based time_point that counts milliseconds. round is used to avoid round-off error associated with double-based representations. round is part of C++17 and later, but "date/date.h" will supply it for you in C++11/14.

The type of tp is time_point<system_clock, milliseconds>.

Next it is convenient to truncate tp to a precision of days:

auto td = floor<days>(tp);

floor is part of C++17 and later, but "date/date.h" will supply it for you in C++11/14. days is a day-precision duration. td is simply a count of days since the Unix epoch, and has type time_point<system_clock, days>.

One can also think of td as a time point to the beginning of the day. So one can subtract it from tp to get the "time of day", or "time since midnight" UTC:

auto tod = tp - td;

tod has type milliseconds is the value is the number of milliseconds since midnight UTC. If you need midnight defined by some time zone, then there's a little more work to do to take the UTC offset into account. Your question is vague on this point.

Putting it all together:

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

int
main()
{
    using namespace date;
    using namespace std::chrono;

    double time_ms=1628517578.547;
    using ds = duration<double>;
    sys_time<ds> time{ds{time_ms}};
    auto tp = round<milliseconds>(time);
    auto td = floor<days>(tp);
    auto tod = tp - td;
    std::cout << "tod = " << tod << '\n';
}

Output:

tod = 50378547ms
like image 161
Howard Hinnant Avatar answered Oct 26 '25 23:10

Howard Hinnant