我正在尝试将日期(以 std::string
形式)转换为 std::chrono::time_point
。为此,我使用了 Boost Date Time。
下面,您可以找到执行此操作的最小工作示例。
但是,我不明白为什么在我看来某些无效的输入字符串似乎不会以某种方式引发异常。
我无法弄清楚这里发生了什么。
#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 的 date/time图书馆。
最佳答案
如果您使用Howard Hinnant's free, open-source date/time library,您的代码将如下所示:
#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
我在 vector 末尾添加了一个有效的字符串/日期,以显示它使用此 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
.
更新
帮助您解释结果:
- 1970-01-01 00:00:00 之后的 1514764800 秒为 2018-01-01 00:00:00
- 1970-01-01 00:00:00 之后的 23587200 秒为 1970-10-01 00:00:00
(都忽略了闰秒,这是常态)
关于c++ - 来自 std::string 的 std::chrono::time_point,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52175032/