Skip to content

๐Ÿ•’ C++ <chrono> Timer Library Overview (Corrected)

This document reflects accurate comparison rules for chrono durations.

The <chrono> library is built around three core concepts:

  • Durations --- represent a span of time
  • Clocks --- provide current time
  • Time points --- specific instants from clocks

โฑ๏ธ Durations

A duration represents:

number ร— period (in seconds)

Template definition:

template<class Rep, class Period>
class duration;
  • Rep = numeric storage type (int, double, etc.)
  • Period = tick size (std::ratio, std::milli, etc.)

Example (full types):

std::chrono::duration<long long, std::ratio<1,1>> a{5};      // 5s
std::chrono::duration<long long, std::ratio<1,1000>> b{500}; // 500ms

๐Ÿ” Conversions

Coarser โ†’ Finer (automatic)

auto s = 2s;
auto ms = std::chrono::milliseconds(s); // OK

Finer โ†’ Coarser (requires cast)

auto ms = 1500ms;
auto s = std::chrono::duration_cast<std::chrono::seconds>(ms);

โš–๏ธ Comparing Durations

โœ… This is VALID and SAFE

auto elapsed = clock::now() - startTime;
static constexpr std::chrono::milliseconds timeout{1500};
if (elapsed >= timeout)

C++ guarantees this works because std::chrono::duration comparisons:

  • Convert both sides to a common_type
  • Perform a safe comparison

So mixed types like:

steady_clock::duration  vs  milliseconds

are handled correctly by the standard.


โš ๏ธ When to Normalize (Best Practice)

You may want to normalize:

auto wait = std::chrono::duration_cast<clock::duration>(timeout);

if (elapsed >= wait)

Why?

  • Ensures both values use same tick representation
  • Avoids mixing float + integer durations
  • Makes behavior explicit and reviewable
  • Controls rounding in one place

๐Ÿง  Rule To Remember

Comparing durations is safe.\ Normalize only when you want explicit control or consistency.


๐Ÿงญ Clocks

Clock Purpose


steady_clock Monotonic, best for timers system_clock Wall clock time high_resolution_clock Highest resolution (alias)

Use steady_clock for timers:

auto now = std::chrono::steady_clock::now();

๐Ÿ“ Time Points

auto start = std::chrono::steady_clock::now();

Subtracting:

auto elapsed = std::chrono::steady_clock::now() - start;

๐Ÿงฎ Timer Pattern (Clean Version)

using clock = std::chrono::steady_clock;

clock::time_point start = clock::now();

template<class Rep, class Period>
bool check(std::chrono::duration<Rep, Period> timeout)
{
    auto elapsed = clock::now() - start;

    if (elapsed >= timeout) // perfectly valid
    {
        start = clock::now();
        return true;
    }
    return false;
}

๐Ÿงช When to Cast (Example)

auto timeout = std::chrono::duration<double, std::milli>{1.5};

auto wait = std::chrono::duration_cast<clock::duration>(timeout);

if (elapsed >= wait)
{
    ...
}

๐Ÿšซ Clock Mixing Rule

steady_clock::now() - system_clock::now(); // โŒ illegal

Clocks must match.


๐Ÿง  Practical Embedded Rule (Your Use Case)

  • Use steady_clock for timing
  • Direct comparisons are fine for integer durations
  • Normalize when using floats or external inputs
  • Avoid unnecessary casting noise

โœ… Final Summary

โœ” Duration = number ร— period\ โœ” Subtract time_points โ†’ duration\ โœ” Chrono comparisons are safe across types\ โœ” duration_cast is for control, not correctness\ โœ” Use steady_clock for timers\ โœ” Never mix clocks


This version reflects actual chrono guarantees + practical engineering guidance.