【发布时间】:2018-07-27 09:26:22
【问题描述】:
我正在尝试通过保留微秒精度将以下格式表示的字符串时间戳:“28.08.2017 03:59:55.0007”转换为 std::chrono::system_clock::time_point。 有没有办法通过使用标准库或提升来实现这一点? 谢谢。
【问题讨论】:
标签: c++ time timestamp boost-date-time
我正在尝试通过保留微秒精度将以下格式表示的字符串时间戳:“28.08.2017 03:59:55.0007”转换为 std::chrono::system_clock::time_point。 有没有办法通过使用标准库或提升来实现这一点? 谢谢。
【问题讨论】:
标签: c++ time timestamp boost-date-time
我会使用 Howard Hinnant 的日期库 https://howardhinnant.github.io/date/date.html
例如:
std::stringstream str( "28.08.2017 03:59:55.0007" );
str.imbue( std::locale() );
std::chrono::time_point< std::chrono::system_clock, std::chrono::microseconds > result;
date::from_stream( str, "%d.%m.%Y %H:%M:%S", result );
std::cout << result.time_since_epoch().count();
【讨论】:
str 灌输当前的全球语言环境,除非您预计开始小数秒的小数点字符会被本地化。您也可以使用%T 代替%H:%M:%S。唯一的区别是风格。语法str >> date::parse(format, time_point) 也有效。你可以坚持解析成std::chrono::system_clock::time_point。虽然未指定,但最粗略的运输 system_clock::time_point 具有微秒精度,足以满足此问题说明。
std::get_time 是 C++11 向前迈出的一大步。但它的致命缺陷是它的接口解析为std::tm,这仅限于秒精度。它从其规范所依赖的strptime 继承了此限制。间接地,strptime在C++11中是,只是它的接口拼写为get_time。 wg21.link/p0355 引入了 time_point 和持续时间解析功能,可以处理亚秒级精度(无需通过旧的 C API 进行交易)。
一个实现可以是:
#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);
}
【讨论】:
timegm 不是标准的。
strptime 你确定标准中存在这个吗?
strptime 不是标准的,但您可以使用标准的get_time 和stringstream。
我想添加一个答案,因为没有一个专门使用该标准的可用答案。
给定输入:istringstream timestamp("28.08.2017 03:59:55.0007"),这可以通过get_time 转换为tm,但要使用小数秒。小数秒需要手动转换(这可以通过将舍入余数除以micro 比率来构造chrono::microseconds 来完成。)所有这些都可以组合成这样的东西:
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));
【讨论】: