【问题标题】:Elegant time print in C++11C++11 中优雅的时间打印
【发布时间】:2014-03-30 14:45:01
【问题描述】:

这就是我想在 C++11 中做的事情:给定两个时间点(例如计时类)为 std::chrono::steady_clock::now(),优雅地打印它们的时间差,例如:

1 day 4 hours 3 minutes 45 seconds

32 minutes 54 seconds 345 milliseconds

请注意,我对简单地使用put_time 不感兴趣,因为我想从最重要的时间单位开始打印。我知道,这是一种仅打印差异的解决方案,但它并不漂亮:我正​​在寻找一个优雅 解决方案:)

干杯!

【问题讨论】:

  • 你现在有什么解决方案?
  • 使用自定义put_time 格式,基于随后按天、小时等划分,有点像@Simple 写的。但我希望能找到更漂亮的东西! :)
  • @senseiwa 我不明白。 “我对简单地使用 put_time 不感兴趣,因为我想从最重要的时间单位开始打印。” 为什么不能使用 put_time 从最重要的时间单位开始时间?恐怕我错过了一点。
  • 因为我想概括打印,虽然很奇怪,但我想避免随后的减法,以便找到非零的最重要的单位。

标签: c++ datetime c++11 time


【解决方案1】:

持续时间可以做算术。

#include <chrono>
#include <iostream>
#include <thread>

int main(){
    using namespace std::chrono;
    using day_t = duration<long, std::ratio<3600 * 24>>;
    auto start = system_clock::now();
    std::this_thread::sleep_for(seconds(1));
    auto end = system_clock::now();
    auto dur = end - start;
    auto d = duration_cast<day_t>(dur);
    auto h = duration_cast<hours>(dur -= d);
    auto m = duration_cast<minutes>(dur -= h);
    auto s = duration_cast<seconds>(dur -= m);
    auto ms = duration_cast<seconds>(dur -= s);
    std::cout << d.count() << " days, "
        << h.count() << " hours, "
        << m.count() << " minutes, "
        << s.count() << " seconds, "
        << ms.count() << " milliseconds\n";

    return 0;
}

输出:

可能重复:Extract year/month/day etc. from std::chrono::time_point in C++

【讨论】:

    【解决方案2】:

    这是一个使用可变参数模板和递归的易于扩展的解决方案。为了便于使用,它定义了ostream&amp; operator&lt;&lt;(ostream&amp;, const duration&amp;)

    #include <chrono>
    #include <iostream>
    #include <tuple>
    
    using day_t = std::chrono::duration<long long, std::ratio<3600 * 24>>;
    
    template<typename> struct duration_traits {};
    
    #define DURATION_TRAITS(Duration, Singular, Plural) \
    template<> struct duration_traits<Duration> { \
        constexpr static const char* singular = Singular; \
        constexpr static const char* plural = Plural; \
    }
    
    DURATION_TRAITS(std::chrono::milliseconds, "millisecond", "milliseconds");
    DURATION_TRAITS(std::chrono::seconds, "second", "seconds");
    DURATION_TRAITS(std::chrono::minutes, "minute", "minutes");
    DURATION_TRAITS(std::chrono::hours, "hour", "hours");
    DURATION_TRAITS(day_t, "day", "days");
    
    using divisions = std::tuple<std::chrono::milliseconds, 
                                 std::chrono::seconds, 
                                 std::chrono::minutes, 
                                 std::chrono::hours, 
                                 day_t>;
    
    namespace detail {
    template<typename...> struct print_duration_impl_ {};
    
    template<typename Head, typename... Tail>
    struct print_duration_impl_<Head, Tail...> {
        template <typename Duration>
        static bool print(std::ostream& os, Duration& dur) {
            const auto started_printing = print_duration_impl_<Tail...>::print(os, dur);
    
            const auto n = std::chrono::duration_cast<Head>(dur);
            const auto count = n.count();
    
            if (count == 0) {
                return started_printing;
            }
    
            if (started_printing) {
                os << ' ';
            }
    
            using traits = duration_traits<Head>;
            os << count << ' ' << (count == 1 ? traits::singular : traits::plural);
            dur -= n;
    
            return true;
        }
    };
    
    template<>
    struct print_duration_impl_<> {
        template <typename Duration>
        static bool print(std::ostream& os, Duration& dur) {
            return false;
        }
    };
    
    template<typename...> struct print_duration {};
    
    template<typename... Args>
    struct print_duration<std::tuple<Args...>> {
        template<typename Duration>
        static void print(std::ostream& os, Duration dur) {
            print_duration_impl_<Args...>::print(os, dur);
        }
    };
    }
    
    template<typename Rep, typename Period>
    std::ostream& operator<<(std::ostream& os, const std::chrono::duration<Rep, Period>& dur) {
        detail::print_duration<divisions>::print(os, dur);
        return os;
    }
    

    通过专门化duration_traits 并将类型插入到分区中的正确位置来添加新的持续时间。例如,添加一个 10 ms 的 jiffy 类型将涉及:

    using jiffy_t = std::chrono::duration<long long, std::centi>;
    DURATION_TRAITS(jiffy_t, "jiffy", "jiffies");
    
    using divisions = std::tuple<std::chrono::milliseconds, 
                                 jiffy_t,
                                 std::chrono::seconds, 
                                 std::chrono::minutes, 
                                 std::chrono::hours, 
                                 day_t>;
    

    三行代码还不错!

    ideone.com 上的实时示例。

    【讨论】:

    • 伙计,这很有趣!
    【解决方案3】:
    template<typename T>
    void print_time_diff(std::ostream& out, T prior, T latter)
    {
        namespace sc = std::chrono;
        auto diff = sc::duration_cast<sc::milliseconds>(latter - prior).count();
        auto const msecs = diff % 1000;
        diff /= 1000;
        auto const secs = diff % 60;
        diff /= 60;
        auto const mins = diff % 60;
        diff /= 60;
        auto const hours = diff % 24;
        diff /= 24;
        auto const days = diff;
    
        bool printed_earlier = false;
        if (days >= 1) {
            printed_earlier = true;
            out << days << (1 != days ? " days" : " day") << ' ';
        }
        if (printed_earlier || hours >= 1) {
            printed_earlier = true;
            out << hours << (1 != hours ? " hours" : " hour") << ' ';
        }
        if (printed_earlier || mins >= 1) {
            printed_earlier = true;
            out << mins << (1 != mins ? " minutes" : " minute") << ' ';
        }
        if (printed_earlier || secs >= 1) {
            printed_earlier = true;
            out << secs << (1 != secs ? " seconds" : " second") << ' ';
        }
        if (printed_earlier || msecs >= 1) {
            printed_earlier = true;
            out << msecs << (1 != msecs ? " milliseconds" : " millisecond");
        }
    }
    

    http://ideone.com/bBNHQp

    【讨论】:

    • 谢谢,这与我现在使用的解决方案非常相似。我想知道是否有更简洁的方式来表达分歧。例如,通过使用log10 并找到最大度量单位,打印文件大小非常简洁。不知道有没有巧妙的办法把这个转换成时间……
    猜你喜欢
    • 2013-03-24
    • 2018-10-23
    • 1970-01-01
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    • 1970-01-01
    相关资源
    最近更新 更多