C++20: Abfrage von Kalenderdaten und Ordinaldaten
![](https://heise.cloudimg.io/width/700/q75.png-lossy-75.webp-lossy-75.foil1/_www-heise-de_/imgs/18/4/5/7/6/3/1/1/shutterstock_1551975515-bad99eee7a7c63ef.jpeg)
(Bild: Kwangmoozaa/Shutterstock.com)
Die erweiterte Chrono-Bibliothek in C++20 macht es relativ einfach, die Zeitdauer zwischen Kalenderdaten abzufragen.
Dieser Artikel ist der sechste in meiner ausführlichen Reise durch die Chrono-Erweiterung in C++20:
- Zeit in C++20: Einführung in die Chrono-Terminologie [1]
- Zeit in C++20: Einführung in die Chrono-Terminologie mit Zeitdauer und Zeitpunkt [2]
- Zeit in C++20: Neue Datentypen für die Tageszeit und das Kalenderdatum [3]
- Zeit in C++20: Kalendertermine erstellen [4]
- Zeit in C++20: Kalendertermine darstellen und prüfen [5]
![](https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/5/7/6/3/1/1/TimelineCpp20CoreLanguage-1529a6191e572b4f.png)
Kalenderdaten abfragen
Das folgende Programm queryCalendarDates.cpp
fragt kurzerhand ein paar Kalenderdaten ab.
// queryCalendarDates.cpp
#include <chrono>
#include <iostream>
int main() {
std::cout << '\n';
using std::chrono::floor;
using std::chrono::January;
using std::chrono::years;
using std::chrono::days;
using std::chrono::hours;
using std::chrono::year_month_day;
using std::chrono::year_month_weekday;
using std::chrono::sys_days;
auto now = std::chrono::system_clock::now();
std::cout << "The current time is: " << now << " UTC\n"; // (1)
std::cout << "The current date is: "
<< floor<days>(now) << '\n';
std::cout << "The current date is: "
<< year_month_day{floor<days>(now)}
<< '\n';
std::cout << "The current date is: "
<< year_month_weekday{floor<days>(now)}
<< '\n';
std::cout << '\n';
auto currentDate = year_month_day(floor<days>(now)); // (2)
auto currentYear = currentDate.year();
std::cout << "The current year is " << currentYear << '\n';
auto currentMonth = currentDate.month();
std::cout << "The current month is " << currentMonth << '\n';
auto currentDay = currentDate.day();
std::cout << "The current day is " << currentDay << '\n';
std::cout << '\n';
auto hAfter = floor<hours>(now) -
sys_days(January/1/currentYear); // (3)
std::cout << "It has been " << hAfter
<< " since New Year!\n";
auto nextYear = currentDate.year() + years(1);
auto nextNewYear = sys_days(January/1/nextYear);
auto hBefore = sys_days(January/1/nextYear) -
floor<hours>(now); // (4)
std::cout << "It is " << hBefore << " before New Year!\n";
std::cout << '\n';
std::cout << "It has been " << floor<days>(hAfter)
<< " since New Year!\n"; // (5)
std::cout << "It is " << floor<days>(hBefore)
<< " before New Year!\n"; // (6)
std::cout << '\n';
}
Mit der C++20-Erweiterung lässt sich ein Zeitpunkt direkt anzeigen, beispielsweise jetzt (1). std::chrono::floor
rundet den Zeitpunkt auf einen Tag std::chrono::sys_days
ab. Dieser Wert kann zur Initialisierung des Datentyps std::chrono::year_month_day
verwendet werden. Wenn ich den Wert schließlich in einen std::chrono::year_month_weekday
-Kalendertyp eintrage, erhalte ich die Antwort, dass dieser bestimmte Tag der dritte Dienstag im Oktober ist.
Natürlich kann ich ein Kalenderdatum auch nach seinen Bestandteilen wie dem aktuellen Jahr, Monat oder Tag (2) fragen.
(3) ist die interessanteste Zeile: Wenn ich vom aktuellen Datum mit Stundenauflösung den ersten Januar des laufenden Jahres abziehe, erhalte ich die Anzahl der Stunden seit dem Jahreswechsel. Wenn ich umgekehrt vom ersten Januar des nächsten Jahres (4) das aktuelle Datum abziehe, erhalte ich die Stunden bis zum neuen Jahr mit der Stundenauflösung. Wer die Stundenauflösung nicht mag: (5) und (6) zeigen die Werte in Tagesauflösung an.
![](https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/5/7/6/3/1/1/queryCalendarDates-ba17095c3ec32186.png)
Jetzt möchte ich die Wochentage meiner Geburtstage wissen.
Abfrage der Wochentage
Dank der erweiterten Chrono-Bibliothek ist es ziemlich einfach, den Wochentag eines bestimmten Kalenderdatums abzufragen.
// weekdaysOfBirthdays.cpp
#include <chrono>
#include <cstdlib>
#include <iostream>
int main() {
std::cout << '\n';
int y;
int m;
int d;
std::cout << "Year: "; // (1)
std::cin >> y;
std::cout << "Month: ";
std::cin >> m;
std::cout << "Day: ";
std::cin >> d;
std::cout << '\n';
auto birthday = std::chrono::year(y)/
std::chrono::month(m)/
std::chrono::day(d); // (2)
if (not birthday.ok()) { // (3)
std::cout << birthday << '\n';
std::exit(EXIT_FAILURE);
}
std::cout << "Birthday: " << birthday << '\n';
auto birthdayWeekday =
std::chrono::year_month_weekday(birthday); // (4)
std::cout << "Weekday of birthday: "
<< birthdayWeekday.weekday() << '\n';
auto currentDate = std::chrono::year_month_day(
std::chrono::floor<std::chrono::days>
(std::chrono::system_clock::now()));
auto currentYear = currentDate.year();
auto age = static_cast<int>(currentDate.year()) -
static_cast<int>(birthday.year()); // (5)
std::cout << "Your age: " << age << '\n';
std::cout << '\n';
std::cout << "Weekdays for your next 10 birthdays"
<< '\n';
for (int i = 1, newYear = (int)currentYear;
i <= 10; ++i ) { // (6)
std::cout << " Age " << ++age << '\n';
auto newBirthday = std::chrono::year(++newYear)/
std::chrono::month(m)/
std::chrono::day(d);
std::cout << " Birthday: " << newBirthday
<< '\n';
std::cout << " Weekday of birthday: "
<< std::chrono::year_month_weekday(newBirthday).weekday()
<< '\n';
}
std::cout << '\n';
}
Zuerst fragt das Programm nach dem Jahr, dem Monat und dem Tag des Geburtstags (1). Anhand der Eingaben wird ein Kalenderdatum erstellt (2) und auf seine Gültigkeit überprüft (3). Jetzt zeige ich den Wochentag des Geburtstags an. Ich benutze das Kalenderdatum, um den Kalendertyp std::chrono::year_month_weekday
auszufüllen (4). Um die int
-Darstellung des Datentyps Jahr zu erhalten, muss ich ihn in int
konvertieren (5). Jetzt kann ich das Alter anzeigen. Schließlich zeigt die for-Schleife für jeden der nächsten zehn Geburtstage (6) die folgenden Informationen an: das Alter, das Kalenderdatum und den Wochentag. Ich muss die Variablen age
und newYear
lediglich inkrementieren.
Hier ist eine Ausführung des Programms mit meinem Geburtstag.
![](https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/5/7/6/3/1/1/weekdaysOfBirthdays-932f26d09326bade.png)
Berechnen von Ordinaldaten
Als letztes Beispiel für die neue Kalenderfunktion möchte ich die Online-Ressource Examples and Recipes [6] von Howard Hinnant vorstellen, die etwa 40 Beispiele für die neue Chrono-Funktionalität enthält. Vermutlich ist die Chrono-Erweiterung in C++20 nicht einfach zu verstehen; deshalb ist es wichtig, so viele Beispiele zu haben. Es empfiehlt sich, diese Beispiele als Ausgangspunkt für weitere Experimente zu nutzen und so das Verständnis dafür zu schärfen. Man kann auch seine eigenen Rezepte hinzufügen.
Um einen Eindruck von den Beispielen und Rezepten zu bekommen, möchte ich ein leicht abgewandeltes Programm von Roland Bock [7] vorstellen, das Ordinaldaten berechnet.
“An ordinal date consists of a year and a day of year (1st of January being day 1, 31st of December being day 365 or day 366). The year can be obtained directly from year_month_day. And calculating the day is wonderfully easy. In the code below, we make us of the fact that year_month_day can deal with invalid dates like the 0th of January:” (Roland Bock)
Ich habe die notwendigen Header in Rolands Programm eingefügt.
// ordinalDate.cpp
#include "date.h"
#include <iomanip>
#include <iostream>
int main()
{
using namespace date;
const auto time = std::chrono::system_clock::now();
const auto daypoint = floor<days>(time); // (1)
const auto ymd = year_month_day{daypoint};
// calculating the year and the day of the year
const auto year = ymd.year();
const auto year_day = daypoint -
sys_days{year/January/0}; // (2)
// (3)
std::cout << year << '-' << std::setfill('0')
<< std::setw(3) << year_day.count()
<< std::endl;
// inverse calculation and check
assert(ymd == year_month_day{sys_days{year/January/0} +
year_day});
}
Ich möchte dem Programm noch ein paar Anmerkungen hinzufügen. (1) schneidet den aktuellen Zeitpunkt ab. Der Wert wird in der folgenden Zeile verwendet, um ein Kalenderdatum zu initialisieren. (2) berechnet die Zeitdauer zwischen den beiden Zeitpunkten. Beide Zeitpunkte nutzen den Tag als Auflösungs. Schließlich gibt year_day.count()
(3) die Zeitdauer in Tagen zurück.
Wie geht's weiter?
Eine wichtige Komponente in meinen Artikeln zur erweiterten Chrono-Bibliothek in C++20 fehlt noch: Zeitzonen. (rme [8])
URL dieses Artikels:
https://www.heise.de/-9692091
Links in diesem Artikel:
[1] https://www.grimm-jaud.de/administrator/index.php?option=com_content&task=article.edit&id=608
[2] https://www.heise.de/blog/Zeit-in-C-20-Grundlegende-Chrono-Terminologie-mit-Zeitdauer-und-Zeitpunkt-9651792.html
[3] https://heise.de/-9664010
[4] https://www.heise.de/blog/Zeit-in-C-20-Kalendertermine-erstellen-9671530.html
[5] https://www.heise.de/blog/Zeit-in-C-20-Kalendertermine-darstellen-und-pruefen-9684590.html
[6] https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes
[7] https://github.com/rbock
[8] mailto:rme@ix.de
Copyright © 2024 Heise Medien