Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare time_t and std::filesystem::file_time_type

I'm converting some code over from boost::filesystem to std::filesystem. Previous code used boost::filesystem::last_write_time() which returns a time_t so direct comparison to a time_t object I already held was trivial. By the way, this time_t I hold is read from file contents persisted long ago, so I'm stuck with using this "time since unix epoch" type.

std::filesystem::last_write_time returns a std::filesystem::file_time_type. Is there a portable way to convert a file_time_type to a time_t, or otherwise portably compare the two objects?

#include <ctime>
#include <filesystem>

std::time_t GetATimeInSecondsSince1970Epoch()
{
    return 1207609200;  // Some time in April 2008 (just an example!)
}

int main()
{
    const std::time_t time = GetATimeInSecondsSince1970Epoch();
    const auto lastWriteTime = std::filesystem::last_write_time("c:\\file.txt");

    // How to portably compare time and lastWriteTime?
}

EDIT: Please note that the sample code at cppreference.com for last_write_time states that it's assuming the clock is a std::chrono::system_clock which implements the to_time_t function. This assumption is not always going to be true and isn't on my platform (VS2017).

like image 408
PeteUK Avatar asked Jul 10 '18 20:07

PeteUK


2 Answers

Fwiw, when C++20 gets here, the portable solution will be:

clock_cast<file_clock>(system_clock::from_time_t(time)) < lastWriteTime

This converts the time_t into file_time as opposed to vice-versa. The advantage of this approach is that file_time typically has a higher precision than time_t. Converting file_time to time_t will loose that precision during the conversion, and thus risk making the comparison inaccurate.

like image 109
Howard Hinnant Avatar answered Oct 20 '22 04:10

Howard Hinnant


I faced the same problem and I solved it using a dedicated code for Visual Studio.

In case of VS, I use the _wstati64 function (w for wide char, because Windows encodes Unicode paths in Utf16) and the wstring convertion of the path class.

The whole thing is gathered in this function:

#if defined ( _WIN32 )
#include <sys/stat.h>
#endif

std::time_t GetFileWriteTime ( const std::filesystem::path& filename )
{
    #if defined ( _WIN32 )
    {
        struct _stat64 fileInfo;
        if ( _wstati64 ( filename.wstring ().c_str (), &fileInfo ) != 0 )
        {
            throw std::runtime_error ( "Failed to get last write time." );
        }
        return fileInfo.st_mtime;
    }
    #else
    {
        auto fsTime = std::filesystem::last_write_time ( filename );
        return decltype ( fsTime )::clock::to_time_t ( fsTime );
    }
    #endif
}
like image 23
S.Clem Avatar answered Oct 20 '22 05:10

S.Clem