Работа с датами и временем в C++: от А до Я
Работа с датами и временем — одна из базовых задач в программировании. Она требуется везде: от логирования событий до расчёта дедлайнов и построения графиков. В C++ исторически эта область была не самой удобной, но с приходом стандарта C++11 и последующих версий (C++14, C++17, C++20) ситуация кардинально изменилась. В этой статье мы разберём все ключевые аспекты: от классических C-функций до современной библиотеки chrono, таймеров, форматирования и парсинга. Материал будет полезен как новичкам, так и опытным разработчикам, желающим систематизировать знания.
1. Классический подход: time_t и структура tm
До появления chrono основным инструментом были функции из <ctime>. Этот подход остаётся актуальным для поддержки старого кода и простых задач.
Основные функции:
time()— возвращает текущее время какtime_t(количество секунд с 1 января 1970 года).localtime()— преобразуетtime_tв структуруtm(локальное время).gmtime()— преобразует в UTC.strftime()— форматируетtmв строку.mktime()— обратное преобразование:tm→time_t.
#include <iostream>
#include <ctime>
int main() {
// Получаем текущее время
std::time_t now = std::time(nullptr);
// Преобразуем в локальное время
std::tm* local_tm = std::localtime(&now);
// Форматируем в строку
char buffer[80];
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", local_tm);
std::cout << "Текущее время: " << buffer << std::endl;
return 0;
}
Минусы подхода:
- Работает только с секундами (миллисекунды и микросекунды недоступны).
- Небезопасно в многопоточных средах (используйте
localtime_rв POSIX). - Структура
tmсодержит поля, которые легко перепутать (год сдвинут на 1900, месяцы с 0). - Отсутствует поддержка часовых поясов и интервалов времени.
2. Современный C++: библиотека chrono (C++11 и новее)
Библиотека chrono — это мощный и типобезопасный инструмент для работы со временем. Она лежит в основе всех современных C++ проектов.
Основные компоненты:
- Часы (clocks):
system_clock(системное время),steady_clock(монотонные часы для замеров),high_resolution_clock(максимальное разрешение). - Моменты времени (time_point): привязаны к конкретным часам.
- Длительности (duration): интервалы времени (секунды, миллисекунды, наносекунды).
#include <iostream>
#include <chrono>
#include <thread>
int main() {
using namespace std::chrono;
// Текущий момент времени
auto now = system_clock::now();
// Преобразуем в time_t для отображения
std::time_t now_c = system_clock::to_time_t(now);
std::cout << "Текущее время: " << std::ctime(&now_c);
// Замер времени выполнения
auto start = steady_clock::now();
std::this_thread::sleep_for(milliseconds(500)); // имитация работы
auto end = steady_clock::now();
auto duration = duration_cast<milliseconds>(end - start);
std::cout << "Прошло: " << duration.count() << " мс" << std::endl;
return 0;
}
Преимущества chrono:
- Высокая точность (наносекунды).
- Типобезопасность (нельзя случайно сложить секунды с миллисекундами).
- Поддержка арифметики (сложение/вычитание длительностей).
- Удобные литералы:
5s,100ms,1h(требуется C++14). - Работает в многопоточных приложениях без дополнительных усилий.
3. Форматирование и парсинг дат в C++20
Стандарт C++20 добавил долгожданные возможности форматирования дат и времени, а также парсинга из строк. Основной инструмент — std::format (из <format>) и расширения для chrono.
Форматирование:
#include <iostream>
#include <chrono>
#include <format> // C++20
int main() {
using namespace std::chrono;
auto now = system_clock::now();
// Форматируем с помощью std::format
std::cout << std::format("Текущее время: {:%Y-%m-%d %H:%M:%S}", now) << std::endl;
// Можно указать часовой пояс
auto tz = current_zone(); // из <chrono>
std::cout << std::format("Время в Москве: {:%Y-%m-%d %H:%M:%S %Z}",
zoned_time{tz, now}) << std::endl;
return 0;
}
Парсинг даты из строки:
#include <iostream>
#include <chrono>
#include <sstream>
int main() {
using namespace std::chrono;
std::string input = "2024-12-31 23:59:59";
std::istringstream iss(input);
sys_seconds tp;
std::chrono::from_stream(iss, "%Y-%m-%d %