web-dev-qa-db-fra.com

Comment analyser la date / heure de la chaîne?

Input: chaînes avec date et heure optionnelle. Différentes représentations seraient sympas mais nécessaires. Les chaînes sont fournies par l'utilisateur et peuvent être mal formées. Exemples:

  • "2004-03-21 12:45:33" (Je considère cela comme la disposition par défaut)
  • "2004/03/21 12:45:33" (disposition facultative)
  • "23.09.2004 04:12:21" (format allemand, facultatif)
  • "2003-02-11" (il manque peut-être du temps)

Sortie nécessaire: Secondes depuis l'époque (1970/01/01 00:00:00) ou tout autre point fixe.

Bonus: En outre, la lecture du décalage UTC de l'heure du système local serait formidable.

L'entrée est supposée être une heure locale sur la machine en question. La sortie doit être UTC. Le système est uniquement Linux (Debian Lenny et Ubuntu sont nécessaires).

J'ai essayé d'utiliser boost/date_time, mais je dois admettre que je ne peux pas faire le tour de la documentation. Les éléments suivants fonctionnent sans la conversion nécessaire de l'heure locale du système en 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);

Je pense boost::date_time peut fournir le décalage UTC nécessaire, mais je ne sais pas comment.

52
Gabriel Schreiber

Bien que je ne sache pas formater une entrée de mois à un chiffre dans boost, je peux le faire après la modification à deux chiffres:

#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");
}

notez que la sortie en secondes de l'époque supposera que la date était 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

Vous pourriez probablement utiliser boost::posix_time::c_time::localtime() de #include <boost/date_time/c_time.hpp> Pour effectuer cette conversion en supposant que l'entrée est dans le fuseau horaire actuel, mais elle est plutôt incohérente: pour moi, par exemple, le résultat sera différent entre aujourd'hui et le mois prochain, lorsque l'heure d'été se termine.

65
Cubbi

boost::gregorian contient certains des éléments dont vous avez besoin sans que vous ne fassiez plus de travail:

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;
}

Il existe un exemple d'utilisation des décalages UTC avec boost::posix_timeici .

Vous pouvez fournir la génération de la date et de l'heure à partir de formats de chaîne d'entrée personnalisés à l'aide de date_input_facet et time_input_facet . Il y a un tutoriel d'E/S sur cette page qui devrait vous aider à démarrer.

11
Steve Townsend

Si le style c est acceptable: strptime () est la voie à suivre, car vous pouvez spécifier le format et prendre en compte les paramètres régionaux:

tm brokenTime;
strptime(str.c_str(), "%Y-%m-%d %T", &brokenTime);
time_t sinceEpoch = timegm(brokenTime);

Différentes dispositions devront être vérifiées avec la valeur de retour (si possible). Le fuseau horaire devra être ajouté en vérifiant l'horloge système (localtime_r () avec time (), tm_zone)

7
stefaanv

la solution la plus simple et portable consiste à utiliser 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 ...

Initialisez un struct tm avec les valeurs int et transmettez-le à mktime pour obtenir une heure de calendrier comme time_t. Pour les conversions de fuseau horaire, veuillez voir informations sur gmtime.

2
Vijay Mathew