New answer for old question. Rationale: updated tools.
Using this free, open source library, one can parse into a std::chrono::time_point<system_clock, milliseconds>
, which has the advantage over a tm
of being able to hold millisecond precision. And if you really need to, you can continue on to the C API via system_clock::to_time_t
(losing the milliseconds along the way).
#include "date.h"
#include <iostream>
#include <sstream>
date::sys_time<std::chrono::milliseconds>
parse8601(std::istream&& is)
{
std::string save;
is >> save;
std::istringstream in{save};
date::sys_time<std::chrono::milliseconds> tp;
in >> date::parse("%FT%TZ", tp);
if (in.fail())
{
in.clear();
in.exceptions(std::ios::failbit);
in.str(save);
in >> date::parse("%FT%T%Ez", tp);
}
return tp;
}
int
main()
{
using namespace date;
using namespace std;
cout << parse8601(istringstream{"2014-11-12T19:12:14.505Z"}) << '\n';
cout << parse8601(istringstream{"2014-11-12T12:12:14.505-5:00"}) << '\n';
}
This outputs:
2014-11-12 19:12:14.505
2014-11-12 17:12:14.505
Note that both outputs are UTC. The parse
converted the local time to UTC using the -5:00
offset. If you actually want local time, there is also a way to parse into a type called date::local_time<milliseconds>
which would then parse but ignore the offset. One can even parse the offset into a chrono::minutes
if desired (using a parse
overload taking minutes&
).
The precision of the parse is controlled by the precision of the chrono::time_point
you pass in, instead of by flags in the format string. And the offset can either be of the style +/-hhmm
with %z
, or +/-[h]h:mm
with %Ez
.