82 / 163 · C++11 · 12 min
chrono units: do not turn 1500 milliseconds into 1 millisecond
Time types bind a number to a unit, but count() returns only a bare count. By converting a millisecond budget through a seconds-level interface, observe truncation toward zero, precision loss, and explicit unit boundaries; do not rely on a real clock or sleep, so the results are repeatable.
In this lesson
The C++ Standard Library: A Tutorial and Reference
The complete body text of the English 2nd edition chapters 1–19 (pp. 1–1030) has been read paragraph by paragraph, plus the bibliography and supplementary chapters S.1–S.3 (pp. 1103–1161); main text L635–44987 and supplementary body L48029–50769 have been read. Subsequently, the 51 PDF pages that contain figure captions and 6 probability-formula/context pages were checked directly, covering all located figures and the two-dimensional formulas in §17.1.5. “full” means the body text and these substantial figures have been read; it does not mean every PDF page was collated. The index was only sampled for navigation, not read entry by entry.
Edition, actual reading range, and original sources →The unit is part of the type
milliseconds{1500} and seconds{1500} have the same count but meanings that differ by a thousand. duration<Rep, Period> records this meaning with a representation type and a compile-time ratio; when adding or subtracting different units, the library chooses a common representation instead of making the caller multiply by a thousand by hand.
Danger usually occurs after calling count(). Putting a millisecond count directly into a seconds type reinterprets the unit; it is not a conversion. Prefer interfaces that accept duration; only when you truly must talk to a system API that takes an integer should you convert at the boundary and label the unit.
Explicit conversion does not mean there is no information loss
The example converts 1500 milliseconds to integer seconds, getting 1 second with a remainder of 500 milliseconds; negative 1500 milliseconds converts to integer seconds as -1, not -2. Integer duration_cast truncates toward zero as integer arithmetic and must not be treated as mathematical floor.
We subtract the conversion result from the original value to inspect the discarded part explicitly. That is more meaningful than only asserting that the conversion did not crash. Compile-time ratio can catch some ratio errors, but it does not guarantee that every runtime count will not overflow; real input still needs a representable range limit.
Separate timeout budgets from calendar dates
A timeout asks how long something lasts, not what the wall clock shows. The book’s distinction among duration, time_point, and clock remains a useful modeling approach today; measuring intervals usually chooses the monotonic steady_clock rather than depending on system time that may be adjusted.
This example neither reads now nor sleeps; it only studies a reproducible unit contract. C++20 has expanded calendar and time-zone facilities; do not copy early methods that pretend a fixed number of hours is a month or a year. When you need to compute dates by day or month, define calendar semantics first rather than disguising them as a count of seconds.
Pitfalls
- duration_cast to a coarser integer unit truncates; it does not round automatically, and negatives are not floored.
- ratio’s compile-time checks do not protect every runtime count operation; converting a huge duration to another unit may still go out of range.
Run an example
Minimum C++11 · complete program · Download .cpp
#include <cassert>
#include <chrono>
#include <ratio>
int main() {
using namespace std::chrono;
const milliseconds budget(1500);
const seconds whole = duration_cast<seconds>(budget);
const milliseconds remainder = budget - whole;
assert(whole.count() == 1);
assert(remainder.count() == 500);
assert(duration_cast<seconds>(milliseconds(-1500)).count() == -1);
const seconds wrong(budget.count());
assert(wrong != budget);
const duration<double> precise = budget;
assert(precise.count() == 1.5);
using Tick = duration<int, std::ratio<1, 4>>;
assert(duration_cast<milliseconds>(Tick(3)).count() == 750);
assert(whole + remainder == budget);
}
Compile locally
g++ -std=c++11 -Wall -Wextra -Wpedantic -pthread books-cpp-standard-library.cpp -o example && ./exampleExpected result
Expected: exit 0, no output; every assert holds.
CHECK YOUR UNDERSTANDING
Close the answer. Explain it.
For non-negative budgets of 0–10000 milliseconds only, write a whole-second conversion that “at least covers the budget.”
Show a reference answer
First validate the range, then set auto seconds = std::chrono::seconds((budget.count() + 999) / 1000);. 0 yields 0, 1 yields 1, 1000 yields 1, 1500 yields 2. The upper bound is limited, so adding 999 is safe; if the range is not limited, use quotient plus a nonzero remainder instead, and check the target representation range. From C++17 you can also use std::chrono::ceil<std::chrono::seconds>(budget).
Check the sources
Drafts and official chapters change. The version mark is only the example’s minimum.