I have a below code from which we are trying to get current timestamp in microseconds since epoch time but we are using steady_clock.
inline uint64_t get_timestamp()
{
std::chrono::time_point<std::chrono::steady_clock> ts = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(ts.time_since_epoch()).count();
}
Is this the right way to do that since as per my understanding steady_clock is used to measure the passage of time not to get the current time of day? Or should I use system_clock for this like as shown below:
inline uint64_t get_timestamp()
{
std::chrono::time_point<std::chrono::system_clock> ts = std::chrono::system_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(ts.time_since_epoch()).count();
}
I need to use std::chrono package only since that's what all our code is using.
The epochs of the chrono clocks are unspecified. But practically you can think of the chrono clocks this way:
The epoch of steady_clock is the time your application launched plus a signed random offset. I.e. you can't depend upon the epoch being the same across application launches. But the epoch will remain stable while an application is running.
The epoch of system_clock is time since New Years 1970, not counting leap seconds, in the UTC timezone. Different implementations implement this with varying precision: libc++ counts microseconds, VS counts 1/10 of microseconds, and gcc counts nanoseconds.
high_resolution_clock is sometimes a type alias for steady_clock and sometimes a type alias for system_clock.
For a time stamp in microseconds I recommend first defining this type alias:
using time_stamp = std::chrono::time_point<std::chrono::system_clock,
std::chrono::microseconds>;
Store that, instead of uint64_t. The type safety of this type will save you countless run time errors. You'll discover your errors at compile time instead.
You can get the current time_stamp with:
using namespace std::chrono;
time_stamp ts = time_point_cast<microseconds>(system_clock::now());
Another possibility for people who couldn't get other solutions to work:
uint64_t microseconds_since_epoch = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
Related
I'm using Howard Hinnant's time zone library.
https://howardhinnant.github.io/date/tz.html
My question: Is it possible to construct a date::local_time object from a std::chrono::time_point?
What I want to to:
// 'tp' exists and is some std::chrono::time_point object
auto locTime = date::local_time<std::chrono::milliseconds>(tp);
The constructor for this doesn't exist so a get a compilation error.
How do I do this (in nice and clean C++17)?
Background:
My ultimate goal is to compare a std::filesystem::file_time_type to a date::local_time<std::chrono::milliseconds>.
I do
auto fileTimeTp = std::chrono::clock_cast<std::chrono::system_clock>(someDirectoryEntryObject.last_write_time());
which gives my my std::chrono::time_point for the file date, but that's where I'm stuck...
This is a two part answer ...
Part 1
My question: Is it possible to construct a date::local_time object from a std::chrono::time_point?
I'm going to assume that std::chrono::time_point refers to std::chrono::system_clock::time_point (each clock has its own family of std::chrono::time_point).
Yes, it is possible. Background: system_clock::time_point is defined as Unix Time which is a close approximation to UTC. So to go from system_clock::time_point (also know as sys_time in the date library / C++20) to local_time, you need to pair the sys_time with a time_zone. This could be your computer's current local time zone, or any other IANA time zone.
To get the computer's current local time zone:
auto tz = date::current_zone();
The type of tz is a date::time_zone const*. time_zone has a member function called to_local that will translate a sys_time into a local_time:
auto locTime = tz->to_local(system_clock::now());
The precision of locTime will match whatever the precision of the input sys_time is.
If you would like to use some other time zone, then you can use date::locate_zone to get a date::time_zone const* to that time zone.
auto locTime = date::locate_zone("America/New_York")->local_time(system_clock::now());
Part 2
My ultimate goal is to compare a std::filesystem::file_time_type to a date::local_time<std::chrono::milliseconds>.
Ah, this won't really involve local_time at all. And unfortunately, file_clock is not implemented in the time_zone library.
In C++20, this will be quite easy: Given a file_time and a sys_time you can convert either to the other using clock_cast:
if (clock_cast<system_clock>(ftp) >= system_clock::now())
...
However in C++17 it is harder, and non-portable. The the time_zone library makes it easier, but not easy.
You first have to deduce the epoch of std::filesystem::file_time_type on your platform. This will be different depending on which implementation of std::filesystem::file_time_type you are using.
Existing epochs include:
* 1970-01-01 00:00:00 UTC
* 1601-01-01 00:00:00 UTC
* 2174-01-01 00:00:00 UTC
Then you subtract the sys_time epoch (sys_days{1970_y/1/1}) and the file_time epoch (e.g. sys_days{1601_y/1/1}), and add/subtract that epoch to convert from one measure to the other.
For example:
constexpr auto diff = sys_days{1970_y/1/1} - sys_days{1601_y/1/1};
file_time_type ftp = ...
system_clock::time_point tp{ftp.time_since_epoch() - diff};
That's unfortunately quite messy, and I'm looking forward to clock_cast working with file_clock in C++20.
I am trying to write a function, which will return the current time in microseconds since 1970. While a debugging I noticed, that the returned numbers are too small. For example: 269104616249. I also added static_assert to check the returned value type is int64_t, which i big enough to hold 292471 years in microseconds. So integer overflow should not be a case here.
What am I doing wrong?
Here is my code:
int64_t NowInMicroseconds() {
static_assert(std::is_same<decltype(duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count()), int64_t>::value);
return duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count();
}
int64_t result = NowInMicroseconds();
There are three chrono-supplied clocks in C++11/14/17 (more in C++20):
system_clock: This measures Unix Time (time since 1970 excluding leap seconds).1
steady_clock: Like a stop-watch. Great for timing, but it can not tell you the time of day.
high_resolution_clock: This has the disadvantages of system_clock and steady_clock, and the advantages of neither. Typically it is a type alias to either system_clock or steady_clock, and which one differs with platform.
You have to use system_clock for measuring time since 1970. Note that this is measured in UTC, not your local time zone. In C++11/14/17 to get the local time since 1970, you will have to either manually take your time zone into account, or use this C++20 chrono preview library.
std::int64_t
NowInMicroseconds()
{
using namespace std::chrono;
return duration_cast<microseconds>(system_clock_clock::now().time_since_epoch()).count();
}
Consider returning a strong type which means "microseconds since 1970" instead of an integral type. Strong type safety helps you find your logic errors at compile time:
std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>
NowInMicroseconds()
{
using namespace std::chrono;
return time_point_cast<microseconds>(system_clock.now());
}
1 This is unspecified in C++11/14/17, but is true on all implementations. C++20 finally nails this epoch down in the spec.
I am using in my projects some time_point<steady_clock> variables in order to do operations at a specific interval. I want to serialize/deserialize in a file those values.
But it seems that the time_since_epoch from a steady_clock is not reliable, although time_since_epoch from a system_clock is quite ok, it always calculates the time from 1970/1/1 (UNIX time)
What's the best solution for me? It seems that I have to convert somehow from steady_clock to system_clock but I don't think this is achievable.
P.S. I already read the topic here: Persisting std::chrono time_point instances
On the cppreference page for std::chrono::steady_clock, it says:
This clock is not related to wall clock time (for example, it can be time since last reboot), and is most suitable for measuring intervals.
The page for std::chrono::system_clock says that most implementations use UTC as an epoch:
The epoch of system_clock is unspecified, but most implementations use Unix Time (i.e., time since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds).
If you're trying to compare times across machines or hoping to correlate the recorded times to real world events (i.e. at 3pm today there was an issue), then you'll want to switch your code over to using the system clock. Anytime you reboot the steady clock will reset and it doesn't relate to wall time at all.
Edit: if you wanted to do an approximate conversion between steady and system timestamps you could do something like this:
template <typename To, typename FromTimePoint>
typename To::time_point approximate_conversion(const FromTimePoint& from) {
const auto to_now = To::now().time_since_epoch();
const auto from_now = FromTimePoint::clock::now().time_since_epoch();
// compute an approximate offset between the clocks and apply that to the input timestamp
const auto approx_offset = to_now - from_now;
return typename To::time_point{from.time_since_epoch() + approx_offset};
}
int main() {
auto steady = std::chrono::steady_clock::now();
auto system = approximate_conversion<std::chrono::system_clock>(steady);
}
This assumes the clocks don't drift apart very quickly, and that there are no large discontinuities in either clock (both of which are false assumptions over long periods of time).
I have a double representing the time in days since midnight (local time zone) 1 Jan 1970 and a string representing the time zone. I would like to convert these to a
date::zoned_time
using Howard Hinnant's date and time zone library.
The background is I need to convert date-times to and from doubles to use in an analytics library. I will also receive date-times as doubles from excel in a local or user-specified time zone.
Here is one attempt I made
using namespace date;
using namespace std::chrono;
typedef date::zoned_time<std::chrono::seconds> datetime;
const double UNIX_MINUS_EXCEL_EPOCH = 25569.0;
const double SECONDS_PER_DAY = 24.0 * 60.0 * 60.0;
datetime timePointFromDouble(double x)
{
double seconds = (x - UNIX_MINUS_EXCEL_EPOCH) * SECONDS_PER_DAY;
system_clock::duration d = duration_cast<system_clock::duration>(duration<double>(seconds));
system_clock::time_point t = system_clock::time_point(d);
auto xx = make_zoned("America/Chicago", t);
return xx;
}
It doesn't compile because the result of make_zoned has the wrong type. Also, I am not convinced it correctly maps the input time in days to the output date-time because of leap seconds and days where daylight saving changes.
Specification:
x is a measure of days since 1899-12-30 00:00:00 in America/Chicago.
Solution:
using datetime = date::zoned_seconds;
datetime
timePointFromDouble(double x)
{
using namespace date;
using namespace std::chrono;
using ddays = duration<double, days::period>;
constexpr auto excel_epoch = local_days{1_d/January/1970} -
local_days{30_d/December/1899};
return datetime{"America/Chicago",
local_seconds{round<seconds>(ddays{x} - excel_epoch)}};
}
Explanation:
The reason your version doesn't compile is because of the conversion to system_clock::time_point, which in practice has a precision of microseconds or finer. But your result type has a precision of seconds, so the library is refusing to implicitly truncate your high-precision t to your lower-precision xx.
The easiest way to fix this is to time_point_cast<seconds>(t). But there's more fun to be had...
<chrono> lives and dies by handling the conversions for you. Any time you're doing the conversions yourself, you should opt for removing those conversions in favor of letting <chrono> do them. This will usually simplify your code, and it may just catch a conversion error.
<chrono> knows about how to convert among various durations, but not about the Excel epoch, so that's one conversion we can't avoid. But we can express that epoch in a higher level language than the mysterious constant 25569.0.
So, from the top:
date::zoned_seconds is a simpler way to write date::zoned_time<std::chrono::seconds>. It is just a convenience typedef.
ddays is a custom duration unit which represents 1 day with a double. This is convenient for converting the scalar input x directly into a <chrono> duration. It is best to get into the <chrono> type system as soon as possible.
The epoch difference is the amount of time between 1970-01-01 and 1899-12-30. The units will be days as I've coded it, but that is an unimportant detail. <chrono> takes care of the units for you.
I'm using local_days as opposed to sys_days to compute the epoch difference. This is a largely symbolic gesture to communicate that the epoch is in a local time, not UTC. It doesn't make a difference in the actual value of the constant that is computed.
Because of the way you worded the question, I assumed you would prefer day-month-year ordering in the code. This is a purely stylistic choice.
If you are writing this in C++11, excel_epoch will have to be made const instead of constexpr. The difference is that C++11 has to compute this constant at run-time and C++14 and later can compute it at compile-time.
When converting from double-based units to integral-based units, I like to use round instead of duration_cast. The difference is that round chooses the nearest representable value, and duration_cast truncates towards zero to the nearest representable value. The round strategy is more likely to result in stable round-trip conversions between the double and integral representations, whereas truncation is more likely to expose one-off differences due to round-off error in the double representation.
The last line has to explicitly get us from double-based to integral-based units, and has to specify seconds to match with the return type, but does not have to worry about converting days into seconds.
The last line uses local_seconds to convert the duration into a time_point because this duration represents a measure in the local time of America/Chicago, as opposed to a measure in UTC. This fixes the epoch to 1899-12-30 00:00:00 in America/Chicago as opposed to 1899-12-30 00:00:00 UTC.
The result does not take leap seconds into account. This is the correct thing to do, because neither does Excel nor system_clock. Just about every computer-based time-keeping protocol out there doesn't count leap seconds. Here is a good description of Unix Time. If you want to convert to a system that counts leap seconds, this library can do that too. It is called utc_clock/utc_time.
The result does take daylight savings time into account for Chicago, including the changes to the daylight savings rules over the years, as best as the IANA database can do (which is exact as far as I know).
How to convert std::chrono::monotonic_clock::now() to milliseconds and cast it to long?
using steady_clock or high_resolution_clock from chrono is also same. I have seen into std::chrono::duration_cast<std::chrono::milliseconds> but I only want the current timestamp and not any duration gaps.
The current timestamp is defined with respect to some point in time (hence it is a duration). For instance, it is "typical" to get a timestamp with respect to the beginning of the Epoch (January 1st 1970, in Unix). You can do that by using time_since_epoch():
namespace chr = std::chrono;
chr::time_point<chr::steady_clock> tp = chr::steady_clock::now();
std::cout << "hours since epoch: "
<< chr::duration_cast<chr::hours>(tp.time_since_epoch()).count()
<< '\n';
To get the value in milliseconds you would need to cast it to std::chrono::milliseconds, instead.
All the built-in clocks have an associated "epoch" which is their base time. The actual date/time of the epoch is not specified, and may vary from clock to clock.
If you just want a number for comparisons then some-clock::now().time_since_epoch() will give you a duration for the time since the epoch for that clock, which you can convert to an integer with the count() member of the duration type. The units of this will depend on the period of the clock. If you want specific units then use duration_cast first:
typedef std::chrono::steady_clock clk;
unsigned long long milliseconds_since_epoch=
std::chrono::duration_cast<std::chrono::milliseconds>(
clk::now().time_since_epoch()).count();
As I said, this is only good for comparisons, not as an absolute time stamp, since the epoch is unspecified.
If you need a UNIX timestamp then you need to use std::chrono::system_clock, which has a to_time_t() function for converting a time_point to a time_t.
Alternatively, you can take a baseline count at a particular point in your program, along with the corresponding time from gettimeofday or something, and then use that to convert relative counts to absolute times.