2

I need to get the current UTC date in a printable format down to the milliseconds in c++11. I need this to run on Windows and Linux, so cross platform code is preferred. If this is impossible I can write two separate implementations.

This is what I have tried:

std::chrono::time_point<std::chrono::high_resolution_clock> time = std::chrono::system_clock::now();
std::time_t tt = std::chrono::high_resolution_clock::to_time_t(time);

struct tm* utc = nullptr;
gmtime_s(utc, &tt);

char buffer[256];
std::strftime(buffer, sizeof(buffer), "%Y-%m-%dT-%H:%M:%S. %MILLESECONDS???, utc);

Though as you can see this does NOT get it down to the milliseconds. I can format the string myself if I need to as long as I can get a millisecond value somehow.

marsh
  • 2,592
  • 5
  • 29
  • 53
  • You're not going to be able to get milliseconds from a `std::tm` object--[they don't store that information](http://en.cppreference.com/w/cpp/chrono/c/tm) – jaggedSpire Oct 17 '16 at 15:42
  • 3
    https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes#since_midnight #research – Lightness Races in Orbit Oct 17 '16 at 15:44
  • 1
    On Linux, [`gettimeofday()`](https://linux.die.net/man/2/gettimeofday) can give usec resolution; on Windows, there is [`GetLocalTime()`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724338(v=vs.85).aspx), which returns ms resolution (or `GetSystemTime` for UTC). – Karsten Koop Oct 17 '16 at 15:44
  • time_t will handle up to seconds only, but every second increment can trigger a counter thread which will count up to 1000ms using std::chrono , the value of which can be printed in the main thread. – seccpur Oct 17 '16 at 15:52
  • @LightnessRacesinOrbit does that return the milliseconds since midnight? Or a date format with milliseconds. I still have to do all the work to convert that to a usable date with leap years etc. It can be done, but I was hoping not to reinvent the wheel. – marsh Oct 17 '16 at 16:19
  • @marsh: What is the difference? What other milliseconds count would you use in a datestamp? Get the date and time as usual, then append the milliseconds... – Lightness Races in Orbit Oct 17 '16 at 16:20
  • 1
    I've updated my answer (http://stackoverflow.com/a/12844843/576911) to specifically answer this question. – Howard Hinnant Oct 17 '16 at 16:38
  • @LightnessRacesinOrbit one is the total milliseconds and one is the remaining milliseconds left until the next second. – marsh Oct 17 '16 at 16:45
  • @marsh: Either of them is trivially converted to what you need using basic arithmetic! What am I missing? – Lightness Races in Orbit Oct 17 '16 at 16:49
  • @LightnessRacesinOrbit I think I am misunderstanding some basic principle, but to convert millseconds to a valid date time do you not have to account for leap years, leap seconds etc. Makes more sense to me to use a pre existing solution and avoid any mistakes in writing your own time class. – marsh Oct 17 '16 at 16:51
  • @marsh: I don't see why; milliseconds do not care what days or hours have been skipped or added. Just apply `% 1000` and you're done! All this requires is an epoch that is a whole number of seconds (so your millis aren't offset), and I'm not aware of any widely-used epoch that is not at a one-second boundary. Even if you used one, again a simple addition/subtraction will get you back to where you need to be. – Lightness Races in Orbit Oct 17 '16 at 16:53
  • @LightnessRacesinOrbit Ok I think I understand now. You are right, I can get the date time normally then use this for the milliseconds. Thanks. – marsh Oct 17 '16 at 17:11

1 Answers1

2

time_t contains seconds only, so you can use std::chrono functions for more precision:

#include <iostream>
#include <chrono>

int main() 
{
    typedef std::chrono::system_clock clock_type;

    auto now = clock_type::now();
    auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
    auto fraction = now - seconds;
    time_t cnow = clock_type::to_time_t(now);

    auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(fraction);
    std::cout << "Milliseconds: " << milliseconds.count() << '\n';
}
Evgeniy
  • 2,481
  • 14
  • 24