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.
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.
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.
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 .
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With