C++ 的时间库之六:日历和时区

前面提到,C++ 11 的时间库提供了各种时钟、时间点以及时间间隔的计算与表达,但是却没有提供日期相关的类型,也没有提供与时区有关的本地时间转换等支持组件,所以用起来不是很顺手。直到 C++ 20 终于补齐了这块短板,时间库具备是时间、日期和时区的完整支持,终于可以替代不安全的 C 函数接口。本篇主要就是介绍 C++ 20 新增的日历和时区相关内容。

1 Time of day

​ 设想一个与时间显式有关的场景,我们拿到了一个当前系统时间的时间点,希望在 UI 界面上显式这个时间。C++ 11 的方法就是先用时间点的 to_time_t() 方法将其转成一个 time_t 类型的秒的计数,然后再用 C 标准库提供的 localtime() 或 gmtime() 系列函数转成离散的时间数据结构 tm,这样就得到以本地时间表示的具体的时、分、秒以及日期信息,可用于界面的显示。这个过程存在两个问题,首先是与 C 的接口互转显得很突兀,其次是将高精度的时间点转成以秒为单位的 time_t 类型计数器会丢失时间精度。当然,我们也可以硬刚 chrono 库,借助时间点和时间间隔的运算符重载拆出具体的时间信息,比如:

auto sys_now_dura = system_clock::now().time_since_epoch();
auto rest_of_day = sys_now_dura % 24h;
auto hour = rest_of_day / 60min;
auto rest_of_hours = rest_of_day % 60min;
auto minute = rest_of_hours / 60s;
auto rest_of_minutes = rest_of_hours % 60s;
auto second = duration_cast<seconds>(rest_of_minutes).count();

//输出 hour:minute:second 

​ C++ 20 提供的hh_mm_ss能更简单地将一个时间间隔分解成时、分、秒的形式,形如其名,定义如下:

template< class Duration >
class hh_mm_ss;

hh_mm_ss提供了几个成员函数,可以很方便地获取分离出来的时、分、秒信息。尽管它有一个 duration 类型的模板参数,但是在使用的时候,编译器可以根据构造函数的参数类型推导出这个模板参数,所以可以省略,比如:

hh_mm_ss hms(5h+43min+12s);  //自动推导的 duration 类型是 seconds

assert(hms.hours().count() == 5);
assert(hms.minutes().count() == 43);
assert(hms.seconds().count() == 12);

利用hh_mm_ss的这个特点,获得当前时间的时、分、秒的代码就非常简单了:

hh_mm_ss hms(system_clock::now().time_since_epoch() % 24h);

auto hour = hms.hours().count(); //整数类型的小时数
auto minute = hms.minutes().count(); //整数类型的分钟数
auto second = hms.seconds().count(); //整数类型的秒数

​ 除了hh_mm_ss类,C++ 20 还提供了判断时间是上午时间还是下午时间的函数,以及转换 12 小时制和 24 小时制的函数。使用也是非常简单:

hh_mm_ss hms(11h+43min+12s);

assert(is_am(hms.hours()));
assert(is_pm(hours(16)));

auto half_h = make12(hours(16));
assert(half_h.hours().count() == 4);

auto full_h = make24(hours(6), true);
assert(full_h.count() == 18);

hh_mm_ss类的构造函数和主要的成员函数都是 constexpr 类型,这意味着可以声明 constexpr 类型的hh_mm_ss对象,同时也可以在其他常量表达式或常量函数中使用hh_mm_ss

2 日历

2.1 基本日历单位

2.1.1 year、month 和 day

​ 既然时间有hh_mm_ss,那么日期应该有year_month_day吧?没错,不仅有year_month_day,还有year_monthmonth_dayyear_month_weekday等等。day、month 和 year 提供了单独的年、月、日基本日历单位的表达,这些对象本身并没有复杂的功能,只是提供了基本的构造、加减运算和比较运算。比如 day,表示一个月内的日期,正常情况下,其值的范围应该是 [1-31] 区间,但是可以用 0 -255 范围内的值初始化一个 day 对象,它不抱怨并不表示它是个有效的日期,可以用成员函数 ok() 来判断一个 day 对象是否是一个有效的日期:

day md{
    15 };
assert(md.ok());
md -= 4d; //前四天是几号?
assert(md == 11d);
md += 21d; //加上 21 天,变成 32
assert(!md.ok()); // 不是合法的日子

注意 std::chrono::daystd::chrono::days

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王晓华-吹泡泡的小猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值