如何在C++20计时器中向日期添加天数?

2022-05-16 00:00:00 c++ c++20 chrono

给定C++20中的新<chrono>工具,如何向日期添加某些天数(例如n)?

当我尝试执行此操作时,出现编译时错误:

auto d = July/4/2020;
auto d2 = d + days{5};
          ~ ^ ~~~~~~~
error: invalid operands to binary expression
   ('std::chrono::year_month_day' and 'std::chrono::days')

解决方案

<chrono>中的日期只是一个以天为单位的时间点。和一个 日期时间仅为chrono::time_point(通常基于 system_clock),精度优于days。和中的规范日期类型 <chrono>为:

chrono::time_point<chrono::system_clock, chrono::days>
这只是一个days-精度time_point基于 system_clock。这个特殊的time_point也有一个便利 类型别名:sys_days

using sys_days = time_point<system_clock, days>;

因此,向sys_days添加天数只需:

sys_days tp = ...;
tp += days{n};
// or
auto tp2 = tp + days{n};

如果只有一天,也可以:

++tp;
这是非常高效的,因为在引擎盖下,它只需添加两个 ints.

如果time_point具有比days更精细的精度,则它仍然是 向其添加days的步骤相同:

auto tp = system_clock::now() + days{n};

当我尝试执行此操作时,出现编译时错误:

auto d = July/4/2020;
auto d2 = d + days{5};
          ~ ^ ~~~~~~~
error: invalid operands to binary expression
   ('std::chrono::year_month_day' and 'std::chrono::days')
上述变量d的类型为year_month_day。即使year_month_day在语义上等同于sys_days, 它不直接支持days精度运算。 year_month_day是以天为单位的时间点(但不是 chrono::time_point)。相反,它是{year, month, day}数据 结构。您可以通过以下方式轻松地执行天精度算术 首先将其转换为sys_days

auto d = July/4/2020;
auto d2 = sys_days{d} + days{5};
在本例中,结果d2的类型为sys_days。如果您想要 结果为year_month_day,然后只需将其转换回:

year_month_day d2 = sys_days{d} + days{5};

此设计的基本原理:

效率。从year_month_daysys_days(和 Back)需要一点数字运算。这不是一个很大的数额。但 与单个整数加法相比,它很大。

如果<chrono>库为year_month_day提供了days精度算法, 该算法将year_month_day转换为sys_days, 进行算术运算,然后将结果转换回 year_month_day。如果您有很多days-精度算术要 这样做,最好是只在sys_days中进行流量,并转换为 year_month_day仅在必要时(即当您需要获取 yearmonthday个字段)。

如果库提供year_month_day的日精度算法, 客户会盲目使用它,没有意识到year_month_day是 错误的数据结构,不适合他们的应用。这将类似于给予 std::list索引运算符(这将非常容易完成):

template <class T, class A>
T&
list<T, A>::operator[](size_type i)
{
    return *advance(begin(), i);
}

提供这样的API只会使编写起来过于简单,效率低下 密码。sys_days是执行days的首选数据结构 精确算术。

它仍然不适用于我:

auto d = July/4/2020;
auto d2 = sys_days{d} + day{5};
          ~~~~~~~~~~~ ^ ~~~~~~
error: invalid operands to binary expression
   ('std::chrono::sys_days' and 'std::chrono::day')
您需要使用days,而不是dayday是日历说明符 用于民用日历中的某一月的某一天。days是一个 chrono::duration。有关更深入的信息,请参阅stack overflow Q/A 讨论这两个概念之间的区别。

如果我有一个year_month_day,我想再增加几天 我知道到不了月底,我能做到吗? 转换为sys_days,从而提高效率?

是。

auto d = July/4/2020;
auto d2 = d.year()/d.month()/(d.day() + days{5});
以上只是将dday字段加5。没有 检查结果是否超过了这个月的最后一天。如果 它确实超过了该月的最后一天,该结果将被存储 在日期字段中(到第255天),d2.ok()将返回false


year_month_day适用于检索yearmonthday 日期中的字段。它也适用于yearsmonths 精度日历算法。sys_days适用于days 精度运算,并用于转换为更精细的精度 (a日期-时间)。

sys_days可以相互转换,不需要 信息丢失。使用任何最有意义的数据结构。 如果您忘记了,编译器会提醒您,就像它为 vector(否push_front)、list(无索引运算符)和 forward_list(否size)。

相关文章