C ++ 20 크로노를 사용하여 날짜에 대한 다양한 사실을 계산하는 방법 날짜가 주어지면

https://www.timeanddate.com/date/weekday.html 은 연중 무휴에 대한 다양한 사실을 계산합니다. 예를 들면 다음과 같습니다.

https://i.stack.imgur.com/WPWuO.png

임의의 날짜가 주어지면 C ++ 20 크로노 사양으로 이러한 숫자를 어떻게 계산할 수 있습니까?



답변

이것은 C ++ 20 크로노 사양 에서 매우 쉽다 . 아래에서는 임의의 날짜를 입력 하고이 정보를에 인쇄하는 함수를 보여줍니다 cout. 이 글을 쓰는 시점에서 C ++ 20 크로노 사양 은 아직 출시되지 않았지만 무료 오픈 소스 라이브러리로 추정됩니다 . 따라서 오늘 시험해보고 C ++ 11 이상을 채택하는 한 배송 응용 프로그램에 포함시킬 수도 있습니다.

이 답변은 함수 형태를 취합니다.

void info(std::chrono::sys_days sd);

sys_days하루 정밀도입니다 time_pointsystem_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사용 하여 날짜와 텍스트를 인쇄하십시오. 오픈 소스 C ++ 20 미리보기 라이브러리는 아직 통합되지 않은 FMT 라이브러리를 , 그래서 약간 변경 형식 문자열을 사용합니다 .formatstrftimeput_time"%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;

의 연도 및 월 필드 sdweekday(요일)이 필요합니다. 이러한 방식으로 한 번에 모두 계산하는 것이 효율적입니다. 우리는 또한 현재 연도의 첫 날과 마지막 날이 필요합니다 이 시점에서 말하기는 어렵지만, 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 일이 1 일인 연도의 일수가 인쇄되고를 포함하지 않은 연도의 남은 일수가 인쇄됩니다 sd. 이를위한 계산은 간단합니다. 각 결과에 의해 제산하여 days{1}일수를 추출하는 방법 dndl목적 서식을 일체형으로.

사실 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. 1 월 y/1/wd[1]의 첫 번째 이며 12 월 의 마지막 입니다.wdy/12/wd[last]wd

wd해당 연도 의 총 개수는 이 두 날짜 사이의 주 수 (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);

이것은 wd연도 y/m대신 첫 달 과 마지막 달로 시작한다는 점을 제외하고는 사실 2와 동일하게 작동합니다 .

사실 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}};


답변