C++ как преобразовать std:: chrono:: time point в long и обратно

мне нужно, чтобы преобразовать std::chrono::time_point и long тип (целое число 64 бита). Im, начиная работать с std::chrono ...

вот мой код:

int main ()
{
     std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

    auto epoch = now.time_since_epoch();
    auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
    long duration = value.count();


    std::chrono::duration<long> dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

этот код компилируется, но не показывает успехов.

почему dt другое, чем now в конце?

чего не хватает в этом коде?

3 ответов


std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

это отличное место для auto:

auto now = std::chrono::system_clock::now();

так как вы хотите, чтобы трафик на millisecond точность, было бы хорошо пойти вперед и скрыться к нему в time_point:

auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

now_ms это time_point на основе system_clock, но с точностью milliseconds вместо любой точности вашего system_clock есть.

auto epoch = now_ms.time_since_epoch();

epoch теперь имеет тип std::chrono::milliseconds. И это следующее утверждение становится по существу no-op (просто делает копию и не делает преобразования):

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);

здесь:

long duration = value.count();

в вашем и моем коде,duration содержит количество milliseconds С эпохи system_clock.

это:

std::chrono::duration<long> dur(duration);

создает duration представлен long, и точностью seconds. Это эффективно reinterpret_casts milliseconds проведено в value to seconds. Это логическая ошибка. Правильный код будет выглядеть так:

std::chrono::milliseconds dur(duration);

этот строка:

std::chrono::time_point<std::chrono::system_clock> dt(dur);

создает time_point на основе system_clock, С возможностью держать точность к system_clockсобственная точность (обычно тоньше миллисекунд). Однако значение времени выполнения будет правильно отражать, что целое число миллисекунд удерживается (при условии моей коррекции по типу dur).

даже с коррекцией, этот тест (почти всегда) потерпит неудачу, хотя:

if (dt != now)

, потому что dt содержит Интеграл количество milliseconds, а now содержит целое число тиков тоньше, чем millisecond (например,microseconds или nanoseconds). Таким образом, только на редкий случай, что system_clock::now() возвращает целое число milliseconds пройдет ли тест.

но вы можете вместо этого:

if (dt != now_ms)

и теперь вы получите ожидаемый результат надежно.

собираем все вместе:

int main ()
{
    auto now = std::chrono::system_clock::now();
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    std::chrono::milliseconds dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

лично я нахожу все std::chrono излишне многословным, и поэтому я бы код это как:

int main ()
{
    using namespace std::chrono;
    auto now = system_clock::now();
    auto now_ms = time_point_cast<milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    milliseconds dur(duration);

    time_point<system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

который будет надежно выводить:

Success.

наконец, я рекомендую исключить временные, чтобы уменьшить преобразование кода между time_point и интегральный тип к минимуму. Эти преобразования опасны, и поэтому чем меньше кода Вы пишете, манипулируя голым интегральным типом, тем лучше:

int main ()
{
    using namespace std::chrono;
    // Get current time with precision of milliseconds
    auto now = time_point_cast<milliseconds>(system_clock::now());
    // sys_milliseconds is type time_point<system_clock, milliseconds>
    using sys_milliseconds = decltype(now);
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    sys_milliseconds dt{milliseconds{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

главная опасность выше не перевод integral_duration as milliseconds на обратном пути к time_point. Один из возможных способов смягчить этот риск-написать:

    sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};

это снижает риск, только убедившись, что вы используете sys_milliseconds на выходе и в двух местах на обратном пути.

и еще один пример: Предположим, вы хотите преобразовать в Интеграл и из интеграла, который представляет любую длительность system_clock поддержка (микросекунды, 10th микросекунд или наносекунд). Тогда вам не нужно беспокоиться об указании миллисекунд, как указано выше. Этот код упрощается до:

int main ()
{
    using namespace std::chrono;
    // Get current time with native precision
    auto now = system_clock::now();
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    system_clock::time_point dt{system_clock::duration{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

это работает, но если вы запустите половину преобразования (out в integral) на одной платформе и другую половину (in from integral) на другой платформе, вы рискуете, что system_clock::duration будут иметь разные точности для двух преобразований.


Я бы также отметил, что есть два способа получить количество МС в точке времени. Я не уверен, какой из них лучше, я сравнил их, и они оба имеют одинаковую производительность, поэтому я думаю, что это вопрос предпочтения. Возможно, Говард мог бы вмешаться:--2-->

auto now = system_clock::now();

//Cast the time point to ms, then get its duration, then get the duration's count.
auto ms = time_point_cast<milliseconds>(now).time_since_epoch().count();

//Get the time point's duration, then cast to ms, then get its count.
auto ms = duration_cast<milliseconds>(tpBid.time_since_epoch()).count();

первый читается более ясно в моем уме, идя слева направо.


time_point объекты только поддержка арифметики с другими time_point или duration объекты.

вам нужно будет преобразовать ваш long до duration указанных единиц, тогда ваш код должен работать правильно.