std::chrono时间库总结

基本概念

C++11中引入了一个新的关于时间的库,所有内容都包括在std::chrono中,使用时直接引用头文件#include<chrono>和命名空间std::chrono即可。

std::chrono库中主要有3个概念,时钟(Clocks)、时间段(Duration)、时间点(timePoint)。

时钟(Clocks)

顾名思义,就是和计时的相关类。主要就有3个,分别是:

  1. 系统时钟(system_clock), 和操作系统的系统时间同步的时钟,一般是unix时间,即从1970年1月1日到当前系统时间的时间间隔。例如系统时间是1970年1月2日23:59:59,那么返回的值即为\(24*60*60=86400\)秒。如果系统时间发生改变,相应的值也会发生改变。一般就是用来读取当前的系统时间。

  2. 单调时钟(steady_clock), 就类似秒表,每一次调用返回的值都会大于上一次调用的值,和系统的时间无关。用于程序计时尽量用steady_clock,可以防止在不同PC上运行导致的返回时间不准确。

  3. 高精度时钟(high_resolution_clock), 提供拥有最短计数周期的时钟,在某些编译器中可能是std::steady_clock或std::system_clock的别名,并且在不同编译器中的实现可能有巨大差异,应该尽量避免使用。

一般来说,我们使用的都是system_clock, steady_clock相比system_clock就少了两个静态成员函数:to_time_tfrom_time_t

下面是两个使用示例:

使用system_clock读取系统时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <chrono>
#include <ctime>

int main()
{
using namespace std::chrono;

duration<int, std::ratio<60*60*24>> oneDay{1}; // 长度为1天的时间段,duration类在下面会说。
system_clock::time_point today = system_clock::now();
system_clock::time_point tomorrow = today + oneDay; // 都重载了加减运算符

// 需要转换为time_t类型
std::time_t curTime = system_clock::to_time_t(today);
std::cout << "Today is: " << ctime(&curTime);

std::time_t nextTime = system_clock::to_time_t(tomorrow);
std::cout << "tomorrow is: " << ctime(&nextTime);
}

输出:

1
2
Today 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
注意,steady_clock没有to_time_tfrom_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;
N表示分子,D表示分母,用秒作为基本单位。例如当N=1,D=1时候,就是1/1 = 1s,当N=1,D=1000时,就是1/1000 = 1ms,当N=60,D=1时,就是60/1 = 1min。

标准库定义了一些常见的时间段:

1
2
3
4
5
6
using 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为的有符号整数存储。
其他的参考:https://cplusplus.com/reference/chrono/duration/ ,懒得写了。

对于duration来说,一般有两种操作:

  1. 时间的增减。

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
3
foo==bar: true
foo: 14
bar: 14
2. 不同单位时间段的转换 可以使用duration_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
4
ms: 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;
可以看出,标准库将时间点定义为:在基准时钟的起始时间加上一个时间段,一次来表示一个时间点。所以时间点都是基于基准时钟的起始时间来的。

常用的函数有:

  1. time_since_epoch(): 返回基于起始时间的时间段。
  2. time_point_cast(): 用来将时间点转换为基于同一个时钟,但为不同单位的时间点。

一般使用时间点的场景就是类似clock的那种,记录两个时间点然后计时,或者转换为时间戳什么的。

时间点加减时间段返回一个新的时间点,时间点加减一个时间点返回一个时间段,和常识都一样,还是挺好理解。


std::chrono时间库总结
https://acmicpc.top/2024/01/20/std-chrono时间库总结/
作者
江欣婷
发布于
2024年1月20日
许可协议