首页 > 解决方案 > 如何在 Windows 上解析 std::put_time("%x") 创建的字符串?

问题描述

初始点

让我们假设 windows 上的第三方组件使用以下函数创建一个表示日期的字符串:

std::string getDate() {
    std::tm t = {};
    std::time_t now = std::time(nullptr);
    localtime_s(&t, &now);
    std::stringstream s;
    s.imbue(std::locale(""));
    s << std::put_time(&t, "%x");
    return s.str();
}

根据您的系统区域设置和短日期格式的设置,您会得到类似15.09.2020or09/15/202015. Sept. 2020等的字符串。

%xcppreferencewrites localized date representation (locale dependent)所述,这是预期的。

问题

如何将生成的字符串解析std::put_time("%x")回 a std::tm(假设相同的语言环境和短日期格式系统设置)?

什么不起作用

STL

std::tm parseDate1(const std::string& date) {
    std::tm t = {};
    std::istringstream ss(date);
    ss.exceptions(std::ifstream::failbit);
    ss.imbue(std::locale(""));
    ss >> std::get_time(&t, "%x");
    return t;
}

不起作用,因为 std::get_time 的实现需要 in 的硬"%d / %m / %y编码%x格式xlocime

促进

std::tm parseDate2(const std::string& date) {
    boost::gregorian::date d;
    auto* input_facet = new boost::gregorian::date_input_facet();
    input_facet->format("%x");
    std::istringstream ss(date);
    ss.exceptions(std::ifstream::failbit);
    ss.imbue(std::locale(std::locale(""), input_facet));    
    ss >> d;
    return boost::gregorian::to_tm(d);  
}

Boost 总是返回1400-Jan-01,因为%x似乎根本没有实现解析。

字符串时间

windows上好像没有。这里有一个实现,但编译和集成似乎并不简单。

解决方法

到目前为止我想出的最好的解决方法是使用 Win32 函数EnumDateFormats()来读取系统DATE_SHORTDATE格式并将这种格式转换为std::get_time()语法,因为它不兼容(例如dd.MM.yyyy需要转换为%d.%m.%Yfor std::get_time())。但这似乎容易出错,而不是“正确”的方法......

它似乎也在内部std::put_time()使用strftime并且std::get_time()是“自我实现的”。我本来希望通过使用相同的格式字符串生成的所有内容都std::put_time()应该是可解析的。std::get_time()但这似乎并非如此,而且似乎也没有记录在案。还是我错过了什么?

标签: c++windowsdatebooststl

解决方案


Plauger 有一篇著名的帖子,他不会解析“Michaelmas 之后的第 14 天”,标准委员会不能让他这样做。你可以做的是put_time一个已知的日期,例如 71/2/1,并尝试剖析结果以重新创建一个详细的模式,以便以后用于解析。


推荐阅读