How to convert std::chrono::time_point to calendar datetime string with fractional seconds?
If system_clock, this class have time_t conversion.
#include <iostream>
#include <chrono>
#include <ctime>
using namespace std::chrono;
int main()
{
system_clock::time_point p = system_clock::now();
std::time_t t = system_clock::to_time_t(p);
std::cout << std::ctime(&t) << std::endl; // for example : Tue Sep 27 14:21:13 2011
}
example result:
Thu Oct 11 19:10:24 2012
EDIT: But, time_t does not contain fractional seconds. Alternative way is to use time_point::time_since_epoch() function. This function returns duration from epoch. Follow example is milli second resolution's fractional.
#include <iostream>
#include <chrono>
#include <ctime>
using namespace std::chrono;
int main()
{
high_resolution_clock::time_point p = high_resolution_clock::now();
milliseconds ms = duration_cast<milliseconds>(p.time_since_epoch());
seconds s = duration_cast<seconds>(ms);
std::time_t t = s.count();
std::size_t fractional_seconds = ms.count() % 1000;
std::cout << std::ctime(&t) << std::endl;
std::cout << fractional_seconds << std::endl;
}
example result:
Thu Oct 11 19:10:24 2012
925
Self-explanatory code follows which first creates a std::tm
corresponding to 10-10-2012 12:38:40, converts that to a std::chrono::system_clock::time_point
, adds 0.123456 seconds, and then prints that out by converting back to a std::tm
. How to handle the fractional seconds is in the very last step.
#include <iostream>
#include <chrono>
#include <ctime>
int main()
{
// Create 10-10-2012 12:38:40 UTC as a std::tm
std::tm tm = {0};
tm.tm_sec = 40;
tm.tm_min = 38;
tm.tm_hour = 12;
tm.tm_mday = 10;
tm.tm_mon = 9;
tm.tm_year = 112;
tm.tm_isdst = -1;
// Convert std::tm to std::time_t (popular extension)
std::time_t tt = timegm(&tm);
// Convert std::time_t to std::chrono::system_clock::time_point
std::chrono::system_clock::time_point tp =
std::chrono::system_clock::from_time_t(tt);
// Add 0.123456 seconds
// This will not compile if std::chrono::system_clock::time_point has
// courser resolution than microseconds
tp += std::chrono::microseconds(123456);
// Now output tp
// Convert std::chrono::system_clock::time_point to std::time_t
tt = std::chrono::system_clock::to_time_t(tp);
// Convert std::time_t to std::tm (popular extension)
tm = std::tm{0};
gmtime_r(&tt, &tm);
// Output month
std::cout << tm.tm_mon + 1 << '-';
// Output day
std::cout << tm.tm_mday << '-';
// Output year
std::cout << tm.tm_year+1900 << ' ';
// Output hour
if (tm.tm_hour <= 9)
std::cout << '0';
std::cout << tm.tm_hour << ':';
// Output minute
if (tm.tm_min <= 9)
std::cout << '0';
std::cout << tm.tm_min << ':';
// Output seconds with fraction
// This is the heart of the question/answer.
// First create a double-based second
std::chrono::duration<double> sec = tp -
std::chrono::system_clock::from_time_t(tt) +
std::chrono::seconds(tm.tm_sec);
// Then print out that double using whatever format you prefer.
if (sec.count() < 10)
std::cout << '0';
std::cout << std::fixed << sec.count() << '\n';
}
For me this outputs:
10-10-2012 12:38:40.123456
Your std::chrono::system_clock::time_point
may or may not be precise enough to hold microseconds.
Update
An easier way is to just use this date library. The code simplifies down to (using C++14 duration literals):
#include "date.h"
#include <iostream>
#include <type_traits>
int
main()
{
using namespace date;
using namespace std::chrono;
auto t = sys_days{10_d/10/2012} + 12h + 38min + 40s + 123456us;
static_assert(std::is_same<decltype(t),
time_point<system_clock, microseconds>>{}, "");
std::cout << t << '\n';
}
which outputs:
2012-10-10 12:38:40.123456
You can skip the static_assert
if you don't need to prove that the type of t
is a std::chrono::time_point
.
If the output isn't to your liking, for example you would really like dd-mm-yyyy ordering, you could:
#include "date.h"
#include <iomanip>
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
using namespace std;
auto t = sys_days{10_d/10/2012} + 12h + 38min + 40s + 123456us;
auto dp = floor<days>(t);
auto time = make_time(t-dp);
auto ymd = year_month_day{dp};
cout.fill('0');
cout << ymd.day() << '-' << setw(2) << static_cast<unsigned>(ymd.month())
<< '-' << ymd.year() << ' ' << time << '\n';
}
which gives exactly the requested output:
10-10-2012 12:38:40.123456
Update
Here is how to neatly format the current time UTC with milliseconds precision:
#include "date.h"
#include <iostream>
int
main()
{
using namespace std::chrono;
std::cout << date::format("%F %T\n", time_point_cast<milliseconds>(system_clock::now()));
}
which just output for me:
2016-10-17 16:36:02.975
C++17 will allow you to replace time_point_cast<milliseconds>
with floor<milliseconds>
. Until then date::floor
is available in "date.h"
.
std::cout << date::format("%F %T\n", date::floor<milliseconds>(system_clock::now()));
Update C++20
In C++20 this is now simply:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
auto t = sys_days{10d/10/2012} + 12h + 38min + 40s + 123456us;
std::cout << t << '\n';
}
Or just:
std::cout << std::chrono::system_clock::now() << '\n';
std::format
will be available to customize the output.
In general, you can't do this in any straightforward fashion. time_point
is essentially just a duration
from a clock-specific epoch.
If you have a std::chrono::system_clock::time_point
, then you can use std::chrono::system_clock::to_time_t
to convert the time_point
to a time_t
, and then use the normal C functions such as ctime
or strftime
to format it.
Example code:
std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(tp);
std::tm timetm = *std::localtime(&time);
std::cout << "output : " << std::put_time(&timetm, "%c %Z") << "+"
<< std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count() % 1000 << std::endl;