Why does std::chrono::system_clock::now() move backwards inside a running C++ program on some Linux systems?

Summary

std::chrono::system_clock can move backwards on Linux because it reflects the system’s real-time clock, which can be adjusted by NTP or other time-correction mechanisms. When the OS steps the clock backward, your process observes that jump. It is not monotonic and never guaranteed to be.
For monotonic timestamps, use std::chrono::steady_clock.

Root Cause

The backward time movement occurs because:

  • system_clock maps directly to the kernel’s real-time clock, which is allowed to jump forward or backward.
  • NTP can “step” the clock when the drift is too large to correct gradually. This step may move time backward.
  • Kernel time adjustments under load (e.g., frequency corrections, clock skew compensation) can cause small backward shifts.
  • Real-time clock (RTC) corrections may propagate into the system clock.

Why This Happens in Real Systems

Real-world Linux systems frequently adjust their clocks:

  • NTP synchronization: When drift exceeds a threshold, NTP performs a backward step instead of a slow correction.
  • Virtualized or heavily loaded environments: CPU scheduling delays and TSC instability can cause non-monotonic readings.
  • Hardware clock inconsistencies: RTC updates or corrections can cause sudden jumps.
  • Clock discipline algorithms: The kernel may apply corrections that temporarily reduce the reported time.

Real-World Impact

Backward time jumps can break:

  • Log ordering, making debugging extremely difficult.
  • Timeout logic, causing timers to fire late or never.
  • ID generation, especially if timestamps are part of uniqueness guarantees.
  • Event sequencing, where ordering depends on timestamp monotonicity.

Example or Code (if necessary and relevant)

Below is an example of switching to a monotonic clock:

#include 
#include 

int main() {
    using clock = std::chrono::steady_clock;
    auto t1 = clock::now();
    // some work
    auto t2 = clock::now();
    if (t2 < t1) {
        std::cout << "steady_clock moved backwards\n";
    }
}

How Senior Engineers Fix It

Experienced engineers avoid system_clock for sequencing or measuring durations:

  • Use steady_clock for monotonic timestamps.
  • Use high_resolution_clock only if it aliases to a monotonic clock (implementation-dependent).
  • Use system_clock only for human-readable wall time, not for ordering or measuring intervals.
  • Design systems to tolerate clock adjustments, especially in distributed environments.

Why Juniors Miss It

Common misconceptions include:

  • Assuming “time always moves forward” inside a process.
  • Believing that NTP only slews time, not realizing it can step backward.
  • Confusing wall-clock time with monotonic time.
  • Not knowing that system_clock is not monotonic by design and is tied to OS-level adjustments.

Senior engineers learn early that monotonicity is a property you must explicitly choose, not something the system guarantees by default.

Leave a Comment