Search code examples
c++c++17c++-chrono

How to convert chrono::seconds to string in HH:MM:SS format in C++?


I have a function which accepts second as argument and returns a string in HH:MM:SS format. Without std::chrono, I can implement it like this:

string myclass::ElapsedTime(long secs) {
  uint32_t hh = secs / 3600;
  uint32_t mm = (secs % 3600) / 60;
  uint32_t ss = (secs % 3600) % 60;
  char timestring[9];
  sprintf(timestring, "%02d:%02d:%02d", hh,mm,ss);
  return string(timestring);
}

Using std::chrono, I can convert the argument to std::chrono::seconds sec {seconds};.

But the how can I convert it to string with the format? I saw the good video tutorial from Howard Hinnant in https://youtu.be/P32hvk8b13M. Unfortunately, there is no example for this case.


Solution

  • Using Howard Hinnant's header-only date.h library it looks like ths:

    #include "date/date.h"
    #include <string>
    
    std::string
    ElapsedTime(std::chrono::seconds secs)
    {
        return date::format("%T", secs);
    }
    

    If you want to write it yourself, then it looks more like:

    #include <chrono>
    #include <string>
    
    std::string
    ElapsedTime(std::chrono::seconds secs)
    {
        using namespace std;
        using namespace std::chrono;
        bool neg = secs < 0s;
        if (neg)
            secs = -secs;
        auto h = duration_cast<hours>(secs);
        secs -= h;
        auto m = duration_cast<minutes>(secs);
        secs -= m;
        std::string result;
        if (neg)
            result.push_back('-');
        if (h < 10h)
            result.push_back('0');
        result += to_string(h/1h);
        result += ':';
        if (m < 10min)
            result.push_back('0');
        result += to_string(m/1min);
        result += ':';
        if (secs < 10s)
            result.push_back('0');
        result += to_string(secs/1s);
        return result;
    }
    

    In C++20, you'll be able to say:

    std::string
    ElapsedTime(std::chrono::seconds secs)
    {
        return std::format("{:%T}", secs);
    }