std::chrono::time_point from std::string

std::chrono::time_point from std::string

本文关键字:std from string point time chrono      更新时间:2023-10-16

我正在尝试将日期(以std::string的形式(转换为std::chrono::time_point。为此,我使用提升日期时间。 下面,您可以找到一个执行此操作的最小工作示例。 但是,我不明白为什么某些在我看来无效的输入字符串似乎没有以某种方式引发异常。 我不知道这里发生了什么。

#include <iostream>
#include <chrono>
#include <sstream>
#include <boost/date_time.hpp>
using Clock = std::chrono::system_clock;
using TimePoint = std::chrono::time_point<Clock>;
TimePoint timePointFromString(const std::string& date, const std::string& format) {
// local takes care of destructing time_input_facet
auto loc = std::locale(std::locale::classic(), new boost::posix_time::time_input_facet(format));
std::stringstream ss{date};
ss.imbue(loc);
boost::posix_time::ptime pt;
ss >> pt;
if (!ss.good()) {
throw std::runtime_error("Cannot parse string");
}
boost::posix_time::ptime time_t_epoch{boost::gregorian::date(1970, 1, 1)};
boost::posix_time::time_duration diff = pt - time_t_epoch;
Clock::duration duration{diff.total_nanoseconds()};
return TimePoint{duration};
}
int main() {
std::string format{"%Y-%m-%d"};
std::vector<std::string> strings {"2018", "2018-", "19700101", "19700103", "19700301"};
for (const auto& s: strings) {
auto tp = timePointFromString(s, format);
std::cout << s << ": " << TimePoint::clock::to_time_t(tp) << std::endl;
}
}

输出:

2018: 1514764800
2018-: 1514764800
19700101: 23587200
19700103: 23587200
terminate called after throwing an instance of 'std::runtime_error'
what():  Cannot parse string

更新:我误解了这段代码,认为它会进行某种模式匹配。事实并非如此(请参阅Öö Tiib的回答和他答案下方的评论(!显然,最好使用霍华德·欣南特的日期/时间库。

以下是使用 Howard Hinnant 的免费开源日期/时间库时代码的外观:

#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::chrono::system_clock::time_point
timePointFromString(const std::string& date, const std::string& format)
{
std::stringstream ss{date};
std::chrono::system_clock::time_point pt;
ss >> date::parse(format, pt);
if (ss.fail())
throw std::runtime_error("Cannot parse date");
return pt;
}
int
main()
{
std::string format{"%Y-%m-%d"};
std::vector<std::string> strings{"2018", "2018-", "19700101", "19700103", "19700301",
"1970-03-01"};
for (const auto& s: strings)
{
try
{
auto tp = timePointFromString(s, format);
using date::operator<<;
std::cout << s << ": " << tp << 'n';
}
catch (std::exception const& e)
{
std::cout << s << ": " << e.what() << 'n';
}
}
}

输出将是:

2018: Cannot parse date
2018-: Cannot parse date
19700101: Cannot parse date
19700103: Cannot parse date
19700301: Cannot parse date
1970-03-01: 1970-03-01 00:00:00.000000

我在向量的末尾添加了一个有效的字符串/日期,以显示它使用此format接受的内容。1970-03-01 00:00:00.0...上的尾随零数将根据平台std::chrono::system_clock::time_point的精度而有所不同。

此外,此代码应该很容易移植到 C++20:

  • 放下#include "date/date.h".
  • 掉落using date::operator<<;
  • date::parse更改为std::chrono::parse

更新

为了帮助您解释结果,请执行以下操作:

  • 1514764800s 之后 1970-01-01 00:00:00 是 2018-01-01 00:00:00
  • 23587200s 在 1970-01-01 00:00:00
  • 之后是 1970-10-01 00:00:00

(都忽略了闰秒,这是常态(

你没有解释你的期望和原因,所以我只是描述你的程序是做什么的。

使用"19700101"和"19700103",它解析"1970"跳过一个字符,解析"10"跳过一个字符并找到字符串的结尾,因此它得出结论,两者都是1970年10月的第一个。

使用"19700301"它解析"1970"跳过一个字符解析"30"并抛出,因为第 30 个月是无稽之谈。

此外,您的输出描述有拼写错误,您抛出"无法解析日期"而不是"无法解析字符串"。