Kalender und Zeitzonen in C++20: Tageszeit
Die chrono-Bibliothek erhält mächtige Erweiterungen. Die wichtigste ist wohl die Unterstützung eines Kalenders und von Zeitzonen.
Mit C++20 erhält die chrono-Bibliothek mächtige Erweiterungen. Die wichtigsten sind sicherlich die Unterstützung eines Kalenders und von Zeitzonen. Das ist aber bei weitem noch nicht alles. C++20 erhält neue Uhren, mächtige Formatierungsmöglichkeiten für Zeitdauern und einen Datentyp für die Tageszeit.
Bevor ich in die Tiefe der erweiterten chrono-Bibliothek und insbesondere in den neuen Datentyp std::chrono::time_of_day
abtauche, möchte ich erst ein paar Bemerkungen loswerden. Zuerst einmal nenne ich alle Datums- und Zeitfunktionalitäten der chrono-Bibliothek vereinfachend die Zeitbibliothek.
Die Zeitbibliothek in C++11
Um die wesentliche Information aus meinem Artikel zur Zeitbibliothek zu erhalten, ist ein Grundverständnis der chrono-Bibliothek in C++11 erforderlich. C++11 hat drei Komponenten zum Umgang mit Zeit definiert:
- Ein Zeitpunkt (time point) wird durch einen Startpunkt – die sogenannte Epoche – und die Zeitdauer definiert.
- Eine Zeitdauer (time duration) definiert die Differenz zwischen zwei Zeitpunkten. Sie wird durch die Anzahl der Ticks eines Zeitgebers bestimmt.
- Der Zeitgeber (clock) besteht aus einem Startpunkt (Epoche) und seinen Ticks. Damit lässt sich der aktuelle Zeitpunkt berechnen.
Ehrlich gesagt, finde ich Zeit ein Mysterium. Einerseits besitzt jeder ein intuitives Verständnis von Zeit, andererseits ist die formale Definition von Zeit sehr anspruchsvoll. So hängen zum Beispiel die drei Komponenten Zeitpunkt, Zeitdauer und Zeitgeber voneinander ab. Wenn du mehr zur Zeitfunktionalität in C++11 lesen möchtest, hier sind meine Artikel dazu: time [1].
Die chrono-Erweiterung in C++20
C++20 erweitert die chrono-Bibliothek um neue Komponenten:
- Die Tageszeit (time of day) ist die Zeitdauer seit Mitternacht, die in Stunden, Minuten, Sekunden und Sekundenbruchteile gesplittet ist.
- Der Kalender steht fĂĽr verschieden Kalenderdaten wie Jahr, Monat, einen Wochentag oder den n-ten Tag einer Woche.
- Eine Zeitzone (time-zone) repräsentiert die Zeit bezogen auf ein geografisches Gebiet.
Im Wesentlichen basiert die Zeitzonenfunktionalität (C++20) auf der Kalenderfunktionalität (C++20) und die Kalenderfunktionalität (C++20) auf der ursprünglichen chrono-Funktionalität (C++11).
Das ist jedoch bei Weitem nicht alles. Die Erweiterung beinhaltet neue Zeitgeber. Mit der neuen Formatierungsbibliothek in C++20 lassen sich Zeitdauern ein- und auslesen.
Die Prototyp-Bibliothek date
Zum jetzigen Zeitpunkt unterstĂĽtzt kein C++ Compiler die chrono-Erweiterungen mit C++20. Dank der Prototyp-Bibliothek date [2]
von Howard Hinnant, die die neuen chrono-Erweiterungen umfasst, lässt sich die neue Funktionalität bereits verwenden. Die Bibliothek ist iauf GitHub gehostet. Es gibt eine paar Möglichkeiten diese date [3]-Bibliothek zu verwenden:
- Du kannst die Bibliothek auf wandbox einsetzen. Howard hat die Headerdatei
date.h
, die fĂĽr die Verwendung vonstd::time_of_day
und die Kalenderdatentypen ausreichend ist, hochgeladen. Hier ist sein Link: Try it out on wandbox! [4] - Kopiere die Header-Datei
date.h
in den Suchpfad deines C++-Compilers. - Lade das Projekt herunter und baue es. Die bereits zitierte GibHub-Seite date [5] enthält die notwendige Information dazu.
Ich habe meine ersten Gehversuche mit dem Online-Compiler unternommen und bin relativ schnell zur Strategie 2 gewechselt.
Notwendiger C++-Standard
Im Allgemeinen ist ein C++14-Compiler ausreichend, um die date
-Bibliothek zu verwenden. Es gibt eine Ausnahme dieser Regel, die ich mit dem folgenden Aufruf erfahren habe:
auto timeOfDay = date::time_of_day(10.h + 98min + 2020s + 0.5s); // C++20
auto timeOfDay = date::hh_mm_ss(10.h + 98min + 2020s + 0.5s); // C++17
Ich verwendete in meinen ersten Gehversuchen die erste Zeile. Die erste Zeile setzt Bestimmung der Argumente eines Klassen-Templates fĂĽr Alias-Templates vor. time_of_day
ist ein Alias fĂĽr hh_mm_ss
: using time_of_day_day = hh_mm_ss<Duration>
. Wird nun anstelle des Alias das Klassen-Template wie in der zweiten Zeile direkt verwendet, ist ein C++17-Compiler ausreichend. Er kann automatisch die Template-Argumente eines Klassen-Templates ermitteln.
Hier gibt es mehr Details zur automatischen Bestimmung der Template-Argumente eines Klassen-Templates in C++17: C++17: Was gibt's Neues in der Kernsprache? [6]
Problem gelöst
Mit C++20 wurde time_of_day
in hh_mm_ss
umbenannt. Howard Hinnant gab mir den entscheidenden Hinweis:
"Prefer to use hh_mm_ss in place of time_of_day. time_of_day got renamed to hh_mm_ss during the standardization process for C++20, and so time_of_day remains strictly as a backwards compatible shim for current and past users of this lib."
Dies war wieder eine fĂĽr einen Early Adopter typische Odyssee.
Portierung auf C++20
Wenn nur die Bestandteile der date
-Bibliothek zum Einsatz kommen, die Bestandteil des C++20-Standards sind, ist die Portierung der Beispiele auf C++20 keine groĂźe Herausforderung. Ersetze zum einen die Header-Dateien der Prototyp-Biblitothek date [7] mit der <chrono>
-Header-Datei und ersetze zum anderen den Namensraum date
mit dem Namensraum std::chrono
:
#include "date.h"
//#include <chrono>
int main() {
using namespace std::chrono_literals;
auto am = date::is_am(10h);
// auto am = std::chrono::is_am(10h);
}
Jetzt beginne ich ĂĽber die chrono-Erweiterungen in C++20 zu schreiben.
Tageszeit
std::chrono::hh_mm_ss
ist die Zeitdauer seit Mitternacht, die in Stunden, Minuten, Sekunden und Sekundenbruchteile gesplittet ist. Dieser Datentyp wird gerne zum Formatieren verwendet. Zuerst einmal gibt die folgende Tabelle einen kompakten Ăśberblick des neuen Datentyps std::chrono::hh_mm_ss. tOfDay
ist eine Instanz dieses Typs.
Das folgende Programm wendet die Funktionen an:
// timeOfDay.cpp
#include "date.h"
#include <iostream>
int main() {
using namespace date; // (3)
using namespace std::chrono_literals;
std::cout << std::boolalpha << std::endl;
auto timeOfDay = date::hh_mm_ss(10.5h + 98min + 2020s + 0.5s); // (1)
std::cout<< "timeOfDay: " << timeOfDay << std::endl; // (2)
std::cout << std::endl;
std::cout << "timeOfDay.hours(): " << timeOfDay.hours() << '\n'; // (4)
std::cout << "timeOfDay.minutes(): " << timeOfDay.minutes() << '\n'; // (4)
std::cout << "timeOfDay.seconds(): " << timeOfDay.seconds() << '\n'; // (4)
std::cout << "timeOfDay.subseconds(): " << timeOfDay.subseconds() << '\n'; // (4)
std::cout << "timeOfDay.to_duration(): " << timeOfDay.to_duration() << '\n'; // (5)
std::cout << std::endl;
std::cout << "date::hh_mm_ss(45700.5s): " << date::hh_mm_ss(45700.5s) << '\n'; // (6)
std::cout << std::endl;
std::cout << "date::is_am(5h): " << date::is_am(5h) << std::endl; // (7)
std::cout << "date::is_am(15h): " << date::is_am(15h) << std::endl; // (7)
std::cout << std::endl;
std::cout << "date::make12(5h): " << date::make12(5h) << std::endl; // (7)
std::cout << "date::make12(15h): " << date::make12(15h) << std::endl; // (7)
std::cout << std::endl;
}
In Zeile 1 erzeuge ich eine neue Instanz von std::chrono::hh_mm_ss: timeOfDay
. Dank der chrono-Literale aus C++14 lassen sich ein paar Zeitdauern zu dem Tageszeitobjekt hinzuaddieren und es damit zu initialisieren. Mit C++20 lässt sich timeOfDay
(Zeile 2) direkt ausgeben. Genau aus diesem Grund muss ich in Zeile 3 den Namensraum date
bekannt machen. Der Rest des Programms sollte einfach zu lesen sein. Die Zeilen (4) gibt die Komponenten der Zeitdauer seit Mitternacht in Stunden, Minuten, Sekunden und Sekundenbruchteilen zurĂĽck. Zeile (5) gibt die Zeitdauer seit Mitternacht in Sekunden zurĂĽck. Die Zeile (6) ist interessanter: Die ĂĽbergebenen Sekunden entsprechen der Zeit, die in Zeile (2) dargestellt wird. Zeile (7) beantwortet die Frage, ob die gegebene Zeit a.m. ist. Zeile (8) gibt schlieĂźlich das 12-Stunden-Ă„quivalent der gegebenen Stunde zurĂĽck.
Dank der date [8]-Bibliothek lässt sich das Programm ausführen.
Wie geht's weiter?
In meinen nächsten Artikel stelle ich die nächste Komponente der chrono-Erweiterung vor: Kalender. ( [9])
URL dieses Artikels:
https://www.heise.de/-4937418
Links in diesem Artikel:
[1] https://www.grimm-jaud.de/index.php/blog/tag/time
[2] https://github.com/HowardHinnant/date
[3] https://github.com/HowardHinnant/date
[4] https://wandbox.org/permlink/L8MwjzSSC3fXXrMd
[5] https://github.com/HowardHinnant/date
[6] https://www.grimm-jaud.de/index.php/blog/c-17-kern
[7] https://github.com/HowardHinnant/date
[8] https://github.com/HowardHinnant/date
[9] mailto:rainer@grimm-jaud.de
Copyright © 2020 Heise Medien