Работа с датами и временем в C++: продвинутый уровень

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Продвинутая работа с датами и временем в C++: от chrono до часовых поясов

Работа с датами и временем — одна из ключевых задач при разработке высоконагруженных систем, логирования, финансовых приложений и планировщиков. В C++ стандартная библиотека предлагает мощный инструментарий, начиная от простых time_t и заканчивая современным <chrono>. В этой статье мы разберём продвинутые техники: точные замеры, часовые пояса, форматирование и расчёты интервалов.

1. Библиотека chrono: duration, time_point и clocks

Стандартная библиотека <chrono> (C++11 и новее) предоставляет типы для представления моментов времени (time_point), длительностей (duration) и часов (clock). Это позволяет писать код, не зависящий от платформы.

#include <iostream>
#include <chrono>
#include <thread>

int main() {
    using namespace std::chrono;

    // Засекаем время начала
    auto start = high_resolution_clock::now();

    // Имитация работы
    std::this_thread::sleep_for(milliseconds(500));

    auto end = high_resolution_clock::now();

    // Вычисляем длительность
    auto duration = duration_cast<milliseconds>(end - start);
    std::cout << "Прошло: " << duration.count() << " мс\n";

    // Работа с duration в разных единицах
    seconds sec(1);
    milliseconds ms = sec; // неявное преобразование (без потерь)
    // milliseconds ms2 = duration_cast<milliseconds>(sec); // явное
    std::cout << "1 секунда = " << ms.count() << " мс\n";

    return 0;
}

Ключевые моменты:

  • duration_cast — преобразование между единицами (может терять точность).
  • high_resolution_clock — максимально точные часы (обычно обёртка над системным таймером).
  • system_clock — системное время, привязанное к календарю.
  • steady_clock — монотонные часы, идеальны для замеров интервалов.

2. Системное время и преобразование в календарные даты

Для работы с календарными датами (год, месяц, день) используйте system_clock и функции to_time_t / from_time_t. Начиная с C++20 появились более удобные средства, но мы рассмотрим классический подход.

#include <iostream>
#include <chrono>
#include <ctime>

int main() {
    using namespace std::chrono;

    // Текущее системное время
    auto now = system_clock::now();
    std::time_t now_c = system_clock::to_time_t(now);

    // Преобразуем в локальное время
    std::tm* local = std::localtime(&now_c);
    std::cout << "Локальное время: " 
              << std::put_time(local, "%Y-%m-%d %H:%M:%S") << "\n";

    // Создаём time_point из календарной даты (C++20 упростит)
    std::tm date = {};
    date.tm_year = 2025 - 1900; // годы от 1900
    date.tm_mon = 3;            // апрель (0-11)
    date.tm_mday = 15;
    date.tm_hour = 12;
    date.tm_min = 30;
    date.tm_sec = 0;
    std::time_t date_c = std::mktime(&date);
    auto date_point = system_clock::from_time_t(date_c);

    // Разница в днях
    auto diff = duration_cast<hours>(now - date_point).count() / 24;
    std::cout << "Дней с 15.04.2025: " << diff << "\n";

    return 0;
}

Важно: std::put_time доступен с C++11. Форматные спецификаторы аналогичны strftime.

3. Часовые пояса и C++20

До C++20 работа с часовыми поясами была нетривиальной. В C++20 появилась библиотека <chrono> с поддержкой time_zone и zoned_time. Если ваш компилятор поддерживает C++20 (GCC 12+, Clang 15+, MSVC 2022 17.4+), вы можете использовать следующий код:

#include <iostream>
#include <chrono>
#include <format> // C++20 для форматирования

int main() {
    using namespace std::chrono;

    // Текущее время в UTC
    auto utc = system_clock::now();

    // Переводим в часовой пояс Москвы (UTC+3)
    auto moscow = zoned_time{"Europe/Moscow", utc};
    std::cout << "Москва: " << moscow << "\n";

    // Переводим в Нью-Йорк
    auto ny = zoned_time{"America/New_York", utc};
    std::cout << "Нью-Йорк: " << ny << "\n";

    // Разница между поясами
    auto diff = moscow.get_local_time() - ny.get_local_time();
    auto hours_diff = duration_cast<hours>(diff);
    std::cout << "Разница: " << hours_diff.count() << " часов\n";

    return 0;
}

Примечание: Для работы с часовыми поясами требуется база данных IANA (обычно поставляется с компилятором или через libc++).

4. Продвинутые расчёты: парсинг, добавление и вычитание

Часто требуется не просто получить текущее время, а выполнить арифметические операции: добавить дни, часы или найти ближайший рабочий день.

#include <iostream>
#include <chrono>
#include <ctime>
#include <sstream>
#include <iomanip>

// Парсинг строки в time_point (формат "YYYY-MM-DD HH:MM:SS")
std::chrono::system_clock::time_point parse_datetime(const std::string& str) {
    std::tm tm = {};
    std::istringstream ss(str);
    ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");                

Блоги

Рекомендаций по книгам