fmt format %H:%M:%S without decimals

504 views Asked by At

I am trying to format a std::chrono::duration object to the format HH:MM::SS, e.g. 16:42:02 being the hours (16), the minutes (42), and the seconds (2).

the library fmt offers useful formatting specifiers for this:

using namespace std::chrono;

auto start = high_resolution_clock::now();
auto end = start + 4s;
fmt::print("{:%H:%M:%S} \n", end);

which unfortuantely prints the seconds in decimals

16:58:55.359425076 

I want to round this to the nearest integer, but cannot figure out where to place the precision specifier (precision 2 merely test-wise):

fmt::print("{:.2%H:%M:%S} \n", end);  // error
fmt::print("{:.2f%H:%M:%S} \n", end);  // error 
fmt::print("{:%H:%M:.2%S} \n", end);  // nonsense: 17:07:.202.454873454 

I am a bit lost staring at the details of the formatspec for chrono...

A compiler explorer example of the above is here.

2

There are 2 answers

0
Howard Hinnant On BEST ANSWER

To round to the nearest second, convert your time point to seconds precision using round<seconds>(tp). Also, high_resolution_clock has no portable relationship to the calendar. You need to use system_clock instead. For gcc, high_resolution_clock is a type alias of system_clock, so it works by accident. But this will fail to compile using MSVC or LLVM tools.

#include <fmt/chrono.h>
#include <fmt/format.h>

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

int main() {
    using namespace std::chrono;

    auto start = round<seconds>(system_clock::now());
    auto end = start + 4s;
    fmt::print("{:%H:%M:%S} \n", end);
}

Demo.

If you would like other rounding modes you can use floor or ceil as well.

0
Toby Speight On

I don't know how well this converts to <fmt> but for the Standard C++ <format>, you could possibly get whole seconds as your locale's alternative representation using the %OS specifier.

Or we can use the locale's representation of the whole time, using %X or %EX.

Certainly, this works on my Debian system (note we pass the "C" locale to format()):

#include <chrono>
#include <format>
#include <iostream>
#include <locale>

int main()
{
    using clock = std::chrono::system_clock;

    std::cout << std::format(std::locale::classic(), "{:%X} \n", clock::now());
}

Produces (for example):

16:42:02