elektroyar
elektroyar личный блог
01 декабря 2019, 23:25

Работа с датой и временем в С++

В свое время для алготрейдерских задач мне нужно было много оперировать датой и временем. Конечно, в С++ и Си есть библиотеки для работы с датой и временем. Но мне захотелось сделать свой велосипед, который бы мог легко и удобно превращать строковое представление времени в метку времени, менять часовой пояс, получать время UTC компьютера, преобразовывать метку времени в стандартный формат даты и времени и обратно и т.д. и т.п. Одним словом, целый спектр задач.

В итоге я сделал библиотеку xtime (ну, громко сказано «библиотека», это всего лишь два файла .cpp и .hpp). Для хранения и преобразования меток времени используется тип данных uint64 либо double, поэтому у данной библиотеки нет проблемы 2038 года.

Используемые типы данных:
  • timestamp_t — тип длиной 64 бита для хранения метки времени.
  • ftimestamp_t - тип с плавающей точкой длиной 64 бита для хранения метки времени с дробной частью секунд.
  • oadate_t - тип с плавающей точкой длиной 64 бита для хранения даты автоматизации (OADate)

Что умеет библиотека, покажу на примерах.

Нужно получить время UTC на компьютере вне зависимости от текущего часового пояса? Без проблем:
#include <iostream>
#include <xtime.hpp>

uint32_t main() {
    std::cout << "Hello world!" << std::endl;
    // Получаем метку времени компьютера
    xtime::timestamp_t t = get_timestamp();
    // выводим в человекочитабельном формате
    std::cout << xtime::get_str_date_time(t) << std::endl;
    /* но можно сразу строку получить
     * В строке время будет представлено как 
     * в примере (24.05.2018 00:00:00)
     */
    std::string str = get_str_date_time();
    /* а может нужен формат OLE Automation Date 
     *(Дата автоматизации OLE)
     */
    std::cout << "oadate " << xtime::get_oadate() << endl;
    return 0;
}
Хочется иметь стандартное представление времени (часы, минуты и пр.) в виде класса с соответствующими объектами? Без проблем:
using namespace xtime;

// Инициализируем датой 24.05.2018
DateTime iTime(24,5,2018);

// Второй вариант инициализации с указанием времени
iTime = DateTime(24,5,2018, 0, 0, 0);
// iTime = DateTime(24,5,2018);

// Третий вариант инициализации (Инициализация с указанием unix-времени в формате ISO)
// iTime = DateTime("2013-12-06T15:23:01+00:00");

// Или инициализируем Unix epoch или Unix time или POSIX time или Unix timestamp
xtime::timestamp_t unix_epoch = 1527120000;

iTime.set_timestamp(unix_epoch);

// Переменные класса DateTime
iTime.day = 24; // день
iTime.month = 5; // месяц
iTime.year = 2018 // год
iTime.hour = 0; // час
iTime.minutes = 0; // минуты
iTime.seconds = 0; // секунды

// Получить Unix epoch или Unix time или POSIX time или Unix timestamp 
unix_epoch = iTime.get_timestamp();

// Вывести время и дату на экран
iTime.print();

// Получить дату и время в виде строки
std::string str = iTime.get_str_date_time(); // В строке будет 24.05.2018 00:00:00
Конечно же можно получать день недели, день года, количество дней в месяце, метку времени начала или конца дня, час, минуту от метки времени и многое другое.

К примеру, получить день недели:
using namespace xtime;

// Получить номер дня недели
uint32_t wday = get_weekday(24,5,2018);

if(wday == SUN) std::cout << "SUN" << std::endl; // Если функция вернула 0 или Воскресенье
else if(wday == MON) std::cout << "MON" << std::endl; // Если функция вернула 1 или Понедельник
else if(wday == TUS) std::cout << "TUS" << std::endl;
else if(wday == WED) std::cout << "WED" << std::endl;
else if(wday == FRI) std::cout << "FRI" << std::endl;
else if(wday == SAT) std::cout << "SAT" << std::endl;

xtime::timestamp_t unix_epoch = 1527120000;

// Второй вариант функции для определения дня недели
wday = get_weekday(unix_epoch);

// Получить день недели через метод класса DateTime
DateTime iTime(24,5,2018);
wday = iTime.get_weekday();
Конвертировать строку в формате ISO в данные класса DateTime:
using namespace xtime;

DateTime iTime;
std::string strISOformattedUTCdatetime = "2013-12-06T15:23:01+00:00";
if(convert_iso(strISOformattedUTCdatetime, iTime) == true) {
  iTime.print();
}
Перевод времени CET во время GMT и обратно с учетом перехода на зимнее время
using namespace xtime;
// получаем время GMT для примера
DateTime startTime(20,3,2018);

xtime::timestamp_t startGMT = startTime.get_timestamp();
// переводим время GMT во время CET
DateTime realCET(convert_gmt_to_cet(startGMT));
realCET.print();
// переводим время CET во время GMT
DateTime realGMT(convert_cet_to_gmt(realCET.get_timestamp()));
realGMT.print();
А еще можно получить синхронизированное UTC время
#include <iostream>
#include <xtime_sync.hpp>

uint32_t main() {
    std::cout << "Hello world!" << std::endl;
    // класс для получения синхронизированного времени
    xtime::TimeSync iTimeSync;
    while(!iTimeSync.is_time_sync()) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    };

    double last_utc = iTimeSync.get_ftimestamp();
    while(true) {
        double real_utc = iTimeSync.get_ftimestamp();
        double pc_utc = xtime::get_ftimestamp();
        if(real_utc - last_utc > 0.1) {
            std::cout 
            << "accuracy: " 
            << iTimeSync.get_accuracy() 
            << " sync utc: " << xtime::get_str_time_ms(real_utc) 
            << " pc utc: " << xtime::get_str_time_ms(pc_utc) << "\r";
            last_utc = real_utc;
        }
    };
    return 0;
}
В последнем случае вам нужно будет подключать в проект библиотеку curl.

Репозиторий с кодом
21 Комментарий
  • meat
    01 декабря 2019, 23:28
    этот пост для тех, кто не умеет программировать?
  • suren
    01 декабря 2019, 23:39
    А какие тайминги у либы? Сколько занимает получение таймстемпа текущего времени? И какая разрешающая способность?
  • ..
    01 декабря 2019, 23:53
    boost::posix_time
    std, boost ::chrono

    надо учится эффективно использовать чужие велосипеды, иначе легко завязнуть в своих
  • Андрей К
    02 декабря 2019, 00:39
    Глянул гитхаб. Все базируется на struct tm.

    Чисто для дальнейшего опыта. Quik уже работает с микросеками. Сама биржа наша уже работает с наносеками. Текущему коду есть куда стремиться. Так как tm не умеет ни микросеки, ни наносеки =).

    Синхрон тоже. Проткол ntp умеет синхронить до микросек. ptp до наносек. Но наша биржа ptp никак не хочет вводить

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн