C++11 actual system time with milliseconds

19,114

Solution 1

Using code from this answer:

#include <chrono>
#include <ctime>
#include <iostream>

template <typename Duration>
void print_time(tm t, Duration fraction) {
    using namespace std::chrono;
    std::printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u]\n", t.tm_year + 1900,
                t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
                static_cast<unsigned>(fraction / milliseconds(1)));

    // VS2013's library has a bug which may require you to replace
    // "fraction / milliseconds(1)" with
    // "duration_cast<milliseconds>(fraction).count()"
}

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

    system_clock::time_point now = system_clock::now();
    system_clock::duration tp = now.time_since_epoch();

    tp -= duration_cast<seconds>(tp);

    time_t tt = system_clock::to_time_t(now);

    print_time(*gmtime(&tt), tp);
    print_time(*localtime(&tt), tp);
}

One thing to keep in mind is that the fact that the timer returns values of sub-millisecond denominations does not necessarily indicate that the timer has sub-millisecond resolution. I think Windows' implementation in VS2015 may finally be fixed, but the timer they've been using to back their chrono implementation so far has been sensitive to the OS timeBeginPeriod() setting, displaying varying resolution, and the default setting is I think 16 milliseconds.

Also the above code assumes that neither UTC nor your local timezone are offset from the epoch of std::chrono::system_clock by a fractional second value.


Example of using Howard's date functions to avoid ctime: http://coliru.stacked-crooked.com/a/98db840b238d3ce7

Solution 2

This answer still uses a bit of C API but is only used in the function, so you can forget about it:

template<typename T>
void print_time(std::chrono::time_point<T> time) {
    using namespace std;
    using namespace std::chrono;

    time_t curr_time = T::to_time_t(time);
    char sRep[100];
    strftime(sRep,sizeof(sRep),"%Y-%m-%d %H:%M:%S",localtime(&curr_time));

    typename T::duration since_epoch = time.time_since_epoch();
    seconds s = duration_cast<seconds>(since_epoch);
    since_epoch -= s;
    milliseconds milli = duration_cast<milliseconds>(since_epoch);

    cout << '[' << sRep << ":" << milli.count() << "]\n";
}

This is merely a rewrite of the code that bames53, but using strftime to shorten the code a bit.

Share:
19,114
ziggy
Author by

ziggy

Updated on July 18, 2022

Comments

  • ziggy
    ziggy almost 2 years

    I've got a problem with getting actual system time with milliseconds. The only one good method I found is in Windows.h, but I can't use it. I'm supposed to use std::chrono. How can I do this?

    I spent a lot of time trying to google it, but I found only second-precision examples.

    I'm trying to get string like this:

    [2014-11-25 22:15:38:449]
    
  • Alex
    Alex over 9 years
    You only need to subtract the seconds from tp because it converts the duration in second, however many they might be. Only seconds s = duration_cast<seconds>(tp); tp -= s;
  • bames53
    bames53 over 9 years
    That's true, the other values are only used in the 'debug' code for displaying the full duration.
  • Howard Hinnant
    Howard Hinnant over 9 years
    And if you don't want to trudge through the C API you can do something like this: howardhinnant.github.io/…?
  • Jay Miller
    Jay Miller over 9 years
    I was pulling together a work-around like this and saw "If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated". That implies that we don't know if we can just add the milliseconds because the seconds out of to_time_t() may be one tick higher. Am I right about that?
  • bames53
    bames53 over 9 years
    @JayMiller Yeah, that's true. I'm not certain what most implementations do. You may want to just go ahead and use Howard's date functions to replace to_time_t() yourself.
  • Jonathan Wakely
    Jonathan Wakely over 9 years
    The %03u conversion assumes the duration<...>::rep is 32-bit. Another way to do it is std::cout << std::put_time(&t, "[%Y-%m-%d %H:%M:%S.") << std::setprecision(3) << std::setfill('0') << fraction / milliseconds(1) << "]\n";
  • bames53
    bames53 over 9 years
    @JonathanWakely True, and the spec actually requires more bits for std::chrono::milliseconds. I'm actually relying on printf format checking to catch that, which unfortunately VS doesn't yet provide (except in their static analysis tool I think). You can see in my second example where I caught this thanks to compiler warnings. I've fixed the first example now.
  • Everyone
    Everyone over 6 years
    If I'm not mistaken strftime is not available on Windows.
  • paxdiablo
    paxdiablo almost 6 years
    Since strftime is part of the C++ standard (in ctime), I suspect it is available in Windows.