https://www.timeanddate.com/date/weekday.html calcula varios datos sobre un día del año, por ejemplo:
Dada una fecha arbitraria, ¿cómo se pueden calcular estos números con la especificación cronológica C ++ 20 ?
https://www.timeanddate.com/date/weekday.html calcula varios datos sobre un día del año, por ejemplo:
Dada una fecha arbitraria, ¿cómo se pueden calcular estos números con la especificación cronológica C ++ 20 ?
Respuestas:
Esto es notablemente fácil con la especificación cronológica C ++ 20 . A continuación muestro una función que ingresa una fecha arbitraria e imprime esta información cout
. Aunque en el momento de escribir este artículo, la especificación cronológica C ++ 20 aún no se envía, se aproxima a una biblioteca gratuita de código abierto . Por lo tanto, puede experimentar con él hoy e incluso incluirlo en las aplicaciones de envío siempre que adopte C ++ 11 o posterior.
Esta respuesta tomará la forma de una función:
void info(std::chrono::sys_days sd);
sys_days
Es un día de precisión time_point
en la system_clock
familia. Eso significa que es simplemente un recuento de días desde 1970-01-01 00:00:00 UTC. El alias de tipo sys_days
es nuevo con C ++ 20, pero el tipo subyacente ha estado disponible desde C ++ 11 ( time_point<system_clock, duration<int, ratio<86400>>>
). Si usa la biblioteca de vista previa de código abierto C ++ 20 , sys_days
está en namespace date
.
El siguiente código asume la función local:
using namespace std;
using namespace std::chrono;
para reducir la verbosidad Si está experimentando con la biblioteca de vista previa de código abierto C ++ 20 , también asuma:
using namespace date;
Bóveda
Para generar las dos primeras líneas es simple:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
Simplemente tome la fecha sd
y úsela format
con las marcas familiares strftime
/ put_time
para imprimir la fecha y el texto. La biblioteca de vista previa de código abierto C ++ 20 aún no ha integrado la biblioteca fmt , por lo que utiliza la cadena de formato ligeramente alterada "%d %B %Y is a %A\n"
.
Esto generará (por ejemplo):
26 December 2019 is a Thursday
Additional facts
Resultados intermedios comunes calculados una vez
Esta sección de la función se escribe en último lugar, porque todavía no se sabe qué cálculos se necesitarán varias veces. Pero una vez que sepa, aquí es cómo calcularlos:
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;
Necesitaremos los campos de año y mes de sd
, y el weekday
(día de la semana). Es eficiente calcularlos de una vez por todas de esta manera. También necesitaremos (varias veces) el primer y último día del año actual. Es difícil saberlo en este momento, pero es eficiente almacenar estos valores como tipo, sys_days
ya que su uso posterior es solo con aritmética orientada al día, que sys_days
es muy eficiente a (velocidades inferiores a nanosegundos).
Dato 1: número de días del año y días restantes del año
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";
Esto imprime el número de día del año, siendo el 1 de enero el día 1, y luego también imprime el número de días restantes en el año, sin incluir sd
. El cálculo para hacer esto es trivial. Dividiendo cada resultado por days{1}
es una manera de extraer el número de días en dn
y dl
en un tipo integral para formatear propósitos.
Dato 2: número de este día de la semana y número total de días de la semana en el año
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
es el día de la semana (de lunes a domingo) calculado en la parte superior de este artículo. Para realizar este cálculo, primero necesitamos las fechas de la primera y la última wd
del año y
. y/1/wd[1]
es el primero wd
en enero y y/12/wd[last]
es el último wd
en diciembre.
El número total de wd
s en el año es solo el número de semanas entre estas dos fechas (más 1). La subexpresión last_wd - first_wd
es el número de días entre las dos fechas. Dividir este resultado por 1 semana da como resultado un tipo integral que contiene el número de semanas entre las dos fechas.
El número de la semana se realiza del mismo modo que el número total de semanas, excepto uno comienza con el día actual en lugar de la última wd
parte del año: sd - first_wd
.
Hecho 3: Número de este día de la semana y número total de días de la semana en el mes
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);
Esto funciona igual que el Hecho 2, excepto que comenzamos con el primer y último wd
s del par año-mes en y/m
lugar de todo el año.
Dato 4: número de días en el año
auto total_days = LastDayOfYear - NewYears + days{1};
cout << format("* Year {:%Y} has ", y) << total_days/days{1} << " days.\n";
El código habla más o menos por sí mismo.
Hecho 5 Número de días en el mes
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";
La expresión y/m/last
es el último día del par año-mes y/m
y, por supuesto, y/m/1
es el primer día del mes. Ambos se convierten para sys_days
que puedan restarse para obtener el número de días entre ellos. Agregue 1 para el recuento basado en 1.
Utilizar
info
se puede usar así:
info(December/26/2019);
o así:
info(floor<days>(system_clock::now()));
Aquí hay un ejemplo de salida:
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 aquellos que no son aficionados a la "sintaxis convencional", existe una "sintaxis de constructor" completa que se puede utilizar en su lugar.
Por ejemplo:
sys_days NewYears = y/1/1;
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
puede ser reemplazado 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, afortunadamente, casi siempre se detecta en el momento de la compilación, pero sigue siendo una molestia). Por lo tanto, sería cauteloso al usar este nuevo abuso de operador de división.