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
    этот пост для тех, кто не умеет программировать?
      • meat
        01 декабря 2019, 23:31
        elektroyar, мне кажется ты сайтом ошибся, тебе на хабр и прочие ресурсы, без обид :)
          • meat
            01 декабря 2019, 23:37
            elektroyar, есть куча вещей, которые могут пригодиться в трейдинге, но работа с датами не только в трейдинге происходит

            у тебя по сути еще одна библиотека для работы с датами с привязкой к C++
  • suren
    01 декабря 2019, 23:39
    А какие тайминги у либы? Сколько занимает получение таймстемпа текущего времени? И какая разрешающая способность?
  • bwc
    01 декабря 2019, 23:53
    boost::posix_time
    std, boost ::chrono

    надо учится эффективно использовать чужие велосипеды, иначе легко завязнуть в своих
      • bwc
        02 декабря 2019, 00:18
        elektroyar, экономии времени ради. чтобы не проектировать-писать-тестировать свое.
    • Андрей К
      02 декабря 2019, 00:31
      bwc, если нужно быстро вычислять, boost сразу в помойку
      • bwc
        02 декабря 2019, 00:55

        Андрей К, я про _быстро_ мало знаю.
        целочисленные boost, std ::chrono, boost::posix_time - медленные?

        • Андрей К
          02 декабря 2019, 13:46
          bwc, ну вот так вот прямо нельзя сказать что бусты сверх медленные. Но их же создают для универсального решения задач, поэтому там много перестраховок. Идет нагромождение кода. А это напрямую влияет на производительность. Например, плавают такие величины, как время вызова их кода. Один раз кусок может отработать за микросеку, второй раз за 10мксек.

          есть много алго, где время взятия меток очень ощутимо для самого алго. Вот именно тут, лучше делать кастом.
          • bwc
            03 декабря 2019, 00:27
            Андрей К, а, не. concern был по поводу chrono. что там все тяжело (а смотреть лень) и можно сделать как тут
            кастом — это личное, свои требования, окружение, история. нет смысла обсуждать исходя из общих представлений.
  • Андрей К
    02 декабря 2019, 00:39
    Глянул гитхаб. Все базируется на struct tm.

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

    Синхрон тоже. Проткол ntp умеет синхронить до микросек. ptp до наносек. Но наша биржа ptp никак не хочет вводить
    • meat
      02 декабря 2019, 13:37
      Андрей К, мне кажется ему все равно, что ты тут пишешь 




      • Андрей К
        02 декабря 2019, 13:41
        meat, ааа =) ну тогда да
  • Technotrade
    02 декабря 2019, 07:37
    А как можно повернуть время назад?
  • Turbo Pascal
    02 декабря 2019, 09:13
    Конечно, в С++ и Си есть библиотеки для работы с датой и временем. Но мне захотелось сделать свой велосипед

    Настоящий русский программист 

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

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