C++ 标准库 chrono
下面对 C++ 标准库中 <chrono>
头文件提供的高精度、类型安全的时间与时钟工具做一次系统、深入的梳理,包括时钟类别、duration
与 time_point
基础、常用别名、运算与转换、定时与睡眠、格式化/解析,以及实践建议。
一、概述
<chrono>
引入于 C++11,提供了类型安全的时间度量体系,替代了传统 C 风格的<ctime>
。- 核心概念围绕两大模板类:
std::chrono::duration<Rep,Period>
:表示一段时间长度(例如 3.5 秒、100 毫秒)std::chrono::time_point<Clock,Duration>
:表示某一时刻,相对于特定时钟的纪元(epoch)
- 配合若干 时钟(Clock) 类型,可进行高精度测时、定时、时间点运算、跨平台的线程睡眠等。
二、时钟(Clocks)
时钟类型 | 说明 | 精度 | 单调性 |
---|---|---|---|
system_clock | 与系统实时时钟对应,可转换为日历时间(time_t ) | 操作系统定义 | 非单调 |
steady_clock | 单调、不可回拨,适合测量间隔,不受系统时间调整影响 | 实现定义 | 单调 |
high_resolution_clock | 提供最高可用精度(通常是 steady_clock 或 system_clock ) | 实现定义 | 取决于底层时钟 |
using namespace std::chrono;
auto t0 = steady_clock::now();
// …执行某些耗时操作…
auto t1 = steady_clock::now();
auto elapsed = t1 - t0; // 类型为 steady_clock::duration
三、duration
:表示时间间隔
1. 定义
template<class Rep, class Period = std::ratio<1>>
class duration;
Rep
:底层数值类型(如int64_t
、double
)Period
:刻度单位,以分数形式表示:std::ratio<1,1000>
→ 毫秒std::ratio<60>
→ 分钟std::nano
/micro
/milli
/ratio<1>
/kilo
…
2. 常用别名
using nanoseconds = duration<long long, nano>; // 10⁻⁹ s
using microseconds = duration<long long, micro>; // 10⁻⁶ s
using milliseconds = duration<long long, milli>; // 10⁻³ s
using seconds = duration<long long>; // 1 s
using minutes = duration<long long, ratio<60>>;
using hours = duration<long long, ratio<3600>>;
3. 运算与转换
- 加减乘除:对同种或可转换
duration
之间可直接相加、相减;也可乘以/除以标量。 duration_cast<To>(d)
:将d
强制转换为To
,会截断精度而非四舍五入。std::chrono::abs(d)
(C++20)取绝对值。
auto d1 = 1500ms; // milliseconds
auto d2 = 1s + 500ms; // 1500ms
auto d3 = duration_cast<seconds>(d1); // 1s (截断)
auto d4 = d1 * 2; // 3000ms
四、time_point
:表示时刻
1. 定义
template<class Clock, class Duration = Clock::duration>
class time_point;
Clock::duration
:决定了time_point
的底层精度- 以时钟的纪元(epoch)为参考,例如
system_clock
通常以 UNIX 纪元 (1970-01-01)
2. 构造与置零
system_clock::time_point t0; // 默认构造:epoch
auto t1 = system_clock::now(); // 当前时刻
3. 运算
- 加减
duration
:tp + d
或tp - d
得到新的time_point
- 差值:
t2 - t1
得到duration
- 比较:支持
<,>,==
等
auto expire = t1 + 5min; // 5 分钟后
if (system_clock::now() < expire) { … }
auto wait = expire - system_clock::now(); // duration
五、定时与线程睡眠
std::this_thread::sleep_for(dur)
:阻塞当前线程持续指定duration
std::this_thread::sleep_until(tp)
:阻塞至指定time_point
#include <thread>
std::cout << "Sleeping for 500ms...\n";
std::this_thread::sleep_for(500ms);
std::cout << "Awake!\n";
- 精度取决于操作系统调度与底层时钟,通常不保证毫秒级精确唤醒。
六、格式化与解析(C++20 起)
C++20 增加了 <chrono>
对日历与格式化的支持,位于 <chrono>
或 <chrono>
+ <format>
。
#include <chrono>
#include <format> // C++20
using namespace std::chrono;
auto now = system_clock::now();
auto dp = floor<days>(now);
year_month_day ymd = dp; // C++20 calendar 类型
auto time_str = std::format("{:%Y-%m-%d %H:%M:%S}", now);
// 例如 "2025-07-12 15:04:05"
floor<Duration>(tp)
:向下取整至指定粒度year_month_day
、weekday
、month_day
等类型支持日历运算std::format
与<format>
的时间格式{:%Y-%m-%d}
与strftime
类似,更类型安全。
七、实践建议
- 测时请用
steady_clock
- 避免系统时间调整的影响;
high_resolution_clock
也可,但需确认其是否单调。
- 避免系统时间调整的影响;
- 存储/序列化用
system_clock
- 与现实世界时间对应,可转换为/自
time_t
,与外部系统交互友好。
- 与现实世界时间对应,可转换为/自
- 慎用
duration_cast
截断- 若需四舍五入,手动加半个单位再截断,或用浮点
duration<double>
做中介。
- 若需四舍五入,手动加半个单位再截断,或用浮点
- 避免睡眠“过度”依赖精度
sleep_for
可能比请求时间更长;对高精度实时控制,应配合忙等或操作系统定时器 API。
- 利用 C++20 日历库
- 对日期运算(加月、验证闰年等)请使用
year_month_day
等类型,胜过手写tm
计算。
- 对日期运算(加月、验证闰年等)请使用
- 类型安全与可读性
- 使用字面量(
100ms
,2h
)和using namespace std::chrono_literals
,代码简洁且避免单位混淆。
- 使用字面量(
通过以上对 <chrono>
中时钟、duration
、time_point
、定时、格式化与实践建议的全面梳理,相信你能在性能测量、任务调度、日志时间戳与日历运算等场景中高效、正确地使用现代 C++ 时间库。祝编码顺利!