https://www.timeanddate.com/date/weekday.html обчислює різні факти про день року, наприклад:
З огляду на довільну дату, як можна обчислити ці числа за специфікацією хронолу C ++ 20 ?
https://www.timeanddate.com/date/weekday.html обчислює різні факти про день року, наприклад:
З огляду на довільну дату, як можна обчислити ці числа за специфікацією хронолу C ++ 20 ?
Відповіді:
Це надзвичайно просто завдяки специфікації C ++ 20 chrono . Нижче я показую функцію, яка вводить довільну дату і друкує цю інформацію cout
. Хоча на момент написання цього документа специфікація хронології C ++ 20 ще не доставлена, вона наближається до безкоштовної бібліотеки з відкритим кодом . Таким чином, ви можете сьогодні експериментувати з ним і навіть включати його в додатки для доставки, якщо ви прийняли 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;
Заголовок
Вивести перші два рядки просто:
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';
(яка, на щастя, майже завжди потрапляє під час компіляції, але все ще викликає роздратування). Тож я б з обережністю користувався цим новим оператором підрозділу.