如何使用GCC 9将`std :: filesystem :: file_time_type`转换为字符串

时间:2019-06-27 10:09:17

标签: c++ std-filesystem gcc9

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

decltype(file_time)::clock

我同时使用C ++ 17和C ++ 20尝试了std::chrono::file_clock$ 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); | ^~~~~~~~~ ,但是它们都不起作用。

{{1}}

https://en.cppreference.com/w/cpp/filesystem/file_time_type上的示例提到它在GCC 9上不起作用,因为C ++ 20允许可移植输出,但是我不知道如何使其工作。如果我不使用C ++ 20,就不能在GCC 9中使用吗?

如果可能,我希望使用带有GCC 9的C ++ 17解决方案。

1 个答案:

答案 0 :(得分:3)

由于system_clock具有to_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);
}

更新:由于我目前还无法发表评论,因此需要澄清为什么会起作用以及可能存在的问题:之所以起作用,是因为同一时钟的两个时间点之间的差异很容易,第二部分,还有一个different sources (2)持续时间时间点的模板operator+,并且比率差异将得到解决在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';
}