第 18.18 節

std::chrono

0瀏覽次數0訪問次數--跳出率--平均停留

What problem does this section solve?

In C, handling time is done through functions like time(), clock(), sleep(), and gettimeofday(), which use different units and types (seconds, milliseconds, microseconds...). This can easily lead to confusion and lacks sufficient precision.

std::chrono is a type-safe time library introduced in C++11. It clearly separates the concepts of "time points", "durations", and "clocks", with units automatically managed within the type system, eliminating the need for manual conversion.

What is this feature?

std::chrono provides three core concepts:

  • Duration duration: A length of time, such as 5 seconds or 10 milliseconds.
  • Time Point time_point: A specific moment, such as 2026-06-02 12:00:00.
  • Clock clock: A tool for obtaining the current time, such as system_clock and steady_clock.

C++ standard version

C++11 (foundational), C++20 introduced calendar and timezone support, among other features.

Required header files

#include <chrono>
#include <thread>  // for std::this_thread::sleep_for

Basic Syntax

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);

Common Clock Comparison

clockFeaturesUsage
system_clockSystem time, convertible to calendar time.Display time, timestamp
steady_clockstrictly increasing, never decreasesTime measurement (most commonly used)
high_resolution_clockHighest Precision ClockRequires the highest precision timing

Example code

Example 1: Measuring the execution time of a segment of code

#include <iostream>
#include <chrono>
#include <thread>  // for sleep

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

    // 记录开始时间
    auto start = steady_clock::now();

    // 模拟耗时操作
    std::this_thread::sleep_for(500ms);

    // 记录结束时间
    auto end = steady_clock::now();

    // 计算耗时
    auto elapsed = end - start;
    auto elapsed_ms = duration_cast<milliseconds>(elapsed);
    auto elapsed_us = duration_cast<microseconds>(elapsed);

    std::cout << "Elapsed: " << elapsed_ms.count() << " ms\n";
    std::cout << "Elapsed: " << elapsed_us.count() << " us\n";

    return 0;
}

Running Result (approximately):

Elapsed: 500 ms
Elapsed: 500000 us

Example 2: Using and Converting Different Time Units Based on Example 1

#include <iostream>
#include <chrono>

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

    // 不同单位
    auto s = 1s;         // 1 秒
    auto ms = 100ms;     // 100 毫秒
    auto us = 500us;     // 500 微秒

    // 时长可以相加
    auto total = s + ms + us;
    std::cout << "total in us: " << duration_cast<microseconds>(total).count() << " us\n";

    // 秒到毫秒的转换
    auto two_seconds = 2s;
    auto as_ms = duration_cast<milliseconds>(two_seconds);
    std::cout << "2s = " << as_ms.count() << " ms\n";

    // 毫秒到秒的转换(会截断)
    auto ms_to_sec = duration_cast<seconds>(1500ms);
    std::cout << "1500ms = " << ms_to_sec.count() << " s\n";  // 1 秒

    return 0;
}

Results

total in us: 1100500 us
2s = 2000 ms
1500ms = 1 s

Example 3: Building on Example 2, implement a simple timer

#include <iostream>
#include <chrono>
#include <functional>

// 简单的计时器:测量函数运行时间
double measure(std::function<void()> func)
{
    using namespace std::chrono;

    auto start = steady_clock::now();
    func();
    auto end = steady_clock::now();

    return duration_cast<microseconds>(end - start).count() / 1000.0;  // 返回毫秒
}

void slow_operation()
{
    int sum = 0;
    for (int i = 0; i < 10000000; ++i)
    {
        sum += i;
    }
    std::cout << "sum = " << sum << "\n";
}

void quick_operation()
{
    int sum = 0;
    for (int i = 0; i < 1000; ++i)
    {
        sum += i;
    }
    std::cout << "sum = " << sum << "\n";
}

int main()
{
    std::cout << "slow_op took " << measure(slow_operation) << " ms\n";
    std::cout << "quick_op took " << measure(quick_operation) << " ms\n";

    return 0;
}

Results may vary depending on the machine.

sum = 887459712
slow_op took 12.5 ms
sum = 499500
quick_op took 0.001 ms

Example 4: Get and format system time based on Example 3

#include <iostream>
#include <chrono>
#include <ctime>
#include <iomanip>

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

    // 获取当前系统时间
    auto now = system_clock::now();

    // 获取自 epoch(1970-01-01)以来的秒数
    auto epoch_seconds = duration_cast<seconds>(now.time_since_epoch());
    std::cout << "Seconds since epoch: " << epoch_seconds.count() << "\n";

    // 转换为 C 风格的 time_t 打印
    std::time_t now_c = system_clock::to_time_t(now);
    std::cout << "Current time: " << std::ctime(&now_c);

    // 计算未来时间点
    auto future = now + 24h;  // C++20 的 24h 字面量
    // 如果没有 C++20,可以用: auto future = now + hours(24);
    std::time_t future_c = system_clock::to_time_t(future);
    std::cout << "24 hours later: " << std::ctime(&future_c);

    return 0;
}

Running Results (date varies by run time):

Seconds since epoch: 1748870400
Current time: Mon Jun  2 12:00:00 2026
24 hours later: Tue Jun  3 12:00:00 2026

runtime results

See the "running results" for each example above.

Key syntax explanation in the example

|Here is the translation of the provided Simplified Chinese Markdown fragment into natural American English, following all specified rules.


ExampleDiscusses whatNewly emerged syntaxWhy write it this wayPrecautions
Example 1Measuring code execution timesteady_clock::now(), duration_cast, literal 500mssteady_clock monotonically increases, making it suitable for timing.Literals require using namespace std::chrono
Example 2Time unit conversion1s100msduration_castTypes automatically manage units, requiring explicit casting during conversion.duration_cast This is truncation, not rounding.
Example 3General-purpose timermeasure(function<void()>)Package it into a reusable utility function.steady_clock is the best choice
Example 4System time and formattingsystem_clock::now()to_time_t()24hsystem_clock can be converted to calendar time.system_clock may be affected by system time adjustments and should not be used for timing purposes.

Do not mix timing and display functions.

RequirementRecommended clockReason
Measure function execution time.steady_clockMonotonically increasing, unaffected by system time adjustments
Timeout checksteady_clockWill not cause timeout errors due to system time jumps.
print the current date and timesystem_clockCan be converted to calendar time.
Generate log timestampsystem_clockhuman-readable

A common mistake is using system_clock for timeout checks. If the system time is adjusted backward by NTP or manually, the program might wait indefinitely without timing out. For measuring duration and handling timeouts, always prioritize using steady_clock.

Example 5: Using steady_clock for timeout judgment

#include <chrono>
#include <iostream>
#include <thread>

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    using namespace std::chrono;

    auto deadline = steady_clock::now() + 300ms;

    while (steady_clock::now() < deadline)
    {
        std::cout << "waiting...\n";
        std::this_thread::sleep_for(100ms);
    }

    std::cout << "timeout\n";

    // 返回 0 表示程序正常结束。
    return 0;
}

Possible results:

waiting...
waiting...
waiting...
timeout

The key here isn't the loop itself, but rather using steady_clock as the timeout benchmark. This pattern is very common in timers, serial read timeouts, and network wait timeouts.

Common Errors

Error 1: Forgetting using namespace std::chrono causes literals not recognized

auto t = 500ms;  // ❌ 编译错误!

Correct approach: add using namespace std::chrono; or write std::chrono::milliseconds(500).

Error 2: Measuring elapsed time using system_clock

auto start = system_clock::now();  // ❌ 系统时间可能被人调回去了!

The correct approach: always use steady_clock for timing measurements.

Error 3: Forgot to use .count() and directly output duration

std::cout << duration_cast<milliseconds>(elapsed);  // ❌ 不能直接输出

Correct approach: std::cout << elapsed_ms.count() << " ms\n";

Error 4: truncation issue of duration_cast

auto sec = duration_cast<seconds>(1500ms);  // 1 秒!不是 1.5 秒

Correct approach: If decimals are needed, use duration<double> or duration_cast<milliseconds> to preserve precision.

使用建议

  • 明确目标:在开始前确定您的具体需求,以便选择最合适的工具或教程。
  • 充分利用资源:参考官方文档、教程和博客,这些资料能帮助您快速上手并解决问题。
  • 实践应用:通过动手操作项目或编写代码来巩固学习成果,提升实际操作能力。
  • 问题解决:遇到困难时,查阅参考资料或寻求社区支持,逐步培养独立解决问题的能力。
  • 分享经验:完成项目后,可以撰写文章或博客分享心得,帮助其他学习者。

如果需要针对特定领域(如单片机、机器人或环境搭建)的进一步建议,请提供更多信息,我将为您细化内容。

  1. Measuring Time with steady_clock:Monotonically increasing and unaffected by system time adjustments.
  2. Displaying time using system_clock can be converted to calendar time.
  3. Use literals like 1s and 100ms instead of writing numbers directly: It's more readable.
  4. duration_cast is truncation, not rounded off: precision will be lost—consider your usage scenarios.
  5. C++20 adds calendar and timezone support: std::chrono::year_month_day, and more, making it more powerful.
  6. Timeout judgment also uses steady_clock: Similar to measuring time consumption, it remains unaffected by system time adjustments.

Summary

  • std::chrono provides type-safe time handling: duration, time_point, and clock.
  • Use steady_clock::now() to measure elapsed time and system_clock::now() to obtain system time.
  • The literals 1s, 100ms, 50us make the time code intuitive and readable.
  • duration_cast performs unit conversion, and .count() gets the value.
  • std::this_thread::sleep_for(500ms) makes a thread sleep.

Engineering expansion

In ROS2, the usage of rclcpp::Duration and rclcpp::Time is very similar to that of std::chrono. Once you have learned std::chrono, understanding ROS2's time handling becomes quite easy. In Boost.Asio, timers also make extensive use of std::chrono::duration.

音乐页