【问题标题】:How to convert `std::filesystem::file_time_type` to a string using GCC 9如何使用 GCC 9 将 `std::filesystem::file_time_type` 转换为字符串
【发布时间】:2019-06-27 10:09:17
【问题描述】:

我正在尝试将文件的修改时间格式化为字符串 (UTC)。以下代码使用 GCC 8 编译,但不是 GCC 9。

#include <chrono>
#include <filesystem>
#include <iomanip>
#include <iostream>
#include <sstream>

namespace fs = std::filesystem;

int main() {
    fs::file_time_type file_time = fs::last_write_time(__FILE__);
    std::time_t tt = decltype(file_time)::clock::to_time_t(file_time);
    std::tm *gmt = std::gmtime(&tt);
    std::stringstream buffer;
    buffer << std::put_time(gmt, "%A, %d %B %Y %H:%M");
    std::string formattedFileTime = buffer.str();
    std::cout << formattedFileTime << '\n';
}

我尝试了decltype(file_time)::clockstd::chrono::file_clock,同时使用了 C++17 和 C++20,但它们都不起作用。

$ g++-9 -std=c++2a -Wall -Wextra -lstdc++fs file_time_type.cpp

file_time_type.cpp: In function ‘int main()’:
file_time_type.cpp:12:50: error: ‘to_time_t’ is not a member of ‘std::chrono::time_point<std::filesystem::__file_clock>::clock’ {aka ‘std::filesystem::__file_clock’}
   12 |     std::time_t tt = decltype(file_time)::clock::to_time_t(file_time);
      |                                                  ^~~~~~~~~

https://en.cppreference.com/w/cpp/filesystem/file_time_type 上的示例提到它不适用于 GCC 9,因为 C++20 将允许可移植输出,但我不知道如何让它工作。如果我不使用 C++20,它不应该与 GCC 9 一起使用吗?

如果可能的话,我更喜欢使用 GCC 9 的 C++17 解决方案。

【问题讨论】:

  • Howard hinnant 的date library 应该可以直接打印时间而不需要转换成time_t
  • @AlanBirtles,谢谢你的建议。我还没有任何第三方依赖项,所以我有点犹豫添加这个库只是为了格式化一个日期。有没有使用标准库的替代方案?
  • 您可以使用 c++20 日期库(源自 Howards),它是一个仅标头库,因此使用它只是从 github 下载标头并包含它的一种情况
  • @AlanBirtles:它尝试使用 Hinnant 的日期库头文件 (github.com/HowardHinnant/date/blob/master/include/date/date.h) 进行转换。然而,我失败了。只有 system_clock 可以进行简单的字符串转换,但文件系统使用 _File_time_clock。最后,我认为这不是“一目了然”的事情。如果您知道解决方案,您可以发布它。这个问题仍然没有公认的答案;-)。当前的答案显然是一种解决方法。

标签: c++ std-filesystem gcc9


【解决方案1】:

由于system_clockto_time_t,最简单的方法是转换为它。这并不完美(由于精度问题),但大多数时候已经足够好了,我也在 MSVC 上使用:

template <typename TP>
std::time_t to_time_t(TP tp)
{
    using namespace std::chrono;
    auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now()
              + system_clock::now());
    return system_clock::to_time_t(sctp);
}

更新:由于我还不能发表评论,因此请澄清一下为什么会这样以及可能存在的问题:它之所以有效,是因为同一时钟的两个时间点之间的差异很容易,对于第二部分,有一个额外的模板operator+ 用于different sources (2)持续时间时间点,并且将在std::common_type 中处理比率差异.

剩下的问题是,对now() 的两次调用不是同时进行的,由于调用之间的时间差异,存在引入小转换错误的轻微风险。有 another question 关于 C++11 时钟转换,它更详细地介绍了错误概率和减少错误的技巧,但是如果您不需要比较结果的往返转换,而只是想格式化时间戳,这个较小的解决方案应该足够好了。

所以要完成原问题的答案:

#include <chrono>
#include <filesystem>
#include <iomanip>
#include <iostream>
#include <sstream>

namespace fs = std::filesystem;

template <typename TP>
std::time_t to_time_t(TP tp)
{
    using namespace std::chrono;
    auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now()
              + system_clock::now());
    return system_clock::to_time_t(sctp);
}

int main() {
    fs::file_time_type file_time = fs::last_write_time(__FILE__);
    std::time_t tt = to_time_t(file_time);
    std::tm *gmt = std::gmtime(&tt);
    std::stringstream buffer;
    buffer << std::put_time(gmt, "%A, %d %B %Y %H:%M");
    std::string formattedFileTime = buffer.str();
    std::cout << formattedFileTime << '\n';
}

【讨论】:

  • 为什么有效?如果这些时钟的精度不同怎么办?
  • @Gulrak 在实际答案中而不是在附加评论中加入对 cme​​ts 的澄清是一种很好的做法。如果您可以发表评论,您可以写一个单行字在评论者的消息框中创建一个 ping;我会这样做的。
  • @fen 由于 Gulrak 还不能写 cmets,显然甚至在他自己的帖子下:他更新了他的答案,回复了关于不同比率的时钟的回复。 (我想这就是你问的问题。)
  • @Peter-ReinstateMonica 对不起,我实际上没有看到,我已经可以评论我自己的帖子,最好阅读 SO 介绍。感谢您向我指出它和 ping。
猜你喜欢
  • 1970-01-01
  • 2018-12-18
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 2021-08-21
  • 2021-04-17
  • 2019-03-31
相关资源
最近更新 更多