Построение std :: chrono :: system_clock :: time_point из продолжительности - PullRequest
0 голосов
/ 27 февраля 2020

У меня есть источник данных, который предоставляет время с начала дня (00: 00: 00Z). Я хочу построить std::chrono::time_point на основе этого ввода.

Для примера, текущее время 2020-02-27T01: 05: 30.687073184. Мой источник предоставляет мне двоичное десятичное значение с точностью до 0,01 секунды. Я создаю промежуточные значения, чтобы отделить синтаксический анализ / посредничество от комбинации.

        using Days = std::chrono::duration<int, std::ratio<86400>>;

        auto hr10  = std::chrono::duration<unsigned, std::ratio<36000>> ( 0 );
        auto hr1   = std::chrono::duration<unsigned, std::ratio<3600>>  ( 1 );
        auto mn10  = std::chrono::duration<unsigned, std::ratio<600>>   ( 0 );
        auto mn1   = std::chrono::duration<unsigned, std::ratio<60>>    ( 5 );
        auto sc10  = std::chrono::duration<unsigned, std::ratio<10>>    ( 3 );
        auto sc1   = std::chrono::duration<unsigned, std::ratio<1>>     ( 0 );
        auto ms100 = std::chrono::duration<unsigned, std::ratio<1, 10>> ( 6 );
        auto ms10  = std::chrono::duration<unsigned, std::ratio<1, 100>>( 8 );

        auto t = hr10 + hr1 + mn10 + mn1 + sc10 + sc1 + ms100 + ms10;  // 393068
        auto now = std::chrono::system_clock::now();
        auto sinceEpoch = now.time_since_epoch();      // 1582765530687073184 ns

        auto today = std::chrono::duration_cast<Days>(sinceEpoch);    // 18319 days
        auto sinceDay = sinceEpoch - today;            // 3930687073184 ns

// There is logic to determine if there is a day roll-over; it is not relevant here
        auto adjust = Days(0);

// Create the time_point
        auto tp = std::chrono::system_clock::time_point();
        std::cout << "\n\tnull:       " << tp.time_since_epoch().count();

        tp += today;
        std::cout << "\n\ttoday:      " << tp.time_since_epoch().count();

        tp += adjust;
        std::cout << "\n\tadjust:     " << tp.time_since_epoch().count();

        tp += t;
        std::cout << "\n\tt:          " << tp.time_since_epoch().count();

        std::cout << "\n\tall-in-one: " << decltype(tp)(today+adjust+t).time_since_epoch().count();

Это приводит к следующему выводу:

        null:       0
        today:      1582761600000000000
        adjust:     1582761600000000000
        t:          1582765530680000000
        all-in-one: 36577304120000000

Я не понимаю, почему постепенно добавляя каждый duration до time_point дает желаемый эффект, но попытка построить time_point из общей продолжительности не дает.

Ответы [ 2 ]

1 голос
/ 27 февраля 2020

Вы переполняете счетчик тиков, добавляя непосредственно объекты duration.

Вы указали типы счетчиков тиков длительности int и unsigned. Общий тип этих unsigned. Поэтому вся математика выполняется в unsigned для today+adjust+t.

Предполагая 32-битное unsigned, типичное максимальное значение - 2^32-1 = 4294967295. Вы ожидаете получить значение 1582761600000000000, которое явно больше.

Просто используйте unsigned long long (или достаточно большой целочисленный тип фиксированного размера) в качестве duration типа счетчика тиков.

Тип, используемый для system_clock::duration (и, следовательно, system_clock::time_point), вероятно, имеет более высокий ранг, чем unsigned, и, кажется, способен хранить полное число.

1 голос
/ 27 февраля 2020

При объявлении собственных типов длительности используйте 64-битные значения

Проблема заключается в переполнении длительности при преобразовании из Days. Изменение пользовательских типов длительности для использования 64-разрядного целого числа устраняет проблему:

        auto hr10  = std::chrono::duration<uint64_t, std::ratio<36000>> ( std::get<0>(bcd) );
        auto hr1   = std::chrono::duration<uint64_t, std::ratio<3600>>  ( std::get<1>(bcd) );
        auto mn10  = std::chrono::duration<uint64_t, std::ratio<600>>   ( std::get<2>(bcd) );
        auto mn1   = std::chrono::duration<uint64_t, std::ratio<60>>    ( std::get<3>(bcd) );
        auto sc10  = std::chrono::duration<uint64_t, std::ratio<10>>    ( std::get<4>(bcd) );
        auto sc1   = std::chrono::duration<uint64_t, std::ratio<1>>     ( std::get<5>(bcd) );
        auto ms100 = std::chrono::duration<uint64_t, std::ratio<1, 10>> ( std::get<6>(bcd) );
        auto ms10  = std::chrono::duration<uint64_t, std::ratio<1, 100>>( std::get<7>(bcd) );

Или, если это нежелательно, приведите t к большему типу перед добавлением today:

        auto tp = std::chrono::system_clock::time_point(
                      std::chrono::duration_cast::microseconds(t) + today + adjust
                  );

Помните, что число наносекунд с 1970 года - это большое число , и оно, безусловно, превысит 32-битное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...