Convert a string with micro second precision to a chrono time_point - c++

This is a quite trivial question. But I couldn't find a trivial answer for this.
I have a timestamp string with microsecond precision, say, 20:38:42.444491. How do I convert this into a proper time object so that I can use it in time comparisons etc...
I was trying to use the date lib by HowardHinnant. However I am not sure how to use it only with a timestamp.
e.g.
#include <iostream>
#include "date.h"
using namespace std;
// This works fine
chrono::system_clock::time_point makeDateTime(const string& s) {
istringstream in{s};
chrono::system_clock::time_point tp;
in >> date::parse("%d/%m/%y %T", tp);
return tp;
}
// This always returns epoch. How to fix this ?
chrono::system_clock::time_point makeTime(const string& s) {
istringstream in{s};
chrono::system_clock::time_point tp;
in >> date::parse("%T", tp);
return tp;
}
int main() {
auto a = makeDateTime("30/03/09 16:31:32.121567");
cout << a.time_since_epoch().count() << endl; // 1238430692121567000
auto b = makeTime("16:31:32.121567");
cout << b.time_since_epoch().count() << endl; // 0
return 0;
}
As shown, I can correctly parse a date-time stamp. But I need to know how to handle it if I only have a time (without a date).

With just a time, you've got a couple of options. But you should definitely not put "just a time" into a system_clock::time_point. The reason for this is that system_clock::time_point has a specific meaning: This measures the time since (or before) 1970-01-01 00:00:00 UTC, excluding leap seconds.
To be fair, this meaning is absent in C++11/14/17, and is only specified in C++20. However all implementations followed this convention in C++11/14/17.
You could store "time of day" in a duration such as microseconds. Then in your code you simply interpret this duration as time elapsed since midnight, where you get to define "midnight" (local midnight? UTC? etc.).
std::chrono::microseconds
makeTime(std::string s)
{
using namespace std;
using namespace std::chrono;
istringstream in{move(s)};
microseconds tp;
in >> date::parse("%T", tp);
return tp;
}
The above solution is simple, and that is good. But it is possible that this "time of day" could be accidentally mixed up with some other duration that doesn't mean "time of day" in a way that would cause logic errors in your program.
To make the above more type-safe, you could create a "time of day" clock:
struct time_of_day
{
using duration = std::chrono::microseconds;
using rep = duration::rep;
using period = duration::period;
using time_point = std::chrono::time_point<time_of_day>;
static constexpr bool is_steady = false;
static
time_point
now()
{
using namespace date;
using namespace std::chrono;
auto t_sys = floor<microseconds>(system_clock::now());
return time_point{t_sys - floor<days>(t_sys)};
};
};
time_of_day::time_point
makeTime(std::string s)
{
using namespace std;
using namespace std::chrono;
istringstream in{move(s)};
microseconds d;
in >> date::parse("%T", d);
return time_of_day::time_point{d};
}
Above I've defined midnight as UTC just to simplify the demonstration.
The time_of_day solution isn't necessarily better. The programmer should decide if the extra complexity cost justifies the type safety benefit.

Related

Parse time-of-day using C++20's chrono facilities / HH's date library

I am trying to parse a time-of-day string in the form of "HH:MM", and receive back the nanoseconds since midnight.
So long as I provide a date and a time I can successfully parse it, eg:
(I am using Howard Hinnant's date library in lieu of C++20's chrono, as my std library (gcc 11.2) doesn't support this yet)
#include <iostream>
#include <chrono>
#include <date/date.h>
int main()
{
std::string str = "1970-01-01 08:00";
std::string format = "%Y-%m-%d %H:%M";
std::istringstream ss(str);
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t;
ss >> date::parse(format, t);
if (ss.fail()) [[unlikely]]
std::cerr << "parse failed\n";
std::cout << "ns=" << t.time_since_epoch().count() << '\n';
return 0;
}
I see that chrono has a "time of day" class, hh_mm_ss, but I don't see any associated parsing functionality.
Is it possible to parse a time-of-day string using a format, eg, "%H:%M"?
The way to do this is to parse a duration such as nanoseconds and interpret that as "time duration since midnight":
#include <iostream>
#include <chrono>
#include <date/date.h>
int main()
{
std::string str = "08:00";
std::string format = "%H:%M";
std::istringstream ss(str);
std::chrono::nanoseconds t;
ss >> date::parse(format, t);
if (ss.fail()) [[unlikely]]
std::cerr << "parse failed\n";
using date::operator<<;
std::cout << "time of day = " << t << '\n';
}
This involves:
Truncate your string inputs to the desired information.
Change the type of t to nanoseconds.
I used the streaming operator for nanoseconds and changed the formatting so that the output is:
time of day = 28800000000000ns
If you would rather get your original output without the ns suffix, then you can print out t.count(), and in that case there is no need for the using date::operator<<;.
If you want to get really fancy you can create your own custom chrono::time_point that has the semantics of "time of day". That's usually overkill. But if you would like to head that direction, here's some thoughts on it: https://stackoverflow.com/a/56727183/576911.

How do I convert a string back into a time_point?

I am taking a system_clock time_point, converting it to a string, and then saving it to a configuration file.
Now I want to read that config file and turn the string back into a time point so that I can calculate the difference in time between two time points.
void SaveLastShuffleTime() {
m_lastShuffleTime = std::chrono::system_clock::now();
auto m_lastShuffleTimeTimeT = std::chrono::system_clock::to_time_t(m_lastShuffleTimeTimepoint);
stringstream m_lastShuffeTimeSS;
m_lastShuffeTimeSS << std::put_time(std::localtime(&m_lastShuffleTimeTimeT), "%Y-%m-%d %X");
m_deviceStateSettings.UpdateDeviceStateSettings(LAST_SHUFFLE_TIME, m_lastShuffeTimeSS.str());
}
void CompareLastShuffleTime() {
m _currentShuffleTime = std::chrono::system_clock::now();
/* READ CONFIG FILE AND CONVERT BACK TO TIME POINT */
int timeSinceLastShuffle = (duration_cast<minutes>(m_currentShuffleTime - m_oldShuffleTime)).count();
}
Please let me know if this is viable. The alternative is to save the timepoint as an integer but I would prefer not to do that.
Thanks
I recommend outputting UTC as opposed to local time so that the difference between timestamps isn't altered by UTC offset jumps (e.g. daylight saving).
C++20 makes this very easy, and allows timestamps with subsecond precision:
#include <cassert>
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace std::chrono;
stringstream s;
auto tp = system_clock::now();
auto tp_save = tp;
s << tp << '\n'; // Write it out
tp = {}; // Zero out the timestamp
s >> parse("%F %T", tp); // Parse it back in
assert(tp == tp_save); // Make sure it is the same
std::cout << s.str(); // This is what was formatted/parsed
}
Example output:
2021-06-17 16:10:10.562738
Vendors are still working on getting this out. But you can use this syntax today with C++11/14/17 and a free, open-source, header-only preview of this part of C++20.1
Just add:
#include "date/date.h"
using namespace date;
and the above works with the preview library.
1 Full disclosure: I am the lead author of this library. I am not pursuing any financial gain from this effort. But sometimes people get grumpy if I don't fully disclose this information.
You could use cctz library. It provides convenient functions for formatting timepoint cctz::format to a string and parsing cctz::parse from a string. And also for working with timezones. Example:
#include <chrono>
#include <iostream>
#include <string>
#include "cctz/time_zone.h"
int main() {
const std::chrono::system_clock::time_point now =
std::chrono::system_clock::now();
std::string now_str =
cctz::format("%Y-%m-%d %H:%M:%S%z", now, cctz::utc_time_zone());
std::cout << now_str << std::endl;
std::chrono::system_clock::time_point tp;
const bool ok =
cctz::parse("%Y-%m-%d %H:%M:%S%z", now_str, cctz::utc_time_zone(), &tp);
if (!ok)
return -1;
}
std::istringstream ss(str);
tm t;
ss >> std::get_time(&t, "%Y-%m-%dT%H:%M:%S");
std::time_t tt = std::mktime(&t);
/// If you don't need UTC time, just comment out the line below.
tt = std::mktime(std::gmtime(&tt));
return std::chrono::system_clock::from_time_t(tt);

How to convert dd-mmm-yyyy and now() to days?

I need convert a dd-mmm-year string to epoch days to do some simple math. Specifically, calculate the number of days from now() to the date of the string.
I'm looking at <chrono> and <ctime> but am not seeing an obvious way to do that? How do you convert dd-mmm-year and now() to epoch days?
This can easily be done with this free, open-source, header-only preview of C++20 , which works with C++11/14/17:
#include "date/date.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
string s1 = "25-Mar-2021";
string s2 = "20-Jul-2021";
istringstream in{s1};
in.exceptions(ios::failbit);
sys_days t1;
in >> parse("%d-%b-%Y", t1);
in.str(s2);
in.clear();
sys_days t2;
in >> parse("%d-%b-%Y", t2);
cout << t2 - t1 << '\n';
}
sys_days is a type alias for std::chrono::time_point<system_clock, duration<int, ratio<86400>>>. But you can think of it as a count of days since since 1970-01-01.
The program above outputs:
117d
The type of the expression t2 - t1 is std::chrono::duration<int, ratio<86400>>.
Here is a live example you can experiment with.
Edit:
You can convert durations (such as t2 - t1) to a signed integral type by using the .count() member function:
auto i = (t2 - t1).count(); // 117
Another way to do it is to divide by days{1}:
auto i = (t2 - t1)/days{1}; // 117
This latter technique gives those who know dimensional analysis a warm fuzzy feeling. :-)
You can convert std::chrono::system_clock::now() to type sys_days like this:
auto t2 = floor<days>(system_clock::now());
This gives the current date according to UTC. If you need the current date according to some other time zone (such as the computer's local time zone setting), then that involves an additional library (at the same link) which is not header-only and involves some installation. In that case one would work in terms of local_days instead of sys_days:
#include "date/tz.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
string s1 = "25-Mar-2021";
istringstream in{s1};
in.exceptions(ios::failbit);
local_days t1;
in >> parse("%d-%b-%Y", t1);
auto t2 = floor<days>(current_zone()->to_local(system_clock::now()));
cout << t2 - t1 << '\n';
}
Output (currently):
1d

C++ calculate time difference between 2 strings with time zone

I need to check the difference between 2 strings timestamp in c++. the timestamp contains the time zone (%Z) variable in it.
I used the diff time function to get difference
In short this is the code i tried:
string current = "2021-02-17 11:26:55 +04";
string old = "2021-02-17 11:26:56 +02";
cout<<current<<endl;
cout<<old<<endl;
struct tm currentTime, reqTime;
strptime(current.c_str(), "%Y-%m-%d %H:%M:%S %Z", &currentTime);
strptime(old.c_str(), "%Y-%m-%d %H:%M:%S %Z", &reqTime);
double seconds = difftime(mktime(&currentTime), mktime(&reqTime));
the codes give a 1 second difference between the 2 times. but it doesn't consider the difference in time zone.
How can I get the difference taking into consideration the time zone (in this example the difference is 2 hours and 1 second
or how can I manually transform both time to GMT and then do the difference
EDIT:
To get current date i used the following:
string currentDateTime() {
time_t now = time(0);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", &tstruct);
return buf;
}
This can easily be done in C++20. Unfortunately this part of C++20 isn't yet shipping. However there exists a free, open-source, header-only preview of this part of C++20 that can be used with C++11/14/17.
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
std::chrono::seconds
diff(std::string const& current, std::string const& old)
{
using namespace std;
using namespace std::chrono;
using namespace date;
istringstream in{current + " " + old};
in.exceptions(ios::failbit);
sys_seconds tp_c, tp_o;
in >> parse("%F %T %z", tp_c) >> parse(" %F %T %z", tp_o);
return tp_c - tp_o;
}
int
main()
{
using date::operator<<;
std::cout << diff("2021-02-17 11:26:55 +04",
"2021-02-17 11:26:56 +02") << '\n';
}
Above, sys_seconds is defined as a UTC time stamp with seconds precision. When this type is parsed with %z, the offset is applied to the parsed local time in order to obtain the UTC value. Then you can just subtract them.
This program outputs:
-7201s
To port this program to C++20, remove:
#include "date/date.h"
using namespace date;
using date::operator<<;

how can i compare a start time with the system clock using ctime/chrono libaray

I'm running into a error trying to compile the program with conversion from double to int. What I want is to be able to display out the difference not just in seconds but in hours/minutes/seconds but I can't think of how to make the difftime work. If there is a better option like using chrono, I would appreciate the help.
#include <chrono>
#include <ctime>
#include <iomanip>
#include <iostream>
int main() {
std::tm now{},;
std::chrono::system_clock::time_point cc;
std::cout << "enter\nyear month day\n";
std::cin >> now.tm_year >> now.tm_mon >> now.tm_mday;
now.tm_year -= 1900;
now.tm_mon -= 1;
std::time_t n = std::mktime(&now);
cc = std::chrono::system_clock::from_time_t(n);
n = std::chrono::system_clock::to_time_t(cc);
std::cout << std::put_time(std::localtime(&n), "%FT%T") << "\n";
std::time_t system_time = time(nullptr);
std::cout << asctime(localtime(&system_time));
double fc = difftime(system_time, mktime(&now));
std::cout << "time diff "<< fc << endl;
}
You should checkout the date lib from howard hinnant.
https://github.com/HowardHinnant/date
The tz lib in it Can do your local time diff calculation in without converting it to utc. (normally you should always convert to utc before calculation, because of the daylight saving time) It also contains format functions to stream it in hour min sec format.
The better way of doing it is using a steady_clock instead of system_clock.
I don't know what your task is but you may use another class such as Stopwatch to generate elapsed time.
#include <chrono>
#include <ctime>
class StopWatch {
private:
chrono::time_point<chrono::steady_clock> start;
public:
void reset() { start = chrono::steady_clock::now(); }
StopWatch() { reset(); }
double elapsedSeconds() {
chrono::duration<double> d = chrono::steady_clock::now() - start;
return chrono::duration_cast<chrono::microseconds>(d).count() / 1000000.;
}};
After that, you can simply use Stopwatch:
int main(void){
Stopwatch s;
cout<<s.elapsedSeconds();
}