4

Does anybody know of a fast, portable way for parsing date/time strings which contain fractional seconds?

For example:

2017-10-23T07:23:08.78

Thus far I can parse everything else with:

std::tm tm = {};
std::stringstream datestr("2017-10-23T07:23:08.78");
datestr >> std::get_time(&tm, "%Y-%m-dT%H:%M:%S.??");

The above snippet was modified from this post.

This other post shows the clever trick of parsing the year twice. Unfortunately, since the fractional second is the last field in my representation, it will overwrite whatever valid field I actually want to use.

The reference documentation (here) does not list any conversion specifier for fractional seconds nor does it list any specifier which can be used to match and discard arbitrary digits (same as %t or %n for whitespace.

To be clear, I am perfectly OK with discarding this portion of the precision. I would prefer not to manipulate it with raw string functions but that seems the only option I can find.

Finally, this string is coming from a remote server so the format is out of my control. My environment is currently Posix though I would prefer as much portability as reasonably possible.


Edit: This question has been flagged as a duplicate of this. I do not believe this to be so as my question is specifically about parsing / discarding tokens which do not have a character specifier. This is unique from the other post which uses, for example, %z to parse timezone (of which I am also not interested in). My question is specifically targeted at parsing, not interpretation of the resultant value.

MysteryMoose
  • 2,211
  • 4
  • 23
  • 47
  • Possible duplicate of [C/C++ time zone correct time conversion (to seconds since epoch)](https://stackoverflow.com/questions/33421450/c-c-time-zone-correct-time-conversion-to-seconds-since-epoch) – Daniel H Oct 24 '17 at 03:28
  • 1
    Well, a `std::tm` doesn't have anywhere to put fractional seconds. So it's hard to imagine doing anything other than just getting the last value yourself after `get_time` advances the stream. – aschepler Oct 24 '17 at 03:29
  • 1
    i use date.h from howardhinnant - totally works fine for me :D https://github.com/HowardHinnant/date/blob/master/include/date/date.h https://howardhinnant.github.io/date/date.html – inxoy Oct 24 '17 at 06:58

1 Answers1

4

Building on the great comment from inxoy above, here is how you could do it with Howard Hinnant's, free, open-source, portable, datetime library:

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

int
main()
{
    std::stringstream datestr("2017-10-23T07:23:08.78");
    date::sys_time<std::chrono::milliseconds> tp;
    datestr >> date::parse("%FT%T", tp);
    if (datestr.fail())
        return 1;
    std::cout << date::format("%F %T\n", tp);
}

date::sys_time<std::chrono::milliseconds> is a type alias for a std::chrono::system_clock::time_point, except with milliseconds precision (you can use any precision you want).

"%F" is a short cut for "%Y-%m-%d", you can use either interchangeably.

If you want it in a std::tm, the wiki page shows how to do this, along with tons of other example code.

The program above portably outputs:

2017-10-23 07:23:08.780

I could have instead used:

std::chrono::system_clock::time_point tp;

and this would have changed my output to:

2017-10-23 07:23:08.780000

The %T formatter will output whatever precision your time_point has, and the %T parser will parse up to as many decimal digits as your time_point has.

"date/date.h" doesn't do time zones. It is strictly UTC (technically Unix Time). If you need to work with time zones (or leap seconds), there is an additional free, open-source IANA time zone library available which builds on top of "date/date.h".

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • What is the additional time (on average, as a rough percentag estimate) for using your library over basic STL time functions? I ask as this is going into API response code so performance is a bit of a concern. A 10% time increase will not break the bank but, say, doubling parse time will be a problem. – MysteryMoose Oct 25 '17 at 16:57
  • If what you're comparing to is another solution parsing from `std::istringstream`, very competitive. The main expense can be the actual use of C++ I/O itself. `date/date.h` is a header-only library (with only one header), so it is very easy for you to download from GitHub and run a timing experiment. Just point at the header and go. – Howard Hinnant Oct 25 '17 at 17:03
  • Hmmm... and now that I think about it, use of `"%F"` over `"%Y-%m-%d"` is going to shave a few cycles off since the parser only has to parse one command instead of 3. – Howard Hinnant Oct 25 '17 at 17:07