Unfortunately std::chrono is not complete to provide a full answer to your question. You will have to use parts of the C library until C++23 at least otherwise you might end up with a race-prone implementation.
The idea is to get the timestamp and convert it to an integer as microseconds since epoch (1970-01-01).
Then use localtime_r
to get the local time broken down in year/month/day/hour/minute/seconds and print it to string.
Finally append the milliseconds as an int padded to 3 digits and return the entire result as an std::string.
constexpr static int64_t ONEMICROSECOND = 1000000;
static std::string nowstr() {
auto now = std::chrono::system_clock::now();
auto onems = std::chrono::microseconds(1);
int64_t epochus = now.time_since_epoch()/onems;
time_t epoch = epochus/ONEMICROSECOND;
struct tm tms{};
localtime_r( &epoch, &tms );
char buf[128];
size_t nb = strftime( buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tms );
nb += ::sprintf( &buf[nb], ".%06d", int(epochus%ONEMICROSECOND) );
return std::string( buf, nb );
}
If you run this as-is it will likely return the timestamp in GMT. You will heave to set your timezone programatically if not set in the environment (as it happens with compiler explorer/Godbolt.
int main() {
setenv("TZ", "/usr/share/zoneinfo/America/New_York", 1);
std::cout << nowstr() << std::endl;
}
Results in
Program stdout
2022-10-01 22:51:03.988759
Compiler explorer link: https://godbolt.org/z/h88zhrr73
UPDATE: if you prefer to use boost::format (std::format is still incomplete on most compilers unfortunately) then you can do
static std::string nowstr() {
auto now = std::chrono::system_clock::now();
auto onems = std::chrono::microseconds(1);
int64_t epochus = now.time_since_epoch()/onems;
time_t epoch = epochus/ONEMICROSECOND;
struct tm tms{};
localtime_r( &epoch, &tms );
std::ostringstream ss;
ss << boost::format( "%04d-%02d-%02d %02d:%02d:%02d.%06d" )
% (tms.tm_year+1900) % (tms.tm_mon+1) % tms.tm_mday
% tms.tm_hour % tms.tm_min % tms.tm_sec
% (epochus%ONEMICROSECOND);
return ss.str();
}