Wiki
std::chrono
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
1.本節解決什麼問題
在 C 語言中,處理時間用 time()、clock()、sleep()、gettimeofday() 等函式,它們使用不同的單位和型別(秒、毫秒、微秒...),容易搞混,精度也不夠。
std::chrono 是 C++11 引入的型別安全的時間庫,把"時間點"、"時長"、"時鐘"概念清晰地分開,單位在型別系統中自動管理,不需要手動換算。
2.這個特性是什麼
std::chrono 提供了三個核心概念:
- 時長
duration:一段時間長度,如 5 秒、10 毫秒。 - 時間點
time_point:某個時刻,如 2026-06-02 12:00:00。 - 時鐘
clock:獲取當前時間的工具,如system_clock、steady_clock。
3.C++ 標準版本
C++11(基礎),C++20 增加了日曆、時區等。
4.需要的標頭檔案
#include <chrono>
#include <thread> // for std::this_thread::sleep_for
5.基本語法
using namespace std::chrono;
// 时长
auto t1 = 5s; // 5 秒
auto t2 = 100ms; // 100 毫秒
auto t3 = 50us; // 50 微秒
auto t4 = 10ns; // 10 纳秒
auto t5 = 1min; // 1 分钟(C++20)
auto t6 = 2h; // 2 小时(C++20)
// 时间点
auto now = std::chrono::system_clock::now(); // 当前时间(系统时钟)
auto now2 = std::chrono::steady_clock::now(); // 单调时钟(不会往回跳)
// 时长转换
auto sec = std::chrono::duration_cast<std::chrono::seconds>(100ms); // 0s(截断)
// 休眠
std::this_thread::sleep_for(500ms);
6.常用時鐘對比
| 時鐘 | 特點 | 用途 |
|---|---|---|
system_clock |
系統時間,可轉換為日曆時間 | 顯示時間,時間戳 |
steady_clock |
單調遞增,不會往回跳 | 測量耗時(最常用) |
high_resolution_clock |
最高精度時鐘 | 需要最高精度的計時 |
7.示例程式碼
7.1.示例 1:測量一段程式碼的執行時間
#include <iostream>
#include <chrono>
#include <thread> // for sleep
int main()
{
// 记录开始时间
auto start = std::chrono::steady_clock::now();
// 模拟耗时操作
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 记录结束时间
auto end = std::chrono::steady_clock::now();
// 计算耗时
auto elapsed = end - start;
auto elapsed_ms = duration_cast<std::chrono::milliseconds>(elapsed);
auto elapsed_us = duration_cast<std::chrono::microseconds>(elapsed);
std::cout << "Elapsed: " << elapsed_ms.count() << " ms\n";
std::cout << "Elapsed: " << elapsed_us.count() << " us\n";
return 0;
}
執行結果(大約):
Elapsed: 500 ms
Elapsed: 500000 us
這裡的us可能有波動,一般是百位數以內級別的波動。
7.2.示例 2:在示例 1 基礎上,不同時間單位的使用和轉換
#include <iostream>
#include <chrono>
int main()
{
using namespace std::chrono_literals; //可以使用1s,100ms,500us这种更便捷
// 不同单位
auto s = 1s; // 1 秒 等同于 auto s = std::chrono::seconds(1);
auto ms = 100ms; // 100 毫秒 等同于 auto ms = std::chrono::milliseconds(100);
auto us = 500us; // 500 微秒 等同于 auto us = std::chrono::microseconds(500);
// 时长可以相加
auto total = s + ms + us;
std::cout << "total in us: " << std::chrono::duration_cast<std::chrono::microseconds>(total).count() << " us\n";
// 秒到毫秒的转换
auto two_seconds = 2s;
auto as_ms = std::chrono::duration_cast<std::chrono::milliseconds>(two_seconds);
std::cout << "2s = " << as_ms.count() << " ms\n";
// 毫秒到秒的转换(会截断)
auto ms_to_sec = std::chrono::duration_cast<std::chrono::seconds>(1500ms);
std::cout << "1500ms = " << ms_to_sec.count() << " s\n"; // 1 秒
return 0;
}
執行結果:
total in us: 1100500 us
2s = 2000 ms
1500ms = 1 s
7.3.示例 3:在示例 2 基礎上,實現一個簡單的計時器
#include <chrono>
#include <cstdio>
#include <functional>
#include <print>
// 简单的计时器:测量函数运行时间
double measure(std::function<void()> func)
{
auto start = std::chrono::steady_clock::now();
func();
auto end = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() / 1000.0; // 返回毫秒(先转us再转ms可以保留小数,只是最终展示形式以ms形式)
}
void slow_operation()
{
long int sum = 0;
for (int i = 0; i < 10000000; ++i)
{
sum += i;
}
std::println("sum = {}",sum);
}
void quick_operation()
{
int sum = 0;
for (int i = 0; i < 1000; ++i)
{
sum += i;
}
std::println("sum = {}",sum);
}
int main()
{
std::print("slow_op took {} ms\n",measure(slow_operation));
std::print("quick_op took {} ms\n",measure(quick_operation));
return 0;
}
執行結果(執行時間因機器而異):
sum = 49999995000000
slow_op took 17.712 ms
sum = 499500
quick_op took 0.005 ms
7.4.示例 4:在示例 3 基礎上,獲取和格式化系統時間
#include <chrono>
#include <ctime>
#include <print>
int main()
{
using namespace std::chrono_literals;
// 获取当前系统时间
auto now = std::chrono::system_clock::now();
// 获取自 epoch(1970-01-01)以来的秒数
auto epoch_seconds = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
std::println("Seconds since epoch: {}",epoch_seconds.count());
// 转换为 C 风格的 time_t 打印 (打印的是本地时间,比如上海时间UTC+8)
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::print("Current time: {}",std::ctime(&now_c)); //std::ctime()自己带一个换行
// 计算未来时间点(C++23的chrono格式化打印,打印UTC时间)
auto future = now + 24h; // C++20 的 24h 字面量
// 如果没有 C++20,可以用: auto future = now + std::chrono::hours(24);
std::println("24 hours later: {:%Y-%m-%d %H:%M:%S}",future); // 末尾会带一串高精度纳秒级部分
//转秒单位,来忽略future带的更高精度的时间(C++23的chrono格式化打印,打印UTC时间)
auto future_sec = std::chrono::time_point_cast<std::chrono::seconds>(future);
std::println("24 hours later: {:%Y-%m-%d %H:%M:%S}",future_sec);
return 0;
}
執行結果(日期因執行時間而異):
Seconds since epoch: 1788875788
Current time: Tue Sep 8 21:56:28 2026
24 hours later: 2026-09-09 13:56:28.573118608
24 hours later: 2026-09-09 13:56:28
這裡為何ctime()和{:%Y-%m-%d %H:%M:%S}打印出來的時間相差8小時呢?
system_clock::now()
↓
绝对时间点
没有“本地时间”这个概念
│
├── ctime()
│ ↓
│ 自动按系统本地时区显示
│
├── 直接 chrono 格式化 system_clock::time_point
│ ↓
│ 按 UTC 显示
│
└── zoned_time
↓
按指定时区显示
所以
13:56 UTC
=
21:56 UTC+8
可以通過以下命令在終端裡看你的電腦在什麼時區裡
date
timedatectl


8.執行結果
見上方每個示例的"執行結果"。
9.示例中的關鍵語法解釋
| 示例 | 講了什麼 | 新出現的語法 | 為什麼這樣寫 | 注意事項 |
|---|---|---|---|---|
| 示例 1 | 測量程式碼耗時 | steady_clock::now()、duration_cast、字面量 500ms |
steady_clock 單調遞增,適合計時 | 字面量需要 using namespace std::chrono |
| 示例 2 | 時長單位轉換 | 1s、100ms、duration_cast |
型別自動管理單位,轉換時要顯式 cast | duration_cast 是截斷,不是四捨五入 |
| 示例 3 | 通用計時器 | measure(function<void()>) |
包裝成一個工具函式,可重複使用 | steady_clock 是最佳選擇 |
| 示例 4 | 系統時間和格式化 | system_clock::now()、to_time_t()、24h |
system_clock 可以轉為日曆時間 | system_clock 可能被系統時間調整影響,不用於計時 |
10.計時和顯示時間不要混用
| 需求 | 推薦時鐘 | 原因 |
|---|---|---|
| 測量函式耗時 | steady_clock |
單調遞增,不受系統時間調整影響 |
| 超時判斷 | steady_clock |
不會因為系統時間跳變導致超時錯誤 |
| 列印當前日期時間 | system_clock |
可以轉換成日曆時間 |
| 生成日誌時間戳 | system_clock |
對人類可讀 |
一個常見錯誤是用 system_clock 做超時判斷。如果系統時間被 NTP 或使用者手動調回去,程式可能“等很久都不超時”。測耗時和超時都優先用 steady_clock。
10.1.示例 5:用 steady_clock 做超時判斷
#include <chrono>
#include <thread>
#include <print>
int main()
{
// 程序从 main 函数开始执行,下面的语句会按顺序运行。
using namespace std::chrono_literals;
auto deadline = std::chrono::steady_clock::now() + 300ms;
while (std::chrono::steady_clock::now() < deadline)
{
std::println("waiting...");
std::this_thread::sleep_for(100ms);
}
std::println("timeout");
// 返回 0 表示程序正常结束。
return 0;
}
可能的執行結果:
waiting...
waiting...
waiting...
timeout
這裡的重點不是迴圈本身,而是超時基準用 steady_clock。這類寫法在定時器、序列埠讀取超時、網路等待超時裡非常常見。
11.常見錯誤
錯誤 1:忘記 using namespace std::chrono_literals 或者 using namespace std::chrono 導致字面量不識別
auto t = 500ms; // ❌ 编译错误!
正確做法:加 using namespace std::chrono_literals; 或 加 using namespace std::chrono 或 寫 std::chrono::milliseconds(500)。
錯誤 2:用 system_clock 測量耗時
auto start = system_clock::now(); // ❌ 系统时间可能被人调回去了!
正確做法:測量耗時一定要用 steady_clock。
錯誤 3:忘記 .count() 直接輸出 duration
std::cout << duration_cast<milliseconds>(elapsed); // ❌ 不能直接输出
正確做法:std::cout << elapsed_ms.count() << " ms\n";
錯誤 4:duration_cast 的截斷問題
auto sec = duration_cast<seconds>(1500ms); // 1 秒!不是 1.5 秒
正確做法:如果需要小數,用 duration<double> 或 duration_cast<milliseconds> 保留精度。
std::chrono::duration<double> sec = 1500ms; //std::chrono::duration<double>的默认单位就是“秒”,只不过底层数值类型从整数变成了 double。
std::println("{}", sec.count()); //输出1.5
auto ms = 1500ms;
std::println("{}", ms.count() / 1000.0); //输出1.5
12.使用建議
- 測量耗時用
steady_clock:單調遞增,不受系統時間調整影響。 - 顯示時間用
system_clock:可以轉為日曆時間。 - 用字面量
1s、100ms而不是直接寫數字:可讀性更好。 duration_cast是截斷,不是四捨五入:精度會丟失,注意使用場景。- C++20 增加了日曆和時區支援:
std::chrono::year_month_day等,更強大。 - 超時判斷也用
steady_clock:和測耗時一樣,不受系統時間調整影響。
13.小結
std::chrono提供型別安全的時間處理:duration(時長)、time_point(時間點)、clock(時鐘)。- 用
steady_clock::now()測量耗時,用system_clock::now()獲取系統時間。 - 字面量
1s、100ms、50us讓時間程式碼直觀易讀。 duration_cast做單位轉換,.count()獲取數值。std::this_thread::sleep_for(500ms)做執行緒休眠。
13.1.工程拓展
在 ROS2 中,rclcpp::Duration 和 rclcpp::Time 的用法和 std::chrono 非常相似。學好了 std::chrono,理解 ROS2 的時間處理就很容易了。在 Boost.Asio 中,定時器也大量使用 std::chrono::duration。