https://www.timeanddate.com/date/weekday.html calcula vários fatos sobre um dia do ano, por exemplo:
Dada uma data arbitrária, como esses números podem ser calculados com a especificação crono C ++ 20 ?
https://www.timeanddate.com/date/weekday.html calcula vários fatos sobre um dia do ano, por exemplo:
Dada uma data arbitrária, como esses números podem ser calculados com a especificação crono C ++ 20 ?
Respostas:
Isso é notavelmente fácil com a especificação C ++ 20 chrono . Abaixo, mostro uma função que insere uma data arbitrária e imprime essas informações em cout
. Embora no momento da redação deste artigo, a especificação do cronógrafo C ++ 20 ainda não estivesse sendo fornecida, ela é aproximada por uma biblioteca de código aberto e gratuita . Para que você possa experimentar hoje e incluí-lo em aplicativos de remessa, desde que adote o C ++ 11 ou posterior.
Esta resposta assumirá a forma de uma função:
void info(std::chrono::sys_days sd);
sys_days
é uma precisão do dia time_point
na system_clock
família. Isso significa que é simplesmente uma contagem de dias desde 1970-01-01 00:00:00 UTC. O alias de tipo sys_days
é novo no C ++ 20, mas o tipo subjacente está disponível desde o C ++ 11 ( time_point<system_clock, duration<int, ratio<86400>>>
). Se você usar a biblioteca de visualização C ++ 20 de código aberto , sys_days
está em namespace date
.
O código abaixo assume a função local:
using namespace std;
using namespace std::chrono;
para reduzir a verbosidade. Se você estiver experimentando a biblioteca de visualização C ++ 20 de código aberto , também assuma:
using namespace date;
Título
Para imprimir as duas primeiras linhas é simples:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
Basta pegar a data sd
e usar format
com os familiares strftime
/ put_time
sinalizadores para imprimir a data e o texto. A biblioteca de visualização C ++ 20 de código aberto ainda não integrou o biblioteca fmt e, portanto, usa a sequência de formatos levemente alterada "%d %B %Y is a %A\n"
.
Isso produzirá (por exemplo):
26 December 2019 is a Thursday
Additional facts
Resultados intermediários comuns calculados uma vez
Esta seção da função foi escrita por último, porque ainda não se sabe quais cálculos serão necessários várias vezes. Mas depois que você souber, aqui está como calculá-los:
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;
Precisamos dos campos de ano e mês de sd
e weekday
(dia da semana). É eficiente calculá-los de uma vez por todas dessa maneira. Também precisaremos (várias vezes) do primeiro e do último dia do ano atual. É difícil dizer neste momento, mas é eficiente armazenar esses valores como tipo, sys_days
pois seu uso subsequente é apenas com aritmética orientada para o dia, que sys_days
é muito eficiente em (velocidades abaixo de nanossegundos).
Fato 1: número do dia do ano e número de dias restantes no ano
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";
Isso imprime o número do dia do ano, com 1º de janeiro sendo o dia 1 e, em seguida, também imprime o número de dias restantes no ano, sem incluir sd
. O cálculo para fazer isso é trivial. Dividir cada resultado por days{1}
é uma maneira de extrair o número de dias dentro dn
e dl
em um tipo integral para fins de formatação.
Fato 2: Número deste dia da semana e número total de dias da semana no ano
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
é o dia da semana (segunda a domingo) computado na parte superior deste artigo. Para realizar esse cálculo, precisamos primeiro das datas do primeiro e do último wd
no ano y
. y/1/wd[1]
é o primeiro wd
de janeiro e y/12/wd[last]
o último wd
de dezembro.
O número total de wd
s no ano é apenas o número de semanas entre essas duas datas (mais 1). A subexpressãolast_wd - first_wd
é o número de dias entre as duas datas. Dividir esse resultado por 1 semana resulta em um tipo integral, mantendo o número de semanas entre as duas datas.
O número da semana é feito da mesma maneira que o número total de semanas, exceto um começa com o dia atual em vez do último wd
do ano: sd - first_wd
.
Fato 3: número deste dia da semana e número total de dias da semana no mês
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);
Isso funciona exatamente como o Fato 2, exceto que começamos com o primeiro e o último wd
s do par ano-mês em y/m
vez do ano inteiro.
Fato 4: Número de dias no ano
auto total_days = LastDayOfYear - NewYears + days{1};
cout << format("* Year {:%Y} has ", y) << total_days/days{1} << " days.\n";
O código praticamente fala por si.
Fato 5 Número de dias no mês
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";
A expressão y/m/last
é o último dia do par ano-mês y/m
e, claro, y/m/1
é o primeiro dia do mês. Ambos são convertidos emsys_days
para que possam ser subtraídos para obter o número de dias entre eles. Adicione 1 para a contagem baseada em 1.
Usar
info
pode ser usado assim:
info(December/26/2019);
ou assim:
info(floor<days>(system_clock::now()));
Aqui está o exemplo de saída:
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.
Editar
Para aqueles que não gostam da "sintaxe convencional", existe uma "sintaxe de construtor" completa que pode ser usada.
Por exemplo:
sys_days NewYears = y/1/1;
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
pode ser substituído por:
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';
(que, felizmente, quase sempre é capturado em tempo de compilação, mas ainda é um aborrecimento). Portanto, eu seria cauteloso ao usar esse novo abuso de operador de divisão.