Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to parse a millisecond date time in C++11

Tags:

c++

c++11

c++14

What would be the next best thing for strptime when we have the datetime string with millisseconds?

Given:

"30/03/09 16:31:32.121"

we can't use the regular strptime because struct tm doesn't store millisseconds. Is there a new class that can achieve this?

like image 370
Nezquick Avatar asked Oct 23 '14 21:10

Nezquick


1 Answers

I would parse these fields manually (reading into int and double for the seconds), then use days_from_civil to convert the year/month/day into a chrono::system_clock::time_point:

std::chrono::system_clock::time_point t(days(days_from_civil(y, m, d)));

where days is:

using days = std::chrono::duration<int, std::ratio<86400>>;

Then you can add to that the hours, minutes and seconds. To handle the fractional seconds you'll need to do a slight dance:

double s;
your_stream >> s;  // 32.121
using namespace std::chrono;
duration<double> dsecs(s);
seconds sec = duration_cast<seconds>(dsecs);
milliseconds ms = duration_cast<milliseconds>(dsecs - sec);
t += sec + ms;

If you prefer, use round from here for your milliseconds conversion:

milliseconds ms = round<milliseconds>(dsecs - sec);

duration_cast is truncate towards zero. There are other rounding modes: floor, round, ceil, at this link.

Wrap it all up in a neat function for easy reuse. :-)

The above code all assumes UTC. If your date/time that you are parsing is known to be offset from UTC, you can add/subtract that offset. All known implementations of system_clock track Unix time, which is seconds since 1970-01-01 in the UTC time zone.

Update

Since writing this answer I've developed a more general library that the OP seemed to be seeking at that time. It can parse a wide variety of sub second precisions directly into a std::chrono::system_clock::time_point like this:

#include "date/date.h"
#include <iostream>
#include <sstream>

int
main()
{
    std::istringstream in{"30/03/09 16:31:32.121\n"
                          "30/03/09 16:31:32.1214"};
    std::chrono::system_clock::time_point tp;
    in >> date::parse("%d/%m/%y %T", tp);
    using namespace date;
    std::cout << tp << '\n';
    in >> date::parse(" %d/%m/%y %T", tp);
    std::cout << tp << '\n';
}

This outputs:

2009-03-30 16:31:32.121000
2009-03-30 16:31:32.121400

This library uses the same techniques and tools as I originally described, but is packaged up and ready to go as a single header library.

like image 175
Howard Hinnant Avatar answered Nov 19 '22 17:11

Howard Hinnant