How do I convert a string back into a time_point? - c++

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);

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.

Convert a string with micro second precision to a chrono time_point

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.

C++ get UTC time with milliseconds

I need to get UTC time with milliseconds, I tried use it:
std::string getCurrentUTC()
{
namespace bg = boost::gregorian;
static char const* const fmt = "%Y-%b-%d %H:%M:%S";
std::ostringstream ss;
ss.imbue(std::locale(std::cout.getloc(), new bg::date_facet(fmt)));
ss << bg::day_clock::universal_day();
return ss.str();
}
But it prints the following:
2020-Jun-29 00:00:00
I need the following format:
2020-Jun-29 00:00:00.000
How can I solve this problem?
You could get the UTC time with millisecond as follow:
struct timeb timebStruct;
ftime(&timebStruct);
struct tm *tmStruct = new tm();
gmtime_r(&timebStruct.time, tmStruct);
std::cout << tmStruct->tm_hour
<< tmStruct->tm_min << tmStruct->tm_sec <<
timebStruct.millitm << std::endl
Using this free, open-source, header-only preview of C++20 <chrono> you can write:
#include "date/date.h"
#include <chrono>
#include <string>
#include <sstream>
std::string
getCurrentUTC()
{
namespace ch = std::chrono;
using date::operator<<;
static char const* const fmt = "%Y-%b-%d %T";
std::ostringstream ss;
auto tp = ch::time_point_cast<ch::milliseconds>(ch::system_clock::now());
ss << date::format(fmt, tp);
return ss.str();
}
This works in C++11/14/17. For me it just output:
2020-Jun-29 13:42:21.946
which is the current time UTC to millisecond precision.
When C++20 <chrono> ships, this will port to it by:
Remove #include "date/date.h".
Remove using date::operator<<;
Add #include <format>
Change date::format to std::format
Change "%Y-%b-%d %T" to "{:%Y-%b-%d %T}".

convert Date to time in millisecond in c++?

I have a requirement where I have to convert given string in date time format to milliseconds from epoch.
In Javascript there is date to time conversion api but in c++ I couldn't find anything as such.
Input would look like '2016-Mar-15 09:23:58.665068'
output should be in milliseconds say 14520000785.
I have tried looking into boost but still couldn't find(or understand) how to do?
Also, going through google I find the other way round i.e. converting milliseconds to date format but not what I require nor any helpful post for same.
Any help will be much appreciated.
Using only standard library features:
#include <ctime>
#include <chrono>
#include <iostream>
int main()
{
std::tm tm = {};
const char* snext = ::strptime("2016-Mar-15 09:23:58.665068", "%Y-%b-%d %H:%M:%S", &tm);
auto time_point = std::chrono::system_clock::from_time_t(std::mktime(&tm));
long long duration_ms = time_point.time_since_epoch() / std::chrono::milliseconds(1) + std::atof(snext) * 1000.0f;
std::cout << duration_ms << std::endl;
}
Prints: 1458033838665
See std::chrono::system_clock::now and std::chrono::milliseconds.
Most straightforward would be to just spell it out:
auto pt = boost::lexical_cast<ptime>("2016-Mar-15 09:23:58.665068");
std::cout << (pt - ptime { {1970,0,0}, {} }).total_milliseconds();
Live On Coliru
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/date_time.hpp>
#include <sstream>
int main() {
using boost::posix_time::ptime;
ptime pt;
{
std::istringstream iss("2016-Mar-15 09:23:58.665068");
auto* f = new boost::posix_time::time_input_facet("%Y-%b-%d %H:%M:%S%f");
std::locale loc(std::locale(""), f);
iss.imbue(loc);
iss >> pt;
}
std::cout << pt << " " << (pt - ptime{{1970,1,1},{}}).total_milliseconds();
}
Prints
2016-Mar-15 09:23:58.665068 1458033838665
Of course, extract the parsing in a helper function. Keep the locale around for reuse etc.

Outputting Date and Time in C++ using std::chrono

I have been upgrading some old code and have been trying to update to c++11 where possible. The following code is how I used to display the time and date in my program
#include <iostream>
#include <string>
#include <stdio.h>
#include <time.h>
const std::string return_current_time_and_date() const
{
time_t now = time(0);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%d %X", &tstruct);
return buf;
}
I would like to output the current time and date in a similar format using std::chrono(or similar) but am unsure how to go about doing so. Any help would be greatly appreciated. Thanks
The <chrono> library only deals with time and not dates, except for the system_clock which has the ability to convert its timepoints to time_t. So using <chrono> for dates will not improve things much. Hopefully we get something like chrono::date in the not too distant future.
That said, you can use <chrono> in the following way:
#include <chrono> // chrono::system_clock
#include <ctime> // localtime
#include <sstream> // stringstream
#include <iomanip> // put_time
#include <string> // string
std::string return_current_time_and_date()
{
auto now = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X");
return ss.str();
}
Note that std::localtime may cause data races. localtime_r or similar functions may be available on your platforms.
Update:
Using a new version of Howard Hinnant's date library you can write:
#include "date.h"
#include <chrono>
#include <string>
#include <sstream>
std::string return_current_time_and_date() {
auto now = std::chrono::system_clock::now();
auto today = date::floor<days>(now);
std::stringstream ss;
ss << today << ' ' << date::make_time(now - today) << " UTC";
return ss.str();
}
This will print out something like "2015-07-24 05:15:34.043473124 UTC".
On an unrelated note, returning const objects has become undesirable with C++11; const return values cannot be moved from. I also removed the trailing const because trailing const is only valid for member functions and this function has no need to be a member.
Here's a C++20 solution:
#include <chrono>
#include <format>
std::string get_current_time_and_date()
{
auto const time = std::chrono::current_zone()
->to_local(std::chrono::system_clock::now());
return std::format("{:%Y-%m-%d %X}", time);
}
std::chrono::time_zone::to_local converts a system clock time point (std::chrono::time_point<std::chrono::system_clock, TDuration>) to a local time point (std::chrono::local_time<TDuration>). This local time point can then be formatted using std::format with formatting options similar to strftime.
Currently, only MSVC has implemented std::format. The calendar and timezone additions to chrono
are currently "partially" implemented by Clang and GCC, but check here for the updated status: https://en.cppreference.com/w/cpp/compiler_support. For more information about the chrono library, read here: https://en.cppreference.com/w/cpp/chrono.
An example:
#include <iostream>
#include <chrono>
#include <ctime>
std::string getTimeStr(){
std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::string s(30, '\0');
std::strftime(&s[0], s.size(), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
return s;
}
int main(){
std::cout<<getTimeStr()<<std::endl;
return 0;
}
Output as below:
For getting also milliseconds, I use chrono and C function localtime_r which is thread-safe (in opposition to std::localtime).
#include <iostream>
#include <chrono>
#include <ctime>
#include <time.h>
#include <iomanip>
int main() {
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::chrono::milliseconds now2 = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
struct tm currentLocalTime;
localtime_r(&currentTime, &currentLocalTime);
char timeBuffer[80];
std::size_t charCount { std::strftime( timeBuffer, 80,
"%D %T",
&currentLocalTime)
};
if (charCount == 0) return -1;
std::cout << timeBuffer << "." << std::setfill('0') << std::setw(3) << now2.count() % 1000 << std::endl;
return 0;
}
For format: http://www.cplusplus.com/reference/ctime/strftime/
bames53 solutions are good, but do not compile on my VS2017. The solution with ctime does not compile because localtime is very deprecated. The one with date.h does not compile with the current date.h I just took off github even though the documentation says they should, because today cannot be streamed as is. I omitted the includes but here is code that works:
void TimeTest()
{
auto n = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(n);
std::tm buf;
localtime_s(&buf, &in_time_t);
std::cout << std::put_time(&buf, "%Y-%m-%d %X") << std::endl;
}
// I just added date.h from this link's guthub to the project.
// https://howardhinnant.github.io/date/date.html
void TimeTest1() {
auto now = std::chrono::system_clock::now();
auto today = floor<date::days>(std::chrono::system_clock::now());
std::cout << date::year_month_day{ today } << ' ' << date::make_time(now - today) << std::endl;
}
// output is
// 2018-04-08 21:19:49
// 2018-04-08 18:19:49.8408289
Feel free to fix bames53 solution and delete mine. My text just won't fit in a comment. I'm sure it can save many people from grief.
The fmt library has the ability to format tm structures: it has the same spec as strftime.
#include <ctime>
#include <fmt/chrono.h>
std::string current_datetime(void)
{
std::time_t tt = std::time(nullptr);
std::tm *tm = std::localtime(&tt);
return fmt::format("{:%Y%m%d}", *tm);
}
Although correct answers were already given, I decided to implement one more solution that outputs also fractional part of second.
You may notice in my code that sometimes I subtract one second from time_t value, - std::chrono::seconds(1), it is because according to documentation to_time_t() may round value instead of truncating (according to doc "If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated"), hence I have to subtract 1 second to make it truncated time.
Try it online!
#include <chrono>
#include <string>
#include <sstream>
#include <iomanip>
std::string FormatTime(std::chrono::system_clock::time_point tp) {
std::stringstream ss;
auto t = std::chrono::system_clock::to_time_t(tp);
auto tp2 = std::chrono::system_clock::from_time_t(t);
if (tp2 > tp)
t = std::chrono::system_clock::to_time_t(tp - std::chrono::seconds(1));
ss << std::put_time(std::localtime(&t), "%Y-%m-%d %T")
<< "." << std::setfill('0') << std::setw(3)
<< (std::chrono::duration_cast<std::chrono::milliseconds>(
tp.time_since_epoch()).count() % 1000);
return ss.str();
}
std::string CurrentTimeStr() {
return FormatTime(std::chrono::system_clock::now());
}
#include <iostream>
int main() {
std::cout << CurrentTimeStr() << std::endl;
}
Example Output:
2021-12-02 04:10:51.876
As suggested by #AndyK, starting from C++20 you can use std::chrono::current_zone() and its method to_local(), they return std::chrono::local_time which is directly convertible to your desired string format by outputting to std::ostringstream or through std::format(). Whole function becomes very short:
#include <chrono>
#include <string>
#include <sstream>
#include <iostream>
std::string CurrentTimeStr() {
return (std::ostringstream{} << std::chrono::current_zone()->to_local(
std::chrono::system_clock::now())).str().substr(0, 23);
}
int main() {
std::cout << CurrentTimeStr() << std::endl;
}
But right now not all compilers support this current_zone() function, online GodBolt servers failed to compile it on trunk CLang and GCC, but MSVC compiles it well. Although my local laptop installation of CLang compiled it too.
You can improve the answer from #bames53 by using Boost lexical_cast instead of string stream manipulations.
Here is what I do:
#include <boost/lexical_cast.hpp>
#include <ctime>
std::string return_current_time_and_date() {
auto current_time = std::time(0);
return boost::lexical_cast<std::string>(std::put_time(std::gmtime(& current_time), "%Y-%m-%d %X"));
}