How do you measure elapsed time, and how do you show a duration?

2.2.9 · L3 · Interview

Predict first

What does this print?

print(Duration.seconds(90).formatted(.time(pattern: .minuteSecond)))
  • 1:30
  • 01:30
  • 90

Predict first

What does this print?

print(Duration.milliseconds(1500))
  • 1.5 seconds
  • 1500 ms
  • 1.5

Mental model. Wall-clock time is the clock on the wall that someone can reset. A monotonic clock is a stopwatch nobody can touch.

Date is wall-clock time and can jump (clock changes, NTP), so subtracting two Date()s is not a reliable stopwatch. Use a monotonic clock: ContinuousClock keeps counting while the device sleeps, SuspendingClock pauses when it sleeps. clock.measure { } returns a Duration. Separately, ProcessInfo.systemUptime and mach_continuous_time are the lower-level options.

To show time to a person, Duration and Date.ComponentsFormatStyle format spans (“1:30”, “2 hr, 5 min”), and RelativeDateTimeFormatter produces “2 hours ago”. TimeInterval is just a Double of seconds, and DateInterval is a start plus a length.

The minuteSecond pattern does not pad the minutes. Pass padMinuteToLength: 2 if you want 01:30.

Duration prints in seconds with units, which makes log lines self-explanatory.

Common traps

  • Timing code with Date(). A clock adjustment mid-measurement gives negative or huge numbers.
  • Choosing Suspending for a timeout that must expire in real time. It stops while asleep.

They might follow up with

  • How would you build a “time ago” label? RelativeDateTimeFormatter with a fixed unitsStyle, refreshed on a timer.
  • Where does Task.sleep fit? It accepts a clock, and Task.sleep(for:) uses ContinuousClock by default.

Related questions

  • 2.2.1 What is a Date in Foundation, and what does it not contain?

← What goes wrong with DateFormatter, and how do you parse a fixed…