c++timec++-chrono

c++ std::chrono implicit conversion standard method


What is the standard/typical method when implicitly converting between time units using std::chrono?

E.g. from ms to ns

// #1
constexpr uint64_t foo_ns = std::chrono::milliseconds(500) / std::chrono::nanoseconds>(1) 

// #2
using std::chrono_literals::operator""ms;
using std::chrono_literals::operator""ns;
constexpr uint64_t foo_ns = 500ms / 1ns;

// #3
constexpr uint64_t foo_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
    std::chrono::milliseconds(500)).count();

# 4
// Some other method

Is duration_cast required in this instance given it's implicit/lossless?


Solution

  • It depends on whether the conversion involves truncation error or not. In your example, milliseconds to nanoseconds, this is a lossless conversion since you can always represent the exact number of milliseconds with nanoseconds:

    auto d1 = 500ms;
    nanoseconds d2 = d1;  // implicit conversion from milliseconds to nanoseconds
    

    If you need to go the other way, an implicit conversion won't compile:

    auto d1 = 500ns;
    milliseconds d2 = d1;  // compile-time error
    

    To perform this truncating conversion, a "named conversion" is required. There are 4 available conversions with different rounding behavior:

    auto d1 = 500ns;
    auto d2 = duration_cast<milliseconds>(d1); // truncate towards 0
    auto d3 = floor<milliseconds>(d1);         // truncate down
    auto d4 = ceil<milliseconds>(d1);          // truncate up
    auto d5 = round<milliseconds>(d1);         // truncate towards nearest
    

    Best practice is to use implicit conversion whenever possible. Truncating conversions might be a source of error in your program. They are easier to search for and review if the named conversions are used only when necessary.

    It is also best practice to not convert to integral types as in your question. When you convert a duration to an integral type you loose the type safety that chrono provides. An int can be anything: apples, lions, nanoseconds whatever. But nanoseconds can only be nanoseconds.

    That being said, it is sometimes necessary to convert to integral types for the purpose of interfacing with code that is not using chrono. Do this conversion only when you have no other choice.