How to format std :: chrono durations?

Is there a convenient way to format std::chrono::durationto the specified format?

std::chrono::high_resolution_clock::time_point now, then;
then = std::chrono::high_resolution_clock::now();
// ...
now = std::chrono::high_resolution_clock::now();
auto duration = now - then;

// base in microseconds:
auto timeInMicroSec =
      std::chrono::duration_cast<std::chrono::microseconds>(duration);

How can I format timeInMicroSechow ss::ms::us?

+4
source share
4 answers

You can use something like:

#include <iomanip>
#include <sstream>

//...

auto c(timeInMicroSec.count());
std::ostringstream oss;
oss << std::setfill('0')          // set field fill character to '0'
    << (c % 1000000000) / 1000000 // format seconds
    << "::"
    << std::setw(3)               // set width of milliseconds field
    << (c % 1000000) / 1000       // format milliseconds
    << "::"
    << std::setw(3)               // set width of microseconds field
    << c % 1000;                  // format microseconds
auto formatted(oss.str());
+1
source

This takes an arbitrary duration of the chronograph and breaks it into other duration values:

template<class...Durations, class DurationIn>
std::tuple<Durations...> break_down_durations( DurationIn d ) {
  std::tuple<Durations...> retval;
  using discard=int[];
  (void)discard{0,(void((
    (std::get<Durations>(retval) = std::chrono::duration_cast<Durations>(d)),
    (d -= std::chrono::duration_cast<DurationIn>(std::get<Durations>(retval)))
  )),0)...};
  return retval;
}

Test code:

int main() {
  auto then = std::chrono::high_resolution_clock::now();
  std::this_thread::sleep_for( std::chrono::seconds(3) );
  auto now = std::chrono::high_resolution_clock::now();
  auto duration = now - then;

  auto clean_duration = break_down_durations<std::chrono::seconds, std::chrono::milliseconds, std::chrono::microseconds>( duration );
  std::cout << std::get<0>(clean_duration).count() << "::" << std::get<1>(clean_duration).count() << "::" << std::get<2>(clean_duration).count() << "\n";
}

The formatting code can be cleared and inserted into the function.

Living example .

It would be fun to write autoformats for such a set of (increasing accuracy) duration.

, ::. , 10 setw . , .

, , std::size_t .count() .

:

template<class...Durations>
std::string format_durations( std::tuple<Durations...> d ) {
  std::size_t values[]={(std::size_t)std::get<Durations>(d).count()...};
  auto ratios = get_ratios<Durations...>();

  std::stringstream ss << std::setfill('0');
  ss << values[0];

  for (std::size_t const& v:values) {
    std::size_t i = &v-values;
    if (i==0) continue;
    ss << "::" << std::setw( log_10_round_up(ratios[i-1]) ) << values[i];
  }
  return ss.str();
}

log_10_round_up get_ratios .

hh: mm: ss - , .

+8

, .
constexpr() ++ 17, , ++ 14.

template<class DurationIn, class FirstDuration, class...RestDurations>
std::string formatDuration(DurationIn d)
{   
    auto val = std::chrono::duration_cast<FirstDuration>(d);

    string out = std::to_string(val.count());

    if constexpr(sizeof...(RestDurations) > 0) {
        out += "::" + formatDuration<DurationIn, RestDurations...>(d - val);
    }

    return out;
}

template<class DurationIn>
std::string formatDuration(DurationIn) { return {}; } // recursion termination

testing mainly, outputs "77 :: 600 :: 42"

auto formattedStr = formatDuration<
    std::chrono::microseconds,
    std::chrono::seconds,
    std::chrono::milliseconds,
    std::chrono::microseconds>(77'600'042us);
+2
source

Here's the solution proposed by @jotik, but using the fmt library , which leads to a much more compact code:

#include <fmt/format.h>

auto c = timeInMicroSec.count();
auto formatted = fmt::format("{}::{:03}::{:03}",
    (c % 1'000'000'000) / 1'000'000, (c % 1'000'000) / 1'000, c % 1'000);
0
source

Source: https://habr.com/ru/post/1669270/


All Articles