https://www.timeanddate.com/date/weekday.html вычисляет различные факты о дне года, например:
Учитывая произвольную дату, как эти числа могут быть вычислены с хронологической спецификацией C ++ 20 ?
https://www.timeanddate.com/date/weekday.html вычисляет различные факты о дне года, например:
Учитывая произвольную дату, как эти числа могут быть вычислены с хронологической спецификацией C ++ 20 ?
Ответы:
Это очень просто с хронологической спецификацией C ++ 20 . Ниже я показываю функцию, которая вводит произвольную дату и печатает эту информацию cout
. Хотя на момент написания этой статьи спецификация C ++ 20 chrono еще не поставлялась, она приближается к бесплатной библиотеке с открытым исходным кодом . Таким образом, вы можете поэкспериментировать с ним сегодня и даже включить его в поставку приложений, если вы используете C ++ 11 или более позднюю версию.
Этот ответ примет форму функции:
void info(std::chrono::sys_days sd);
sys_days
Точность дня time_point
в system_clock
семье. Это означает, что это просто количество дней с 1970-01-01 00:00:00 UTC. Псевдоним типа sys_days
является новым в C ++ 20, но базовый тип доступен с C ++ 11 ( time_point<system_clock, duration<int, ratio<86400>>>
). Если вы используете библиотеку предварительного просмотра C ++ 20 с открытым исходным кодом , sys_days
находится в namespace date
.
Код ниже предполагает локальную функцию:
using namespace std;
using namespace std::chrono;
уменьшить многословие. Если вы экспериментируете с библиотекой предварительного просмотра C ++ 20 с открытым исходным кодом , также предположите:
using namespace date;
Heading
Вывести первые две строки просто:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
Просто возьмите дату sd
и используйте format
знакомые strftime
/ put_time
флаги, чтобы распечатать дату и текст. C ++ 20 библиотеки просмотра с открытым исходным кодом еще не интегрировала библиотеку FMT , и поэтому использует слегка измененную строку формата "%d %B %Y is a %A\n"
.
Это выведет (например):
26 December 2019 is a Thursday
Additional facts
Общие промежуточные результаты вычисляются один раз
Этот раздел функции написан последним, потому что еще не известно, какие вычисления понадобятся несколько раз. Но как только вы знаете, вот как их вычислить:
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;
Нам понадобятся поля года и месяца sd
, а также weekday
(день недели). Таким способом их можно вычислить раз и навсегда. Нам также понадобятся (несколько раз) первый и последний дни текущего года. Трудно сказать , в этот момент, но это эффективно хранить эти значения типа , sys_days
как их последующее использование только с однодневной ориентированной арифметики , которая sys_days
является очень эффективным при (скорости субнаносекундной).
Факт 1: число дней в году и количество дней, оставшихся в году
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";
Это печатает номер дня года, где 1 января - день 1, а затем также выводит количество дней, оставшихся в году, не включая sd
. Вычисление, чтобы сделать это тривиально. Разделение каждого результата days{1}
- это способ извлечения количества дней в dn
и dl
для целочисленного типа в целях форматирования.
Факт 2: номер этого дня недели и общее количество дней недели в году.
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
день недели (с понедельника по воскресенье), вычисленный в начале этой статьи. Для выполнения этого вычисления нам сначала нужны даты первого и последнего числа wd
в году y
. y/1/wd[1]
первый wd
в январе и y/12/wd[last]
последний wd
в декабре.
Общее количество wd
s в году - это количество недель между этими двумя датами (плюс 1). Подвыражение last_wd - first_wd
- это количество дней между двумя датами. Разделение этого результата на 1 неделю приводит к целочисленному типу, содержащему количество недель между двумя датами.
Номер недели делается таким же образом , как общее число недель , за исключением одного начинается с текущим днем вместо последнего wd
года: sd - first_wd
.
Факт 3: номер этого дня недели и общее количество дней недели в месяце.
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);
Это работает так же, как Факт 2, за исключением того, что мы начинаем с первого и последнего wd
с пары год-месяц y/m
вместо всего года.
Факт 4: количество дней в году
auto total_days = LastDayOfYear - NewYears + days{1};
cout << format("* Year {:%Y} has ", y) << total_days/days{1} << " days.\n";
Код в значительной степени говорит сам за себя.
Факт 5 Количество дней в месяце
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";
Выражение y/m/last
является последним днем пары год-месяц y/m
и, конечно, y/m/1
первым днем месяца. Оба преобразуются в sys_days
так, что они могут быть вычтены, чтобы получить количество дней между ними. Добавьте 1 для подсчета на основе 1.
использование
info
можно использовать так:
info(December/26/2019);
или вот так:
info(floor<days>(system_clock::now()));
Вот пример вывода:
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.
редактировать
Для тех, кто не любит «обычный синтаксис», есть полный «синтаксис конструктора», который можно использовать вместо этого.
Например:
sys_days NewYears = y/1/1;
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
можно заменить на:
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';
(которое, к счастью, почти всегда ловится во время компиляции, но все же вызывает раздражение). Так что я буду осторожен при использовании нового злоупотребления оператором подразделения.