Skip to content

C++ Date & Time

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.

  • 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), and std::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_point is typically obtained from a clock’s now() function.
  • Durations: Represent a span of time, like “5 seconds” or “200 milliseconds”. std::chrono::duration is a template class storing a count and a time unit (e.g., std::chrono::seconds, std::chrono::milliseconds, std::chrono::nanoseconds).

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 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;
}

<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;
}

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.