From d7e7adb4963e6acc8c0d287e18ea062bdd7f3fb3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 10 Aug 2021 16:09:03 +0200 Subject: [PATCH] time/FileTime: add ChronoToFileTime() --- src/time/FileTime.hxx | 49 ++++++++++++++++++++++++++++++++++++++ test/time/TestFileTime.cxx | 4 ++++ 2 files changed, 53 insertions(+) diff --git a/src/time/FileTime.hxx b/src/time/FileTime.hxx index 6319d7749..a5c79a422 100644 --- a/src/time/FileTime.hxx +++ b/src/time/FileTime.hxx @@ -53,6 +53,21 @@ ToInt64(FILETIME ft) noexcept return ToUint64(ft); } +constexpr FILETIME +ToFileTime(uint_least64_t t) noexcept +{ + FILETIME ft{}; + ft.dwLowDateTime = DWORD(t); + ft.dwHighDateTime = DWORD(t >> 32); + return ft; +} + +constexpr FILETIME +ToFileTime(int_least64_t t) noexcept +{ + return ToFileTime(uint_least64_t(t)); +} + /* "A file time is a 64-bit value that represents the number of 100-nanosecond intervals" https://docs.microsoft.com/en-us/windows/win32/sysinfo/file-times */ @@ -104,6 +119,40 @@ FileTimeToChrono(FILETIME ft) noexcept return unix_epoch + sys_duration; } +constexpr FILETIME +ToFileTime(FileTimeDuration d) noexcept +{ + return ToFileTime(d.count()); +} + +constexpr FILETIME +UnixEpochDurationToFileTime(FileTimeDuration d) noexcept +{ + /** + * The number of days between the Windows FILETIME epoch + * (1601-01-01T00:00) and the Unix epoch (1970-01-01T00:00). + */ + constexpr int_least64_t windows_unix_days = 134774; + constexpr int_least64_t windows_unix_hours = windows_unix_days * 24; + + constexpr FileTimeDuration windows_unix_delta{std::chrono::hours{windows_unix_hours}}; + + return ToFileTime(d + windows_unix_delta); +} + +inline FILETIME +ChronoToFileTime(std::chrono::system_clock::time_point tp) noexcept +{ + /* this is guaranteed to be 0 in C++20 */ + const auto unix_epoch = std::chrono::system_clock::from_time_t(0); + + const auto since_unix_epoch = tp - unix_epoch; + const auto ft_since_unix_epoch = + std::chrono::duration_cast(since_unix_epoch); + + return UnixEpochDurationToFileTime(ft_since_unix_epoch); +} + constexpr std::chrono::seconds DeltaFileTimeS(FILETIME a, FILETIME b) noexcept { diff --git a/test/time/TestFileTime.cxx b/test/time/TestFileTime.cxx index 9a1a6474c..da7eaad2e 100644 --- a/test/time/TestFileTime.cxx +++ b/test/time/TestFileTime.cxx @@ -49,4 +49,8 @@ TEST(Time, FileTimeToChrono) ASSERT_EQ(stat(".", &st), 0); ASSERT_EQ(std::chrono::system_clock::to_time_t(tp), st.st_mtime); + + const auto ft2 = ChronoToFileTime(std::chrono::system_clock::from_time_t(st.st_mtime)); + const auto tp2 = FileTimeToChrono(ft2); + ASSERT_EQ(std::chrono::system_clock::to_time_t(tp2), st.st_mtime); }