I am trying to convert a string timestamp expressed in the following format: "28.08.2017 03:59:55.0007" to a std::chrono::system_clock::time_point by preserving the microseconds precision. Is there any way to achieve this by using the standard library or boost? Thanks.
C++ Convert a string timestamp to std::chrono::system_clock::time_point
4.4k views Asked by Michal Turlik At
3
There are 3 answers
12
On
One implementation can be:
#include <ctime>
#include <cmath>
#include <chrono>
#include <string>
#include <cstdint>
#include <stdexcept>
std::chrono::system_clock::time_point parse_my_timestamp(std::string const& timestamp) {
auto error = [×tamp]() { throw std::invalid_argument("Invalid timestamp: " + timestamp); };
std::tm tm;
auto fraction = ::strptime(timestamp.c_str(), "%d.%m.%Y %H:%M:%S", &tm);
if(!fraction)
error();
std::chrono::nanoseconds ns(0);
if('.' == *fraction) {
++fraction;
char* fraction_end = 0;
std::chrono::nanoseconds fraction_value(std::strtoul(fraction, &fraction_end, 10));
if(fraction_end != timestamp.data() + timestamp.size())
error();
auto fraction_len = fraction_end - fraction;
if(fraction_len > 9)
error();
ns = fraction_value * static_cast<std::int32_t>(std::pow(10, 9 - fraction_len));
}
else if(fraction != timestamp.data() + timestamp.size())
error();
auto seconds_since_epoch = std::mktime(&tm); // Assumes timestamp is in localtime. For UTC use timegm.
auto timepoint_ns = std::chrono::system_clock::from_time_t(seconds_since_epoch) + ns;
return std::chrono::time_point_cast<std::chrono::system_clock::duration>(timepoint_ns);
}
0
On
Thought I'd add an answer since there isn't one available that exclusively uses the standard.
Given the input: istringstream timestamp("28.08.2017 03:59:55.0007"), this could be converted to a tm via get_time, but for the fractional seconds. The fractional seconds would need to be converted manually (this could be done by constructing chrono::microseconds from the rounded remainder divided by the micro ratio.) All this could be combined into something like this:
tm tmb;
double r;
timestamp >> get_time(&tmb, "%d.%m.%Y %T") >> r;
const auto output = chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::from_time_t(mktime(&tmb))) + chrono::microseconds(lround(r * micro::den));
I'd make use of Howard Hinnant's date library https://howardhinnant.github.io/date/date.html
e.g.: