2014-02-27 5 views
10

Это то, что я хотел бы сделать на C++ 11: учитывая два момента времени (например, класс времени) как std::chrono::steady_clock::now(), напечатайте их разницу во времени элегантно, например:Elegant time print in C++ 11

1 day 4 hours 3 minutes 45 seconds 

или

32 minutes 54 seconds 345 milliseconds 

Пожалуйста, обратите внимание, что я не заинтересован в использовании просто put_time, так как я хочу, чтобы напечатать начиная с наиболее значительными единичным времени. Я знаю, это решение просто распечатать разницу, но это не очень: я ищу элегантный решение :)

Cheers!

+0

Какое решение у вас есть прямо сейчас? – RedX

+0

Использование пользовательского форматирования 'put_time', основанного на последующем делении на дни, часы, ..., вроде как @Simple. Но я надеюсь найти что-нибудь красивее! :) – senseiwa

+0

@senseiwa Я не понимаю. * «Меня не интересует просто использование put_time, так как я хочу печатать, начиная с самой значительной единицы времени». * Почему вы не можете использовать 'put_time' для начала с самого значительного периода времени? Боюсь, я упускаю момент. – Ali

ответ

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

+0

Спасибо, это очень похоже на решение, которое я использую прямо сейчас. Мне было интересно, есть ли более совпадающий способ выражения разделов. Например, размеры файлов печати довольно совпадают, используя 'log10' и находя максимальную единицу измерения. Я не знаю, есть ли умный способ транспонирования этого времени ... – senseiwa

3

Продолжительность может выполнять арифметические действия.

#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; 
} 

Выход:

enter image description here

Возможный дубликат: Extract year/month/day etc. from std::chrono::time_point in C++

3

Вот легко расширяемой решение с использованием VARIADIC шаблонов и рекурсию. Он определяет ostream& operator<<(ostream&, const duration&) для удобства использования.

#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-миллисекундного типа включает в себя:

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.

+1

Человек, это очень интересно! – senseiwa