std::chrono
Type-safe time and duration library — durations, clocks, time points, and C++20 calendar and timezone types.
std::chronosince C++11A type-safe time library that models durations (quantities of time), time points (moments anchored to a clock), and clocks (sources of time), extended in C++20 with civil-calendar types, IANA timezone support, and additional precision clocks.
Overview
std::chrono is built on three orthogonal concepts:
duration<Rep, Period>— a tick count of typeRepwhere each tick spansPeriod(astd::ratio) seconds. Arithmetic between durations of different periods compiles only when the conversion is lossless, or when you explicitly callduration_cast.time_point<Clock, Duration>— a point in time measured from a clock's epoch, statically bound to that clock. Subtracting twotime_points of the same clock yields aduration; subtracting across clocks is a compile error.- Clocks — tag types exposing
now()and adurationtypedef. C++11 introduced three; C++20 added four more with precisely specified epochs.
C++20 substantially extended the library: civil-calendar types (year_month_day, weekday, month_day, …), IANA timezone support (time_zone, zoned_time), parsing via std::chrono::parse, and new clocks.
Syntax
Duration template and predefined aliases
// Primary template
template<class Rep, class Period = std::ratio<1>>
class std::chrono::duration;
// C++11 predefined aliases
std::chrono::nanoseconds // duration<long long, std::nano>
std::chrono::microseconds // duration<long long, std::micro>
std::chrono::milliseconds // duration<long long, std::milli>
std::chrono::seconds // duration<long long>
std::chrono::minutes // duration<long long, std::ratio<60>>
std::chrono::hours // duration<long long, std::ratio<3600>>
// C++20 predefined aliases
std::chrono::days // duration<int, std::ratio<86400>>
std::chrono::weeks // duration<int, std::ratio<604800>>
std::chrono::months // duration<int, std::ratio<2629746>> // 30.436875 days
std::chrono::years // duration<int, std::ratio<31556952>> // 365.2425 daysUser-defined literals require using namespace std::chrono_literals; (C++11):
auto t = 2h + 30min + 15s; // chrono::hours, minutes, seconds
auto d = 500ms + 250us; // chrono::milliseconds, microseconds
auto n = 100ns; // chrono::nanosecondsC++20 literal trap:
15dcreatesstd::chrono::day{15}— a calendar day number, not adaysduration.2025ycreatesstd::chrono::year{2025}— a calendar year, not ayearsduration. There are no UDL suffixes fordays,weeks,months, oryearsdurations; construct them directly:std::chrono::days{7}.
Duration operations
using namespace std::chrono;
// Implicit conversion is allowed only when lossless
seconds s = 5min; // OK: minutes → seconds is exact
// minutes m = 90s; // Error: potential loss of precision
// Explicit conversion truncates toward zero
auto m = duration_cast<minutes>(90s); // 1min, not 1.5
// C++17: directed rounding
floor<seconds>(1500ms).count(); // 1
round<seconds>(1500ms).count(); // 2 (nearest)
ceil<seconds>(1500ms).count(); // 2
abs(-500ms).count(); // 500 // C++17
// Raw tick value
milliseconds{2500}.count(); // 2500
duration<double, std::ratio<1>>{0.5}.count(); // 0.5 — fractional secondsClock comparison
| Clock | Monotonic | Epoch | C++ version |
|---|---|---|---|
steady_clock | Yes | Unspecified | C++11 |
system_clock | No | Unix epoch (C++20: guaranteed) | C++11 |
high_resolution_clock | Impl-defined | Impl-defined | C++11 |
utc_clock | Yes | Unix epoch + leap seconds | C++20 |
tai_clock | Yes | 1958-01-01 (TAI) | C++20 |
gps_clock | Yes | 1980-01-06 (GPS) | C++20 |
file_clock | Impl-defined | Implementation-defined | C++20 |
high_resolution_clock is an alias for steady_clock on most implementations (GCC/libstdc++, recent MSVC). Never assume its epoch or monotonicity; prefer steady_clock explicitly.
Examples
Timing a block of code
#include <chrono>
#include <print> // C++23
template<class F>
std::chrono::microseconds timed(F&& f) {
auto start = std::chrono::steady_clock::now();
f();
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start);
}
auto us = timed([] { process_batch(); });
std::println("elapsed: {} µs", us.count());
// C++20: duration types are directly formattable
std::println("elapsed: {}", us); // "12345µs"Sleeping with steady deadlines
#include <chrono>
#include <thread>
using namespace std::chrono_literals;
std::this_thread::sleep_for(100ms);
// Absolute deadline prevents drift accumulation in loops
auto next = std::chrono::steady_clock::now();
for (int i = 0; i < 10; ++i) {
next += 200ms;
do_periodic_work();
std::this_thread::sleep_until(next);
}Wall-clock timestamps and formatting (C++20)
#include <chrono>
#include <format> // C++20
auto now = std::chrono::system_clock::now();
// Truncate to seconds resolution
auto now_s = std::chrono::floor<std::chrono::seconds>(now);
// ISO 8601 UTC
auto utc = std::format("{:%Y-%m-%dT%H:%M:%SZ}", now_s);
// "2026-05-22T14:23:05Z"
// Local civil time via IANA timezone database (C++20)
auto zt = std::chrono::zoned_time{
std::chrono::current_zone(),
std::chrono::system_clock::now()
};
auto local = std::format("{:%Y-%m-%d %H:%M:%S %Z}", zt);
// "2026-05-22 16:23:05 CEST"Calendar date arithmetic (C++20)
#include <chrono>
using namespace std::chrono;
// Construct a specific date
year_month_day launch{year{2026}, June, day{1}};
// Convert a system_clock time_point to a calendar date
year_month_day today = floor<days>(system_clock::now());
// Duration between two dates — convert to sys_days first
days diff = sys_days{launch} - sys_days{today};
// Day of week
weekday wd{sys_days{today}};
bool is_friday = (wd == Friday);
// Last day of a month (C++20)
year_month_day_last last_feb = year{2026} / February / last;
year_month_day end_of_feb{last_feb}; // 2026-02-28Parsing a date string (C++20)
#include <chrono>
#include <sstream>
std::chrono::sys_days date;
std::istringstream ss("2026-06-01");
ss >> std::chrono::parse("%Y-%m-%d", date);
// date == sys_days for 2026-06-01Converting between clocks (C++20)
#include <chrono>
auto sys_now = std::chrono::system_clock::now();
// system_clock ignores leap seconds; utc_clock counts them
auto utc_now = std::chrono::clock_cast<std::chrono::utc_clock>(sys_now);
// time_point_cast: change duration granularity, keep the clock
auto at_second = std::chrono::time_point_cast<std::chrono::seconds>(sys_now);Best Practices
Always use steady_clock for measuring elapsed time. Only use system_clock when you need a wall-clock value to display or store as a timestamp. The two are not substitutable: system_clock can jump backward on NTP corrections or forward on DST transitions.
Pass duration objects across API boundaries, never raw integers. A parameter typed std::chrono::milliseconds self-documents its unit and rejects unit mismatches at the call site. An int64_t timeout_ms parameter is a latent bug.
Know which rounding mode you need. duration_cast truncates; floor, round, and ceil (C++17) give directed rounding. For display, round is usually correct. For deadline computation, ceil avoids delivering early.
Seed RNGs with steady_clock, not time(0). time(0) has one-second resolution; two processes spawned in the same second get identical sequences.
auto seed = std::chrono::steady_clock::now().time_since_epoch().count();
std::mt19937_64 rng{static_cast<uint64_t>(seed)};For calendar date arithmetic, use C++20 types. Do not implement leap-year logic or month-end arithmetic manually. year_month_day handles these correctly; converting to sys_days for duration arithmetic is the idiomatic approach.
Common Pitfalls
system_clock for elapsed time
// Bad: can go backward or jump
auto start = std::chrono::system_clock::now();
do_work();
auto elapsed = std::chrono::system_clock::now() - start; // may be negative
// Good
auto start = std::chrono::steady_clock::now();
do_work();
auto elapsed = std::chrono::steady_clock::now() - start; // always >= 0C++20 calendar literals are not durations
using namespace std::chrono_literals;
auto x = 7d; // std::chrono::day{7} — a calendar day number, NOT a duration
auto y = 2025y; // std::chrono::year{2025} — a calendar year, NOT a duration
// To construct durations for days/weeks/months/years:
auto seven_days = std::chrono::days{7};
auto two_years = std::chrono::years{2};duration_cast truncates, not rounds
// duration_cast truncates toward zero
std::chrono::duration_cast<std::chrono::seconds>(999ms).count(); // 0, not 1
// When nearest-value is needed:
std::chrono::round<std::chrono::seconds>(999ms).count(); // 1
std::chrono::round<std::chrono::seconds>(500ms).count(); // 0 (round to even)Month overflow in calendar arithmetic
using namespace std::chrono;
year_month_day d{year{2026}, January, day{31}};
// Adding one month naively produces an invalid date
auto next = d.year() / (d.month() + months{1}) / d.day();
next.ok(); // false — 2026-02-31 does not exist
// Converting to sys_days normalises the overflow (Feb 31 → Mar 3)
year_month_day normalised{sys_days{next}};
// For end-of-month clamping, use year_month_day_last explicitly
auto eom = d.year() / (d.month() + months{1}) / last; // 2026-02-28Comparing .count() values of different duration types
std::chrono::seconds s{1};
std::chrono::milliseconds ms{1000};
s.count() == ms.count(); // false: 1 == 1000
s == ms; // true: implicit conversion, then compareNever compare .count() values across duration types. Compare the duration objects directly; the library applies the appropriate unit conversion.
See Also
<ctime>—time_t,tm,strftimefor C-style time and legacy API interopstd::format/std::print(C++20/23) —{:%Y-%m-%d %H:%M:%S}format specifiers work directly onduration,time_point,zoned_time, and calendar typesstd::this_thread::sleep_for/sleep_until(<thread>) — chrono-aware thread blockingstd::filesystem::file_time_type—file_clock::time_pointreturned bystd::filesystem::last_write_timestd::condition_variable::wait_for/wait_until— chrono-aware condition variable blocking