这非常容易C++20 计时规范 http://eel.is/c++draft/#time。下面我展示了一个函数,它输入任意日期,并将该信息打印到cout
。尽管在撰写本文时,C++20 计时规范 http://eel.is/c++draft/#time尚未发货,大约为免费的开源库 https://github.com/HowardHinnant/date。因此,您现在就可以尝试它,甚至只要您采用 C++11 或更高版本,就可以将其包含在发布的应用程序中。
这个答案将采用函数的形式:
void info(std::chrono::sys_days sd);
sys_days
是日精度time_point
in the 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 预览库 https://github.com/HowardHinnant/date, sys_days
is in namespace date
.
下面的代码假设函数本地:
using namespace std;
using namespace std::chrono;
以减少冗长。如果您正在尝试开源 C++20 预览库 https://github.com/HowardHinnant/date,还假设:
using namespace date;
Heading
输出前两行很简单:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
只需要日期即可sd
并使用format
与熟悉的strftime
/put_time
打印日期和文本的标志。这开源 C++20 预览库 https://github.com/HowardHinnant/date还没有整合FMMT库 https://github.com/fmtlib/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
is very在(亚纳秒速度)下高效。
事实 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}
是一种提取天数的方法dn
and 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
年月对的 sy/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。
Use
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.
Edit
对于那些不喜欢“常规语法”的人,可以使用完整的“构造函数语法”。
例如:
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}};