5

I want to be able to put into a string the local time and date with millisecond resolution like so:

YYYY-MM-DD hh:mm:ss.sss

Seems like a simple thing to do, but I haven't found a simple answer for how to do this. I am writing in C++ and do have access to 11 compiler but am fine using a C solution if it's cleaner. I found a post here with a solution Get both date and time in milliseconds but surely it can't be that difficult given use of standard libraries. I'm probably going to move forward with that type of solution but was hoping to add to the knowledge base by asking the question here on SO.

I know this will work but again, seems unnecessarily difficult:

#include <sys/time.h>
#include <stdio.h>

int main(void)
{
    string sTimestamp;
    char acTimestamp[256];

    struct timeval tv;
    struct tm *tm;

    gettimeofday(&tv, NULL);

    tm = localtime(&tv.tv_sec);

    sprintf(acTimestamp, "%04d-%02d-%02d %02d:%02d:%02d.%03d\n",
            tm->tm_year + 1900,
            tm->tm_mon + 1,
            tm->tm_mday,
            tm->tm_hour,
            tm->tm_min,
            tm->tm_sec,
            (int) (tv.tv_usec / 1000)
        );

    sTimestamp = acTimestamp;

    cout << sTimestamp << endl;

    return 0;
}

Tried looking at put_time for C++ and strftime for the old C way. Both only allow me to get to second resolution best I can tell. You can see the two approaches I've gotten so far below. I would like to put it into a string

auto t = std::time(nullptr);
auto tm = *std::localtime(&t);
std::cout << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << std::endl;

time_t rawtime;
struct tm * timeinfo;
char buffer[80];

time (&rawtime);
timeinfo = localtime(&rawtime);

strftime(buffer,sizeof(buffer),"%Y-%m-%d %I:%M:%S",timeinfo);
std::string str(buffer);

std::cout << str;

Only thing I can figure out is to use gettimeofday and get rid of all the data except the last second and append it to the timestamp, still wish there was a cleaner approach.

Anyone find a solution that works better?

Community
  • 1
  • 1
Brian
  • 3,264
  • 4
  • 30
  • 43
  • 1
    Possible duplicate of [Getting the current time in milliseconds](http://stackoverflow.com/questions/3756323/getting-the-current-time-in-milliseconds) – Richard Critten Mar 16 '17 at 14:36
  • Have you looked in [``](http://en.cppreference.com/w/cpp/chrono)? – Cory Kramer Mar 16 '17 at 14:36
  • @RichardCritten I would not consider this a duplicate of that particular question, because that is asking about C so will not have any of the C++ libraries that provide time utilities. – Cory Kramer Mar 16 '17 at 14:37
  • I need local time, will update question – Brian Mar 16 '17 at 14:45
  • 1
    I can't think of a differet way than attaching the milliseconds after. For an approach using `` there is this old answer: https://stackoverflow.com/questions/31281293/timestamps-for-embedded-system/31281976#31281976 – Galik Mar 16 '17 at 14:47
  • Nitpick: You've got four `s` in your format but your words say `milliseconds`. Which do you really want? – Howard Hinnant Mar 16 '17 at 14:48
  • milliseconds, sorry for the typo, fixing it now – Brian Mar 16 '17 at 14:52
  • @Galik, didn't see that post, but that looks more like what I was looking for. I guess I could be marked duplicate of that question. I spent 15 minutes searching and didn't find that post though. Thanks so much!! – Brian Mar 16 '17 at 15:07

1 Answers1

6

I would recommend looking at Howard Hinnant's date library. One of the examples given in the wiki shows how to get the current local time, up to the given precision of your std::chrono::system_clock implementation (nanoseconds on Linux, from memory?):

EDIT: As Howard points out in the comments, you can use date::floor() to obtain the desired precision. So to generate a string as requested in the question, you could do something like this:

#include "tz.h"
#include <iostream>
#include <string>
#include <sstream>

std::string current_time()
{
    const auto now_ms = date::floor<std::chrono::milliseconds>(std::chrono::system_clock::now());
    std::stringstream ss;
    ss << date::make_zoned(date::current_zone(), now_ms);
    return ss.str();
}

int main()
{
    std::cout << current_time() << '\n';
} 
Tristan Brindle
  • 16,281
  • 4
  • 39
  • 82
  • 1
    Upvoted. But this gives "too much precision." :-) You can `floor(system_clock::now())` to nail the requested precision. – Howard Hinnant Mar 16 '17 at 14:46
  • Nitpick: This will include the timezone abbreviation. You can `format` the `zoned_time` returned from `make_zoned` with `"%F %T"` if the timezone abbreviation is not desired. And `format` returns a `string`. – Howard Hinnant Mar 16 '17 at 15:04
  • @HowardHinnant I really should just have left it to you to answer! Feel free to edit :) – Tristan Brindle Mar 16 '17 at 15:05
  • Not at all. I am very happy to see other people using and recommending this library! :-) I hope my suggestions are helpful. – Howard Hinnant Mar 16 '17 at 15:06