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