C++11 introduces the
<chrono> library helpful to work with time spans. In this post, I go through its most important parts and show some examples.
Duration is the simplest type comprising of a ratio (e.g. 1:1000 for milliseconds) and the number of ticks. A single object is guaranteed to hold a timespan nearing 300 years.
You can implicitly cast values to more precise types, and there’s duration_cast<> to handle unsafe casting to more general ones. Duration supports basic arithmetics, so you can quickly add durations, multiply them, etc. Many of these operations will be evaluated at compilation time.
There are predefined durations, from an hour to a nanosecond. C++14 introduces duration literals, what makes it even easier to express timespans in code.
$ clang++ -std=c++14 durations.cpp -o durations.exe && ./durations.exe 24h 1440min 86400s 86400000000ms 86400000000000ns 40min 3h + 52min + 40s - 2ns = 13959999999998ns
We need the clock to get durations from the system. Chrono clock is a type containing some basic information: what type it returns, whether it is a stable clock (so that we avoid problems with system clock adjustments), and ability to get the current time.
The standard library provides three of them:
- system_clock represents time as held by the system. It also provides to_time_t() method.
- stable_clock is guaranteed to be monotonic
- high_resolution_clock returns as precise time as possible
A clock returns a time point, from which we extract further information.
std::chrono::timepoint is a duration since the start of the epoch of the clock (Unix epoch is the de facto standard, at least for
system_clock). Every time point is associated with its clock and data from different ones is not interoperable.
Timepoints have basic algebra that returns durations. That makes it easy to calculate how long action took:
$ clang++ -std=c++14 timepoints.cpp -o timepoints.exe && ./timepoints.exe Operation took: 277ms
Here’s a quick diagram showing how these things work together:
We want to run input-update-render loop continuously, but it makes no sense to render scene trillion times a second since nobody would notice a change. Instead, loop allocates any free time to updates, so that game runs “no faster” than 60 frames per second.
$ clang++ -std=c++14 gameloop.cpp -o gameloop.exe && ./gameloop.exe Loop: > updating... > updating... > updating... > updating... > updating... Loop: > updating... > updating... > updating... > updating... > updating... Loop: > updating... > updating... > updating... > updating... > updating... > updating...
Notice, that the third frame could squash one update more in 16ms.
Notice that timestamps could be different since there are two separate time reads in the code:
$ clang++ -std=c++14 unixtimestamp.cpp -o unixtimestamp.exe && ./unixtimestamp.exe std::chrono only: 1492084951 with std::ctime: 1492084951
Unfortunately, our library does not support dates out of the box. That is by design (I think I saw some official explanation for this, will update when I recall the place). Good news is, Howard Hinnant wrote an excellent
date library (GitHub).