Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ parse date/time with microseconds

I am using strptime to parse a date and time with a specific format. The format uses the Python formatting directives, which are exactly the same as the C directives except there is an additional %f directive in Python for milliseconds defined as Microsecond as a decimal number, zero-padded on the left.. So for example:

std::tm tmb;
strptime("2010-12-30T01:20:30.0Z", "%Y-%m-%dT%H:%M:%S.%fZ", &tmb);

This would cause a parsing error because of the %f. I cannot do a straight remove because directives like %m and %d can take either one or two digits.

Additionally, this is a problem because the %f directive can take from 1 to 6 digits. Is there a way to work around this issue?

I am working in C++, if there are any built-in functions that can help.

like image 331
Mohak Saxena Avatar asked Jun 06 '17 19:06

Mohak Saxena


People also ask

What is ffff in timestamp?

The "fff" custom format specifier represents the three most significant digits of the seconds fraction; that is, it represents the milliseconds in a date and time value.

How are milliseconds represented in date format?

Usually we display time in in 12 hour format hh:mm:aa format (e.g. 12:30 PM) or 24 hour format HH:mm (e.g. 13:30), however sometimes we also want to show the milliseconds in the time. To show the milliseconds in the time we include “SSS” in the pattern which displays the Milliseconds.

How do you convert DateTime to milliseconds?

A simple solution is to get the timedelta object by finding the difference of the given datetime with Epoch time, i.e., midnight 1 January 1970. To obtain time in milliseconds, you can use the timedelta. total_seconds() * 1000 .


1 Answers

Using Howard Hinnant's free, open-source, C++11, header-only datetime library, you can easily parse any precision you want. You just can't put it into a tm since that is limited to seconds precision.

For example:

#include "date.h"
#include <cassert>
#include <sstream>

int
main()
{
    std::chrono::system_clock::time_point tp;
    std::istringstream ss{"2010-12-30T01:20:30.123456Z"};
    ss >> date::parse("%FT%TZ", tp);
    assert(!ss.fail());
    using namespace date;
    using namespace std::chrono_literals;
    assert(tp == sys_days(2010_y/dec/30) + 1h + 20min + 30s + 123456us);
}

This uses C++14 chrono literals. If you're in C++11, the last two lines would look like:

    using namespace std::chrono;
    assert(tp == sys_days(2010_y/dec/30) + hours{1} + minutes{20} +
                                           seconds{30} + microseconds{123456});

If you're stuck with pre-<chrono> C++ (C++98/C++03), this library won't help you.

The precision of the parse is controlled by the precision of the time_point that you input into the parse function, instead of by a formatting flag. The parse will attempt to parse as many decimal digits as your time_point will hold, but will gracefully give up if it gets less digits:

sys_time<nanoseconds> tp; // type-alias for a system_clock::time_point
                          //   with nanoseconds precision
ss >> date::parse("%FT%TZ", tp);  // still ok

If there are more digits than needed, the parse will fail, but only because it won't see the trailing (required) Z:

sys_time<milliseconds> tp;
ss >> date::parse("%FT%TZ", tp);
assert(ss.fail());  // found "4" instead of "Z"

If the Z hadn't been part of the format, it would have parsed "2010-12-30T01:20:30.123" into the milliseconds-precsion time_point.

This library has complete parsing and formatting facilities available, built on top of the std <chrono> library, so that you never have to deal with the ancient tm structure. But you can convert to/from tm (at seconds precision) for communicating with other code if you need to.

"%F" is a shortcut for "%Y-%m-%d". You can use either.

"%T" is a shortcut for "%H:%M:%S". You can use either.

like image 156
Howard Hinnant Avatar answered Oct 07 '22 00:10

Howard Hinnant