Modern computers have at least two kinds of clocks: a time-of-day clock and a monotonic clock. Although both measure time, it is important to distinguish between them, since they serve different purposes.
Time-of-day clocks
A time-of-day clock does what you intuitively expect of a clock: it returns the current date and time according to a calendar (also known as wall-clock time). For example, clock_gettime(CLOCK_REALTIME) on Linux and System.currentTimeMillis in Java return the number of seconds (or milliseconds) since the epoch, defined as midnight UTC on January 1, 1970, according to the Gregorian calendar, not counting leap seconds. Some systems use other dates as their reference point. (Although the Linux clock is called real-time, it has nothing to do with real-time operating systems, as discussed in “Provididng response time guarantees”.)
Time-of-day clocks are usually synchronized with NTP, which means that a timestamp from one machine (ideally) means the same as a timestamp on another machine. However, time-of-day clocks also have various oddities, as described in the next section. In particular, if the local clock is too far ahead of the NTP server, it may be forcibly reset and appear to jump back to a previous point in time. These jumps, as well as similar jumps caused by leap seconds, make time-of-day clocks unsuitable for measuring elapsed time.
Time-of-day clocks can also experience jumps due to the start and end of Daylight Saving Time (DST), although these can be avoided by always using UTC as the time zone, which does not have DST. Historically, these clocks had quite a coarse-grained resolution (e.g., moving forward in steps of 10 ms on older Windows systems). On recent systems, this is less of a problem.
Monotonic clocks
A monotonic clock is suitable for measuring a duration (time interval), such as a timeout or a service’s response time; clock_gettime(CLOCK_MONOTONIC) or clock_gettime(CLOCK_BOOTTIME) on Linux and System.nanoTime in Java, for example, measure time using a monotonic clock. The name comes from the fact that this type of clock is guaranteed to always move forward (whereas a time-of-day clock may jump back in time).
You can check the value of a monotonic clock at one point in time, do something, and then check the clock again at a later time. The difference between the two values tells you how much time elapsed between the two checks—more like a stopwatch than a wall clock. However, the absolute value of the clock is meaningless; it might be the number of nanoseconds since the computer was booted up, or something similarly arbitrary. In particular, it makes no sense to compare monotonic clock values from two computers, because they don’t mean the same thing.
On a server with multiple CPU sockets, there may be a separate timer per CPU, which is not necessarily synchronized with other CPUs. Operating systems compensate for any discrepancy and try to present a monotonic view of the clock to application threads, even as they are scheduled across multiple CPUs. However, it is wise to take this guarantee of monotonicity with a pinch of salt.
NTP may adjust the frequency at which the monotonic clock moves forward (this is known as slewing the clock) if it detects that the computer’s local quartz is moving faster or slower than the NTP server. By default, NTP allows the clock rate to be sped up or slowed down by up to 0.05%, but it cannot cause the monotonic clock to jump forward or backward. The resolution of monotonic clocks is usually quite good: on most systems they can measure time intervals in microseconds or less.
In a distributed system, using a monotonic clock for measuring elapsed time (e.g., timeouts) is usually fine, because it doesn’t assume any synchronization between different nodes’ clocks and is not sensitive to slight inaccuracies of measurement.