Работа с датами и временем в C++: от <ctime> до современного <chrono>
Работа с датами и временем — одна из ключевых задач в любом серьёзном приложении: от логов и бэкапов до таймеров и финансовых расчётов. В C++ исторически сложилось два подхода: классический C-стиль через заголовочный файл <ctime> и современный, типобезопасный подход через библиотеку <chrono>, появившуюся в C++11 и значительно расширенную в C++20. В этой статье мы разберём оба метода, научимся получать текущее время, измерять интервалы, форматировать даты и избегать типичных ошибок.
1. Классический способ: <ctime> и std::time_t
До C++11 единственным стандартным способом работы со временем были функции из C: time(), localtime(), strftime(). Этот подход до сих пор используется в легаси-коде и простых задачах.
Получение текущего времени
Функция std::time(nullptr) возвращает количество секунд с 1 января 1970 года (Unix-эпоха) в виде целого числа std::time_t.
#include <iostream>
#include <ctime>
int main() {
std::time_t now = std::time(nullptr);
std::cout << "Текущее время (сек с эпохи): " << now << std::endl;
return 0;
}
Преобразование в читаемый формат
Чтобы получить структуру с компонентами (год, месяц, день, часы и т.д.), используйте std::localtime() или std::gmtime().
#include <iostream>
#include <ctime>
int main() {
std::time_t now = std::time(nullptr);
std::tm* local = std::localtime(&now);
std::cout << "Год: " << (local->tm_year + 1900) << std::endl;
std::cout << "Месяц: " << (local->tm_mon + 1) << std::endl;
std::cout << "День: " << local->tm_mday << std::endl;
return 0;
}
Форматирование строки с strftime
Функция std::strftime() позволяет гибко отформатировать дату в строку по заданному шаблону.
#include <iostream>
#include <ctime>
int main() {
std::time_t now = std::time(nullptr);
std::tm* local = std::localtime(&now);
char buffer[80];
std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H:%M:%S", local);
std::cout << "Текущая дата и время: " << buffer << std::endl;
return 0;
}
⚠️ Важно: std::localtime() и std::gmtime() возвращают указатель на статический буфер — это не потокобезопасно. В C++11 появились реентерабельные версии localtime_s (Windows) или localtime_r (POSIX).
2. Современный C++: библиотека <chrono>
Библиотека <chrono> предлагает строгую типизацию, работу с разными единицами времени и высокую точность. Основные компоненты:
- Часы (clocks):
system_clock,steady_clock,high_resolution_clock - Моменты времени (time_point): привязка к конкретному моменту
- Длительности (duration): интервалы времени (секунды, миллисекунды и т.д.)
Получение текущего момента
#include <iostream>
#include <chrono>
#include <ctime> // для std::time_t
int main() {
auto now = std::chrono::system_clock::now();
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
std::cout << "Текущее время: " << std::ctime(&now_time);
return 0;
}
Измерение интервалов времени (таймер)
Одна из самых частых задач — замерить время выполнения кода. Для этого идеально подходит std::chrono::steady_clock (монотонные часы, не подвержены корректировкам).
#include <iostream>
#include <chrono>
#include <thread>
int main() {
auto start = std::chrono::steady_clock::now();
// Имитация работы
std::this_thread::sleep_for(std::chrono::milliseconds(500));
auto end = std::chrono::steady_clock::now();
auto diff = end - start;
std::cout << "Прошло: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(diff).count()
<< " мс" << std::endl;
return 0;
}
Работа с длительностями
Библиотека поддерживает все стандартные единицы: nanoseconds, microseconds, milliseconds, seconds, minutes, hours (и даже days с C++20).
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono_literals;
auto duration = 2h + 30min + 15s; // 2 часа 30 минут 15 секунд
auto total_sec = std::chrono::duration_cast<std::chrono::seconds>(duration);
std::cout << "Всего секунд: " << total_sec.count() << std::endl;
return 0;
}
3. Форматирование дат в C++20
Начиная с C++20, в <chrono