提问人:DeepBlue 提问时间:7/14/2023 最后编辑:DeepBlue 更新时间:7/17/2023 访问量:64
如何使用 C++ 日期库解析秒和亚秒之间没有小数点的字符串?
How to parse strings with no decimal point between seconds and subseconds using the C++ date library?
问:
我目前正在使用 Howard Hinnant 的外部日期库,并且在解析与日期时间相关的字符串时遇到问题。解析字符串是没有问题的,因为我能够指定秒和亚秒之间的小数点。解析字符串,如 but 不起作用。HH:mm:ssSSS
HH:mm:ss,SSS
HH:mm:ssSSS
我在这里发现了一个类似的问题。但是,它没有回答如何处理这种情况的问题。我不想更改字符串以设置秒和亚秒之间,只是为了处理这种特殊情况,特别是因为这只是我必须处理的任意众多情况之一。std::numpunct
.
具体来说,通过使用如下所述的标点符号分面,可以在解析具有秒和亚秒的字符串时设置自定义小数分隔符。但是,似乎不可能完全省略秒和亚秒之间的小数分隔符,因为 (a) 仅适用于字符类型,并且 (b) 在通过日期库解析时使用 null 终止符根本不起作用。date::parse
std::numpunct
因此我的问题:有没有办法解析像 via 和 这样的字符串?HH:mm:ssSSS
date::parse()
std::numpunct
class PunctuationFacet
: public std::numpunct<char>
{
public:
PuncutationFacet(char numericPunctuation, size_t referenceCount = 0)
: std::numpunct<char>(referenceCount)
, _numericPunctuation(numericPunctuation)
protected:
char do_decimal_point() const { return _numericPunctuation; }
private:
char _numericPunctuation;
std::optional<uin64_t> parse(std::string_view value, char numericPunctuation)
{
date::sys_time<std::chrono::milliseconds> timepoint;
std::stringstream ss;
ss.imbue(std::locale(ss.getloc(), new PunctuationFacet(numericPunctuation)));
ss << value;
ss >> date::parse("%H:%M:%S", timepoint);
if (ss.fail()) [[unlikely]]
{
return std::nullopt;
}
return timepoint.time_since_epoch().count();
}
int main(int argumentCount, char **arguments)
{
auto timestampDoesWork = parse("14:20:51,123", ',');
auto timestampDoesNotWork = parse("14:20:51123", 0);
}
答:
一些程序员在评论中回答了这个问题,但在几天没有正式答案之后,我认为是时候做一个了。
Howard Hinnant的日期库和C++ chrono都没有办法解析带有隐式小数点字符的秒。std::numpunct
在下面的问题评论中,可以看出秒中的位数可以从 0 到某个尚未指定的数字不等。而这个答案并没有解决这种复杂性。
但是,对于未来的读者,以下是使用 Howard Hinnant 的日期库将表单的持续时间解析为的方法:HH:mm:ssSSS
std::chrono::milliseconds
#include "date/date.h"
#include <iostream>
#include <sstream>
#include <string>
// parse HH:mm:ssSSS
std::chrono::milliseconds
my_parse(std::string t)
{
std::istringstream in{std::move(t)};
in.exceptions(std::ios::failbit);
int ms;
std::chrono::seconds s;
in >> date::parse("%T", s) >> ms;
return s + std::chrono::milliseconds{ms};
}
int
main()
{
using date::operator<<;
std::cout << my_parse("14:20:51123") << '\n';
}
输出:
51651123ms
这将通过更改为 轻松移植到 C++20。date::parse
std::chrono::parse
诀窍是先解析成,使用(或等效的),然后将剩余的数字解析为 an 并将其转换为 .使用固定数量的数字,这很容易。seconds
%T
%H:%M:%S
int
int
std::chrono::milliseconds
对于可变数量的数字,人们必须计算数字并将它们解释到适当的精度。当然是可行的,但需要的代码比这里显示的要多,并且更倾向于“你必须自己做”。
评论
HH:mm:ss
HH:mm:ss
SSS