Wang's blog

日期时间库

Published on

std::chrono是源于boost的C++新时间库,其中包含3个主要类型以及一些辅助函数。

时间间隔

类模板std::chrono::duration用于表示时间间隔。其定义如下:

template<
    class Rep,
    class Period = std::ratio<1>
> class duration;

其中,Rep为计次数的算术类型,可为整型、浮点型;Period为计次周期,为分数类型(std::ratio),单位为秒。例如,如果Period为std::ratio<1, 1000>,则表示计次周期为毫秒。每个duration对象包含一个Rep类型的次数,可用count()成员函数获取。次数×周期即为duration对象表示的时间间隔。常用的duration类型已经预定义:

  • nanoseconds:duration<至少64位的有符号整数类型, std::nano>
  • microseconds:duration<至少55位的有符号整数类型, std::micro>
  • milliseconds:duration<至少45位的有符号整数类型, std::milli>
  • seconds:duration<至少35位的有符号整数类型, std::ratio<1>>
  • minutes:duration<至少29位的有符号整数类型, std::ratio<60>>
  • hours:duration<至少23位的有符号整数类型, std::ratio<3600>>

其中,std::nano为std::ratio<1, 1000000000>,std::micro为std::ratio<1, 1000000>,std::milli为std::ratio<1, 1000>。C++20还添加了days、weeks、months和years。

// 10秒
std::chrono::seconds ten_seconds(10);
// 5小时
std::chrono::hours five_hours(5);

时间间隔字面值

C++14中添加了一些字面值后缀操作符,可以方便地生成时间间隔字面值:

  • h:小时
  • min:分钟
  • s:秒
  • ms:毫秒
  • us:微妙
  • ns:纳秒
using namespace std::chrono_literals;
auto two_hours = 2h;
auto five_minutes = 5min;

时间间隔转换

不同单位的时间间隔之间可以相互转换,转换规则为:

  • 当整数时间间隔相互转换且源间隔单位可被目标间隔单位整除,或浮点时间间隔相互转换时,不会发生精度损失,可使用duration类的构造函数隐式转换
  • 浮点时间间隔转整数时间间隔时,如果浮点值为NaN,无穷或相对整数间隔单位来说过大时,会出现未定义行为
  • 其它情况(浮点时间间隔转整数时间间隔,或整数时间间隔相互转换但源间隔单位不能被目标间隔单位整除)下,会发生截断造成精度损失,情况与static_cast相同
// high_resolution_clock使用最小时间单位,且为整数时间间隔
auto t1 = std::chrono::high_resolution_clock::now();
// ......
auto t2 = std::chrono::high_resolution_clock::now();

// 整数时间间隔转换为浮点时间间隔,无需使用duration_cast
std::chrono::duration<double, std::milli> fp_ms = t2 - t1;

// 整数时间间隔转换为更大的单位(最小单位->毫秒),需要使用duration_cast
auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);

// 整数时间间隔转换为更小的单位(毫秒->微秒),无需使用duration_cast
std::chrono::duration<long, std::micro> int_usec = int_ms;

时间点

类模板std::chrono::time_point表示时间中的一个点,其定义如下:

template<
    class Clock,
    class Duration = typename Clock::duration
> class time_point;

一个time_point对象表示从一个时钟Clock的纪元起始开始,经过一个类型为Duration的对象表示的时间间隔所到达的时间点。通过时钟的now()函数可以获得当前时间点,其它时间点一般通过计算得到。

时钟

chrono库中定义了3种时钟:

  • system_clock:系统时钟。即操作系统上看到的时钟,可在任何时候被调节
  • steady_clock:稳定(单调)时钟。随物理时间向前移动,不能被调整,适于计算时间间隔
  • high_resolution_clock:拥有最小计次周期的时钟。在不同标准库的实现不一致,尽量不要使用

每个时钟都包含一个时间间隔类型与时间点类型,同时包含一个纪元起始时间(一般使用Unix起始时间)。使用时钟的now()成员函数可以获得当前时间点,时间点相减可以获得时间间隔。

// 获取起始时间
auto start = std::chrono::steady_clock::now();
// .......
// 获取结束时间
auto end = std::chrono::steady_clock::now();
// 计算时间间隔
auto time_diff = end - start;
// 将时间间隔转换为以毫秒为单位
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(time_diff);