Zeit in C++20: Kalendertermine erstellen

Der Artikel taucht tiefer in das Konzept von Kalenderdaten in C++ ein und zeigt, wie man sie erstellt.

In Pocket speichern vorlesen Druckansicht

(Bild: Kwangmoozaa/Shutterstock.com)

Lesezeit: 3 Min.
Von
  • Rainer Grimm
Inhaltsverzeichnis

C++20 unterstützt Konstanten und Literale, um die Verwendung von Datentypen für Kalender und Datum zu vereinfachen.

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++.

Wer mehr über die Grundlagen erfahren möchte, sollte meine vorherigen Artikel lesen:

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.

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} oder year_month_day_last(2010y,month_day_last(month(3)))
  • (4): der zweite Donnerstag im März 2020: {year(2020)/March/Thursday[2]} oder year_month_weekday(2020y, month(March), Thursday[2])
  • (5): der letzte Montag im März 2010: {year(2010)/March/Monday[last]} oder year_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.

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.

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)