Как преобразовать `std::filesystem::file_time_type` в строку, используя GCC 9
Я пытаюсь отформатировать время изменения файла в виде строки (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)::clock
а также std::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 позволит переносить вывод, но я понятия не имею, как его получить работает. Разве это не должно работать с GCC 9, если я просто не использую C++20?
Я бы предпочел решение C++17 с GCC 9, если это возможно.
0 ответов
Как 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);
}
Обновление: поскольку я еще не могу комментировать, некоторые пояснения относительно того, почему это работает и что может быть проблемой: это работает, потому что разница между двумя точками времени одних и тех же часов проста, а для второй части существует дополнительный шаблонoperator+
по длительности и временной точки из различных источников (2) и коэффициент различий будет заботиться о вstd::common_type
.
Остается проблема в том, что два вызова now()
не одновременно, существует небольшой риск появления небольшой ошибки преобразования из-за разницы во времени между этими вызовами. Существует еще один вопрос о преобразованиях часов 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';
}