A duration is a count and a unit¶
Level: 201 · working knowledge
One line: std::chrono::milliseconds{1500} is the number 1500 plus a unit the compiler tracks for you — conversions that could lose something have to be asked for by name, and forgetting that a duration is not a number is how the talk once measured a clock at 0ns.
#include <chrono>
using namespace std::chrono_literals;
auto timeout = 1500ms; // 1500, in milliseconds
auto whole = std::chrono::duration_cast<std::chrono::seconds>(timeout); // 1s — you asked to lose 500ms
Verified output of a_duration_is_a_count_and_a_unit.cpp — regenerated by tools/run_examples.py and held to the same answer key on libstdc++ and libc++ in CI, never hand-typed.
ms.count() = 1500
ms = 1500ms
1s + 250ms = 1250ms
1s - 2s = -1s
2s as ms = 2000ms
1500ms as double = 1.5s
ms -> s implicitly: false
1500ms 2500ms -1500ms
duration_cast 1s 2s -1s
floor 1s 2s -2s
ceil 2s 3s -1s
round 2s 2s -2s
numeric_limits<nanoseconds>::is_specialized = false
numeric_limits<nanoseconds>::max() = 0ns
nanoseconds::max() = 9223372036854775807ns
...in whole years = 292
A count and a unit¶
std::chrono::milliseconds is duration< a signed integer of at least 45 bits , std::milli> — a rep that holds the count and a period that says what one count is worth, the same pair every clock defines (What a clock is). Arithmetic between two units happens in the finer one, so 1s + 250ms is 1250ms; and the count is signed, so 1s - 2s is -1s. .count() hands back the bare number, which is where the compiler stops being able to help.
Converting¶
A conversion that cannot lose anything happens by itself: 2s into milliseconds, or an integer count into a floating-point one, which keeps the fraction — 1500ms becomes 1.5s. A conversion that could lose something does not compile until you say how to lose it — is_convertible_v<milliseconds, seconds> is false — and the four ways of saying it are the rows of the table in the output:
duration_casttruncates toward zero, so1500msis1sand-1500msis-1s.floorrounds down, so-1500msis-2s.ceilrounds up.roundgoes to the nearest, and a tie goes to the even number:1500msis2s, and so is2500ms.
duration_cast is the one most code reaches for, and for negative durations it is usually not the one it means.
The talk's Min = 0ns¶
The talk's How long does it take? slide times back-to-back calls to now() and keeps the smallest gap. Its first version starts the running minimum like this:
and prints Min = 0ns. The next slide swaps in 1'000'000'000ns and gets "20-30ns!". The slides leave the reason to the talk; the output above shows it. std::numeric_limits is specialised for arithmetic types, not for duration, and for the unspecialised template the standard says "all member functions return a value-initialized object" (numeric.limits.general ↗) — a duration of zero. std::min(0ns, gap) is 0ns for every non-negative gap, so the minimum never moves. The maximum the slide wanted is a member of duration itself:
If you are coming from another language¶
- Rust. One type,
std::time::Duration, for every unit — seconds plus nanoseconds, unsigned — so1s - 2shas nowhere to go:checked_subreturnsNone, and plain-panics. C++ puts the unit in the type and lets the count go negative: A Duration cannot be negative ↗. - Python.
datetime.timedeltais the typed duration: one type for every unit, negative allowed, and normalised rather than truncated —timedelta(seconds=1) - timedelta(seconds=2)prints-1 day, 23:59:59. The clock functions skip it and returnfloatseconds, orintnanoseconds from the_nsvariants such astime.perf_counter_ns(). - ABAP. (Not machine-checked.) There is no duration type: a length of time is an integer or a packed number with its unit in the variable's name, such as
lv_runtime_us— the conventiondurationexists to replace.
See also¶
- What a clock is —
repandperiod, from the clock's side - A time point knows its clock — what subtracting two time points hands you
- The cost of asking the time — the measurement the
0nsslide was trying to make (outline) - cppreference: duration ↗