C++ Date & Time
C++ Date and Time with
Section titled “C++ Date and Time with ”Modern C++ provides powerful tools for date and time manipulation through the <chrono> header, introduced in C++11 and significantly enhanced in C++20. While C++ still supports the older C-style <ctime> library for compatibility, <chrono> offers a type-safe, flexible, and more expressive approach.
Key Concepts in <chrono>:
Section titled “Key Concepts in <chrono>:”- Clocks: Represent the source of time points. Common clocks include
std::chrono::system_clock(wall clock time, potentially adjustable),std::chrono::steady_clock(monotonic, good for measuring intervals), andstd::chrono::high_resolution_clock(most precise available clock). - Time Points: Represent a specific point in time relative to a clock’s epoch (starting point). A
std::chrono::time_pointis typically obtained from a clock’snow()function. - Durations: Represent a span of time, like “5 seconds” or “200 milliseconds”.
std::chrono::durationis a template class storing a count and a time unit (e.g.,std::chrono::seconds,std::chrono::milliseconds,std::chrono::nanoseconds).
Getting the Current Time
Section titled “Getting the Current Time”To get the current wall clock time, use std::chrono::system_clock::now():
#include <iostream>#include <chrono>
int main() { // Get the current time point from the system clock std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
// A time_point itself isn't directly printable in a human-readable format easily pre-C++20. // We often convert it for output or calculations.
// Example: Get time since epoch (useful for some APIs) auto duration_since_epoch = now.time_since_epoch();
// Convert duration to seconds (as a double for fractional part) std::chrono::duration<double> seconds_since_epoch = duration_since_epoch; std::cout << "Seconds since epoch (Jan 1, 1970 UTC): " << seconds_since_epoch.count() << std::endl;
return 0;}Formatting Date and Time (Pre-C++20 Approach)
Section titled “Formatting Date and Time (Pre-C++20 Approach)”Before C++20’s formatting additions to <chrono>, a common way to get human-readable output was to convert the system_clock::time_point to the older C time_t type, which can then be used with functions like std::localtime (or std::gmtime for UTC) and std::put_time (from <iomanip>) for formatted output.
Caution: std::localtime is not thread-safe on all platforms as it often uses a static internal buffer. Safer alternatives like localtime_s (Windows) or localtime_r (POSIX) exist but are platform-specific. For cross-platform, thread-safe formatting, C++20’s <chrono> or external libraries like fmt or Boost.Locale are recommended.
Here’s an example using std::put_time:
#include <iostream>#include <chrono>#include <ctime> // For time_t, tm, localtime#include <iomanip> // For std::put_time#include <sstream> // For formatting to string (optional)
int main() { // Get the current time point auto now = std::chrono::system_clock::now();
// Convert time_point to time_t std::time_t now_c = std::chrono::system_clock::to_time_t(now);
// Convert time_t to tm struct for local time (potentially not thread-safe) // Note: std::localtime returns a pointer to a statically allocated struct. std::tm now_tm = *std::localtime(&now_c);
// Format the time using std::put_time std::cout << "Current local time: "; std::cout << std::put_time(&now_tm, "%Y-%m-%d %H:%M:%S %Z") << std::endl; // ISO 8601-like format + timezone
// Example: Format date only std::cout << "Current date: "; std::cout << std::put_time(&now_tm, "%A, %B %d, %Y") << std::endl; // e.g., Tuesday, August 22, 2023
// For UTC time, use std::gmtime instead of std::localtime (also potentially not thread-safe) std::tm utc_tm = *std::gmtime(&now_c); std::cout << "Current UTC time: "; std::cout << std::put_time(&utc_tm, "%Y-%m-%d %H:%M:%S UTC") << std::endl;
return 0;}The format codes used in std::put_time (like %Y, %m, %d) are the same as those used by the C function strftime. Common codes include:
%Y: Year with century (e.g., 2023)%m: Month as a zero-padded decimal number (01-12)%d: Day of the month as a zero-padded decimal number (01-31)%H: Hour (24-hour clock) as a zero-padded decimal number (00-23)%M: Minute as a zero-padded decimal number (00-59)%S: Second as a zero-padded decimal number (00-60)%Z: Time zone name or abbreviation (if available)%A: Full weekday name (e.g., Sunday)%B: Full month name (e.g., January)
C++20 Enhancements
Section titled “C++20 Enhancements”C++20 significantly enhances <chrono> by adding calendars, time zones, and direct formatting capabilities via std::format (requires <format> header). This avoids the need for time_t conversions and the associated thread-safety concerns.
Example using C++20 std::format (requires a C++20 compliant compiler and standard library):
// Requires C++20 features#include <iostream>#include <chrono>#include <format> // C++20 header
int main() { auto now = std::chrono.system_clock.now();
// Direct formatting using std::format std::cout << std::format("Current local time: {:%Y-%m-%d %H:%M:%S %Z}\n", now); std::cout << std::format("Current UTC time: {:%Y-%m-%d %H:%M:%S UTC}\n", now);
// Formatting with specific time zones (if supported by implementation) try { auto zt = std::chrono::zoned_time{ "America/New_York", now }; std::cout << std::format("New York time: {:%Y-%m-%d %H:%M:%S %Z}\n", zt); } catch (const std::chrono::nonexistent_local_time& e) { std::cerr << "Time zone error: " << e.what() << '\n'; } catch (const std::chrono::ambiguous_local_time& e) { std::cerr << "Time zone error: " << e.what() << '\n'; }
return 0;}Working with Durations
Section titled “Working with Durations”<chrono> makes working with time durations type-safe and intuitive.
#include <iostream>#include <chrono>#include <thread> // For std::this_thread::sleep_for
int main() { using namespace std::chrono_literals; // Enable convenient literals like 10s, 200ms
auto start = std::chrono::high_resolution_clock::now();
// Simulate some work std::this_thread::sleep_for(1500ms); // Sleep for 1.5 seconds
auto end = std::chrono::high_resolution_clock::now();
// Calculate the duration std::chrono::duration<double> elapsed_seconds = end - start; auto elapsed_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Elapsed time: " << elapsed_seconds.count() << " s\n"; std::cout << "Elapsed time: " << elapsed_milliseconds.count() << " ms\n";
return 0;}Summary
Section titled “Summary”The <chrono> library is the modern C++ standard for handling dates and times. It provides type-safe clocks, time points, and durations. While formatting required conversion to C types before C++20, modern C++ offers direct formatting capabilities, making date/time manipulation safer and more convenient.