I have some arbitrary epoch, like July 13, 1988. Essentially I want to measure the time relative to this. I was thinking of writing a custom clock class, so that I could write code like this:
using std::chrono;
time_point<My_Clock> tp;
std::cout << duration_cast<seconds>(tp.time_since_epoch()).count() << std::endl;
Is this possible? If not, what's the cleanest way to accomplish this?
The hard part of writing this custom clock is figuring out how to write its now()
function. In the example below I base the now()
off of system_clock
's now()
. First I do some detective work to discover that my system_clock
has an epoch of New Years 1970, neglecting leap seconds. This is known as unix time. As it turns out, every implementation I'm aware of (and I think I've checked them all) have this very same epoch (but this is unspecified by the C++11 standard).
Next I compute that 1988-07-13 is 6768 days after 1970-01-01. Using these two facts, the rest is easy:
#include <chrono>
struct My_Clock
{
typedef std::chrono::seconds duration;
typedef duration::rep rep;
typedef duration::period period;
typedef std::chrono::time_point<My_Clock> time_point;
static const bool is_steady = false;
static time_point now() noexcept
{
using namespace std::chrono;
return time_point
(
duration_cast<duration>(system_clock::now().time_since_epoch()) -
hours(6768*24)
);
}
};
MyClock
needs nested typedefs to describe its duration
, rep
, period
, and time_point
. Based on your question, I've chosen seconds
as the duration
, but you can choose anything you want.
For the now()
function I just call the system_clock::now()
and subtract off the epoch in units of seconds. I got just a little clever with this computation by writing everything in terms of MyClock::duration
so that I can more easily change duration
. Note that I was able to subtract off the epoch in terms of hours
, which implicitly converts to duration
(which is seconds
). Alternatively I could have built myself a custom duration
of days:
typedef std::chrono::duration<int, std::ratio_multiply<std::chrono::hours::period,
std::ratio<24>>> days;
And then the return of now()
could have been written:
return time_point
(
duration_cast<duration>(system_clock::now().time_since_epoch()) -
days(6768)
);
At any rate, now you can use this like:
#include <iostream>
int
main()
{
using namespace std::chrono;
time_point<My_Clock> tp = My_Clock::now();
std::cout << tp.time_since_epoch().count() << '\n';
}
Which for me just printed out:
786664963
Which demonstrates that today (2013-06-16) is approximately 24.9 years after 1988-07-13.
In C++20 you can use the updated <chrono>
calendrical services to eliminate the "magic number" from the implementation:
#include <chrono>
struct My_Clock
{
typedef std::chrono::seconds duration;
typedef duration::rep rep;
typedef duration::period period;
typedef std::chrono::time_point<My_Clock> time_point;
static const bool is_steady = false;
static time_point now() noexcept
{
using namespace std::chrono;
return time_point
{
duration_cast<duration>(system_clock::now() - sys_days{July/13/1988})
};
}
};
There is no run-time expense for this convenience. The sub-expression sys_days{July/13/1988}
is optimized at compile-time into a count of days since the system_clock
epoch, and then further converted to system_clock::duration
(still at compile-time) before being subtracted from system_clock::now()
.
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