Free — no signup required

Monotonic Clocks vs. Wall Clocks

2 min read

Two Kinds of Time in Every OS

Before diving into logical clocks, it is worth understanding a distinction that trips up many engineers: most operating systems expose two fundamentally different types of clocks.

Wall Clock (Real-Time Clock):
This is the clock that tells you "it is currently 2:34 PM on Tuesday." It is synchronized with NTP and represents calendar time. The problem: it can jump forward (NTP correction), jump backward (NTP correction of a fast clock), or repeat (leap second). It is not safe to use for measuring elapsed time.

Monotonic Clock:
This clock only ever moves forward. It is not synchronized with NTP and has no relationship to calendar time — it typically counts nanoseconds since the system booted. It is safe for measuring elapsed time (e.g., "how long did this function take?") because it will never go backward.

In most languages, the distinction is explicit: Python exposes a separate time.monotonic() alongside time.time(), and elapsed-time measurements should always use the former. Go takes a different approach — time.Now() embeds both a wall-clock and a monotonic reading in the same time.Time value, and time.Since() automatically uses the monotonic component, making the safe choice the default rather than something you have to opt into explicitly.

Why This Matters in Distributed Systems

A common bug: a developer measures a timeout using time.time() (wall clock). An NTP correction fires mid-measurement and moves the clock backward by 100ms. The timeout now appears to have taken 100ms less than it actually did, and the timeout never fires. The system hangs.

Always use monotonic clocks for measuring elapsed time and timeouts. Use wall clocks only when you need to communicate a point in calendar time to a human or another system.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free