https://www.timeanddate.com/date/weekday.html berechnet verschiedene Fakten zu einem Tag des Jahres, zum Beispiel:
Wie können diese Zahlen bei einem beliebigen Datum mit der C ++ 20-Chronospezifikation berechnet werden ?
https://www.timeanddate.com/date/weekday.html berechnet verschiedene Fakten zu einem Tag des Jahres, zum Beispiel:
Wie können diese Zahlen bei einem beliebigen Datum mit der C ++ 20-Chronospezifikation berechnet werden ?
Antworten:
Dies ist mit der C ++ 20 Chrono-Spezifikation bemerkenswert einfach . Unten zeige ich eine Funktion, die ein beliebiges Datum eingibt und diese Informationen an druckt cout
. Obwohl zum Zeitpunkt dieses Schreibens die C ++ 20-Chronospezifikation noch nicht ausgeliefert wurde, wird sie durch eine kostenlose Open-Source-Bibliothek angenähert . Sie können also heute damit experimentieren und es sogar in Versandanwendungen aufnehmen, solange Sie C ++ 11 oder höher verwenden.
Diese Antwort hat die Form einer Funktion:
void info(std::chrono::sys_days sd);
sys_days
ist eine Tagespräzision time_point
in der system_clock
Familie. Das heißt, es ist einfach eine Anzahl von Tagen seit 1970-01-01 00:00:00 UTC. Der Typalias sys_days
ist neu in C ++ 20, aber der zugrunde liegende Typ ist seit C ++ 11 ( time_point<system_clock, duration<int, ratio<86400>>>
) verfügbar . Wenn Sie die Open-Source-Vorschau-Bibliothek C ++ 20 verwenden , sys_days
ist in namespace date
.
Der folgende Code setzt funktionslokal voraus:
using namespace std;
using namespace std::chrono;
Ausführlichkeit zu reduzieren. Wenn Sie mit der Open-Source-Vorschau-Bibliothek C ++ 20 experimentieren , nehmen Sie außerdem Folgendes an:
using namespace date;
Überschrift
Die ersten beiden Zeilen auszugeben ist einfach:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
Nehmen Sie einfach das Datum sd
und verwenden Sie es format
mit den bekannten strftime
/ put_time
Flags, um das Datum und den Text auszudrucken. Die Open-Source-Vorschau-Bibliothek C ++ 20 hat die fmt-Bibliothek noch nicht integriert und verwendet daher die leicht geänderte Formatzeichenfolge "%d %B %Y is a %A\n"
.
Dies gibt (zum Beispiel) Folgendes aus:
26 December 2019 is a Thursday
Additional facts
Gemeinsame Zwischenergebnisse einmal berechnet
Dieser Abschnitt der Funktion wird zuletzt geschrieben, da man noch nicht weiß, welche Berechnungen mehrmals benötigt werden. Aber sobald Sie es wissen, können Sie sie wie folgt berechnen:
year_month_day ymd = sd;
auto y = ymd.year();
auto m = ymd.month();
weekday wd{sd};
sys_days NewYears = y/1/1;
sys_days LastDayOfYear = y/12/31;
Wir benötigen die Jahres- und Monatsfelder von sd
und den weekday
(Wochentag). Es ist effizient, sie auf diese Weise ein für alle Mal zu berechnen. Wir werden auch (mehrmals) den ersten und den letzten Tag des laufenden Jahres benötigen. Es ist schwer , an diesem Punkt zu sagen, aber es ist effizient diese Werte als Typ speichern sys_days
als ihre spätere Verwendung nur mit Tag orientierte Arithmetik ist , die sys_days
ist sehr an (Subnanosekundenbereich Geschwindigkeiten) effizient.
Fakt 1: Anzahl der Tage des Jahres und Anzahl der verbleibenden Tage im Jahr
auto dn = sd - NewYears + days{1};
auto dl = LastDayOfYear - sd;
cout << "* It is day number " << dn/days{1} << " of the year, "
<< dl/days{1} << " days left.\n";
Dies druckt die Tagesnummer des Jahres aus, wobei der 1. Januar der 1. Tag ist, und druckt dann auch die Anzahl der verbleibenden Tage im Jahr aus, ohne Berücksichtigung sd
. Die Berechnung dazu ist trivial. Durch Teilen jedes Ergebnisses durch days{1}
können Sie die Anzahl der Tage in dn
und dl
in einen ganzzahligen Typ für Formatierungszwecke extrahieren .
Fakt 2: Anzahl dieser Wochentage und Gesamtzahl der Wochentage im Jahr
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
auto total_wd = (last_wd - first_wd)/weeks{1} + 1;
auto n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number ", wd) << n_wd << " out of "
<< total_wd << format(" in {:%Y}.\n}", y);
wd
ist der Wochentag (Montag bis Sonntag), der oben in diesem Artikel berechnet wird. Um diese Berechnung durchzuführen, benötigen wir zuerst die Daten der ersten und letzten wd
im Jahr y
. y/1/wd[1]
ist der erste wd
im Januar und y/12/wd[last]
der letzte wd
im Dezember.
Die Gesamtzahl der wd
s im Jahr ist nur die Anzahl der Wochen zwischen diesen beiden Daten (plus 1). Der Unterausdruck last_wd - first_wd
ist die Anzahl der Tage zwischen den beiden Daten. Das Teilen dieses Ergebnisses durch 1 Woche führt zu einem integralen Typ, der die Anzahl der Wochen zwischen den beiden Daten enthält.
Die Wochennummer wird auf die gleiche Weise wie die Gesamtzahl der Wochen angegeben, außer dass eine mit dem aktuellen Tag anstelle des letzten wd
des Jahres beginnt : sd - first_wd
.
Fakt 3: Anzahl dieser Wochentage und Gesamtzahl der Wochentage im Monat
first_wd = y/m/wd[1];
last_wd = y/m/wd[last];
total_wd = (last_wd - first_wd)/weeks{1} + 1;
n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number }", wd) << n_wd << " out of "
<< total_wd << format(" in {:%B %Y}.\n", y/m);
Dies funktioniert genau wie Fakt 2, außer dass wir mit dem ersten und letzten wd
s des Jahr-Monat-Paares y/m
anstelle des gesamten Jahres beginnen.
Fakt 4: Anzahl der Tage im Jahr
auto total_days = LastDayOfYear - NewYears + days{1};
cout << format("* Year {:%Y} has ", y) << total_days/days{1} << " days.\n";
Der Code spricht so ziemlich für sich.
Fakt 5 Anzahl der Tage im Monat
total_days = sys_days{y/m/last} - sys_days{y/m/1} + days{1};
cout << format("* {:%B %Y} has ", y/m) << total_days/days{1} << " days.\n";
Der Ausdruck y/m/last
ist der letzte Tag des Jahr-Monat-Paares y/m
und natürlich y/m/1
der erste Tag des Monats. Beide werden so konvertiert, sys_days
dass sie subtrahiert werden können, um die Anzahl der Tage zwischen ihnen zu erhalten. Addiere 1 für die 1-basierte Anzahl.
Verwenden
info
kann wie folgt verwendet werden:
info(December/26/2019);
oder so:
info(floor<days>(system_clock::now()));
Hier ist eine Beispielausgabe:
26 December 2019 is a Thursday
Additional facts
* It is day number 360 of the year, 5 days left.
* It is Thursday number 52 out of 52 in 2019.
* It is Thursday number 4 out of 4 in December 2019.
* Year 2019 has 365 days.
* December 2019 has 31 days.
Bearbeiten
Für diejenigen, die die "konventionelle Syntax" nicht mögen, gibt es eine vollständige "Konstruktorsyntax", die stattdessen verwendet werden kann.
Zum Beispiel:
sys_days NewYears = y/1/1;
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
kann ersetzt werden durch:
sys_days NewYears = year_month_day{y, month{1}, day{1}};
sys_days first_wd = year_month_weekday{y, month{1}, weekday_indexed{wd, 1}};
sys_days last_wd = year_month_weekday_last{y, month{12}, weekday_last{wd}};
std::cout << "a*b = " << a*b << "; a^b = " << a^b << '\n';
(das glücklicherweise fast immer zur Kompilierungszeit abgefangen wird, aber dennoch ärgerlich ist). Daher wäre ich vorsichtig, wenn ich diesen neuen Missbrauch von Abteilungsbetreibern verwende.