I was working with some POSIX APIs recently and needed to supply a timespec
value. I primarily work with std::chrono
types in C++ and was surprised that there were no (obvious) existing conversion methods. Below are a few utility functions that I came up with to handle common conversions.
Table of Contents
timespec Refresher
As a quick refresher, timespec
is a type defined in the ctime
header (aka time.h
). The timespec
type can be used to store either a time interval or absolute time. The type is a struct
with two fields:
struct timespec {
time_t tv_sec;
long tv_nsec;
}
The tv_sec
field represents either a general number of seconds, or seconds elapsed since 1970, and tv_nsec
represents the count of nanoseconds.
Conversion Functions
A timespec
can represent either an absolute time or time interval. With std::chrono
, these are two separate concepts: std::chrono::duration
represents an interval, while std::chrono::time_point
represents an absolute time.
We need for four functions to convert between the two C++ time concepts and timespec
:
timespec
tostd::chrono::duration
std::chrono::duration
totimespec
timespec
tostd::chrono::timepoint
std::chrono::time_point
totimespec
timespec
to std::chrono::duration
Converting from a timespec
to a std::chrono::duration
(nanoseconds
below) is straightforward: we convert tv_sec
to std::chrono::seconds
and tv_nsec
to std::chrono::nanoseconds
, and then cast the result to our target return type, std::chrono::nanoseconds
.
using namespace std::chrono; // for example brevity
constexpr nanoseconds timespecToDuration(timespec ts)
{
auto duration = seconds{ts.tv_sec}
+ nanoseconds{ts.tv_nsec};
return duration_cast<nanoseconds>(duration);
}
std::chrono::duration
to timespec
Converting from std::chrono::duration
to timespec
is a two step process. First we capture the portion of the duration which can be represented by a round number of seconds. We subtract this count from the total duration to get the remaining nanosecond count.
Once we have the two components, we can create our timespec
value.
using namespace std::chrono; // for example brevity
constexpr timespec durationToTimespec(nanoseconds dur)
{
auto secs = duration_cast<seconds>(dur);
dur -= secs;
return timespec{secs.count(), dur.count()};
}
timespec
to std::chrono::timepoint
For the std::chrono::time_point
examples, I’ve used the system_clock
as the reference clock.
To convert a timespec
value to std::chrono::time_point
, we first use our timespecToDuration()
function to get a std::chrono::duration
. We then use a duration_cast
to convert std::chrono::duration
to our reference clock duration (system_clock::duration
).
We can then create a std::chrono::time_point
value from our std::chrono::system_clock::duration
.
using namespace std::chrono; // for example brevity
constexpr time_point<system_clock, nanoseconds>
timespecToTimePoint(timespec ts)
{
return time_point<system_clock, nanoseconds>{
duration_cast<system_clock::duration>(timespecToDuration(ts))};
}
std::chrono::time_point
to timespec
To convert from a std::chrono::time_point
to timespec
, we take a similar approach to the std::chrono::duration
conversion.
First we capture the portion of the duration which can be represented by a round number of seconds. We subtract this count from the total duration to get the remaining nanosecond count.
Once we have the two components, we can create our timespec value.
using namespace std::chrono; // for example brevity
constexpr timespec timepointToTimespec(
time_point<system_clock, nanoseconds> tp)
{
auto secs = time_point_cast<seconds>(tp);
auto ns = time_point_cast<nanoseconds>(tp) -
time_point_cast<nanoseconds>(secs);
return timespec{secs.time_since_epoch().count(), ns.count()};
}
Bonus: timeval conversions
Another common time structure with POSIX systems is timeval
, which is defined in the sys/time.h
. This type is very similar to timespec
:
struct timeval
{
time_t tv_sec;
suseconds_t tv_usec;
}
We can convert between timeval
and std::chrono
types in the same manner shown above, except std::chrono::microseconds
is used in place of std::chrono::nanoseconds
.
using namespace std::chrono; // for example brevity
constexpr microseconds timevalToDuration(timeval tv)
{
auto duration = seconds{tv.tv_sec} + microseconds{tv.tv_usec};
return duration_cast<microseconds>(duration);
}
“using std::chrono;” is wrong, it is “using namespace std::chrono;”