std::chrono时间库总结
基本概念
C++11中引入了一个新的关于时间的库,所有内容都包括在std::chrono
中,使用时直接引用头文件#include<chrono>
和命名空间std::chrono
即可。
std::chrono
库中主要有3个概念,时钟(Clocks)、时间段(Duration)、时间点(timePoint)。
时钟(Clocks)
顾名思义,就是和计时的相关类。主要就有3个,分别是:
系统时钟(system_clock), 和操作系统的系统时间同步的时钟,一般是unix时间,即从1970年1月1日到当前系统时间的时间间隔。例如系统时间是1970年1月2日23:59:59,那么返回的值即为\(24*60*60=86400\)秒。如果系统时间发生改变,相应的值也会发生改变。一般就是用来读取当前的系统时间。
单调时钟(steady_clock), 就类似秒表,每一次调用返回的值都会大于上一次调用的值,和系统的时间无关。用于程序计时尽量用steady_clock,可以防止在不同PC上运行导致的返回时间不准确。
高精度时钟(high_resolution_clock), 提供拥有最短计数周期的时钟,在某些编译器中可能是std::steady_clock或std::system_clock的别名,并且在不同编译器中的实现可能有巨大差异,应该尽量避免使用。
一般来说,我们使用的都是system_clock,
steady_clock相比system_clock就少了两个静态成员函数:to_time_t
和from_time_t
。
下面是两个使用示例:
使用system_clock读取系统时间。
1 |
|
输出: 1
2Today is: Sat Jan 20 01:46:56 2024
tomorrow is: Sun Jan 21 01:46:56 2024
记录函数的运行时间一般使用steady_clock: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <iostream>
#include <chrono>
#include <ctime>
int main()
{
using namespace std::chrono;
steady_clock::time_point start = steady_clock::now();
for (int i = 0;i < 1000;i ++) std::cout << '*';
std::cout << std::endl;
steady_clock::time_point end = steady_clock::now();
duration<double, std::ratio<1>> period = duration_cast<duration<double>>(end - start);
// 直接调用构造函数初始化也行
// duration<double, std::ratio<1>> period(end-start);
std::cout << "Took " << period.count() << " seconds" << std::endl;
}1
Took 2.7105e-05 seconds
to_time_t
和from_time_t
,只能提供基本计时操作。
时间段(Durations)
顾名思义就是表示一段持续的时间,比如1s、1min、1day等,需要指定单位,所以Duration需要提供一个模板来指定。
他的定义如下: 1
template<class Rep, class Period = std::ratio<1>> class duration;
Period
就是用来表示时间段的单位,比如天、分钟、秒等。Rep
就是实际用来存储数据类型。比如10秒,则Period
就为std::ratio<1>
,
Rep
就为int
,数值为10。如果要表示10.0秒,则Rep
就为double
。一般
Period
类是std::ratio
的别名,也就是一个分数(比率),定义如下:
1
template <intmax_t N, intmax_t D = 1> class ratio;
标准库定义了一些常见的时间段: 1
2
3
4
5
6using nanoseconds = duration<_GLIBCXX_CHRONO_INT64_T, ratio<1,1000000000>>; // 纳秒,使用至少64位的有符号整数存储
using microseconds = duration<_GLIBCXX_CHRONO_INT64_T, ratio<1, 1000000>>; // 微秒,使用至少55位的有符号整数存储
using milliseconds = duration<_GLIBCXX_CHRONO_INT64_T, ratio<1, 1000>>; // 毫秒,使用至少45位的有符号整数存储
using seconds = duration<_GLIBCXX_CHRONO_INT64_T>;
// 秒,使用长度不小于35位的有符号整数存储
using minutes = duration<_GLIBCXX_CHRONO_INT64_T, ratio<60, 1>>; // 分钟, 使用长度不小于29为的有符号整数存储。
对于duration来说,一般有两种操作:
- 时间的增减。
duration重载了大多数运算符,可以直接进行运算: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// duration operators
#include <iostream>
#include <ratio>
#include <chrono>
int main ()
{
std::chrono::duration<int> foo{};
std::chrono::duration<int> bar (10);
// counts: foo bar
// --- ---
foo = bar; // 10 10
foo = foo + bar; // 20 10
++foo; // 21 10
--bar; // 21 9
foo *= 2; // 42 9
foo /= 3; // 14 9
bar += ( foo % bar ); // 14 14
std::cout << std::boolalpha;
std::cout << "foo==bar: " << (foo==bar) << std::endl; // == 运算符比较两个时间段的值
std::cout << "foo: " << foo.count() << std::endl;
std::cout << "bar: " << bar.count() << std::endl;
return 0;
}1
2
3foo==bar: true
foo: 14
bar: 14duration_cast
函数来转换: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <iostream>
#include <chrono>
int main ()
{
std::chrono::seconds s (1); // 1 second
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds> (s);
std::cout << "ms: " << ms.count() << std::endl;
std::cout << "s: " << s.count() << std::endl;
ms += std::chrono::milliseconds(2500); // 3500 millisecond
s = std::chrono::duration_cast<std::chrono::seconds> (ms);
std::cout << "ms: " << ms.count() << std::endl;
std::cout << "s: " << s.count() << std::endl;
return 0;
}1
2
3
4ms: 1000
s: 1
ms: 3500
s: 3
时间点(time_point)
时间点表示一个确切的时间,例如:2024年1月20日1:49:53。 时钟(clocks)返回的值就是一个时间点,两个时间点之间的差值就是一段时间(duration)。
时间点的定义如下: 1
template<class Clock, class Duration = typename Clock::duration> class time_point;
常用的函数有:
time_since_epoch()
: 返回基于起始时间的时间段。time_point_cast()
: 用来将时间点转换为基于同一个时钟,但为不同单位的时间点。
一般使用时间点的场景就是类似clock的那种,记录两个时间点然后计时,或者转换为时间戳什么的。
时间点加减时间段返回一个新的时间点,时间点加减一个时间点返回一个时间段,和常识都一样,还是挺好理解。