How to convert std::filesystem::file_time_type to time_t?

As already said, there is no perfect way to do that in C++17. Depending on the actual use-case it might be good enough to use a portable approximation. Based on my answer to "How to convert std::filesystem::file_time_type to a string using GCC 9", I want to suggest the helper function used there:

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

Be aware, that it uses a call to now() on each clock, so it is not an exact, round-trip-guaranteed solution, but it might be usable for you, until the gap in the library is closed. It is based on the fact that difference between time points of the same clock is easy and there is an operator+ for duration and time_point of different sources.

For ways to lower the risk of a relevant error even more, I want to point to the conversion between C++11 clocks where some statistical analysis was made with ideas to mitigate possible errors, but when acceptable, I just use the code above.


Before C++20? There is no portable way to do that. It worked in that version of Visual Studio because that version of VS's filesystem implementation just so happens to use system_clock for the filesystem clock type. This is not required by the C++ standard, but it is allowed. So your code just so happened to work.

Pre-C++20, there was no mechanism to align two clocks together, so that time from one could be converted into the time of another. So if the filesystem clock isn't system_clock, you're out of luck. You would have to write implementation-specific code using knowledge of how that implementation implemented their filesystem clock (basically knowing what epoch it uses) so that you could manually convert it to a system_clock::time_point.

C++20 gives system_clock a fixed epoch to be used across all implementations (UNIX-time), and requires that file_clock be able to convert its time points into system_clock time points.


After some digging I managed to rewrite the example they give and it seems to work; the key being converting to system_clock then to 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);
}

Tags:

C++

Chrono