wake-up-neo.com

Wie kann ich Datum und Uhrzeit aus einem String analysieren?

Eingabe: Zeichenketten mit Datum und optionaler Uhrzeit. Unterschiedliche Darstellungen wären nett aber notwendig. Die Zeichenfolgen werden vom Benutzer bereitgestellt und können fehlerhaft sein. Beispiele:

  • "2004-03-21 12:45:33" (Ich halte dies für das Standardlayout)
  • "2004/03/21 12:45:33" (optionales Layout)
  • "23.09.2004 04:12:21" (deutsches Format, optional)
  • "2003-02-11" (möglicherweise fehlt die Zeit)

Benötigte Ausgabe: Sekunden seit der Epoche (1970/01/01 00:00:00) oder ein anderer fester Punkt.

Bonus: Auch das Auslesen des UTC-Offsets der lokalen Systemzeit wäre toll.

Die Eingabe wird als Ortszeit der betreffenden Maschine angenommen. Die Ausgabe muss UTC sein. System ist nur Linux (Debian Lenny und Ubuntu benötigt).

Ich habe versucht, boost/date_time, muss aber zugeben, dass ich mich nicht um die Dokumentation kümmern kann. Folgendes funktioniert ohne die erforderliche Umrechnung von der System-Ortszeit in 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);

Meiner Ansicht nach boost::date_time kann den benötigten UTC-Offset bereitstellen, aber ich würde nicht wissen, wie.

52

Obwohl ich nicht weiß, wie ich eine einstellige Monatseingabe in Boost formatieren kann, kann ich dies nach der zweistelligen Bearbeitung tun:

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

beachten Sie, dass für die Ausgabe in Sekunden ab Epoche davon ausgegangen wird, dass das Datum in UTC angegeben wurde:

~ $ ./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

Sie könnten wahrscheinlich boost::posix_time::c_time::localtime() aus #include <boost/date_time/c_time.hpp> Verwenden, um diese Konvertierung durchzuführen, vorausgesetzt, die Eingabe befindet sich in der aktuellen Zeitzone, aber sie ist ziemlich inkonsistent: Für mich beispielsweise ist das Ergebnis anders zwischen heute und nächsten Monat, wenn die Sommerzeit endet.

65
Cubbi

boost::gregorian hat einige Dinge, die du brauchst, ohne dass du mehr arbeitest:

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

Es gibt ein Beispiel für die Verwendung von UTC-Offsets mit boost::posix_timehier .

Sie können die Generierung von Datum und Uhrzeit aus benutzerdefinierten Eingabezeichenfolgenformaten bereitstellen, indem Sie date_input_facet und time_input_facet . Es gibt ein I/O-Tutorial auf diese Seite , das Ihnen helfen soll, loszulegen.

11
Steve Townsend

Wenn der C-Stil akzeptabel ist: strptime () ist der richtige Weg, da Sie das Format angeben und das Gebietsschema berücksichtigen können:

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

Unterschiedliche Layouts müssen mit dem Rückgabewert überprüft werden (falls möglich). Die Zeitzone muss durch Überprüfen der Systemuhr (localtime_r () mit time (), tm_zone) ergänzt werden.

7
stefaanv

die einfachste, tragbare Lösung ist die Verwendung von 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 ...

Initialisiere ein struct tm mit den int Werten und übergeben Sie es an mktime, um eine Kalenderzeit als time_t. Für Zeitzonenumrechnungen bitte siehe Informationen auf gmtime.

2
Vijay Mathew