Wie konvertiere ich einen std::chrono::time_point in lang und zurück?

Lesezeit: 8 Minuten

Benutzer-Avatar
Mendes

Ich muss konvertieren std::chrono::time_point nach und von a long Typ (Ganzzahl 64 Bit). Ich fange an, mit zu arbeiten std::chrono

Hier ist mein Code:

int main ()
{
     std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

    auto epoch = now.time_since_epoch();
    auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
    long duration = value.count();


    std::chrono::duration<long> dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Dieser Code wird kompiliert, zeigt jedoch keinen Erfolg.

Warum ist dt anders als now Am Ende?

Was fehlt in diesem Code?

  • Ich bin mit der Chrono-Bibliothek nicht allzu vertraut, aber ich glaube, Sie müssen sie verwenden std::chrono::duration<long,std::milli> dur und selbst dann erhalten Sie möglicherweise Rundungsfehler (std::chrono::system_clock hat wahrscheinlich eine höhere Auflösung als Millisekunden).

    – MikeMB

    6. Juli 2015 um 22:41 Uhr

  • @MikeMB Alle Uhren auf einigermaßen neuer Hardware sollten sowieso eine Genauigkeit von etwa Mikrosekunde / Sub-Mikrosekunde haben. Siehe einen Artikel mit dem Titel Die drei Uhren. Tatsächlich haben Fenster normalerweise eine höhere Genauigkeit mit system_clock (etwa 100-mal größer), aber selbst das ist normalerweise Sub-Mikrosekunde.

    – Werliös

    26. Mai 2020 um 1:47 Uhr

Benutzer-Avatar
Howard Hinnant

std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

Dies ist ein großartiger Ort für auto:

auto now = std::chrono::system_clock::now();

Da willst Du Traffic an millisecond Präzision, es wäre gut, voranzugehen und es in der verdeckten time_point:

auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

now_ms ist ein time_pointbezogen auf system_clockaber mit der Genauigkeit von milliseconds statt was auch immer Präzision Ihre system_clock hat.

auto epoch = now_ms.time_since_epoch();

epoch hat jetzt Typ std::chrono::milliseconds. Und diese nächste Anweisung wird im Wesentlichen zu einem No-Op (erstellt einfach eine Kopie und führt keine Konvertierung durch):

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);

Hier:

long duration = value.count();

Sowohl in Ihrem als auch in meinem Code duration hält die Zahl von milliseconds seit der Epoche der system_clock.

Dies:

std::chrono::duration<long> dur(duration);

Erstellt ein duration dargestellt mit a longund eine Genauigkeit von seconds. Dies effektiv reinterpret_castist die milliseconds gehalten value zu seconds. Es ist ein Logikfehler. Der richtige Code würde wie folgt aussehen:

std::chrono::milliseconds dur(duration);

Diese Linie:

std::chrono::time_point<std::chrono::system_clock> dt(dur);

schafft ein time_point bezogen auf system_clockmit der Fähigkeit, eine Genauigkeit zu halten system_clock‘s native Genauigkeit (in der Regel feiner als Millisekunden). Der Laufzeitwert gibt jedoch korrekt wieder, dass eine ganzzahlige Anzahl von Millisekunden gehalten wird (unter der Annahme meiner Korrektur des Typs von dur).

Auch mit der Korrektur wird dieser Test (fast immer) fehlschlagen:

if (dt != now)

Da dt enthält eine ganze Zahl von millisecondsaber now enthält eine ganzzahlige Anzahl von Ticks feiner als a millisecond (z.B microseconds oder nanoseconds). Also nur auf die seltene Gelegenheit das system_clock::now() gab eine ganze Zahl von zurück milliseconds würde die Prüfung bestehen.

Aber Sie können stattdessen:

if (dt != now_ms)

Und Sie erhalten jetzt zuverlässig Ihr erwartetes Ergebnis.

Alles zusammen:

int main ()
{
    auto now = std::chrono::system_clock::now();
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    std::chrono::milliseconds dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Ich persönlich finde alle std::chrono übermäßig ausführlich und so würde ich es codieren als:

int main ()
{
    using namespace std::chrono;
    auto now = system_clock::now();
    auto now_ms = time_point_cast<milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    milliseconds dur(duration);

    time_point<system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Was zuverlässig ausgeben wird:

Success.

Schließlich empfehle ich, Temporäre zu eliminieren, um den Code zu reduzieren, der zwischen ihnen konvertiert time_point und Integraltyp auf ein Minimum. Diese Konvertierungen sind gefährlich, und je weniger Code Sie schreiben, um den reinen ganzzahligen Typ zu manipulieren, desto besser:

int main ()
{
    using namespace std::chrono;
    // Get current time with precision of milliseconds
    auto now = time_point_cast<milliseconds>(system_clock::now());
    // sys_milliseconds is type time_point<system_clock, milliseconds>
    using sys_milliseconds = decltype(now);
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    sys_milliseconds dt{milliseconds{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Die Hauptgefahr oben ist nicht Dolmetschen integral_duration wie milliseconds auf dem Rückweg nach a time_point. Eine Möglichkeit, dieses Risiko zu mindern, besteht darin, Folgendes zu schreiben:

    sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};

Dies reduziert das Risiko darauf, nur sicherzustellen, dass Sie es verwenden sys_milliseconds auf dem Weg nach draußen und an den beiden Orten auf dem Rückweg.

Und noch ein Beispiel: Nehmen wir an, Sie möchten in und aus einem Integral konvertieren, das eine beliebige Dauer darstellt system_clock unterstützt (Mikrosekunden, 10th von Mikrosekunden oder Nanosekunden). Dann brauchen Sie sich nicht um die Angabe von Millisekunden wie oben zu kümmern. Der Code vereinfacht sich zu:

int main ()
{
    using namespace std::chrono;
    // Get current time with native precision
    auto now = system_clock::now();
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    system_clock::time_point dt{system_clock::duration{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Dies funktioniert, aber wenn Sie die Hälfte der Konvertierung (aus dem Integral) auf einer Plattform und die andere Hälfte (ein vom Integral) auf einer anderen Plattform ausführen, gehen Sie das Risiko ein system_clock::duration haben unterschiedliche Genauigkeiten für die beiden Konvertierungen.

  • @BrentNash: Vorsicht, ich könnte dich darauf ansprechen. 😉 Ich werde auf der Cppcon 2015 sein (cppcon.org) darüber gesprochen: howardhinnant.github.io/date_v2.html . Das Thema ist sehr eng mit dem verwandt time_point_cast<milliseconds>(now) in meiner Antwort oben. Nur die Dauer ist natürlicher: time_point_cast<days>(now).

    – Howard Hinnant

    7. Juli 2015 um 19:57 Uhr

  • Tippfehler im letzten Kommentar: gröber, nicht gröber. Tolle Antwort.

    – Dirk Edelbüttel

    7. Dezember 2016 um 18:14 Uhr


  • Das Problem mit Englisch ist, dass es mit einem C++-Compiler nicht analysiert werden kann und der Compiler eine bessere Rechtschreibprüfung bietet. 🙂

    – Howard Hinnant

    7. Dezember 2016 um 19:23 Uhr

  • Das ist sehr hilfreich, obwohl ich denke, es wäre ein bisschen besser gewesen, wenn Sie nicht überall ‘auto’ verwendet hätten. Nur für faule Leute wie mich, die sehen möchten, welche Typen manipuliert werden, ohne woanders suchen zu müssen. Vielen Dank @HowardHinnant

    – Marko Paulo

    4. Oktober 2017 um 17:38 Uhr

  • Ab zu gehen system_clock::now() zu ms seit 1970 in a long: long i = system_clock::now().time_since_epoch()/1ms;

    – Howard Hinnant

    8. September 2021 um 17:25 Uhr


Ich möchte auch darauf hinweisen, dass es zwei Möglichkeiten gibt, die Anzahl der ms im Zeitpunkt zu erhalten. Ich bin mir nicht sicher, welches besser ist, ich habe sie verglichen und sie haben beide die gleiche Leistung, also denke ich, dass es eine Frage der Präferenz ist. Vielleicht könnte Howard einspringen:

auto now = system_clock::now();

//Cast the time point to ms, then get its duration, then get the duration's count.
auto ms = time_point_cast<milliseconds>(now).time_since_epoch().count();

//Get the time point's duration, then cast to ms, then get its count.
auto ms = duration_cast<milliseconds>(tpBid.time_since_epoch()).count();

Der erste liest sich deutlicher in meinem Kopf, wenn ich von links nach rechts gehe.

als einzelne Zeile:

long value_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch()).count();

time_point Objekte nur Arithmetik mit anderen unterstützen time_point oder duration Objekte.

Sie müssen Ihre konvertieren long zu einem duration der angegebenen Einheiten, dann sollte Ihr Code korrekt funktionieren.

1018840cookie-checkWie konvertiere ich einen std::chrono::time_point in lang und zurück?

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

Privacy policy