c++ - Cómo analizar la fecha/hora de la cadena?
datetime boost (4)
Entrada : cadenas con fecha y hora opcional. Las diferentes representaciones serían agradables pero necesarias. Las cadenas son suministradas por el usuario y pueden estar mal formadas. Ejemplos:
-
"2004-03-21 12:45:33"
(considero que este es el diseño predeterminado) -
"2004/03/21 12:45:33"
(diseño opcional) -
"23.09.2004 04:12:21"
(formato alemán, opcional) -
"2003-02-11"
(puede que falte el tiempo)
Salida necesaria : Segundos desde Epoch (1970/01/01 00:00:00) o algún otro punto fijo.
Bonificación : Además, leer el desplazamiento UTC de la hora del sistema local sería genial.
Se supone que la entrada es una hora local en la máquina en cuestión. La salida debe ser UTC. El sistema es solo Linux (se necesitan Debian Lenny y Ubuntu).
Intenté usar boost/date_time
, pero debo admitir que no puedo boost/date_time
la documentación. Lo siguiente funciona sin la conversión necesaria de la hora local del sistema a UTC:
std::string date = "2000-01-01";
boost::posix_time::ptime ptimedate = boost::posix_time::time_from_string(date);
ptimedate += boost::posix_time::hours(Hardcoded_UTC_Offset);// where to get from?
struct tm = boost::posix_time::to_tm(ptimedate);
int64_t ticks = mktime(&mTmTime);
Creo que boost::date_time
puede proporcionar el desplazamiento UTC necesario, pero no sé cómo.
Aunque no sé cómo formatear una entrada de un solo dígito en el impulso, puedo hacerlo después de la edición de dos dígitos:
#include <iostream>
#include <boost/date_time.hpp>
namespace bt = boost::posix_time;
const std::locale formats[] = {
std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d %H:%M:%S")),
std::locale(std::locale::classic(),new bt::time_input_facet("%Y/%m/%d %H:%M:%S")),
std::locale(std::locale::classic(),new bt::time_input_facet("%d.%m.%Y %H:%M:%S")),
std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d"))};
const size_t formats_n = sizeof(formats)/sizeof(formats[0]);
std::time_t pt_to_time_t(const bt::ptime& pt)
{
bt::ptime timet_start(boost::gregorian::date(1970,1,1));
bt::time_duration diff = pt - timet_start;
return diff.ticks()/bt::time_duration::rep_type::ticks_per_second;
}
void seconds_from_epoch(const std::string& s)
{
bt::ptime pt;
for(size_t i=0; i<formats_n; ++i)
{
std::istringstream is(s);
is.imbue(formats[i]);
is >> pt;
if(pt != bt::ptime()) break;
}
std::cout << " ptime is " << pt << ''/n'';
std::cout << " seconds from epoch are " << pt_to_time_t(pt) << ''/n'';
}
int main()
{
seconds_from_epoch("2004-03-21 12:45:33");
seconds_from_epoch("2004/03/21 12:45:33");
seconds_from_epoch("23.09.2004 04:12:21");
seconds_from_epoch("2003-02-11");
}
tenga en cuenta que la salida de segundos a partir de la época asumirá que la fecha estaba en UTC:
~ $ ./test | head -2
ptime is 2004-Mar-21 12:45:33
seconds from epoch are 1079873133
~ $ date -d @1079873133
Sun Mar 21 07:45:33 EST 2004
Probablemente boost::posix_time::c_time::localtime()
usar boost::posix_time::c_time::localtime()
desde #include <boost/date_time/c_time.hpp>
para realizar esta conversión suponiendo que la entrada está en la zona horaria actual, pero es bastante inconsistente: para Yo, por ejemplo, el resultado será diferente entre hoy y el mes que viene, cuando termine el horario de verano.
Si c-style es aceptable: strptime () es el camino a seguir, porque puede especificar el formato y puede tener en cuenta la configuración regional:
tm brokenTime;
strptime(str.c_str(), "%Y-%m-%d %T", &brokenTime);
time_t sinceEpoch = timegm(brokenTime);
Se deberán verificar diferentes diseños con el valor de retorno (si es posible). La zona horaria tendrá que ser agregada al verificar el reloj del sistema (localtime_r () con time (), tm_zone)
la solución más simple y portátil es usar scanf
:
int year, month, day, hour, minute, second = 0;
int r = 0;
r = scanf ("%d-%d-%d %d:%d:%d", &year, &month, &day,
&hour, &minute, &second);
if (r == 6)
{
printf ("%d-%d-%d %d:%d:%d/n", year, month, day, hour, minute,
second);
}
else
{
r = scanf ("%d/%d/%d %d:%d:%d", &year, &month, &day,
&hour, &minute, &second);
// and so on ...
Inicialice una struct tm
con los valores int
y páselo a mktime
para obtener un tiempo de calendario como time_t
. Para las conversiones de zona horaria, consulte la información sobre gmtime
.
boost::gregorian
tiene algunas de las cosas que necesitas sin que hagas más trabajo:
using namespace boost::gregorian;
{
// The following date is in ISO 8601 extended format (CCYY-MM-DD)
std::string s("2000-01-01");
date d(from_simple_string(s));
std::cout << to_simple_string(d) << std::endl;
}
Hay un ejemplo sobre cómo usar compensaciones UTC con boost::posix_time
here .
Puede proporcionar la generación de fecha y hora a partir de formatos de cadenas de entrada personalizadas usando date_input_facet
y time_input_facet
. Hay un tutorial de E / S en esta página que debería ayudarlo a comenzar.