【问题标题】:Is std::get_time broken in g++ and clang++?std::get_time 在 g++ 和 clang++ 中被破坏了吗?
【发布时间】:2016-09-29 21:30:16
【问题描述】:

我今天正在处理一些时间函数,并注意到使用%r(或%p)的标准转换似乎不适用于在g++ 或clang++ 上通过std::get_time() 进行的输入。有关 g++ 和 clang++,请参阅 this live code version。它确实似乎在使用 VC++ 的 Windows 下按预期工作(请参阅closely related question)。另请注意,无论是否包含imbue 行,效果都是相同的。如果重要的话,我的 Linux 机器上的语言环境设置为 "en_US.UTF-8"

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <ctime>

int main(){
    std::tm t{};
    std::stringstream ss{"1:23:45 PM"};
    ss.imbue(std::locale(std::cin.getloc(), 
             new std::time_get_byname<char>("en_US")));
    ss >> std::get_time(&t, "%r");
    if (ss.fail()) {
        std::cout << "Conversion failed\n" << std::put_time(&t, "%r") << '\n';
    } else {
        std::cout << std::put_time(&t, "%r") << '\n';
    }
}

【问题讨论】:

  • 这似乎是一个 libstdc++ 问题。使用 libc++ 的 clang 可以很好地解析。
  • @HowardHinnant:你是right。我应该重新命名问题吗?
  • 看起来implementation 无法处理%r%p。如果还有其他地方应该处理它们,我找不到。

标签: c++ c++11 time c++14


【解决方案1】:

正如评论者所指出的,这实际上是libstdc++ 中的一个错误(遗漏)。 bug report 已提交。

【讨论】:

    【解决方案2】:

    坏消息是get_time() 比 OP 和评论者想象的更坏。它也绝对不适用于"%F" 格式说明符(ISO-8601 格式的日期,例如"2019-01-13")。我稍微修改了 OP 的代码来证明这一点。在 Ubuntu 18.04.1 下使用 g++ 版本 7.3.0 编译:

    #include <iostream>
    #include <iomanip>
    #include <sstream>
    #include <string>
    #include <ctime>
    
    int main(){
        std::tm tdate{0,0,0,0,0,0,0,0,-1}; // was t{};
        std::istringstream ins{"2019-01-13"};
        ss.imbue(std::locale(std::cin.getloc(), 
                 new std::time_get_byname<char>("en_US")));
        ss >> std::get_time(&tdate, "%F");
        if (ss.fail()) {
            std::cout << "Conversion failed\n" << std::put_time(&tdate, "%F") << '\n';
        } else {
            std::cout << std::put_time(&tdate, "%F") << '\n';
        }
    

    这是输出:

    Conversion failed
    1900-01-00
    

    小提示:强烈建议在尝试任何处理之前将std::tm 对象清零。

    更新:这是一个依赖于 UNIX 函数 strptime 的解决方法(请注意,这不是 C 或 C++ 标准函数!)。我展示了带有 ISO8601 日期解析的代码示例。

    首先,让我们检测 GNU stdlibc++ 库并拉入 &lt;time.h&gt; 标头。 (在某些平台上,标头可能是&lt;sys/time.h&gt;):

    #include <cstddef>
    #if defined(__GLIBCXX__) || defined(__GLIBCPP__)
    #define GET_TIME_WORKAROUND
    #include <time.h>
    #endif
    

    然后解析:

    #ifdef GET_TIME_WORKAROUND
    char *result = strptime(datestr.c_str(), "%F", &_cal);
    if (result == nullptr) {
        throw std::invalid_argument{ "Date(" + datestr + "): ISO-8601 date expected" };
    }
    #else
    // proper C++11
    // ........
    

    【讨论】:

      猜你喜欢
      • 2011-02-14
      • 2013-03-30
      • 1970-01-01
      • 1970-01-01
      • 2021-05-17
      相关资源
      最近更新 更多