【问题标题】:How to convert std::filesystem::file_time_type to time_t?如何将 std::filesystem::file_time_type 转换为 time_t?
【发布时间】:2020-04-04 15:25:53
【问题描述】:

我使用 MSVC2015 为 windows 编写了一个解决方案,其中以下代码转换 std::filesystem::last_write_time 结果 time_t:

time_t ftime = std::file_time_type::clock::to_time_t(fs::last_write_time("/Path/filename"))

效果很好。然后,当我尝试使用 gcc 9.3 (-std=C++2a) 将解决方案移植到 Linux 时,出现以下错误:

错误:'to_time_t' 不是 'std::chrono::time_point::clock' {aka 'std::filesystem::__file_clock'}的成员

我搜索了一个解决方案,但我发现的解决方案是基于 cplusplus.com 的 std::filesystem::last_write_time 示例中包含的解决方案。解决方法如下图:

auto ftime = fs::last_write_time(p);
std::time_t cftime = decltype(ftime)::clock::to_time_t(ftime);

不幸的是,它对我不起作用。实际上,该示例有一条评论说它不适用于 MSVC(在 MSVC2015 工作)或 GCC 9; C++20 将允许可移植输出。

现在,我被困住了……如何使用 gcc 进行这种转换?

【问题讨论】:

    标签: c++ chrono


    【解决方案1】:

    如前所述,在 C++17 中没有完美的方法可以做到这一点。根据实际用例,使用可移植的近似值可能就足够了。根据我对"How to convert std::filesystem::file_time_type to a string using GCC 9" 的回答,我想建议那里使用的辅助函数:

    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);
    }
    

    请注意,它会在每个时钟上调用now(),因此它不是一个精确的、保证往返的解决方案,但它可能对您有用,直到库中的空白被关闭。这是基于同一时钟的时间点之间的差异很容易,并且不同来源的durationtime_point有一个operator+

    对于进一步降低相关错误风险的方法,我想指出 the conversion between C++11 clocks 进行了一些统计分析 减少可能的错误的想法,但如果可以接受,我只使用上面的代码。

    【讨论】:

      【解决方案2】:

      在 C++20 之前?没有便携的方法可以做到这一点。它在该版本的 Visual Studio 中工作,因为该版本的 VS 文件系统实现恰好使用 system_clock 作为文件系统时钟类型。这不是 C++ 标准所要求的,但它是允许的。所以你的代码恰好可以工作。

      在 C++20 之前,没有将两个时钟对齐在一起的机制,因此可以将一个时钟的时间转换为另一个时钟的时间。因此,如果文件系统时钟不是 system_clock,那么你就不走运了。您必须使用该实现如何实现其文件系统时钟的知识(基本上知道它使用哪个时代)来编写特定于实现的代码,以便您可以手动将其转换为system_clock::time_point

      C++20 为 system_clock 提供了一个固定的纪元,可用于所有实现(UNIX 时间),并要求 file_clock 能够将其时间点转换为 system_clock 时间点。

      【讨论】:

      • 我可以看到这个固定的时代没有在 gcc 9.3 上实现(我用 -std=C++2a 尝试过)。也许它是在 gcc 10 上实现的?
      【解决方案3】:

      经过一番挖掘,我设法重写了他们给出的示例,它似乎有效;密钥转换为system_clock,然后转换为time_t

      #include <iostream>
      #include <chrono>
      #include <iomanip>
      #include <fstream>
      #include <filesystem>
      namespace fs = std::filesystem;
      using namespace std::chrono_literals;
      int main()
      {
        fs::path p = fs::current_path() / "example.bin";
        std::ofstream(p.c_str()).put('a'); // create file
        auto ftime = fs::last_write_time(p);
        auto cftime = std::chrono::system_clock::to_time_t(std::chrono::file_clock::to_sys(ftime));
      
        std::cout << "File write time is " << std::asctime(std::localtime(&cftime)) << '\n';
      
        fs::last_write_time(p, ftime + 1h); // move file write time 1 hour to the future
        ftime = fs::last_write_time(p);     // read back from the filesystem
      
        cftime = std::chrono::system_clock::to_time_t(std::chrono::file_clock::to_sys(ftime));
        std::cout << "File write time is " << std::asctime(std::localtime(&cftime)) << '\n';
        fs::remove(p);
      }
      

      【讨论】:

        【解决方案4】:

        C++20 解决方案

        const auto fileTime = std::filesystem::last_write_time(filePath);
        const auto systemTime = std::chrono::clock_cast<std::chrono::system_clock>(fileTime);
        const auto time = std::chrono::system_clock::to_time_t(systemTime);
        

        【讨论】:

          【解决方案5】:

          这不是问题的直接答案,也可能不是便携式解决方案, 但我遇到了将 std::filesystem::file_time_type 转换为 std::chrono::system_clock::time_point 的类似问题(可以轻松转换为time_t) 在 Visual Studio 2017 中,这对我有用,可能会帮助其他也在搜索中的人......

          using namespace std::chrono;
          
          // a dummy file_time_type to work with
          const auto ftp = std::filesystem::file_time_type::clock::now();
          
          // get the ticks and subtract the file time epoch adjustment
          const auto ticks = ftp.time_since_epoch().count() - __std_fs_file_time_epoch_adjustment;
          
          // create a time_point from ticks
          const auto tp = system_clock::time_point(system_clock::time_point::duration(ticks));
          
          // finaly convert to time_t
          std::time_t tt = system_clock::time_point::clock::to_time_t(tp);
          

          【讨论】:

            【解决方案6】:

            另一个不直接的解决方案:如果你碰巧在使用 boost...

                inline std::string filestamp(const std::string& path) {
                    std::time_t t = boost::filesystem::last_write_time(path);
                    return std::asctime(std::localtime(&t));
                }
            

            【讨论】:

              【解决方案7】:

              这在 C++17 中对我有用。使用 FileTimeToSystemTime 以人类可读的格式返回文件时间。从那里您使用 mktime 转换为 time_t

              auto filetime = entry.last_write_time();
              SYSTEMTIME  stSystemTime;
              if (FileTimeToSystemTime((const FILETIME*)&filetime, &stSystemTime))
              {
              printf("Year = %d,  Month = %d,  Day = %d,  Hour = %d,  Minute = %d\n", stSystemTime.wYear, stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wHour, stSystemTime.wMinute);
              }
              

              【讨论】:

                猜你喜欢
                • 2018-12-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-08-21
                • 2016-11-01
                • 2012-06-28
                相关资源
                最近更新 更多