c++ - 使用 C++20 chrono,如何计算有关日期的各种事实
问题描述
https://www.timeanddate.com/date/weekday.html计算一年中某一天的各种事实,例如:
给定任意日期,如何使用C++20 chrono 规范计算这些数字?
解决方案
使用C++20 chrono 规范,这非常容易。下面我展示了一个输入任意日期的函数,并将此信息打印到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;
标题
输出前两行很简单:
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 日是第 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
一年中 s 的总数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);
这就像事实 2 一样,除了我们从wd
年月对的第一个和最后一个 s开始,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
是 year-month pair 的最后一天,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}};
推荐阅读
- out-of-memory - 飞轮本地 - 管理员 - 内存耗尽致命错误
- ibm-mq - 通过命令行创建 MQ 潜艇时获得“未授权”
- java - Java:返回从包含“目标”的“短语”中的任何元素中删除的 ArrayList。
- javascript - 如何在javascript中的过滤器方法中相乘
- python - Selenium Chromedriver 可执行文件需要在路径中(它是)
- opencv - 如何跟踪快速移动的物体?
- python-3.x - 使用map的二维数组正方形元素并将其传递给python进一步处理
- ios - 当我在明确选择一行之前选择 UIPickerView 上的“完成”按钮时,应用程序崩溃
- c# - 使用在另一个类中创建的对象
- microsoft-edge - 查看 Edge 浏览器的版本