Chrono duration to time string - c++

I have a few lines of code that takes the system clock on my Windows machine and converts it to a double.
std::chrono::time_point<std::chrono::system_clock> currentNow =
std::chrono::system_clock::now();
auto duration = currentNow.time_since_epoch();
double millis = static_cast<double>(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
double origin_time = millis / 1000;
I would like to reverse this later on and convert the double to a string being the format YYYY-mm-dd HH:MM:SS.ffffffff
The first step I have right now is taking the double and passing it as a parameter to chrono::duration.
auto rep = std::chrono::duration<double>(origin_time);
How would I go about using the chrono library to achieve the string specified above, thanks!

Construct a new time_point containing the current epoch:
auto epoch = std::chrono::time_point<std::chrono::system_clock>();
Add your converted duration to this time_point:
auto oldNow = epoch + std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::duration<double>(origin_time));
Convert it into a std::time_t:
auto t_c = std::chrono::system_clock::to_time_t(oldNow);
Print it using formatting facilities for time_t:
std::cout << std::put_time(std::localtime(&t_c), "%F %T");
Example output:
2020-01-10 18:45:48
See it live!
You'll notice it is missing the .ffffffff part. That's because std::put_time has no formatting option for it. You can easily calculate the value yourself and put it at the end of the string, if that's important for you.
Also note that this is much better accomplished using C++20 chrono or Howard's Date library (which is basically the same thing, except for a few bits here and there) as noted in the comments by the man himself. For an overview on it, you may be interested in this answer.

Related

Converting time to local zone time: issue with hh_ss_mm template args (C++ 14)

I'm using C++14 and the famous Date library by #HowardHinnant
I'm trying to convert a GMT (UTC) time to the time inside of some timezone. I need to have it in the tm struct.
All seems good except I can't seem to properly construct the hms object. My template arguments mismatch.
tm Time_hrv::gmtTM_to_timezoneTM(const tm& timeTM_gmt, const std::string& wanted_timezoneStr){
assert(timeTM_gmt.tm_year < 1000);// the year of tm should be relative to 1900. For example, 2020 should be 120.
assert(timeTM_gmt.tm_mon < 12);// [0,11]
assert(timeTM_gmt.tm_mday > 0 && timeTM_gmt.tm_mday<=31);// [0,31]
time_t timeT_gmt = Time_hrv::timeTM_to_timeT(timeTM_gmt);
auto chronoTime_gmt = std::chrono::system_clock::from_time_t(timeT_gmt);
const date::time_zone* wanted_timeZone = timeZone_fromString(wanted_timezoneStr);
//https://stackoverflow.com/a/70759851/9007125
//NOTICE: local_time isn't necessarily the computer's local time.
//It is a local time that has not yet been associated with a time zone.
//When you construct a zoned_time, you associate a local time with a time zone.
auto lt = wanted_timeZone->to_local(chronoTime_gmt);
auto localDay = date::floor<date::days>(lt);
date::year_month_day ymd{ localDay };
date::hh_mm_ss<std::chrono::milliseconds> hms{ lt - localDay }; //<--- error here
tm result = {0};
result.tm_year = int{ymd.year()} - 1900;
result.tm_mon = unsigned{ymd.month()} -1;
result.tm_mday = unsigned{ymd.day()};
result.tm_hour = (int)hms.hours().count();
result.tm_min = (int)hms.minutes().count();
result.tm_sec = (int)hms.seconds().count();
return result;
}
This is chrono giving you a bad error message for a real problem: You are attempting to silently truncate a fine precision expression (lt - localDay) to a coarser precision (milliseconds).
The expression lt - localDay is a type that has precision of system_clock::duration, which is somewhere between microseconds and nanoseconds depending on your platform. This is true, even though the source (and thus the value) of chronoTime_gmt only has precision of seconds at run time.
The easiest fix is to recognize that anything coming from a tm is at best seconds precision by truncating to seconds precision early:
auto chronoTime_gmt = date::floor<std::chrono::seconds>
(std::chrono::system_clock::from_time_t(timeT_gmt));
Now chronoTime_gmt has type time_point<system_clock, seconds>. And therefore the later expression lt - localDay will also have type seconds, which will implicitly convert to the milliseconds precision of your hh_mm_ss.
A suggestion is to also use seconds for the template parameter of your hh_mm_ss since the milliseconds precision goes unused. This won't change correctness or performance of your code, but the reader of your code will no longer spend time wondering why you chose milliseconds and then didn't use it.

Converting Epoch time with timezone to Excel format time?

I need to be able to convert Epoch time to Excel time.
Why Excel, because working with the numeric excel time is faster that any parsing done on display formats.
Current time of 2018-06-08 12:46:58 CDTwith UTC 1528480019 should give 0.5326157.
But converted to the New_York time or 2018-06-08 13:46:58 EDT will give 0.574282367.
I only need to convert the time field to Excel style.
Here is my incomplete code:
double GetTime(Datetime currtime, std::string tz = "TZ=America/New_York")
{
std::time_t t = currtime;
//tzset(tz);
std::tm tm = *std::localtime(&t);
return ((tm.tm_hour * 3600 + (tm.tm_min) * 60.0 + tm.tm_sec) / 86400.0);
}
The code works, but only for local time which is "America/Chicago".
I have been unable to use the set the timezone to the one I might need.
Also tm seems to be limited to seconds, but I need to handle milliseconds and microseconds as well.
Furthermore, I need it to be fast and the the current implementation parses the time into separate fields and then I combine it into what I need which seems to do a lot of extra work.
This problem can easily be solved with Howard Hinnant's free, open-source date/time/timezone library, which is very efficient. This library is also in the current C++20 working draft, under namespace std::chrono. So in the future, porting your code to just use the std::lib ought to be as easy as changing a few namespaces.
double
GetTime(std::chrono::system_clock::time_point currtime,
date::time_zone const* tz = date::current_zone())
{
using namespace date;
using namespace std::chrono;
zoned_time<system_clock::duration> zt{tz, currtime};
auto lt = zt.get_local_time();
auto ld = floor<days>(lt);
using ExcelTime = duration<double, days::period>;
ExcelTime tod = lt - ld;
return tod.count();
}
Instead of taking a Datetime it takes a std::chrono::system_clock::time_point, and instead of a std::string, a date::time_zone const*.
On the three big platforms (llvm/gcc/MSVS), the coarsest system_clock::time_point is microseconds, which meets your precision goals.
Step one is to create a zoned_time which is a pairing of a time_point with a time_zone. From this one can get a local_time.
floor<days> truncates the precision of a time_point to days. If one subtracts the day-precision time_point from the finer-precision time_point, one gets the local time-of-day.
If you store this local time-of-day in a chrono::duration that has a double as its representation, and a period of 1 day, then you get the Excel Time-Of-Day format.
This can be used like:
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << std::fixed << std::setprecision(9);
std::cout << GetTime(sys_seconds{1528480019s}, locate_zone("America/Chicago")) << '\n';
zoned_time<system_clock::duration> zt{"America/New_York",
local_days{2018_y/6/8} + 13h + 46min + 58s};
std::cout << GetTime(zt.get_sys_time(), zt.get_time_zone()) << '\n';
}
which outputs:
0.532627315
0.574282407
Above, I struggled to come as close as possible to your existing API. However if you adopt this library, you can make it even simpler, and slightly more efficient, by adopting a "more native" API:
std::chrono::duration<double, date::days::period>
GetTime(const date::zoned_time<std::chrono::system_clock::duration>& zt)
{
using namespace date;
auto lt = zt.get_local_time();
return lt - floor<days>(lt);
}
Now GetTime takes just a single parameter of type zoned_time<system_clock::duration>, and returns a duration<double, days::period>. All that's left for GetTime to do is truncate the local time to days-precision and subtract to get time-of-day.
The demo in main is also simplified:
std::cout << GetTime({"America/Chicago", sys_seconds{1528480019s}}).count() << '\n';
std::cout << GetTime({"America/New_York",
local_days{2018_y/6/8} + 13h + 46min + 58s}).count() << '\n';
And gives the same output as before.

Validate timestamp for a particular duration in C++

I want to see whether my data is 120 second old by looking at the timestamp of the data so I have below code:
uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));
In the above code data_holder->getTimestamp() is uint64_t which returns timestamp in milliseconds. Does my above code looks right?
I'd probably do something like this:
auto now = system_clock::now().time_since_epoch();
// Use the correct time duration below. Milliseconds could be wrong, see 1)
auto diff = now - std::chrono::milliseconds(data_holder->getTimestamp());
bool is_old = diff > std::chrono::seconds{120};
// bool is_old = diff > 120s; // From C++14 onwards.
1) As mentioned, milliseconds could be the wrong unit to use for getTimestamp(). All possible types are
std::chrono::hours
std::chrono::minutes
std::chrono::seconds
std::chrono::milliseconds
std::chrono::microseconds
std::chrono::nanoseconds
You probably have to try out which one to use, because that depends on data_holder->getTimestamp().
Note: Big one
Making sure to use system_clock to measure time since epoch will work most likely. But the standard doesn't require that a clock's epoch is the UNIX epoch. You have encountered this with steady_clock already.
You'd have to calculate the difference between the clock's epoch and the epoch yourself (and I don't know of a way to do that right now for any clock). For system_clock, if you don't trust it to use the unix epoch you can use the following:
system_clock::duration time_since_unix_epoch()
{
std::tm epoch;
epoch.tm_mday = 1;
epoch.tm_mon = 0;
epoch.tm_year = 70;
std::time_t epocht = mktime(&epoch);
return system_clock::now() - system_clock::from_time_t(epocht);
}
instead of system_clock::now(). I'd prefer this method.
Unfortunatly you can't just replace system_clock with another clock from std::chrono because only std::system_clock offers from_time_t(time_t) which converts a real date to the internal time_point used by the clock.

fully separated date with milliseconds from std::chrono::system_clock

My current pattern (for unix) is to call gettimeofday, cast the tv_sec field to a time_t, pass that through localtime, and combine the results with tv_usec. That gives me a full date (year, month, day, hour, minute, second, nanoseconds).
I'm trying to update my code to C++11 for portability and general good practice. I'm able to do the following:
auto currentTime = std::chrono::system_clock::now( );
const time_t time = std::chrono::system_clock::to_time_t( currentTime );
const tm *values = localtime( &time );
// read values->tm_year, etc.
But I'm stuck on the milliseconds/nanoseconds. For one thing, to_time_t claims that rounding is implementation defined (!) so I don't know if a final reading of 22.6 seconds should actually be 21.6, and for another I don't know how to get the number of milliseconds since the previous second (are seconds guaranteed by the standard to be regular? i.e. could I get the total milliseconds since the epoch and just modulo it? Even if that is OK it feels ugly).
How should I get the current date from std::chrono::system_clock with milliseconds?
I realised that I can use from_time_t to get a "rounded" value, and check which type of rounding occurred. This also doesn't rely on every second being exactly 1000 milliseconds, and works with out-of-the-box C++11:
const auto currentTime = std::chrono::system_clock::now( );
time_t time = std::chrono::system_clock::to_time_t( currentTime );
auto currentTimeRounded = std::chrono::system_clock::from_time_t( time );
if( currentTimeRounded > currentTime ) {
-- time;
currentTimeRounded -= std::chrono::seconds( 1 );
}
const tm *values = localtime( &time );
int year = values->tm_year + 1900;
// etc.
int milliseconds = std::chrono::duration_cast<std::chrono::duration<int,std::milli> >( currentTime - currentTimeRounded ).count( );
Using this free, open-source library you can get the local time with millisecond precision like this:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << make_zoned(current_zone(),
floor<milliseconds>(system_clock::now())) << '\n';
}
This just output for me:
2016-09-06 12:35:09.102 EDT
make_zoned is a factory function that creates a zoned_time<milliseconds>. The factory function deduces the desired precision for you. A zoned_time is a pairing of a time_zone and a local_time. You can get the local time out with:
local_time<milliseconds> lt = zt.get_local_time();
local_time is a chrono::time_point. You can break this down into date and time field types if you want like this:
auto zt = make_zoned(current_zone(), floor<milliseconds>(system_clock::now()));
auto lt = zt.get_local_time();
local_days ld = floor<days>(lt); // local time truncated to days
year_month_day ymd{ld}; // {year, month, day}
time_of_day<milliseconds> time{lt - ld}; // {hours, minutes, seconds, milliseconds}
// auto time = make_time(lt - ld); // another way to create time_of_day
auto y = ymd.year(); // 2016_y
auto m = ymd.month(); // sep
auto d = ymd.day(); // 6_d
auto h = time.hours(); // 12h
auto min = time.minutes(); // 35min
auto s = time.seconds(); // 9s
auto ms = time.subseconds(); // 102ms
Instead of using to_time_t which rounds off you can instead do like this
auto tp = std::system_clock::now();
auto s = std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
auto t = (time_t)(s.count());
That way you get the seconds without the round-off. It is more effective than checking difference between to_time_t and from_time_t.
I read the standard like this:
It is implementation defined whether the value is rounder or truncated, but naturally the rounding or truncation only occurs on the most detailed part of the resulting time_t. That is: the combined information you get from time_t is never more wrong than 0.5 of its granularity.
If time_t on your system only supported seconds, you would be right that there could be 0.5 seconds systematic uncertainty (unless you find out how things were implemented).
tv_usec is not standard C++, but an accessor of time_t on posix. To conclude, you should not expect any rounding effects bigger than half of the smallest time value difference your system supports, so certainly not more than 0.5 micro seconds.
The most straight forward way is to use boost ptime. It has methods such as fractional_seconds()
http://www.boost.org/doc/libs/1_53_0/doc/html/date_time/posix_time.html#date_time.posix_time.ptime_class
For interop with std::chrono, you can convert as described here: https://stackoverflow.com/a/4918873/1149664
Or, have a look at this question: How to convert std::chrono::time_point to calendar datetime string with fractional seconds?

Inputs to sleep_until()

As per an answer to my previous question, I am trying to use sleep_until() but cannot find a tutorial that tells me how to use it with an actual time such as 1400:00h.
There are examples like this: std::this_thread::sleep_until(system_clock::now() + seconds(10));, but I would like something that actually lets me specify a clock time. What format should this be in? I would appreciate any examples.
To wait until a specified clock time, you need to get a time_t that represents that clock time, and then use std::chrono::system_clock::from_time_t to create a std::chrono::system_clock::time_point which you can then use with the xxx_until functions such as std::this_thread::sleep_until.
e.g.
void foo(){
tm timeout_tm={0};
// set timeout_tm to 14:00:01 today
timeout_tm.tm_year = 2013 - 1900;
timeout_tm.tm_mon = 7 - 1;
timeout_tm.tm_mday = 10;
timeout_tm.tm_hour = 14;
timeout_tm.tm_min = 0;
timeout_tm.tm_sec = 1;
timeout_tm.tm_isdst = -1;
time_t timeout_time_t=mktime(&timeout_tm);
std::chrono::system_clock::time_point timeout_tp=
std::chrono::system_clock::from_time_t(timeout_time_t);
std::this_thread::sleep_until(timeout_tp);
}
Have a look here: std::chrono
There are all sorts of date/time representation formats you'll need.
you want to use mktime to make up a time specification which you can use in sleep_until as done here