目录
- 编译期有理数
- 持续时间 duration
- 时钟
- 时间点
本文主要记录C++标准中提供的时间处理工具,并提供简单实现的Linux平台的定时器demo
C++标准库中的chrono库提供了处理时间和日期相关的功能,头文件:#include<chrono>
;这个库包含以下组件:
- 持续时间 duration
- 时钟 Clock
- 时间点 Time point
- 日期 Date(C++20)
- 时区 Time zone(C++ 20)
<ctime>
头文件提供了C风格的时间和日期工具。
时间单位转换:1秒(s) = 1000 毫秒(ms) = 1,000,000 微秒(μs) = 1,000,000,000 纳秒(ns) = 1,000,000,000,000 皮秒(ps)
编译期有理数
ratio库可以精确表示任何在编译期使用的有限有理数(#include<ratio>
)。有理数的分子和分母通过类型为std::intmax_t
的编译期常量表示,这是一种有符号的整数类型,最大宽度由编译器指定。
ratio对象的定义方式和普通对象的定义方式不同,而且不能调用ratio对象的方法,需要使用类型别名,如定义一个表示1/60的有理数编译期常量:using r1 = ratio<1, 60>
using r1 = std::ratio<1, 60>; // 表示1/60
// r1有理数的分子(num)和分母(den)是编译期常量,可通过以下方式访问:
std::intmax_t num { r1::num };
std::intmax_t den { r1::den };
ratio是一个编译期常量,分子和分母需要在编译期确定
std::intmax_t n {1};
std::intmax_t d {60};
using r2 = std::ratio<n, d>; // 编译失败,n和d是变量,需要定义为常量
constexpr std::intmax_t n {1};
constexpr std::intmax_t d {60};
using r2 = std::ratio<n, d>;
ratio库支持有理数的加减乘除,由于所有这些操作都是在编译期进行的,所有不能使用标准算术运算符,可使用的算术ratio模板包含ratio_add
,ratio_subtract
, ratio_multiply
,ratio_divide
执行加减乘除。
持续时间 duration
表示两个时间点之间的间隔时间,通过模板化的std::chrono::duration
类来表示。
duration的两个模板参数分别是 Rep 和 Period,第一个参数Rep是用来表示时间数量的类型,通常是一个整数或浮点数类型,如long,double等。第二个模板参数Period 是一个 std::ratio
类型,表示时间单位,如果不指定会使用默认值ratio<1>
, 也就是1s。
示例代码:
// 创建一个 duration 对象,表示 10 秒
std::chrono::duration<int> ten_seconds(10);
// 创建一个 duration 对象,表示半分钟(30秒)
std::chrono::duration<double, std::ratio<30, 1>> half_a_minute(1);
// 创建一个 duration 对象,表示 120 毫秒
std::chrono::duration<long, std::milli> tt(120);// 打印:
std::cout << ten_seconds.count() << "senconds\n";
std::cout << half_a_minute.count() << " half minutes or " << std::chrono::duration_cast<std::chrono::seconds>(half_a_minute).count() << " seconds\n";
std::cout << tt.count() << "milliseconds\n";
输出:
10 senconds
1 half minutes or 30 seconds
120 milliseconds
支持以下方法或操作:
- 支持算术运算:
+,-,*,/, ==, <==>
duration d
:默认构造duration d(d1)
:copy构造,复制一个duration,d2可能拥有不同的单位类型duration d(val)
:以d的单位类型建立一个durationd = d1
:将d1赋值给d,可能存在隐式转换count()
:返回间隔的时间数量duration_cast<D>(d)
:返回d转换为类型D之后的结果static duraton::zero()
:返回持续时间值等于0的durationstatic duration::min() / static duration max()
: 返回duration模板指定的类型参数表示的最小值/最大值持续时间的duration值duration::rep
:获取tick的类型duration::period
:获得单位类型的类型
以下为算术运算和对象拷贝赋值示例:
std::chrono::duration<long, ratio<60>> d3{10}; // d3.count()输出:10
std::chrono::duration<long, ratio<1>> d4{14}; // d4.count()输出:14
if (d3 > d4) {std::cout << "d3 > d4" << endl;
}
++d4; // d4.count()输出:15
d4 *= 2; // d4.count()输出:30
std::chrono::duration<double, ratio<60>> d5 {d3 + d4}; // d5.count()输出:10.5
以上示例说明,duration会按照时间单位(duration的第二个参数)进行隐式类型转换,同理,如下示例:
std::chrono::duration<long> d7 { 30 }; // d7.count()输出:30
std::chrono::duration<double, ratio<60>> d8 { d7 }; // d8.count()输出:0.5
标准库定义了以下时间单位,可以直接使用:
using atto = ratio<1, 1000000000000000000LL>;
using femto = ratio<1, 1000000000000000LL>;
using pico = ratio<1, 1000000000000LL>;
using nano = ratio<1, 1000000000>;
using micro = ratio<1, 1000000>;
using milli = ratio<1, 1000>;
using centi = ratio<1, 100>;
using deci = ratio<1, 10>;
using deca = ratio<10, 1>;
using hecto = ratio<100, 1>;
using kilo = ratio<1000, 1>;
using mega = ratio<1000000, 1>;
using giga = ratio<1000000000, 1>;
using tera = ratio<1000000000000LL, 1>;
using peta = ratio<1000000000000000LL, 1>;
using exa = ratio<1000000000000000000LL, 1>;
// 如:
std::chrono::duration<long, std::milli> d(20);
为了更方便和易于理解,标准库中定义了如下时间单位,可以直接使用:
using nanoseconds = duration<long long, nano>;
using microseconds = duration<long long, micro>;
using milliseconds = duration<long long, milli>;
using seconds = duration<long long>;
using minutes = duration<int, ratio<60>>;
using hours = duration<int, ratio<3600>>;
// 使用如下:
std::chrono::seconds s(10); // s.count() 输出:10
时钟
时钟由time_point和duration组成,即定义时间点的起点和一个tick周期(就是计时单位,如秒),不同的clock有不同的起点。一般当处理两个时间点的差距时,必须提供相同的起点/clock。
标准库提供了三个clock:
system_clock
:所提供的timepoint将关联至现行系统的即时时钟,这个clock提供便捷函数to_time_t()和from_time_t(),允许转换成C的系统时间类型time_t;精度为100ns- steady_clock:它保证不会被调整;精度为ms
- high_resolution_clock:表现的是系统中带有最短tick周期的clock,可能就是steady_clock或者system_clock,取决于编译器;精度为100ns
clock提供的类型定义和static成员:
- clock::duration:获得clock的duration成员
- clock::rep:获得tick类型
- clock::period:获得单位类型的类型,等价于clock::duration::period
- clock::time_point:获得clock的timepoint类型
- clock::is_steady:如果clock是steady则为true
- clock::now:获得一个用来表现目前时间的time_point
- Timepoint:表现出某个特定时间点,关联至某个clock的某个正值或负值duration
C和Posix中的时间相关函数#include<ctime>
:注意,time_t
通常只是始自unix起始点(1970.1.1)的秒数,但不能保证如此
system_clock定义的方法: - to_time_t():将给定的time_point转换为time_t
- from_time_t():将time_t转换为time_point
时间点
time_point类表示某个时间点,存储为相对于纪元(epoch)的duration,表示开始时间。time_point总是和特定的clock关联,纪元就是所关联的clock的原点。例如 UNIX/Linux的时间纪元是1970年1月1日,duration用秒度量。
time_point类包含time_since_epoch 函数,它返回的duration表示所关联clock的纪元和保存的时间点之间的时间。
C++支持合理的time_point和duration算术运算
time_point有三个构造函数:
- time_point():构造一个time_point,通过duration::zero进行初始化,得到的time_point表示所关联clock的纪元
- time_point(const duration&d):构造一个time_point,通过给定的duration进行初始化,得到的time_point表示纪元+d