skip to content

What arithmetic and comparison operations does kotlin.time.Duration support, and how does multiplying or dividing durations behave?

level: middleimportance: must knowfreq 50%

answer

  1. duration / duration => Double ratio (gotcha)
  2. duration * / scalar => Duration
  3. Comparable: <, >, ==, ranges all work
  4. Equality is span-based: 1.seconds == 1000.milliseconds
  5. INFINITE saturates; indeterminate forms throw

basics

~20 s

You can add and subtract two durations, multiply or divide a duration by a number, divide one duration by another to get a ratio, negate it, and compare them with < or >. Durations also implement Comparable.

solid answer

~40 s

Duration is a Comparable<Duration> with full operator support. You can add/subtract two durations (5.seconds + 100.milliseconds), negate (-d) or use unaryMinus, and take absoluteValue. Scaling: duration * Int/Double and duration / Int/Double return a Duration. Dividing two durations (a / b) returns a plain Double ratio — useful for 'how many times does b fit in a'. Comparison uses the Comparable contract so <, >, ==, and ranges work. Helpful predicates: isPositive(), isNegative(), isInfinite(), isFinite(). Edge cases: Duration.INFINITE absorbs finite arithmetic (INFINITE + 5.seconds == INFINITE), multiplying INFINITE by 0 or dividing INFINITE / INFINITE yields NaN-like results that throw, and overflow saturates toward INFINITE rather than wrapping. Equality compares the actual time span, so 1000.milliseconds == 1.seconds is true.

code

kotlin · 12 lines
kotlin
import kotlin.time.Duration.Companion.seconds
import kotlin.time.Duration.Companion.milliseconds

fun main() {
    val a = 10.seconds
    val b = 4.seconds
    println(a / b)                 // 2.5   (Double ratio)
    println(a * 2)                 // 20s   (Duration)
    println(a > b)                 // true
    println(1.seconds == 1000.milliseconds) // true
    println((-a).absoluteValue)    // 10s
}

go deeper

for a junior

Knows you can add, subtract, and compare durations with normal operators.

for a middle

Distinguishes scaling (×/÷ scalar -> Duration) from ratio (÷ duration -> Double) and knows equality is span-based.

for a senior

Explains saturation toward INFINITE on overflow, indeterminate forms throwing, and the predicate helpers.

for a principal

Reasons about Duration arithmetic as a small algebra (typed dimensional analysis) and its overflow-safety guarantees vs raw Long math in concurrency/timeout code.

## Operators on Duration `Duration` implements `Comparable<Duration>` and overloads a rich operator set. Key distinction: **adding/subtracting** combine two durations, **scaling** combines a duration with a scalar, and **dividing two durations** yields a scalar. ### Additive operators ```kotlin val total = 5.seconds + 100.milliseconds // 5.1s val diff = 1.minutes - 10.seconds // 50s val neg = -diff // unaryMinus -> -50s val abs = neg.absoluteValue // 50s ``` ### Scaling (duration ⊗ scalar -> Duration) ```kotlin val doubled = 5.seconds * 2 // 10s (operator times) val third = 9.seconds / 3 // 3s (operator div by Int/Double) ``` Both `Int` and `Double` scalars are supported on `times` and `div`. ### Ratio (duration / duration -> Double) ```kotlin val ratio: Double = 10.seconds / 4.seconds // 2.5 (how many 4s fit in 10s) ``` This overload returns a **Double**, not a Duration — a common gotcha. Use it for proportions/percentages. ### Comparison & equality Because `Duration` is `Comparable`, `<`, `>`, `<=`, `>=`, `==`, `coerceIn`, `min`/`max`, and ranges all work. **Equality is value-based on the actual span**, so unit doesn't matter: ```kotlin println(1.seconds == 1000.milliseconds) // true println(60.seconds > 1.minutes) // false (equal) ``` ### Predicates `isPositive()`, `isNegative()`, `isInfinite()`, `isFinite()` cover the sign/finiteness checks instead of comparing to `Duration.ZERO` by hand (though comparing to ZERO also works). ### Infinity & saturation - `Duration.INFINITE` behaves like a positive infinity: `INFINITE + 5.seconds == INFINITE`. - Arithmetic **saturates** toward `INFINITE`/`-INFINITE` on overflow rather than silently wrapping a Long. - Indeterminate forms (e.g. `INFINITE * 0`, `INFINITE / INFINITE`) throw `IllegalArgumentException` because the result is undefined. ### Why it matters Value-based equality and the typed ratio operator make duration math safe and expressive — you never accidentally compare millis-as-Long to seconds-as-Long.

  • What does 10.seconds / 4.seconds return, and why is its type surprising?
    It returns a Double, 2.5 — the ratio of the two spans. People expect a Duration, but dividing a span by a span is dimensionless.
  • What happens on arithmetic overflow of a Duration?
    It saturates to Duration.INFINITE (or -INFINITE) rather than wrapping the underlying Long, so you get a clearly-infinite value instead of a corrupted one.

saying these in an interview costs you the question

  • Thinking duration / duration returns a Duration instead of a Double
  • Assuming Duration equality is unit-sensitive (it is value/span-based)
  • Claiming overflow wraps like a Long rather than saturating to INFINITE
  • Forgetting Duration is Comparable, so < / > / ranges work directly

context