skip to content

TimeSource & TimeMark

A TimeMark from a monotonic TimeSource lets you ask elapsedNow() later and do arithmetic on deadlines. TestTimeSource is the reason to care in interviews: it makes time-dependent logic testable without sleeping.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

How do you measure how long a block of code takes using TimeSource.Monotonic, and why use it instead of System.currentTimeMillis()?

level: juniorimportance: must knowfreq 55%

answer

  1. markNow() -> TimeMark, elapsedNow() -> Duration
  2. Monotonic = steady, never goes backward
  3. Wall clock (currentTimeMillis) can jump
  4. ValueTimeMark is an inline value class (no alloc)
  5. Get a typed Duration, not a raw Long

basics

~10 s

Call TimeSource.Monotonic.markNow() before the code to get a TimeMark, then call mark.elapsedNow() after to get a Duration. It uses a steady clock that never jumps backward, unlike wall-clock millis.

solid answer

~30 s

TimeSource.Monotonic.markNow() returns a TimeMark (a ValueTimeMark) recording the current reading of the monotonic clock. After running your code, call mark.elapsedNow() to get a kotlin.time.Duration of how much time passed. The monotonic source is designed for measuring elapsed time: it is steady and not affected by NTP adjustments, daylight-saving, or the user changing the system clock, so it never goes backward. System.currentTimeMillis() is wall-clock time and can jump if the clock is adjusted, producing negative or wildly wrong durations. You get a typed Duration (with .inWholeMilliseconds, .inWholeNanoseconds, etc.) instead of raw longs you must subtract and unit-track yourself.

code

kotlin · 10 lines
kotlin
import kotlin.time.TimeSource

fun main() {
    val source = TimeSource.Monotonic
    val mark = source.markNow()
    Thread.sleep(50)
    val elapsed = mark.elapsedNow()
    println(elapsed)                    // e.g. 50.1ms
    println(elapsed.inWholeMilliseconds) // 50
}

go deeper

for a junior

Knows the markNow() -> elapsedNow() pair and that it returns a Duration.

for a middle

Explains why monotonic beats wall-clock for elapsed measurement and that it never goes backward.

for a senior

Mentions ValueTimeMark being an inline value class (zero-alloc) and that Monotonic maps to nanoTime on the JVM.

for a principal

Frames the wall-clock-vs-monotonic split as a domain decision and can reason about clock-source guarantees across platforms.

## The problem Measuring how long something takes seems trivial: read the clock before, read it after, subtract. But `System.currentTimeMillis()` reads the *wall clock* — the human calendar time. That clock can be moved: NTP can step it, daylight-saving changes it, a user can set it. If it moves backward mid-measurement you get a negative or absurd elapsed value. ## TimeSource and the monotonic clock A **`TimeSource`** is Kotlin's abstraction for "something I can read the current time-point from." The built-in one for measuring durations is **`TimeSource.Monotonic`** (a `TimeSource.WithComparableMarks`). It wraps a *monotonic* clock (`System.nanoTime()` on the JVM) — a clock that only moves forward at a steady rate and has no defined relationship to calendar time. It is the right tool for *elapsed* measurement, the wrong tool for "what time is it." ## TimeMark **`markNow()`** captures the current reading and returns a **`TimeMark`**. On `Monotonic` this is the inline value class `ValueTimeMark`, so capturing a mark allocates nothing. A `TimeMark` is a *point*, not a duration. To get the time since the mark, call **`elapsedNow()`**, which returns a **`kotlin.time.Duration`**: ```kotlin import kotlin.time.TimeSource val mark = TimeSource.Monotonic.markNow() doWork() val elapsed = mark.elapsedNow() // Duration println("took $elapsed") // e.g. "took 12.3ms" println(elapsed.inWholeMilliseconds) ``` ## Why Duration, not Long `Duration` is a typed, unit-safe value. You read it with `.inWholeMilliseconds`, `.inWholeNanoseconds`, `.inWholeSeconds`, or destructure with `toComponents`. No more "is this millis or nanos?" guessing that plagues raw-`Long` math. ## Rule of thumb - Measuring elapsed time / timeouts / benchmarks -> `TimeSource.Monotonic`. - Showing or storing a calendar time -> wall clock (`Clock`/`Instant`), not `Monotonic`.

  • Can you turn a TimeMark into a calendar timestamp like '2026-06-23 10:00'?
    No. A monotonic TimeMark has no relationship to wall-clock/calendar time; it is only meaningful for measuring durations between marks. Use Clock/Instant for calendar time.
  • What backs TimeSource.Monotonic on the JVM?
    System.nanoTime(), which is a monotonic high-resolution timer with no defined epoch.

A stopwatch (monotonic) vs the clock on the wall (wall-clock): the stopwatch only counts forward from when you pressed start, the wall clock can be reset to any time.

saying these in an interview costs you the question

  • Using System.currentTimeMillis() for benchmarking elapsed time
  • Thinking markNow() returns a Duration rather than a TimeMark
  • Believing a Monotonic mark can be formatted as a date
  • Subtracting raw nanoTime longs by hand instead of using Duration

context

open as a page

Explain mark + Duration arithmetic and comparing two TimeMarks. What does (markB - markA) give, and what does hasPassedNow() mean?

level: middleimportance: should knowfreq 40%

basics

~20 s

You can add or subtract a Duration to a mark to get a shifted mark, subtract two marks to get the Duration between them, and compare marks. hasPassedNow() returns true once the current time is at or past that mark.

open as a page

You need to time a block and also keep the result. Compare doing it manually with markNow()/elapsedNow() versus measureTime/measureTimedValue, and when does the manual TimeMark approach win?

level: middleimportance: should knowfreq 25%

basics

~20 s

For timing one self-contained block, measureTime { } (returns a Duration) or measureTimedValue { } (returns both the value and Duration) is cleanest. Use manual markNow()/elapsedNow() when the start and end are in different places, like a deadline or multi-stage timing.

open as a page

How do you test time-dependent code deterministically with TestTimeSource? Show how marks behave as you advance virtual time.

level: seniorimportance: should knowfreq 35%

basics

~20 s

TestTimeSource is a fake clock you control. It does not advance on its own; you call plusAssignDuration (the += operator) to move virtual time forward. Marks taken from it then report exactly the elapsed time you advanced, so tests are deterministic.

open as a page

What is ValueTimeMark, why is it a value class, and what subtle pitfalls exist with monotonic marks (wraparound, no calendar meaning, cross-platform reading)?

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

ValueTimeMark is the inline value-class TimeMark returned by Monotonic, so creating marks allocates nothing. Marks have no calendar meaning, are only comparable within one source, and rely on the platform's monotonic timer, which differs per platform.

open as a page