steady_clock c++ datetime c++11 std chrono

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