首页 > 编程笔记 > C++笔记 阅读:2

C++ chrono日历功能的用法(非常详细)

C++11 提供的 chrono 库提供了对时钟、时间点和持续时间的支持,但表示时间和日期并不容易,特别是在日历和时区方面。

C++20 标准通过扩展现有的 chrono 库纠正了这一点:
在本节中,我们将学习如何使用日历对象。所有 chrono 功能都在 <chrono> 头文件中 std::chrono 和 std::chrono_literals 命名空间中可用。

C++ chrono使用方式

我们可以使用 C++20 的 chrono 日历功能来:
1) 用年、月、日表示公历日期,作为 year_month_day 类型的实例。使用标准的用户自定义字面量、常量和重载操作符/来构造这样的对象:
// format: year / month / day
year_month_day d1 = 2020y / 1 / 15;
year_month_day d2 = 2020y / January / 15;
// format: day / month / year
year_month_day d3 = 15d / 1 / 2020;
year_month_day d4 = 15d / January / 2020;
// format: month / day / year
year_month_day d5 = 1 / 15d / 2020;
year_month_day d6 = January / 15 / 2020;

2) 将特定年月日的第 n 个工作日表示为 year_month_weekday 类型的实例:
// format: year / month / weekday
year_month_weekday d1 = 2020y / January / Monday[1];
// format: weekday / month / year
year_month_weekday d2 = Monday[1] / January / 2020;
// format: month / weekday / year
year_month_weekday d3 = January / Monday[1] / 2020;

3) 确定当前日期,并基于它计算其他日期,例如明天和昨天对应的日期:
auto today = floor<days>(std::chrono::system_clock::now());
auto tomorrow = today + days{ 1 };
auto yesterday = today - days{ 1 };

4) 确定特定年份和月份的第一天和最后一天:
year_month_day today = floor<days>(std::chrono::system_clock::now());
year_month_day first_day_this_month = today.year() / today.month() / 1;
year_month_day last_day_this_month = today.year() / today.month() / last;
year_month_day last_day_feb_2020 = 2020y / February / last;
year_month_day last_ymd{today.year(),month_day_last{month{ 2 } }};
year_month_day last_ymd{ };

5) 计算两个日期之间的天数:
inline int number_of_days(date::sys_days const& first, date::sys_days const& last)
{
    return (last - first).count();
}

auto days = number_of_days(2020_y / apr / 1, 2020_y / dec / 25);

6) 检查日期是否有效:
auto day = 2020_y / January / 33;
auto is_valid = day.ok();

7) 使用 time_of_day<Duration> 类模板以时、分和秒形式表示一天中的时间:
time_of_day<std::chrono::seconds> td{13h + 12min + 11s};
std::cout << td << '\n';  // 13:12:11

8) 创建带有日期和时间部分的时间点:
auto tp = sys_days{ 2020_y / April / 1 } + 12h + 30min + 45s;
std::cout << tp << '\n';  // 2020-04-01 12:30:45

9) 确定一天中的当前时间,并以不同的精度表示:
auto tp = std::chrono::system_clock::now();
auto dp = floor<days>(tp);

time_of_day<std::chrono::milliseconds> time{
    std::chrono::duration_cast<std::chrono::milliseconds>(tp - dp)
};
std::cout << time << '\n';  // 13:12:11.625

time_of_day<std::chrono::minutes> time{std::chrono::duration_cast<std::chrono::minutes>(tp - dp) };
std::cout << time << '\n';  // 13:12

C++ chrono工作原理

我们在示例中看到的 year_month_day 和 year_month_weekday 类型只是为支持日历而添加到 chrono 库的许多新类型中的一部分。

下表列出了 std::chrono 命名空间中的所有类型及其所代表的含义:

类型 描述
day 一月中的一天
month 一年中的一月
year 公历中的一年
weekday 公历一周中的一天
weekday_indexed 一月中的第 n 个工作日,其中n的取值范围为 [1,5](1 代表一月中的第一个工作日,5 为第 5 个)
weekday_last 一月中的最后一个工作日
month_day 特定月份的特定天
month_day_last 特定月份的最后一天
month_weekday 特定月份的第n个工作日
month_weekday_last 特定月份的最后一个工作日
year_month 特定年份的特定月份
year_month_day 特定的年月日
year_month_day_last 特定年份和月份的最后一天
year_month_weekday 特定年份和月份的第 n 个工作日
year_month_weekday_last 特定年份和月份的最后一个工作日

表中列出的所有类型有:
此外,operator/ 针对许多类型进行了重载,以使我们能够轻松地创建公历日期。当创建日期(年、月、日)时,可以选择三种不同的格式:
在这些情况下,“日”可以是:
为了消除表示日、月和年的整数间的歧义,标准库提供了两个用户自定义字面量:""y 用于构造 std::chrono::year 类型的字面量,""d 用于构造 std::chrono::day 类型的字面量。

此外,还有一些常量表示:
我们可以使用它们来构造日期,例如 2020y/April/1、25d/December/2020 或 Sunday[last]/May/2020。

year_month_day 类型提供了与 std::chrono::sys_days 之间的隐式转换,该类型是一个 std::chrono::time_point,精度为一天(24 小时)。还有一个称为 std::chrono::sys_seconds 的伴生类型,它是一个精确到 1 秒的 time_point。

time_point 和 sys_days/sys_seconds 之间的显式转换,可以使用 std::chrono::time_point_cast() 或 std::floor() 来执行。

要表示一天中的某个时刻,可以使用 std::chrono::time_of_day 类型,该类型表示从午夜开始经过的时间,以时、分、秒和子秒的形式表示。这个类模板针对不同的精度(std::chrono::hours、std::chrono::minutes 和 std::chrono::seconds)进行了特化。此类型主要用作格式化工具,它有两个名为 make12() 和 make24() 的成员,它们用于将输出的时间格式更改为 12 小时或 24 小时格式。

总结

本节描述的日期和时间工具都基于 std::chrono::system_clock。

自 C++20 以来,这个时钟测量 Unix 时间,即自 1970 年 1 月 1 日 00:00:00 UTC 开始的时间。这意味着隐式时区是 UTC。但是,在大多数情况下,人们感兴趣的可能是特定时区的当地时间。为此,chrono 库还增加了对时区的支持。

相关文章