C++ Chrono Detailed Complete Guide | 'Time Library' Guide
이 글의 핵심
std::chrono is a C++11 library that handles time intervals and points in a type-safe manner using duration, time_point, and clock. This guide covers unit conversion, steady_clock vs system_clock selection, and measurement/timeout code with examples.
Introduction
std::chrono is a type-safe time handling library introduced in C++11. It consists of three core concepts: duration (time interval), time_point (time point), and clock (clock).
Reality in Production
When learning development, everything is clean and theoretical. But production is different. You wrestle with legacy code, chase tight deadlines, and face unexpected bugs. The content covered in this guide was initially learned as theory, but I realized “ah, that’s why it’s designed this way” while applying it to actual projects.
What stands out in my memory is the trial and error from my first project. I did it as I learned from books but spent days not knowing why it didn’t work. Eventually, I found the problem through a senior developer’s code review and learned a lot in the process. This guide covers not only theory but also pitfalls you may encounter in practice and their solutions.
1. chrono Basic Structure
Core Concepts
Here is detailed implementation code using C++. Import the necessary modules and understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
int main() {
// 1. duration: time interval (length of time)
// std::chrono::seconds: duration type in seconds
std::chrono::seconds sec(10); // 10 seconds
// std::chrono::milliseconds: duration type in milliseconds
std::chrono::milliseconds ms(1000); // 1000 milliseconds = 1 second
// Other units: hours, minutes, microseconds, nanoseconds
// 2. time_point: time point (specific time)
// std::chrono::system_clock::now(): current system time
// time_point is duration from epoch (1970-01-01 00:00:00)
auto now = std::chrono::system_clock::now();
// 3. clock: clock (method to measure time)
// - system_clock: system time (wall clock time, adjustable)
// Convertible to calendar time, affected by system time changes
// - steady_clock: monotonic (never goes backward)
// Suitable for time measurement, unaffected by system time changes
// - high_resolution_clock: high precision (most precise clock)
// Usually an alias for steady_clock
return 0;
}
Clock Types
| Clock | Characteristics | Use Case |
|---|---|---|
| system_clock | System time, adjustable | Current time, timestamp |
| steady_clock | Monotonic, not adjustable | Performance measurement, timer |
| high_resolution_clock | Highest precision | Precise measurement |
2. Time Measurement
Basic Measurement
Here is detailed implementation code using C++. Import the necessary modules and process data with loops. Understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
#include <thread>
int main() {
// using namespace: std::chrono can be omitted
using namespace std::chrono;
// Start time: record current time
// high_resolution_clock::now(): measure current time with most precise clock
// Returns time_point type (specific time)
auto start = high_resolution_clock::now();
// Perform work: code to measure
for (int i = 0; i < 1000000; ++i) {
// volatile: prevent compiler optimization (so loop isn't removed)
volatile int x = i * i;
}
// End time: record time after work completion
auto end = high_resolution_clock::now();
// Elapsed time: end - start
// end - start: duration type (time interval)
// duration_cast<milliseconds>: convert to milliseconds
// Type conversion from original unit (nanoseconds, etc.) to milliseconds
auto duration = duration_cast<milliseconds>(end - start);
// count(): extract numeric value from duration
std::cout << "Execution time: " << duration.count() << "ms" << std::endl;
return 0;
}
Output:
Execution time: 15ms
Timer Class
Here is detailed implementation code using C++. Import the necessary modules, define a class to encapsulate data and functionality, and process data with loops. Understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
// Timer class: automatic time measurement with RAII pattern
class Timer {
// time_point: type that stores specific time
std::chrono::time_point<std::chrono::high_resolution_clock> start;
std::string name;
public:
// Constructor: start timer
// Initialize start to current time with initialization list
Timer(const std::string& name = "Timer")
: start(std::chrono::high_resolution_clock::now()), name(name) {}
// Destructor: stop timer (automatically called when object is destroyed)
// RAII: automatically measure time with object lifetime
~Timer() {
auto end = std::chrono::high_resolution_clock::now();
// duration_cast<microseconds>: convert to microseconds
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
// count(): extract numeric value from duration
std::cout << name << " elapsed: " << duration.count() << "μs" << std::endl;
}
// Intermediate measurement: output intermediate elapsed time without stopping timer
// lap: lap time (section time)
void lap() {
auto now = std::chrono::high_resolution_clock::now();
// Calculate elapsed time from start to now
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
std::cout << name << " lap: " << duration.count() << "ms" << std::endl;
}
};
void processData() {
// Create Timer object: start time measurement from this point
Timer t("processData");
// Task 1
for (int i = 0; i < 1000000; ++i) {}
// Intermediate check: output task1 completion time
t.lap();
// Task 2
for (int i = 0; i < 2000000; ++i) {}
// Intermediate check: output task2 completion time
t.lap();
// Function end: Timer destructor automatically called → output total elapsed time
}
int main() {
processData();
return 0;
}
Output:
processData lap: 5ms
processData lap: 15ms
processData elapsed: 15234μs
3. duration (Time Interval)
Basic Usage
Here is detailed implementation code using C++. Import the necessary modules and understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
// Create time interval: duration type
// std::chrono::seconds: duration in seconds
seconds sec(10); // 10 seconds
// std::chrono::milliseconds: duration in milliseconds
milliseconds ms(10000); // 10000 milliseconds = 10 seconds
// std::chrono::minutes: duration in minutes
minutes min(1); // 1 minute = 60 seconds
// std::chrono::hours: duration in hours
hours hr(1); // 1 hour = 60 minutes = 3600 seconds
// Get value: extract numeric value with count() method
std::cout << "Seconds: " << sec.count() << std::endl; // 10
std::cout << "Milliseconds: " << ms.count() << std::endl; // 10000
return 0;
}
Time Conversion
Here is detailed implementation code using C++. Import the necessary modules and understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
seconds s(10); // 10 seconds
// Higher → Lower (implicit conversion possible)
// Large unit → Small unit: no information loss
// seconds → milliseconds: 10 seconds = 10000 milliseconds
milliseconds ms = s; // 10000ms (automatic conversion)
std::cout << "Milliseconds: " << ms.count() << std::endl; // 10000
// Lower → Higher (explicit duration_cast required)
// Small unit → Large unit: possible information loss
milliseconds ms2(1500); // 1500 milliseconds = 1.5 seconds
// duration_cast<seconds>: explicit conversion (truncate decimal)
seconds s2 = duration_cast<seconds>(ms2); // 1s (discard 0.5 seconds)
std::cout << "Seconds: " << s2.count() << std::endl; // 1
return 0;
}
Time Operations
Here is detailed implementation code using C++. Import the necessary modules and perform branching with conditionals. Understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
seconds s1(10); // 10 seconds
seconds s2(5); // 5 seconds
// Addition: duration + duration
auto sum = s1 + s2; // 15s
// Subtraction: duration - duration
auto diff = s1 - s2; // 5s
// Multiplication: duration * scalar
auto mul = s1 * 2; // 20s (10 seconds * 2)
// Division: duration / scalar
auto div = s1 / 2; // 5s (10 seconds / 2)
std::cout << "Sum: " << sum.count() << "s" << std::endl;
std::cout << "Difference: " << diff.count() << "s" << std::endl;
std::cout << "Multiplication: " << mul.count() << "s" << std::endl;
std::cout << "Division: " << div.count() << "s" << std::endl;
// Comparison: durations can be compared
// <, >, <=, >=, ==, != all supported
if (s1 > s2) {
std::cout << "s1 is longer" << std::endl;
}
return 0;
}
4. time_point (Time Point)
Current Time
Here is detailed implementation code using C++. Import the necessary modules and understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
// Current time: time_point type
// system_clock::now(): current system time (wall clock time)
auto now = system_clock::now();
// Time since epoch: time from Unix epoch (1970-01-01 00:00:00 UTC)
// time_since_epoch(): convert time_point to duration
// current time - epoch = elapsed time
auto epoch = now.time_since_epoch();
// duration_cast<milliseconds>: convert to milliseconds
auto ms = duration_cast<milliseconds>(epoch);
// count(): extract millisecond value (milliseconds since January 1, 1970)
std::cout << "Since epoch: " << ms.count() << "ms" << std::endl;
// Example: 1743000000000ms (about 55 years)
return 0;
}
Time Operations
Here is detailed implementation code using C++. Import the necessary modules and understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
auto now = system_clock::now();
// 1 hour later
auto future = now + hours(1);
// 30 minutes ago
auto past = now - minutes(30);
// Time difference
auto diff = future - now;
auto hours_diff = duration_cast<hours>(diff);
std::cout << "Time difference: " << hours_diff.count() << " hours" << std::endl;
return 0;
}
5. Practical Examples
Example 1: Benchmark
Here is detailed implementation code using C++. Import the necessary modules and understand the role of each part while examining the code.
#include <chrono>
#include <vector>
#include <algorithm>
#include <iostream>
template<typename Func>
void benchmark(const std::string& name, Func func) {
using namespace std::chrono;
auto start = high_resolution_clock::now();
func();
auto end = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(end - start);
std::cout << name << ": " << duration.count() << "μs" << std::endl;
}
int main() {
std::vector<int> v(1000000);
benchmark("Generation", [&]() {
std::generate(v.begin(), v.end(), std::rand);
});
benchmark("Sorting", [&]() {
std::sort(v.begin(), v.end());
});
benchmark("Search", [&]() {
std::binary_search(v.begin(), v.end(), 500000);
});
return 0;
}
Output:
Generation: 45231μs
Sorting: 123456μs
Search: 12μs
Example 2: Timeout
Here is the longTask implementation:
#include <chrono>
#include <thread>
#include <future>
#include <iostream>
int longTask() {
std::this_thread::sleep_for(std::chrono::seconds(2));
return 42;
}
int main() {
using namespace std::chrono;
auto future = std::async(std::launch::async, longTask);
// Wait 1 second
auto status = future.wait_for(seconds(1));
if (status == std::future_status::timeout) {
std::cout << "Timeout!" << std::endl;
} else {
std::cout << "Result: " << future.get() << std::endl;
}
return 0;
}
Output:
Timeout!
Example 3: Periodic Execution
Here is detailed implementation code using C++. Import the necessary modules and process data with loops. Understand the role of each part while examining the code.
#include <chrono>
#include <thread>
#include <iostream>
void periodicTask() {
using namespace std::chrono;
auto nextRun = steady_clock::now();
const auto interval = seconds(1);
for (int i = 0; i < 5; ++i) {
nextRun += interval;
// Perform task
std::cout << "Task " << i + 1 << std::endl;
// Wait until next execution
std::this_thread::sleep_until(nextRun);
}
}
int main() {
periodicTask();
return 0;
}
6. chrono Literals (C++14)
Using Literals
Here is detailed implementation code using C++. Import the necessary modules and process data with loops. Understand the role of each part while examining the code.
#include <chrono>
#include <thread>
#include <iostream>
int main() {
using namespace std::chrono_literals;
// Create duration with literals
auto d1 = 10s; // seconds
auto d2 = 500ms; // milliseconds
auto d3 = 100us; // microseconds
auto d4 = 1min; // minutes
auto d5 = 2h; // hours
// Combination
auto total = 1h + 30min + 45s;
std::cout << "Total time: "
<< std::chrono::duration_cast<std::chrono::seconds>(total).count()
<< " seconds" << std::endl; // 5445 seconds
// With sleep_for
std::this_thread::sleep_for(100ms);
return 0;
}
7. Common Issues
Issue 1: Unit Conversion
Here is detailed implementation code using C++. Import the necessary modules and understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
seconds sec(10);
// ❌ Implicit conversion not allowed (lower → higher)
// milliseconds ms = sec; // Error
// ✅ duration_cast
auto ms = duration_cast<milliseconds>(sec);
std::cout << "Milliseconds: " << ms.count() << std::endl; // 10000
return 0;
}
Issue 2: Clock Selection
Here is detailed implementation code using C++. Import the necessary modules and process data with loops. Understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
#include <thread>
void wrongClock() {
using namespace std::chrono;
// ❌ system_clock (affected by system time changes)
auto start = system_clock::now();
// What if user changes system time?
std::this_thread::sleep_for(seconds(1));
auto end = system_clock::now();
auto duration = duration_cast<milliseconds>(end - start);
// Could be negative!
std::cout << "Elapsed: " << duration.count() << "ms" << std::endl;
}
void correctClock() {
using namespace std::chrono;
// ✅ steady_clock (guaranteed monotonic)
auto start = steady_clock::now();
std::this_thread::sleep_for(seconds(1));
auto end = steady_clock::now();
auto duration = duration_cast<milliseconds>(end - start);
// Always positive
std::cout << "Elapsed: " << duration.count() << "ms" << std::endl;
}
int main() {
correctClock();
return 0;
}
Issue 3: Precision Loss
Here is detailed implementation code using C++. Import the necessary modules and understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
milliseconds ms(1500);
// duration_cast: truncation
auto s1 = duration_cast<seconds>(ms);
std::cout << "Truncation: " << s1.count() << "s" << std::endl; // 1s (500ms loss)
// C++17: round
auto s2 = round<seconds>(ms);
std::cout << "Round: " << s2.count() << "s" << std::endl; // 2s
// C++17: ceil
auto s3 = ceil<seconds>(ms);
std::cout << "Ceil: " << s3.count() << "s" << std::endl; // 2s
// C++17: floor
auto s4 = floor<seconds>(ms);
std::cout << "Floor: " << s4.count() << "s" << std::endl; // 1s
return 0;
}
Issue 4: Type Inference
Here is detailed implementation code using C++. Import the necessary modules and understand the role of each part while examining the code.
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
// ❌ Type unclear
auto d1 = 10; // int
// ✅ Explicit type
seconds d2(10);
// ✅ Literal (C++14)
using namespace std::chrono_literals;
auto d3 = 10s;
std::cout << "d2: " << d2.count() << "s" << std::endl;
std::cout << "d3: " << d3.count() << "s" << std::endl;
return 0;
}
8. Practical Example: Performance Profiler
Here is detailed implementation code using C++. Import the necessary modules, define a class to encapsulate data and functionality, process data with loops, and perform branching with conditionals. Understand the role of each part while examining the code.
#include <chrono>
#include <string>
#include <map>
#include <iostream>
class Profiler {
using Clock = std::chrono::high_resolution_clock;
using TimePoint = std::chrono::time_point<Clock>;
std::map<std::string, TimePoint> starts;
std::map<std::string, long long> totals; // microseconds
public:
void start(const std::string& name) {
starts[name] = Clock::now();
}
void stop(const std::string& name) {
auto end = Clock::now();
auto it = starts.find(name);
if (it != starts.end()) {
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
end - it->second
);
totals[name] += duration.count();
starts.erase(it);
}
}
void report() {
std::cout << "\n=== Profiling Results ===" << std::endl;
for (const auto& [name, total] : totals) {
if (total < 1000) {
std::cout << name << ": " << total << "μs" << std::endl;
} else if (total < 1000000) {
std::cout << name << ": " << (total / 1000.0) << "ms" << std::endl;
} else {
std::cout << name << ": " << (total / 1000000.0) << "s" << std::endl;
}
}
}
};
void algorithm1() {
for (int i = 0; i < 1000000; ++i) {}
}
void algorithm2() {
for (int i = 0; i < 2000000; ++i) {}
}
int main() {
Profiler profiler;
// Measure algorithm 1
profiler.start("algorithm1");
algorithm1();
profiler.stop("algorithm1");
// Measure algorithm 2
profiler.start("algorithm2");
algorithm2();
profiler.stop("algorithm2");
// Run multiple times
for (int i = 0; i < 5; ++i) {
profiler.start("algorithm1");
algorithm1();
profiler.stop("algorithm1");
}
profiler.report();
return 0;
}
Output:
=== Profiling Results ===
algorithm1: 25.5ms
algorithm2: 8.3ms
Summary
Key Points
- chrono: C++11 time library
- duration: Time interval (seconds, milliseconds, etc.)
- time_point: Time point
- clock: system_clock, steady_clock, high_resolution_clock
- duration_cast: Unit conversion
- Literals:
10s,500ms(C++14)
Clock Selection Guide
| Purpose | Clock | Reason |
|---|---|---|
| Performance measurement | steady_clock | Monotonic |
| Timer | steady_clock | Unaffected by time adjustment |
| Current time | system_clock | System time |
| Timestamp | system_clock | Unix epoch conversion |
| Precise measurement | high_resolution_clock | Highest precision |
Practical Tips
Usage Principles:
- Performance measurement:
steady_clock - Current time:
system_clock - Lower→Higher conversion:
duration_cast - Use literals (
10s,500ms)
Performance:
steady_clockis fastestduration_castis compile-time- Literals improve readability
- Use Timer class with RAII
Cautions:
system_clockaffected by time adjustmentduration_casttruncates (precision loss)- Lower→Higher conversion is explicit
- Negative duration possible
Next Steps
- C++ Duration
- C++ Time Point
- C++ Timer Utilities
Related Articles
- C++ duration |
- C++ Chrono Complete Guide |
- C++ Chrono Literals |
- C++ ratio |
- C++ steady_clock |