https://www.timeanddate.com/date/weekday.html calcola vari fatti su un giorno dell'anno, ad esempio:
Data una data arbitraria, come possono essere calcolati questi numeri con la specifica cronografo C ++ 20 ?
https://www.timeanddate.com/date/weekday.html calcola vari fatti su un giorno dell'anno, ad esempio:
Data una data arbitraria, come possono essere calcolati questi numeri con la specifica cronografo C ++ 20 ?
Risposte:
Questo è straordinariamente facile con la specifica cronografo C ++ 20 . Di seguito mostro una funzione che inserisce una data arbitraria e stampa queste informazioni su cout
. Anche se al momento della stesura di questo documento, la specifica cronografo C ++ 20 non è ancora disponibile, è approssimata da una libreria open source gratuita . Quindi puoi sperimentarlo oggi e persino includerlo nelle applicazioni di spedizione purché adotti C ++ 11 o versioni successive.
Questa risposta assumerà la forma di una funzione:
void info(std::chrono::sys_days sd);
sys_days
è una precisione diurna time_point
in system_clock
famiglia. Ciò significa che è semplicemente un conteggio di giorni dal 1970-01-01 00:00:00 UTC. L'alias del tipo sys_days
è nuovo con C ++ 20, ma il tipo sottostante è disponibile da C ++ 11 ( time_point<system_clock, duration<int, ratio<86400>>>
). Se si utilizza la libreria di anteprima open source C ++ 20 , sys_days
è in namespace date
.
Il codice seguente assume funzione locale:
using namespace std;
using namespace std::chrono;
per ridurre la verbosità. Se stai sperimentando la libreria di anteprima open source C ++ 20 , supponi anche:
using namespace date;
Intestazione
L'output delle prime due righe è semplice:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
Basta prendere la data sd
e utilizzare format
con i familiari strftime
/ put_time
flag per stampare la data e il testo. La libreria di anteprima C ++ 20 open source non ha ancora integrato la libreria fmt e quindi utilizza la stringa di formato leggermente modificata "%d %B %Y is a %A\n"
.
Questo produrrà (per esempio):
26 December 2019 is a Thursday
Additional facts
Risultati intermedi comuni calcolati una volta
Questa sezione della funzione è scritta per ultima, perché non si sa ancora quali calcoli saranno necessari più volte. Ma una volta che sai, ecco come calcolarli:
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;
Avremo bisogno dei campi dell'anno e del mese sd
e del weekday
(giorno della settimana). È efficiente calcolarli una volta per tutte in questo modo. Avremo anche bisogno (più volte) del primo e dell'ultimo giorno dell'anno in corso. È difficile dirlo a questo punto, ma è efficiente memorizzare questi valori come tipo sys_days
poiché il loro uso successivo è solo con l'aritmetica orientata al giorno che sys_days
è molto efficiente a (velocità al di sotto dei nanosecondi).
Fatto 1: numero di giorni dell'anno e numero di giorni rimasti nell'anno
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";
Ciò stampa il numero del giorno dell'anno, con il 1 ° gennaio come giorno 1, quindi stampa anche il numero di giorni rimanenti nell'anno, escluso sd
. Il calcolo per farlo è banale. Dividere ogni risultato per days{1}
è un modo per estrarre il numero di giorni in dn
e dl
in un tipo integrale ai fini della formattazione.
Fatto 2: numero di questo giorno feriale e numero totale di giorni feriali nell'anno
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
è il giorno della settimana (dal lunedì alla domenica) calcolato all'inizio di questo articolo. Per eseguire questo calcolo abbiamo prima bisogno delle date del primo e dell'ultimo wd
dell'anno y
. y/1/wd[1]
è il primo wd
a gennaio ed y/12/wd[last]
è l'ultimo wd
a dicembre.
Il numero totale di wd
s nell'anno è solo il numero di settimane tra queste due date (più 1). La sottoespressione last_wd - first_wd
è il numero di giorni tra le due date. Dividendo questo risultato per 1 settimana si ottiene un tipo integrale che tiene il numero di settimane tra le due date.
Il numero della settimana viene fatto allo stesso modo come il numero totale di settimane, tranne uno inizia con il giorno corrente invece che l'ultimo wd
dell'anno: sd - first_wd
.
Fatto 3: numero di questo giorno feriale e numero totale di giorni feriali nel mese
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);
Funziona proprio come Fact 2, tranne per il fatto che iniziamo con la prima e l'ultima wd
s della coppia anno-mese y/m
anziché l'intero anno.
Fatto 4: numero di giorni dell'anno
auto total_days = LastDayOfYear - NewYears + days{1};
cout << format("* Year {:%Y} has ", y) << total_days/days{1} << " days.\n";
Il codice parla praticamente da solo.
Fatto 5 Numero di giorni del mese
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";
L'espressione y/m/last
è l'ultimo giorno della coppia anno-mese y/m
e ovviamente y/m/1
è il primo giorno del mese. Entrambi vengono convertiti in sys_days
modo che possano essere sottratti per ottenere il numero di giorni tra di loro. Aggiungi 1 per il conteggio basato su 1.
Uso
info
può essere usato in questo modo:
info(December/26/2019);
o in questo modo:
info(floor<days>(system_clock::now()));
Ecco un esempio di output:
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.
modificare
Per coloro che non amano la "sintassi convenzionale", esiste invece una "sintassi del costruttore" che può essere utilizzata.
Per esempio:
sys_days NewYears = y/1/1;
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
può essere sostituito da:
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';
(che, per fortuna, è quasi sempre catturato al momento della compilazione, ma è comunque un fastidio). Quindi sarei cauto quando usi questo nuovo abuso da operatore di divisione.