# Measuring Execution Time Safely with Monotonic Clocks

**Quick Answer:** Measuring execution time using wall-clock functions like `Date.now()` or `System.currentTimeMillis()` can yield negative durations if your server synchronizes its clock mid-operation. To measure elapsed code performance accurately, always use monotonic clock APIs like `performance.now()` in JavaScript or `System.nanoTime()` in Java, which strictly count forward from an arbitrary baseline.

Imagine profiling an asynchronous task in your API that typically takes 200 milliseconds to complete, only for your logging framework to report a duration of `-800ms`. While a negative duration sounds like a physics violation, I often see this exact issue trip up engineers who rely on wall-clock time for benchmarking.

When I time execution intervals, relying on time-of-day calls exposes metrics to background operating system updates. In my experience, understanding how system time works—and why monotonic clocks exist—will prevent your benchmarks from reporting impossible numbers.

## Why does Date.now() produce negative durations?

`Date.now()` in JavaScript and `System.currentTimeMillis()` in Java read the system's wall-clock time, which continuously synchronizes with external network servers. If Network Time Protocol (NTP) adjusts your system clock backward mid-execution, subtracting your start timestamp from your end timestamp produces a negative duration.

Wall-clock APIs return the server's current opinion of the global time of day. This time isn't static or linear; background processes continuously adjust it to prevent clock drift across distributed infrastructure. A manual system administrator edit or an automatic NTP sync can shift your server's clock backward by a full second at any given moment.

Let's walk through a hypothetical scenario. Say you log a start time of `1,000ms` using a wall-clock API right before executing a task that takes `200ms`. If an NTP server sync fires mid-task and sets your machine's clock back by `1,000ms`, your ending timestamp becomes `200ms`. Subtracting start from finish yields a result of `-800ms` for a task that ran normally.

```javascript
// Unsafe: Wall-clock time can shift mid-execution
const start = Date.now();
await executeTask();
const duration = Date.now() - start; // Can be negative!
```

## What is a monotonic clock and how does it work?

A monotonic clock is an internal CPU timer that steadily counts forward from an arbitrary starting point, such as system boot time, without ever jumping backward or skipping. Because it ignores global time-of-day adjustments, it provides a safe baseline for measuring interval durations between two events.

Unlike wall-clock timers, the actual number returned by a monotonic clock has no real-world calendar meaning. You cannot convert a raw monotonic reading into a human-readable date or time string like "10:15 AM." Its sole purpose is delta computation: taking two readings and subtracting the first from the second to yield an exact elapsed time.

Because monotonic sources are bound to hardware ticks rather than atomic clock synchronization, they guarantee strict forward progression. They remain completely unaffected by leap seconds, daylight saving shifts, or NTP corrections.

| Feature | Wall-Clock Timer | Monotonic Clock |
| :--- | :--- | :--- |
| **JavaScript API** | `Date.now()` | `performance.now()` |
| **Java API** | `System.currentTimeMillis()` | `System.nanoTime()` |
| **Primary Purpose** | Displaying calendar time of day | Measuring elapsed code execution |
| **NTP Adjustment Risk** | Subject to clock skew and backward jumps | Completely immune to time adjustments |
| **Return Value** | Milliseconds since Unix Epoch | Ticks since an arbitrary starting baseline |

## How do you measure execution time correctly in JavaScript and Java?

In JavaScript, use `performance.now()` instead of `Date.now()` to get sub-millisecond, monotonic timing data. In Java, replace `System.currentTimeMillis()` with `System.nanoTime()` to measure elapsed execution durations safely.

When I write performance measurements, I rely on these APIs to guarantee a continuous forward-moving timeline. Here is how you write safe interval calculations in both environments.

In JavaScript:

```javascript
const start = performance.now();
doWork();
const duration = performance.now() - start; // Always positive and precise
```

In Java:

```java
long start = System.nanoTime();
doWork();
long durationNanos = System.nanoTime() - start; // Immune to NTP clock skew
```

By ensuring your timing logic relies on monotonic clocks, your metrics, traces, and performance profiling will remain accurate regardless of what your underlying operating system does with its wall clock.

## Frequently Asked Questions

### Can I convert a monotonic timestamp into a human-readable date?
No. Monotonic clock values are arbitrary numbers based on points like system startup. To log human-readable timestamps, use wall-clock functions like `Date.now()`, but save monotonic APIs strictly for elapsed time calculations.

### Is performance.now() supported in Node.js?
Yes. Modern Node.js environments support `performance.now()` globally, matching the browser Web API implementation for high-resolution timing.

### Do monotonic clocks handle operating system sleep mode?
Behavior varies across operating systems and runtimes. While a monotonic clock will never move backward when a system wakes from sleep, the time spent sleeping may or may not be counted in the total elapsed interval.
