c++ - steady_clock - Cómo convertir std:: chrono:: time_point a calendario datetime string con fracciones de segundos?
date c++ (5)
Cómo convertir std :: chrono :: time_point a calendario datetime string con fracciones de segundos? Por ejemplo: "10-10-2012 12: 38: 40.123456".
En general, no puedes hacer esto de manera directa. time_point
es esencialmente solo una duration
de una época específica del reloj.
Si tiene un std::chrono::system_clock::time_point
, entonces puede usar std::chrono::system_clock::to_time_t
para convertir el time_point
a time_t
, y luego usar las funciones normales de C, como strftime
o strftime
para formatearlo.
Código de ejemplo:
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;
Esto funcionó para mí para un formato como YYYY.MM.DD-HH.MM.SS.fff. Intentar que este código sea capaz de aceptar cualquier formato de cadena será como reinventar la rueda (es decir, hay funciones para todo esto en Boost).
std::chrono::system_clock::time_point string_to_time_point(const std::string &str)
{
using namespace std;
using namespace std::chrono;
int yyyy, mm, dd, HH, MM, SS, fff;
char scanf_format[] = "%4d.%2d.%2d-%2d.%2d.%2d.%3d";
sscanf(str.c_str(), scanf_format, &yyyy, &mm, &dd, &HH, &MM, &SS, &fff);
tm ttm = tm();
ttm.tm_year = yyyy - 1900; // Year since 1900
ttm.tm_mon = mm - 1; // Month since January
ttm.tm_mday = dd; // Day of the month [1-31]
ttm.tm_hour = HH; // Hour of the day [00-23]
ttm.tm_min = MM;
ttm.tm_sec = SS;
time_t ttime_t = mktime(&ttm);
system_clock::time_point time_point_result = std::chrono::system_clock::from_time_t(ttime_t);
time_point_result += std::chrono::milliseconds(fff);
return time_point_result;
}
std::string time_point_to_string(std::chrono::system_clock::time_point &tp)
{
using namespace std;
using namespace std::chrono;
auto ttime_t = system_clock::to_time_t(tp);
auto tp_sec = system_clock::from_time_t(ttime_t);
milliseconds ms = duration_cast<milliseconds>(tp - tp_sec);
std::tm * ttm = localtime(&ttime_t);
char date_time_format[] = "%Y.%m.%d-%H.%M.%S";
char time_str[] = "yyyy.mm.dd.HH-MM.SS.fff";
strftime(time_str, strlen(time_str), date_time_format, ttm);
string result(time_str);
result.append(".");
result.append(to_string(ms.count()));
return result;
}
Hubiera puesto esto en un comentario sobre la respuesta aceptada, ya que es allí donde pertenece, pero no puedo. Entonces, solo en caso de que alguien obtenga resultados poco confiables, esta podría ser la razón.
Tenga cuidado con la respuesta aceptada, falla si el punto de tiempo es anterior a la época.
Esta línea de código:
std::size_t fractional_seconds = ms.count() % 1000;
producirá valores inesperados si ms.count () es negativo (ya que size_t no está destinado a contener valores negativos).
Se sigue un código autoexplicativo que primero crea un std::tm
correspondiente a 10-10-2012 12:38:40, lo convierte a un std::chrono::system_clock::time_point
, agrega 0.123456 segundos, y luego lo imprime convirtiendo de nuevo a std::tm
. Cómo manejar los segundos fraccionarios está en el último paso.
#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'';
}
Para mí este producto:
10-10-2012 12:38:40.123456
Su std::chrono::system_clock::time_point
puede o no ser lo suficientemente preciso como para contener microsegundos.
Actualizar
Una forma más fácil es simplemente usar esta biblioteca de fechas . El código se simplifica hasta (usando literales de duración C ++ 14):
#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'';
}
qué salidas:
2012-10-10 12:38:40.123456
Puede saltarse el static_assert
si no necesita probar que el tipo de t
es un std::chrono::time_point
.
Si la salida no es de su agrado, por ejemplo, realmente le gustaría ordenar dd-mm-aaaa, usted podría:
#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'';
}
que da exactamente el resultado solicitado:
10-10-2012 12:38:40.123456
Actualizar
Aquí es cómo formatear prolijamente la hora actual UTC con milisegundos de precisión:
#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()));
}
que solo me dio salida:
2016-10-17 16:36:02.975
C ++ 17 le permitirá reemplazar time_point_cast<milliseconds>
con floor<milliseconds>
. Hasta entonces, la date::floor
está disponible en "date.h"
.
std::cout << date::format("%F %T/n", date::floor<milliseconds>(system_clock::now()));
Si system_clock, esta clase tiene time_t conversión.
#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
}
resultado del ejemplo:
Thu Oct 11 19:10:24 2012
EDITAR: Pero, time_t no contiene segundos fraccionarios. Otra forma es usar la función time_point :: time_since_epoch (). Esta función devuelve la duración de epoch. El ejemplo siguiente es la fracción de segundo mili de resolución.
#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;
}
resultado del ejemplo:
Thu Oct 11 19:10:24 2012
925