How to convert std::chrono::time_point to string
Howard Hinnant's free, open source, header-only, portable date/time library is a modern way to do this that doesn't traffic through the old C API, and doesn't require that you discard all of your sub-second information. This library is also being proposed for standardization.
There is a lot of flexibility in formatting. The easiest way is to just stream out:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
std::cout << std::chrono::system_clock::now() << '\n';
}
This just output for me:
2017-09-15 13:11:34.356648
The using namespace date;
is required in order to find the streaming operator for the system_clock::time_point
(it isn't legal for my lib to insert it into namespace std::chrono
). No information is lost in this format: the full precision of your system_clock::time_point
will be output (microseconds
where I ran this on macOS).
The full suite of strftime
-like formatting flags is available for other formats, with minor extensions to handle things like fractional seconds. Here is another example that outputs with millisecond precision:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << format("%D %T %Z\n", floor<milliseconds>(system_clock::now()));
}
which just output for me:
09/15/17 13:17:40.466 UTC
The most flexible way to do so is to convert it to struct tm
and then use strftime
(it's like sprintf
for time). Something like:
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&now_c);
/// now you can format the string as you like with `strftime`
Look up the documentation for strftime
here.
If you have localtime_s
or localtime_r
available you should use either in preference to localtime
.
There are many other ways to do this, but, while mostly easier to use, these result in some predefined string representation. You could just "hide" all of the above in a function for ease of use.
Code solution
The following function converts from chrono
time_point
to string (serialization).
#include <chrono>
#include <iomanip>
#include <sstream>
using time_point = std::chrono::system_clock::time_point;
std::string serializeTimePoint( const time_point& time, const std::string& format)
{
std::time_t tt = std::chrono::system_clock::to_time_t(time);
std::tm tm = *std::gmtime(&tt); //GMT (UTC)
//std::tm tm = *std::localtime(&tt); //Locale time-zone, usually UTC by default.
std::stringstream ss;
ss << std::put_time( &tm, format.c_str() );
return ss.str();
}
// example
int main()
{
time_point input = std::chrono::system_clock::now();
std::cout << serializeTimePoint(input, "UTC: %Y-%m-%d %H:%M:%S") << std::endl;
}
Time zone
The time_point
data-type has no internal representation for the time-zone, in consequence, the time-zone is aggregated by the conversion to std::tm
(by the functions gmtime
or localtime
). It is not recommended to add/substract the time-zone from the input, because you would get an incorrect time-zone displayed with %Z
, thus, it is better to set the correct local time (OS dependent) and use localtime()
.
Technical vs User-friendly serialization
For technical usage, hard-coded time format is a good solution. However, to display to users, one should use a locale
to retrieve the user preference and show time-stamp in that format.
C++20
Since C++20, we have nice serialization and parsing functions for time_point and duration.
std::chrono::to_stream
std::chrono::format