# Clocks and ordering

> Why wall clocks can’t order events across machines, and what Lamport and vector clocks do instead.

Concept · Consistency & coordination · https://levelcode.org/concepts/clocks-and-ordering

Ordering events is easy on one machine and surprisingly hard across many, because each machine has its own clock.

## Two kinds of clock

- **Wall-clock time** (a date and time) is synchronised by NTP, typically to within a few milliseconds of other machines — but it **drifts**, and NTP can **step** it forwards or backwards. Leap seconds and misconfigured hosts make it worse.
- **Monotonic time** only moves forward and measures elapsed time on one machine. It's meaningless across machines.

Use monotonic time for durations and timeouts (Go's `time.Since` does). Never order events from different machines by wall-clock timestamp alone: a write on a machine whose clock runs 20 ms fast can appear "newer" than a later write elsewhere, and last-write-wins will keep the wrong one.

## Lamport clocks

A Lamport clock is a counter per node:

```text
on each local event:     counter += 1
on sending a message:    counter += 1; attach counter
on receiving (c_msg):    counter = max(counter, c_msg) + 1
```

If event A could have caused event B, A's timestamp is smaller. Breaking ties by node ID gives every event a total order all nodes agree on. Lamport clocks can't tell you whether two events were **concurrent**.

## Vector clocks

Each node keeps a counter **per node**. Comparing two vectors tells you whether one event happened before the other or whether they were concurrent — which is how some databases detect conflicting writes that need merging. The cost is a vector that grows with the number of writers.

## Hybrid and bounded clocks

- **Hybrid logical clocks** (CockroachDB, MongoDB) combine physical time with a logical counter: close to wall time, but respecting causality.
- **Bounded uncertainty:** Google Spanner's TrueTime uses GPS and atomic clocks to know the maximum clock error, and waits out that uncertainty before committing, which gives globally consistent timestamps.

## In practice

When order matters, let one place assign it: a single leader, a per-partition sequence number (as in chat), or a log. See [unique ID generation](https://levelcode.org/concepts/unique-ids) and [consistency models](https://levelcode.org/concepts/consistency-models).
