【问题标题】:localtime_s and strftime usage building ISO time stringlocaltime_s 和 strftime 使用构建 ISO 时间字符串
【发布时间】:2016-07-11 11:55:20
【问题描述】:

我编写了以下函数,它接收一个时间点并返回一个以毫秒为单位的 ISO 字符串:

std::string TimePointToISOString(const std::chrono::time_point<std::chrono::system_clock>& time)
    {
        std::time_t rawTime = std::chrono::system_clock::to_time_t(time);
        struct tm timeinfo;
        localtime_s(&timeinfo, &rawTime);

        std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(time.time_since_epoch());
        std::size_t frac_seconds = ms.count() % 1000;

        char buffer[32];
        std::strftime(buffer, 32, "%FT%TZ", &timeinfo);

        std::string bufferStr(buffer);
        std::stringstream ss;
        ss << bufferStr.substr(0, 19) << "." << std::setw(3) << std::setfill ('0') << frac_seconds << bufferStr.substr(20);

        return ss.str();
    }

我曾经在 Linux 上使用 localtime() 函数运行它,完全没有问题。现在我正在迁移到 Windows/VS2012,编译器建议将localtime() 更改为更安全的localtime_s(),立即完成。

转换后,strftime 调用确实在运行时崩溃并出现以下错误:

Expression: ("Invalid format directive", 0)

编译运行良好。感谢您帮助了解这里发生了什么。我猜是一些我无法注意到的简单事情......

【问题讨论】:

    标签: c++ c++11 strftime chrono localtime


    【解决方案1】:

    %F%T 转换是在 C99 中添加的,VS 2012 仅支持 C89。

    尽管它仍然没有尝试支持所有 C99,但我相信 VS 2015 添加了足够多的功能(尤其是 C99 库函数,它们也是 C++11 的一部分),它应该可以正常工作。

    如果您需要继续使用旧的编译器/库,%F 和 %T 基本上都是 C89 中已支持的某些格式的“快捷方式”。如果我正确阅读了要求,则以下内容应该是等效的:

    std::strftime(buffer, 32, "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
    

    顺便说一句,如果您的编译器支持 C++11,则使用 std::put_time 而不是 strftime 通常更容易、更简洁。

    【讨论】:

    • 杰瑞,我试过ss &lt;&lt; std::put_time(&amp;timeinfo, "%FT%TZ"); 也没有成功...同样的错误...看到%FT%TZ 在VS2012 中根本不支持。所以我改成了"%Y-%m-%dT%H:%M:%SZ" and is working with strftime`和std::put_time。感谢您的帮助。
    • @Mendes:是的,我猜put_time 只不过是strftime 的一个包装器(或者两者都使用相同的引擎),因此对于任何给定的编译器,两者都可能支持相同的转换——在它们之间切换纯粹是为了方便,不太可能影响您原来的问题。
    【解决方案2】:

    这是一个很好的问题(赞成)。杰里科芬的回答是一个很好的答案(也被赞成)。这个答案是关于添加有关已知可在 VS-2013 及更高版本、gcc 和 clang 上运行的替代开源解决方案的更多信息。此替代方案将产生 相同 输出到 TimePointToISOString。为了区分它,我给它起了另一个名字:to_local_string:

    std::string
    to_local_string(const std::chrono::system_clock::time_point& time)
    {
        using namespace date;
    
        auto zone = current_zone();
        auto local = floor<std::chrono::milliseconds>(zone->to_local(time).first);
        auto dp = floor<days>(local);
        year_month_day ymd = dp;
        std::stringstream ss;
        ss << ymd << 'T' << make_time(local-dp);
        return ss.str();
    }
    

    这使用此处找到的时区数据库解析器:

    https://github.com/HowardHinnant/date

    并在此处记录:

    http://howardhinnant.github.io/tz.html

    这是IANA Timezone database 的解析器,在这里用于简单地查找本地时区的UTC 偏移量。一旦找到本地时间点(存储为std::chrono::system_clock::time_point),它就会使用this library 将其分解为字段类型年/月/日/小时/分钟/秒/毫秒,其实现位于同一个github 站点。

    我刚刚在同一时间点同时运行了TimePointToISOStringto_local_string,输出为:

    2016-03-23T22:54:52.626
    2016-03-23T22:54:52.626
    

    【讨论】:

      猜你喜欢
      • 2013-04-21
      • 2016-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-25
      • 2017-03-24
      • 2014-05-09
      • 2012-08-08
      相关资源
      最近更新 更多