Zeit in C++20: Kalendertermine erstellen
Der Artikel taucht tiefer in das Konzept von Kalenderdaten in C++ ein und zeigt, wie man sie erstellt.
- Rainer Grimm
C++20 unterstützt Konstanten und Literale, um die Verwendung von Datentypen für Kalender und Datum zu vereinfachen.
Wer mehr über die Grundlagen erfahren möchte, sollte meine vorherigen Artikel lesen:
- Zeit in C++20: Einführung in die Chrono-Terminologie
- Zeit in C++20: Einführung in die Chrono-Terminologie mit Zeitdauer und Zeitpunkt
- Zeit in C++20: Neue Datentypen für die Tageszeit und das Kalenderdatum
Konstanten und Literale für Kalendertypen
Beginnen wir mit den Konstanten für std::chrono::weekday
und std::chrono::month
.
std::chrono::weekday
std::chrono::Monday
std::chrono::Thuesday
std::chrono::Wednesday
std::chrono::Thursday
std::chrono::Friday
std::chrono::Saturday
std::chrono::Sunday
std::chrono::month
std::chrono::January
std::chrono::February
std::chrono::March
std::chrono::April
std::chrono::May
std::chrono::June
std::chrono::July
std::chrono::August
std::chrono::September
std::chrono::October
std::chrono::November
std::chrono::December
C++20 unterstützt für die Datentypen std::chrono::day
und std::chrono::year
zwei neue Literale: d
und y
. Mehr Details dazu finden sich im Artikel Zeit in C++20: Einführung in die Chrono-Terminologie mit Zeitdauer und Zeitpunkt.
Kalenderdaten erstellen
Das Programm createCalendar.cpp
zeigt verschiedene Möglichkeiten, Kalenderdaten zu erstellen.
// createCalendar.cpp
#include <chrono>
#include <iostream>
int main() {
std::cout << '\n';
using namespace std::chrono_literals;
using std::chrono::last;
using std::chrono::year;
using std::chrono::month;
using std::chrono::day;
using std::chrono::year_month;
using std::chrono::year_month_day;
using std::chrono::year_month_day_last;
using std::chrono::year_month_weekday;
using std::chrono::year_month_weekday_last;
using std::chrono::month_weekday;
using std::chrono::month_weekday_last;
using std::chrono::month_day;
using std::chrono::month_day_last;
using std::chrono::weekday_last;
using std::chrono::weekday;
using std::chrono::January;
using std::chrono::February;
using std::chrono::June;
using std::chrono::March;
using std::chrono::October;
using std::chrono::Monday;
using std::chrono::Thursday;
using std::chrono::Sunday;
constexpr auto
yearMonthDay{year(1940)/month(6)/day(26)}; // (1)
std::cout << yearMonthDay << " ";
std::cout << year_month_day(1940y, June, 26d) << '\n'; // (2)
std::cout << '\n';
constexpr auto yearMonthDayLast{year(2010)/March/last}; // (3)
std::cout << yearMonthDayLast << " ";
std::cout <<
year_month_day_last(2010y, month_day_last(month(3)))
<< '\n';
constexpr auto
yearMonthWeekday{year(2020)/March/Thursday[2]}; // (4)
std::cout << yearMonthWeekday << " ";
std::cout << year_month_weekday(2020y,
month(March),
Thursday[2]) << '\n';
constexpr auto
yearMonthWeekdayLast{year(2010)/March/Monday[last]}; // (5)
std::cout << yearMonthWeekdayLast << " ";
std::cout << year_month_weekday_last(2010y,
month(March),
weekday_last(Monday));
std::cout << "\n\n";
constexpr auto day_{day(19)}; // (6)
std::cout << day_ << " ";
std::cout << day(19) << '\n';
constexpr auto month_{month(1)}; // (7)
std::cout << month_ << " ";
std::cout << month(1) << '\n';
constexpr auto year_{year(1988)}; // (8)
std::cout << year_ << " ";
std::cout << year(1988) << '\n';
constexpr auto weekday_{weekday(5)};
std::cout << weekday_ << " ";
std::cout << weekday(5) << '\n';
constexpr auto yearMonth{year(1988)/1};
std::cout << yearMonth << " ";
std::cout << year_month(year(1988), January) << '\n';
constexpr auto monthDay{10/day(22)};
std::cout << monthDay << " ";
std::cout << month_day(October, day(22)) << '\n';
constexpr auto monthDayLast{June/last};
std::cout << monthDayLast << " ";
std::cout << month_day_last(month(6)) << '\n';
constexpr auto monthWeekday{2/Monday[3]};
std::cout << monthWeekday << " ";
std::cout << month_weekday(February, Monday[3]) << '\n';
constexpr auto monthWeekDayLast{June/Sunday[last]};
std::cout << monthWeekDayLast << " ";
std::cout << month_weekday_last(June, weekday_last(Sunday))
<< '\n';
std::cout << '\n';
}
Es gibt zwei Möglichkeiten, ein Kalenderdatum zu erstellen: die sogenannte Cute-Syntax yearMonthDay{year(1940)/month(6)/day(26)}
(1) oder den expliziten Datentyp date::year_month_day(1940y, June, 26d)
(2). Ich verschiebe die Erklärung der Cute-Syntax auf den nächsten Abschnitt. Der explizite Datentyp ist interessant, weil er die Datums-Zeit-Literale 1940y
, 26d
und die vordefinierte Konstante June
verwendet. Das war der offensichtliche Teil des Programms.
(3), (4) und (5) bieten weitere Möglichkeiten, Kalenderdaten zu erstellen.
- (3): der letzte Tag des März 2010:
{year(2010)/March/last}
oderyear_month_day_last(2010y,month_day_last(month(3)))
- (4): der zweite Donnerstag im März 2020:
{year(2020)/March/Thursday[2]}
oderyear_month_weekday(2020y, month(March), Thursday[2])
- (5): der letzte Montag im März 2010:
{year(2010)/March/Monday[last]}
oderyear_month_weekday_last(2010y, month(March), weekday_last(Monday))
Die übrigen Datentypen stehen für einen Tag (6), einen Monat (7) oder ein Jahr (8). Man kann sie als Grundbausteine für vollständig spezifizierte Kalenderdaten kombinieren, wie in (3), (4) oder (5).
Dies ist die Ausgabe des Programms:
Wie versprochen, möchte ich nun über die Cute-Syntax schreiben.
Cute-Syntax
Die Cute-Syntax besteht aus überladenen Divisionsoperatoren zur Angabe eines Kalenderdatums. Die überladenen Operatoren unterstützen Zeitliterale (z.B. 2020y, 31d
) und std::chrono::month
Konstanten wie std::chrono::January, std::chrono::February, ..., std::chrono::December
.
Die folgenden drei Kombinationen von Jahr, Monat und Tag sind mit der Cute-Syntax möglich.
year/month/day
day/month/year
month/day/year
Diese Kombinationen sind nicht willkürlich gewählt. Sie sind die weltweit am häufigsten verwendeten. Jede andere Kombination ist nicht erlaubt.
Wenn man also den Datentyp year
, month
oder day
für das erste Argument auswählt, ist der Typ für die beiden anderen Argumente nicht mehr nötig, und eine Zahl tut es auch.
// cuteSyntax.cpp
#include <chrono>
#include <iostream>
int main() {
std::cout << '\n';
constexpr auto yearMonthDay{std::chrono::year(1966)/6/26};
std::cout << yearMonthDay << '\n';
constexpr auto dayMonthYear{std::chrono::day(26)/6/1966};
std::cout << dayMonthYear << '\n';
constexpr auto monthDayYear{std::chrono::month(6)/26/1966};
std::cout << monthDayYear << '\n';
constexpr auto
yearDayMonth{std::chrono::year(1966)/std::chrono::month(26)/6};
std::cout << yearDayMonth << '\n';
std::cout << '\n';
Die letzten Werte für Jahr/Tag/Monat sind nicht erlaubt und führen zu einer Laufzeitmeldung.
Wie geht es weiter?
Um ein Kalenderdatum {Jahr(2010)/March/last}
in einer lesbaren Form, beispielsweise als 2020-03-31 anzuzeigen, kommen die Operatoren local_days
oder sys_days
zum Einsatz.
(rme)