1

I have been looking around to get what I want but I couldn't find anything hence my question (hopefully not a duplicate!)

I am looking to get a microsecond resolution epoch time (to be converted to a Date string) of the clock perhaps using chrono.

Following is what works for me for seconds resolution:

auto secondsEpochTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
std::cout << "Date string = " << ctime(&secondsEpochTime);

However when I change seconds to microseconds, ctime doesn't seem to reflect the correct date.

auto microSecondsEpochTime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
std::cout << "Date string = " << ctime(&microSecondsEpochTime); // incorrect Date
xyf
  • 664
  • 1
  • 6
  • 16
  • If on Linux, [here's an approach I wrote which works in C and C++](https://stackoverflow.com/a/71889097/4561887), but it doesn't use `std::chrono`. – Gabriel Staples Oct 02 '22 at 04:35

2 Answers2

1

You will have to use parts of the C library until C++23 at least

Umm... If your platform supports the full C++20 spec (at least with regards to format and chrono):

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

int
main()
{
    auto tp = std::chrono::system_clock::now();
    std::chrono::zoned_time zt{std::chrono::current_zone(),
        std::chrono::time_point_cast<std::chrono::microseconds>(tp)};
    std::cout << "Date string = " << std::format("{:%a %b %e %T %Y}", zt) << '\n';
}

Sample output:

Date string = Sat Oct  1 23:32:24.843844 2022
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • seemingly there needs to be more work to be done to include format https://onlinegdb.com/sz8hXJieY – xyf Oct 02 '22 at 03:48
  • MSVC/latest is the only platform I'm aware of that is shipping so far. There's a free, open-source preview of this here: https://github.com/HowardHinnant/date that works with C++11/14/17. If you don't need time zone support (you do for `current_zone()`), then you can use the header-only date.h portion of the library. To get time zone support you need tz.h/tz.cpp. – Howard Hinnant Oct 02 '22 at 12:31
0

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();
}
Something Something
  • 3,999
  • 1
  • 6
  • 21