Zeit in C++: Parser formatierter Eingaben

In diesem Artikel geht es um den Formatspezifizierer zum Verarbeiten von Eingaben.

In Pocket speichern vorlesen Druckansicht
Wecker, Zeit

(Bild: Kwangmoozaa/Shutterstock.com)

Lesezeit: 3 Min.
Von
  • Rainer Grimm
Inhaltsverzeichnis

Dieser Artikel ist der elfte in meiner ausführlichen Reise durch die Chrono-Erweiterung in C++20.

  1. Zeit in C++20: Einführung in die Chrono-Terminologie
  2. Zeit in C++20: Einführung in die Chrono-Terminologie mit Zeitdauer und Zeitpunkt
  3. Zeit in C++20: Neue Datentypen für die Tageszeit und das Kalenderdatum
  4. Zeit in C++20: Kalendertermine erstellen
  5. Zeit in C++20: Kalendertermine darstellen und prüfen
  6. Zeit in C++20: Kalenderdaten abfragen und Ordinaldaten
  7. Zeit in C++20: Details zu der Arbeit mit Zeitzonen
  8. Zeitzonen in C++20: Online-Klassen
  9. Zeit in C++20: Chrono I/O
  10. C++20: Chrono I/O: Unformatiert und formatiert
Modernes C++ – Rainer Grimm

Rainer Grimm ist seit vielen Jahren als Softwarearchitekt, Team- und Schulungsleiter tätig. Er schreibt gerne Artikel zu den Programmiersprachen C++, Python und Haskell, spricht aber auch gerne und häufig auf Fachkonferenzen. Auf seinem Blog Modernes C++ beschäftigt er sich intensiv mit seiner Leidenschaft C++.

Die Chrono-Bibliothek unterstützt formatierte Eingaben auf zwei Arten. Man kann die Funktionen std::chrono::from_stream oder std::chrono::parse verwenden. Beide Funktionen benötigen einen Eingabestrom und parsen die Eingabe entsprechend der Formatspezifikation in einen Zeitpunkt. Alle Formatspezifikationen außer %q für die Einheit, die entsprechend den Literalen für Zeitdauern angehängt werden, können verwendet werden.

std::chrono::from_stream hat Überladungen für die verschiedenen Uhrentypen.

Uhren

  • std::chrono::system_time
  • std::chrono::utc_time
  • std::chrono::tai_time
  • std::chrono::gps_time
  • std::chrono::file_time
  • std::chrono::local_time

Kalenderdaten

  • std::chrono::year_month_day
  • std::chrono::year_month
  • std::chrono::month_day
  • std::chrono::weekday
  • std::chrono::year
  • std::chrono::month
  • std::chrono::day

Die verschiedenen Überladungen benötigen in der elementaren Form einen Eingabestrom is, einen Formatstring fmt und einen Zeitpunkt oder ein Kalenderobjekt chro – std::chrono::from_stream(is, fmt, chro). Das Chrono-Objekt aus dem Eingabestrom wird dann entsprechend dem Formatstring geparst.

Man kannst auch eine Abkürzung abb für eine Zeitzone und einen Offset der UTC-Zeit angeben: std::chrono::from_stream(is, fmt, chro, abb, off). Der Offset hat den Datentyp std::chrono::minutes.

Das Programm inputChrono.cpp verwendet eine formatierte Eingabe, um einen Zeitpunkt und ein Kalenderdatum aus einem Eingabestrom zu lesen.

// inputChrono.cpp

#include <chrono>
#include <iostream>
#include <string>
#include <sstream>

int main() {

    std::cout << '\n';

    std::chrono::sys_seconds timePoint;
    std::istringstream iStream1{"2021-08-11 21:49:35"};     //(1)
    std::chrono::from_stream(iStream1, "%F %T", timePoint); //(2)
    if (iStream1) std::cout << "timePoint: "  
      << timePoint << '\n';
    else std::cerr << "timepoint: Reading failed\n";

    std::chrono::year_month_day date1;
    std::istringstream iStream2{"11/08/21"};                //(3)
    std::chrono::from_stream(iStream2, "%x", date1);        //(4)
    if (iStream2) std::cout << "date1: "  << date1 << '\n';
    else std::cerr << "date1: Reading failed\n";

    std::chrono::year_month_day date2;
    std::istringstream iStream3{"11/15/21"};
    std::chrono::from_stream(iStream3, "%x", date2);        //(5)
    if (iStream3) std::cout << "date2: "  << date2 << '\n';
    else std::cerr << "date2: Reading failed\n";

    std::cout << '\n';

}

In den (1 und 2) entsprechen die Daten im Eingabestrom (iStream1) dem Formatstring ("%F %T"). Das Gleiche gilt für den Eingabestrom iStream2 (3) und den entsprechenden Formatstring "%x" (4). Im Gegensatz dazu gibt es keinen fünfzehnten Monat, und der Parse-Schritt in (5) schlägt fehl. Infolgedessen wird das Failbit des iStream3 gesetzt. Die Verwendung von iStream3 in einem booleschen Ausdruck ergibt false.

Analog zu std::chrono::from_stream kan man die Funktion std::chrono::parse zum Parsen von Eingaben verwenden. Der folgende Codeschnipsel zeigt ihre Gleichwertigkeit.

std::chrono::from_stream(is, fmt, chro)
is >> std::chrono::parse(fmt, chro)


Statt std::chrono::from_stream wird std::chrono::parse direkt auf dem Eingabestrom is aufgerufen. std::chrono::parse benötigt außerdem einen Format-String fmt und ein Chrono-Objekt chro.

Daher kann ich das vorherige Programm inputChrono.cpp mit std::chrono::from_stream direkt in das Programm inputChronoParse.cpp mit std::chrono::parse umschreiben.

// inputChronoParse.cpp

#include <chrono>
#include <iostream>
#include <string>
#include <sstream>

int main() {

    std::cout << '\n';

    std::chrono::sys_seconds timePoint;
    std::istringstream iStream1{"2021-08-11 21:49:35"};
    iStream1 >> std::chrono::parse("%F %T", timePoint);
    if (iStream1) std::cout << "timePoint: "  << timePoint << '\n';
    else std::cerr << "timepoint: Reading failed\n";

    std::chrono::year_month_day date1;
    std::istringstream iStream2{"11/08/21"};
    iStream2 >> std::chrono::parse("%x", date1);
    if (iStream2) std::cout << "date1: "  << date1 << '\n';
    else std::cerr << "date1: Reading failed\n";

    std::chrono::year_month_day date2;
    std::istringstream iStream3{"11/15/21"};
    iStream3 >> std::chrono::parse("%x", date2);
    if (iStream3) std::cout << "date2: "  << date2 << '\n';
    else std::cerr << "date2: Reading failed\n";

    std::cout << '\n';

}

Jetzt bin ich fertig mit meiner genauen Vorstellung der Chrono-Bibliothek. In meinem nächsten Artikel werde ich über Concurrency in C++20 schreiben. (rme)