Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print a bunch of integers with the same formatting?

I would like to print a bunch of integers on 2 fields with '0' as fill character. I can do it but it leads to code duplication. How should I change the code so that the code duplication can be factored out?

#include <ctime>
#include <sstream>
#include <iomanip>
#include <iostream>

using namespace std;

string timestamp() {

    time_t now = time(0);

    tm t = *localtime(&now);

    ostringstream ss;

    t.tm_mday = 9; // cheat a little to test it
    t.tm_hour = 8;

    ss << (t.tm_year+1900)
       << setw(2) << setfill('0') << (t.tm_mon+1) // Code duplication
       << setw(2) << setfill('0') <<  t.tm_mday
       << setw(2) << setfill('0') <<  t.tm_hour
       << setw(2) << setfill('0') <<  t.tm_min
       << setw(2) << setfill('0') <<  t.tm_sec;

    return ss.str();
}

int main() {

    cout << timestamp() << endl;

    return 0;
}

I have tried

std::ostream& operator<<(std::ostream& s, int i) {

    return s << std::setw(2) << std::setfill('0') << i;
}

but it did not work, the operator<< calls are ambigous.


EDIT I got 4 awesome answers and I picked the one that is perhaps the simplest and the most generic one (that is, doesn't assume that we are dealing with timestamps). For the actual problem, I will probably use std::put_time or strftime though.

like image 688
Ali Avatar asked Sep 16 '25 07:09

Ali


2 Answers

In C++20 you'll be able to do this with std::format in a less verbose way:

    ss << std::format("{}{:02}{:02}{:02}{:02}{:02}",
                      t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
                      t.tm_hour, t.tm_min, t.tm_sec);

and it's even easier with the {fmt} library that supports tm formatting directly:

auto s = fmt::format("{:%Y%m%d%H%M%S}", t);
like image 65
vitaut Avatar answered Sep 17 '25 23:09

vitaut


You need a proxy for your string stream like this:

struct stream{
    std::ostringstream ss;
    stream& operator<<(int i){
        ss << std::setw(2) << std::setfill('0') << i;
        return *this; // See Note below
    }
}; 

Then your formatting code will just be this:

stream ss;
ss << (t.tm_year+1900)
   << (t.tm_mon+1)
   << t.tm_mday
   << t.tm_hour
   << t.tm_min
   << t.tm_sec;

return ss.ss.str();

ps. Note the general format of my stream::operator<<() which does its work first, then returns something.

like image 28
quamrana Avatar answered Sep 17 '25 22:09

quamrana