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.