c++ c++11 date-parsing datetime-parsing

Cómo analizar una cadena de fecha en un c++ 11 std:: chrono time_point o similar?



c++11 date-parsing (3)

Esto es más bien C-ish y no tan elegante de una solución como la respuesta de Simple, pero creo que podría funcionar. Esta respuesta probablemente sea incorrecta, pero la dejaré para que alguien pueda publicar correcciones.

#include <iostream> #include <ctime> int main () { struct tm timeinfo; std::string buffer = "Thu, 9 Jan 2014 12:35:00"; if (!strptime(buffer.c_str(), "%a, %d %b %Y %T", &timeinfo)) std::cout << "Error."; time_t now; struct tm timeinfo2; time(&now); timeinfo2 = *gmtime(&now); time_t seconds = difftime(mktime(&timeinfo2), mktime(&timeinfo)); time(&seconds); struct tm result; result = *gmtime ( &seconds ); std::cout << result.tm_sec << " " << result.tm_min << " " << result.tm_hour << " " << result.tm_mday; return 0; }

Considere una cadena de formato de fecha histórica:

Thu Jan 9 12:35:34 2014

Quiero analizar esa cadena en algún tipo de representación de fecha C ++, luego calcular la cantidad de tiempo que ha transcurrido desde entonces.

A partir de la duración resultante, necesito acceso a los números de segundos, minutos, horas y días.

¿Se puede hacer esto con el nuevo espacio de nombres C ++ 11 std::chrono ? Si no, ¿cómo debería hacerlo hoy?

Estoy usando g ++ - 4.8.1 aunque, presumiblemente, una respuesta solo debe apuntar a la especificación de C ++ 11.


Nueva respuesta para una vieja pregunta. Justificación de la nueva respuesta: la pregunta fue editada desde su forma original porque las herramientas en ese momento no manejarían exactamente lo que se estaba preguntando. Y la respuesta aceptada resultante da un comportamiento sutilmente diferente de lo que la pregunta original pedía.

No estoy tratando de dejar la respuesta aceptada. Es una buena respuesta. Es solo que la API C es tan confusa que es inevitable que ocurran errores como este.

La pregunta original era analizar "Thu, 9 Jan 2014 12:35:34 +0000" . Entonces, claramente, la intención era analizar una marca de tiempo que representa una hora UTC. Pero strptime (que no es C o C ++ estándar, sino que es POSIX) no analiza el desplazamiento UTC posterior indicando que se trata de una marca de tiempo UTC (lo formateará con %z , pero no lo analizará).

La pregunta fue editada para preguntar sobre "Thu Jan 9 12:35:34 2014" . Pero la pregunta no fue editada para aclarar si se trataba de una marca de tiempo UTC, o una marca de tiempo en la zona horaria local actual de la computadora. La respuesta aceptada supone implícitamente que la marca de tiempo representa la zona horaria local actual de la computadora debido al uso de std::mktime .

std::mktime no solo transforma el tipo de campo tm en el tipo de serie time_t , sino que también realiza un ajuste de compensación desde el huso horario local de la computadora a UTC.

Pero, ¿qué ocurre si queremos analizar una marca de tiempo UTC como pregunta original (sin editar)?

Eso se puede hacer hoy utilizando esta nueva biblioteca gratuita de código abierto .

#include "date.h" #include <iostream> #include <sstream> int main() { using namespace std; using namespace date; istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"}; sys_seconds tp; in >> parse("%a, %d %b %Y %T %z", tp); }

Esta biblioteca puede analizar %z . Y date::sys_seconds es solo un typedef para:

std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>

La pregunta también pregunta:

A partir de la duración resultante, necesito acceso a los números de segundos, minutos, horas y días.

Esa parte ha quedado sin respuesta. Así es como lo haces con esta biblioteca . Para esta parte también voy a usar una segunda biblioteca de solo encabezado "chrono_io.h" :

#include "chrono_io.h" #include "date.h" #include <iostream> #include <sstream> int main() { using namespace std; using namespace date; istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"}; sys_seconds tp; in >> parse("%a, %d %b %Y %T %z", tp); auto tp_days = floor<days>(tp); auto hms = make_time(tp - tp_days); std::cout << "Number of days = " << tp_days.time_since_epoch() << ''/n''; std::cout << "Number of hours = " << hms.hours() << ''/n''; std::cout << "Number of minutes = " << hms.minutes() << ''/n''; std::cout << "Number of seconds = " << hms.seconds() << ''/n''; }

floor<days> trunca el punto de tiempo de precisión de time_point a un punto de tiempo de precisión de time_point . Si resta los días-precision time_point de tp , se queda con una duration que representa el tiempo transcurrido desde la medianoche (UTC).

La función de fábrica make_time toma cualquier duration (en este caso, tiempo desde la medianoche) y crea un tipo de campo de {hours, minutes, seconds} con getters para cada campo. Si la duración tiene una precisión mayor que segundos, este tipo de campo también tendrá un getter para las subsegundas.

Finalmente, usando "chrono_io.h" , uno puede simplemente imprimir todas estas duraciones. Este ejemplo genera:

Number of days = 16079[86400]s Number of hours = 12h Number of minutes = 35min Number of seconds = 34s

El [86400]s representa las unidades de la duration que tiene días de precisión. Entonces 2014-01-09 es 16079 días después de 1970-01-01.


std::tm tm = {}; std::stringstream ss("Jan 9 2014 12:35:34"); ss >> std::get_time(&tm, "%b %d %Y %H:%M:%S"); auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));

GCC anterior a la versión 5 no implementa std::get_time . También deberías poder escribir:

std::tm tm = {}; strptime("Thu Jan 9 2014 12:35:34", "%a %b %d %Y %H:%M:%S", &tm); auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));