Here is a version that allows you to inline a duration with operator<<
It only prints what is necessary and allows setting the precision you want:
#include <chrono>
#include <iomanip>
#include <optional>
#include <ostream>
std::ostream& operator<<(std::ostream& os, std::chrono::nanoseconds ns)
{
using namespace std::chrono;
using days = duration<int, std::ratio<86400>>;
auto d = duration_cast<days>(ns);
ns -= d;
auto h = duration_cast<hours>(ns);
ns -= h;
auto m = duration_cast<minutes>(ns);
ns -= m;
auto s = duration_cast<seconds>(ns);
ns -= s;
std::optional<int> fs_count;
switch (os.precision()) {
case 9: fs_count = ns.count();
break;
case 6: fs_count = duration_cast<microseconds>(ns).count();
break;
case 3: fs_count = duration_cast<milliseconds>(ns).count();
break;
}
char fill = os.fill('0');
if (d.count())
os << d.count() << "d ";
if (d.count() || h.count())
os << std::setw(2) << h.count() << ":";
if (d.count() || h.count() || m.count())
os << std::setw(d.count() || h.count() ? 2 : 1) << m.count() << ":";
os << std::setw(d.count() || h.count() || m.count() ? 2 : 1) << s.count();
if (fs_count.has_value())
os << "." << std::setw(os.precision()) << fs_count.value();
if (!d.count() && !h.count() && !m.count())
os << "s";
os.fill(fill);
return os;
}
Here are some usage examples:
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono_literals;
int main()
{
cout << 918734032564785ns << "\n";
cout << setprecision(3) << 918734032564785ns << "\n";
cout << setprecision(9) << 918734032564785ns << "\n";
cout << setprecision(0) << 918734032564785ns << "\n";
cout << setprecision(3) << 432034ms << "\n";
cout << 14h + 32min + 37s + 645ms << "\n";
cout << 86472s << "\n";
cout << 4324ms << "\n";
return 0;
}
Output:
10d 15:12:14.032564
10d 15:12:14.032
10d 15:12:14.032564785
10d 15:12:14
7:12.034
14:32:37.645
1d 00:01:12.000
4.324s