I´m writing a C++ code that needs to access an old C library that uses timeval as a representation of the current time.
In the old package to get the current date/time we used:
struct timeval dateTime;
gettimeofday(&dateTime, NULL);
function(dateTime); // The function will do its task
Now I need to use C++ chrono, something as:
system_clock::time_point now = system_clock::now();
struct timeval dateTime;
dateTime.tv_sec = ???? // Help appreaciated here
dateTime.tv_usec = ???? // Help appreaciated here
function(dateTime);
Later in code I need the way back, building a time_point
variable from the returned struct timeval
:
struct timeval dateTime;
function(&dateTime);
system_clock::time_point returnedDateTime = ?? // Help appreacited
I´m using C++11.
Here is how to do the conversion both without using manual conversion factors, or depending upon the unspecified rounding mode of time_t
:
timeval
to_timeval(std::chrono::system_clock::time_point tp)
{
using namespace std::chrono;
auto s = time_point_cast<seconds>(tp);
if (s > tp)
s = s - seconds{1};
auto us = duration_cast<microseconds>(tp - s);
timeval tv;
tv.tv_sec = s.time_since_epoch().count();
tv.tv_usec = us.count();
return tv;
}
std::chrono::system_clock::time_point
to_time_point(timeval tv)
{
using namespace std::chrono;
return system_clock::time_point{seconds{tv.tv_sec} + microseconds{tv.tv_usec}};
}
to_timeval
takes care to round the tp
down (in case it is negative). The POSIX spec is a bit vague on this but I'm assuming that timeval
represents time points prior to the epoch with negative tv_sec
values, and then positive tv_usec
values. Then it is a simple operation to find the microseconds
since the last second
.
If I'm incorrect about my assumption (and a more precise POSIX spec can be found), <chrono>
has the power to model whatever the heck it does.
The reverse conversion, assuming the conventions above, is incredibly readable. It requires no comment.
This can all be tested like this:
timeval
make_timeval(time_t s, long us)
{
timeval tv;
tv.tv_sec = s;
tv.tv_usec = us;
return tv;
}
bool
operator==(timeval x, timeval y)
{
return x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec;
}
int
main()
{
using namespace std::chrono;
assert(make_timeval(0, 0) == to_timeval(system_clock::time_point{}));
assert(make_timeval(1, 0) == to_timeval(system_clock::time_point{seconds{1}}));
assert(make_timeval(1, 400000) == to_timeval(system_clock::time_point{seconds{1} + microseconds{400000}}));
assert(make_timeval(-1, 400000) == to_timeval(system_clock::time_point{seconds{-1} + microseconds{400000}}));
assert(to_time_point(make_timeval(0, 0)) == system_clock::time_point{});
assert(to_time_point(make_timeval(1, 0)) == system_clock::time_point{seconds{1}});
assert(to_time_point(make_timeval(1, 400000)) == system_clock::time_point{seconds{1} + microseconds{400000}});
assert(to_time_point(make_timeval(-1, 400000)) == system_clock::time_point{seconds{-1} + microseconds{400000}});
}
This is all predicated on the assumption that the epoch for timeval
and system_clock
are identical. This is not specified, but is true for all existing implementations. With any luck we can standardize this existing practice in the near future.
Be aware that in POSIX timeval
is used both as a time_point
and a duration
. So to_time_point
could result in a run time error if the timeval
is currently representing a time duration. And to_timeval
could result in a run time error if the client interprets the result as a time duration.
[Edited to use time_val
instead of free vars]
Assuming you trust your system_clock
with milliseconds accuracy, you can go like this:
struct timeval dest;
auto now=std::chrono::system_clock::now();
auto millisecs=
std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()
);;
dest.tv_sec=millisecs.count()/1000;
dest.tv_usec=(millisecs.count()%1000)*1000;
std::cout << "s:" << dest.tv_sec << " usec:" << dest.tv_usec << std::endl;
Use std::chrono::microseconds
in duration_cast
and adjust your (div/mod) code accordingly for the higher precision - take care on how much you trust the accuracy of the values you obtain.
The conversion back is:
timeval src;
// again, trusting the value with only milliseconds accuracy
using dest_timepoint_type=std::chrono::time_point<
std::chrono::system_clock, std::chrono::milliseconds
>;
dest_timepoint_type converted{
std::chrono::milliseconds{
src.tv_sec*1000+src.tv_usec/1000
}
};
// this is to make sure the converted timepoint is indistinguishable by one
// issued by the system_clock
std::chrono::system_clock::time_point recovered =
std::chrono::time_point_cast<std::chrono::system_clock::duration>(converted)
;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With