Zhihar
Zhihar

Reputation: 1428

C++: setting time using suffixes

Tell me, Can the following exist in C ++ 11/14/17:

1) set time using time suffixes

double time1 = 1s; // time1 = 1.0
double time2 = 2m; // time2 = 120.0
double time3 = 7ms; // time3 = 0.007 

2) get the string value of the time with the suffix as set

std::cout << getTime(time1); // cout 1s
std::cout << getTime(time2); // cout 2s
std::cout << getTime(time3); // cout 7ms

Upvotes: 4

Views: 3751

Answers (4)

Ted Lyngmo
Ted Lyngmo

Reputation: 117308

  1. Yes, via std::chrono_literals.

  2. Not directly, but you can print the typeid (usable for debugging) or provide overloads for streaming durations yourself.

I have included explicit overloads of operator<< here, but as @JeJo, it can also be done with templates: https://wandbox.org/permlink/o495eXlv4rQ3z6yP

#include <iostream>
#include <chrono>
#include <typeinfo>

using namespace std::chrono_literals;

// example overloads for streaming out durations
std::ostream& operator<<(std::ostream& os, const std::chrono::nanoseconds& v) {
    return os << v.count() << "ns";
}
std::ostream& operator<<(std::ostream& os, const std::chrono::microseconds& v) {
    return os << v.count() << "us";
}
std::ostream& operator<<(std::ostream& os, const std::chrono::milliseconds& v) {
    return os << v.count() << "ms";
}
std::ostream& operator<<(std::ostream& os, const std::chrono::seconds& v) {
    return os << v.count() << "s";
}
std::ostream& operator<<(std::ostream& os, const std::chrono::minutes& v) {
    return os << v.count() << "min";
}
std::ostream& operator<<(std::ostream& os, const std::chrono::hours& v) {
    return os << v.count() << "h";
}

int main() {
    auto time1 = 1s;
    auto time2 = 2min;
    auto time3 = 7ms;
    std::cout << time1.count() << " " << typeid(time1).name() << "\n";
    std::cout << time2.count() << " " << typeid(time2).name() << "\n";
    std::cout << time3.count() << " " << typeid(time3).name() << "\n";
    std::cout << time1 << "\n";
    std::cout << time2 << "\n";
    std::cout << time3 << "\n";
}

Possible output:

1 NSt6chrono8durationIlSt5ratioILl1ELl1EEEE
2 NSt6chrono8durationIlSt5ratioILl60ELl1EEEE
7 NSt6chrono8durationIlSt5ratioILl1ELl1000EEEE
1s
2min
7ms

Upvotes: 6

Yksisarvinen
Yksisarvinen

Reputation: 22269

All of the modern C++ time utilities are described in the reference for <chrono> library

  1. Yes, starting from we have std::literals::chrono_literals, allowing us to use following literals:

    operator""h
    operator""min
    operator""s
    operator""ms
    operator""us
    operator""ns
    

    For example (from cppreference):

    #include <iostream>
    #include <chrono>
    
    int main()
    {
        using namespace std::chrono_literals;
        auto day = 24h;
        auto halfhour = 0.5h;
        std::cout << "one day is " << day.count() << " hours\n"
                  << "half an hour is " << halfhour.count() << " hours\n";
    }
    

  1. Not directly, but starting from there exists std::chrono::duration, with several convenient helper types to help describe time correctly (e.g. std::chrono::millisceonds, std::chrono::hours etc.). Using those, you can easily do what is needed.

    Shortened example from cppreference. As you can see, unit has to be printed separately, but choosing the right unit to print would be easy enough with some template magic.

    #include <iostream>
    #include <chrono>
    
    int main()
    {     
        std::chrono::seconds sec(1);
    
        std::cout << sec.count() <<" second is equal to:\n";
    
        // integer scale conversion with no precision loss: no cast
        std::cout << std::chrono::microseconds(sec).count() << " microseconds\n";
    
        // integer scale conversion with precision loss: requires a cast
        std::cout << std::chrono::duration_cast<std::chrono::minutes>(sec).count()
                  << " minutes\n";
    }
    

Upvotes: 4

Qaz
Qaz

Reputation: 61920

  1. Yes, as of C++14, you can use the user-defined literals described here to create durations:

    #include <chrono>
    using namespace std::literals;
    auto time1 = 1s; // std::chrono::seconds{1}
    auto time2 = 2min; // std::chrono::minutes{2}
    auto time3 = 7ms; // std::chrono::milliseconds{7}
    

    These create type-safe objects that store an integral value. You can use double internally fairly easily, but those specializations don't come with a pretty type alias out of the box:

    namespace chr = std::chrono;
    using dbl_seconds = chr::duration<double, chr::seconds::period>;
    // Likewise for other units
    dbl_seconds time1 = 1s;
    

    If you absolutely need the internal value (usually a bad idea), you can access it with .count().

  2. This is planned to come in C++20:

    std::cout << time1; // 1s, or 1.000000s if using double
    

    Until then, the best you can do with standard C++ is to suck it up and use count():

    std::cout << time1.count() << 's'; // 1s
    

For a good look into the library, watch Howard's CppCon talk. His other talks cover the planned C++20 additions.

Upvotes: 4

Stephan Dollberg
Stephan Dollberg

Reputation: 34538

1) No

2) No, not directly. There exist the operators to convert to the chrono types (though that is on integers and not on doubles) but they don't have operator<< overloads. boost::chrono has pretty printers (they are deprecated though). However, they are fully written out and not just the short form.

See:

Upvotes: -1

Related Questions