C++ Konvertieren eines Zeitstrings in Sekunden aus der Epoche

Lesezeit: 6 Minuten

C Konvertieren eines Zeitstrings in Sekunden aus der Epoche
Martin York

Ich habe einen String mit folgendem Format:

2010-11-04T23:23:01Z

Das Z zeigt an, dass die Zeit UTC ist.
Ich würde dies eher als Epochenzeit speichern, um den Vergleich zu vereinfachen.

Was ist die empfohlene Methode dafür?

Derzeit (nach einer schnellen Suche) ist der einfache Algorithmus:

1: <Convert string to struct_tm: by manually parsing string>
2: Use mktime() to convert struct_tm to epoch time.

// Problem here is that mktime uses local time not UTC time.

  • _mkgmtime() in meinem CRT. Ymmv.

    – Hans Passant

    9. November ’10 um 20:04

  • @Loki, wir brauchen kein Meta-Tag, um alle Dinge abzufangen, die betriebssystemneutral sind. Bitte beenden Sie die Neuerstellung des Tags.

    – Charles

    26. September ’12 um 0:38


  • @Charles: Bitte hör auf, meine Frage zu ändern. Ich hätte jedoch den Hinweis erhalten, dass die Bearbeitung meiner Meinung nach ungültig ist, nachdem ich sie zum zweiten Mal zurückgeändert habe.

    – Martin York

    26. September ’12 um 6:42


  • @Loki, und ich dachte, Sie hätten den Hinweis bekommen, dass andere Benutzer auf der Site die Notwendigkeit eines neuen generischen Catch-All-Tags für diese Frage und nur diese Frage nicht sehen. Bitte fügen Sie entweder ein Wiki-Tag hinzu und fügen Sie das Tag anderen Fragen hinzu, für die es relevant ist, oder Sie werden weiterhin sehen, dass andere Benutzer das Tag entfernen.

    – Charles

    26. September ’12 um 15:04

  • @Loki – es hilft nicht viel, dass das Tag die ganze Zeit falsch geschrieben wurde …

    – Bo Person

    27. September ’12 um 20:12

C Konvertieren eines Zeitstrings in Sekunden aus der Epoche
Martin York

Mit der C++11-Funktionalität können wir jetzt Streams verwenden, um Zeiten zu analysieren:

Die iomanip std::get_time konvertiert eine Zeichenfolge basierend auf einem Satz von Formatparametern und konvertiert sie in a struct tz Objekt.

Sie können dann verwenden std::mktime() um dies in einen Epochenwert umzuwandeln.

#include <iostream>
#include <sstream>
#include <locale>
#include <iomanip>

int main()
{
    std::tm t = {};
    std::istringstream ss("2010-11-04T23:23:01Z");

    if (ss >> std::get_time(&t, "%Y-%m-%dT%H:%M:%S"))
    {
        std::cout << std::put_time(&t, "%c") << "n"
                  << std::mktime(&t) << "n";
    }
    else
    {
        std::cout << "Parse failedn";
    }
    return 0;
}

  • Dieser Code befasst sich nicht mit dem OP-Problem (ich weiß nicht, warum er ihn akzeptiert hat). std::mktime nimmt die lokale Zeitzone an und gibt die falsche Zeit aus. Es gibt 1288909381 auf meiner Maschine (GMT+01:00 zu diesem Datum), das ist 10 pm, nicht 11 pm bei UTC. Der richtige Zeitstempel wäre jedoch gewesen 1288912981.

    – Zabuzard

    31. Juli ’19 um 16:08


  • @Zabuza Würdest du nicht denken, dass der OP besser weiß, was er will als du? Wenn Sie nicht wissen, warum er es akzeptiert hat, sollten Sie das vielleicht zuerst klären, sonst Ihre Behauptung This code does not address OPs issue ist verdächtig.

    – Martin York

    31. Juli ’19 um 23:04

Dies ist das ISO8601-Format. Sie können verwenden strptime Funktion, um es zu parsen %FT%T%z Streit. Es ist nicht Teil des C++-Standards, obwohl Sie eine Open-Source-Implementierung davon verwenden können (Dies, zum Beispiel).

Sie können eine Funktion wie z strptime einen String in a umwandeln struct tm, anstatt es manuell zu parsen.

C Konvertieren eines Zeitstrings in Sekunden aus der Epoche
Steve Townsend

Es ist kein exakter Betrug, aber Sie werden die Antwort von @Cubbi von hier aus nützlich finden, wette ich. Dies setzt insbesondere die UTC-Eingabe voraus.

Boost unterstützt auch die direkte Konvertierung von ISO 8601 über boost::posix_time::from_iso_string der ruft boost::date_time::parse_iso_time, auch hier würden Sie einfach das nachgestellte ‘Z’ entfernen und die TZ als implizite UTC behandeln.

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

Das Problem hierbei ist, dass mktime die Ortszeit und nicht die UTC-Zeit verwendet.

Linux bietet timegm was Sie wollen (zB mktime für UTC-Zeit).

Hier ist meine Lösung, die ich gezwungen habe, nur “Zulu” (Z-Zeitzone) zu akzeptieren. Beachten Sie, dass strptime scheint die Zeitzone nicht richtig zu analysieren, obwohl glib dies anscheinend unterstützt. Deshalb werfe ich einfach eine Ausnahme aus, wenn die Zeichenfolge nicht auf ‘Z’ endet.

static double EpochTime(const std::string& iso8601Time)
{
    struct tm t;
    if (iso8601Time.back() != 'Z') throw PBException("Non Zulu 8601 timezone not supported");
    char* ptr = strptime(iso8601Time.c_str(), "%FT%T", &t);
    if( ptr == nullptr)
    {
        throw PBException("strptime failed, can't parse " + iso8601Time);
    }
    double t2 = timegm(&t); // UTC
    if (*ptr)
    {
        double fraction = atof(ptr);
        t2 += fraction;
    }
    return t2;
}

C Konvertieren eines Zeitstrings in Sekunden aus der Epoche
Howard Hinnant

Neue Antwort auf eine alte Frage. Begründung für neue Antwort: Falls Sie verwenden möchten <chrono> Typen, um ein Problem wie dieses zu lösen.

Zusätzlich zu C++11/C++14 benötigen Sie dies kostenlose Open-Source-Bibliothek für Datum/Uhrzeit:

#include "tz.h"
#include <iostream>
#include <sstream>

int
main()
{
    std::istringstream is("2010-11-04T23:23:01Z");
    is.exceptions(std::ios::failbit);
    date::sys_seconds tp;
    date::parse(is, "%FT%TZ", tp);
    std::cout << "seconds from epoch is " << tp.time_since_epoch().count() << "sn";
}

Dieses Programm gibt aus:

seconds from epoch is 1288912981s

Wenn die Analyse in irgendeiner Weise fehlschlägt, wird eine Ausnahme ausgelöst. Wenn Sie keine Ausnahmen werfen möchten, tun Sie es nicht is.exceptions(std::ios::failbit);, sondern suche stattdessen nach is.fail().

1642081564 227 C Konvertieren eines Zeitstrings in Sekunden aus der Epoche
Yippie-Ki-Yay

Du könntest das nutzen boost::date_time und schreibe einen kleinen manuellen Parser (wahrscheinlich regexp-basiert) für deine Saiten.

.

486910cookie-checkC++ Konvertieren eines Zeitstrings in Sekunden aus der Epoche

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy