2

I am attempting to send over the FILETIME of a file to my server, which is written in C#. From there, I can use the function DateTime.FromFileTime() to parse the file's time. I am aware there is a Win32 API called GetFileTime(), but in the interest of saving lines of code, I was wondering if it was possible to use std::filesystem and somehow convert it to FILETIME?

I have tried casting like so:

f.lastwrite = entry.last_write_time();

But this cast is not allowed, unfortunately. Is it possible to convert the last_write_time() to FILETIME so it can be sent over, or is that not possible?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Meme Machine
  • 949
  • 3
  • 14
  • 28
  • 3
    If you're sending a time over the Internet, it would be better to do it in text, with a specific format and known timezone, rather than as an integer. – Nicol Bolas May 19 '22 at 19:26
  • What is _wrong_ with using `GetFileTime`, since it gives you exactly what you want? – Paul Sanders May 19 '22 at 19:34
  • 1
    @PaulSanders Nothing is inherently wrong, it would just require more lines of code and I was trying to stick to using std::filesystem. If it's not possible, that's fine. – Meme Machine May 19 '22 at 19:37

1 Answers1

1

You can convert the last_write_time() value to std::time_t via std::chrono::file_clock::to_sys() and std::chrono::system_clock::to_time_t(), and then convert time_t to FILETIME using simple arithmetic.

For example:

#include <windows.h>
#include <filesystem>
#include <chrono>

void stdFileTimeType_to_FILETIME(const std::filesystem::file_time_type &ftime, FILETIME &ft)
{
    std::time_t t = std::chrono::system_clock::to_time_t(
        std::chrono::file_clock::to_sys(ftime)
    );
    ULARGE_INTEGER ul;
    ul.QuadPart = (t * 10000000LL) + 116444736000000000LL;
    ft.dwLowDateTime = ul.LowPart;
    ft.dwHighDateTime = ul.HighPart;
}

FILETIME lastwrite;
stdFileTimeType_to_FILETIME(entry.last_write_time(), lastwrite);

UPDATE: Alternatively, have a look at GetFileAttributesEx(), which can retrieve FILETIME ftLastWriteTime (amongst other things) given a file path string instead of an open file HANDLE, as with GetFileTime():

#include <windows.h>
#include <filesystem>
#include <chrono>

void getLastWriteTime_as_FILETIME(const std::filesystem::path &filePath, FILETIME &ft)
{
    WIN32_FILE_ATTRIBUTE_DATA fad;
    if (GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &fad))
        ft = fad.ftLastWriteTime;
    else
        ft.dwLowDateTime = ft.dwHighDateTime = 0;
}

FILETIME lastwrite;
getLastWriteTime_as_FILETIME(entry.path(), lastwrite);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Doesn't that limit the precision to one second? `GetFileTime` is a lot more precise than that, as I'm sure you both know. – Paul Sanders May 19 '22 at 22:34
  • @PaulSanders "*Doesn't that limit the precision to one second?*" - basically, yes. But unless you know the exact implementation of `file_time_type` and can do the necessary math yourself from `file_time_type` directly to `FILETIME`, this is about as good as you can get with standard functionality. Otherwise, like you said earlier, just use `GetFileTime()` instead, or `GetFileAttributesEx()` (which doesn't require opening the file). – Remy Lebeau May 19 '22 at 22:56
  • Absolutely. If it looks like Windows and quacks like Windows ... `GetFileAttributesEx()` a good idea. – Paul Sanders May 19 '22 at 23:00
  • On Windows I believe that `FILETIME` and `std::filesystem::file_time_type` share the same epoch and the same precision. So just converting from serial to fields should do the job, without any loss of precision. See https://stackoverflow.com/a/72031262/576911. However I'm not clear on what epoch the client of this conversion wants to see. – Howard Hinnant May 20 '22 at 00:37