summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2021-08-10 14:07:15 +0200
committerMax Kellermann <max@musicpd.org>2021-08-10 15:16:59 +0200
commit45354a421c2a790413385174ef642a839a664cd6 (patch)
treebe6fcafb06df38380ba108e50f7fa9de6edcf397
parent9fc3c6091036373497c2cab52708b059a65af8df (diff)
time/FileTime: preserve the FILETIME resolution
Don't truncate the FILETIME to second resolution to pass it to std::chrono::system_clock::from_time_t(); instead, calculate the offset between the FILETIME epoch and the std::system_clock::time_point epoch, and use that to initialize the time_point directly.
-rw-r--r--src/time/FileTime.hxx30
1 files changed, 25 insertions, 5 deletions
diff --git a/src/time/FileTime.hxx b/src/time/FileTime.hxx
index 4ac323331..6319d7749 100644
--- a/src/time/FileTime.hxx
+++ b/src/time/FileTime.hxx
@@ -71,17 +71,37 @@ FileTimeToChronoDuration(FILETIME ft) noexcept
return FileTimeDuration(ToInt64(ft));
}
-constexpr time_t
-FileTimeToTimeT(FILETIME ft) noexcept
+/**
+ * Calculate a std::chrono::duration specifying the duration between
+ * the unix epoch and the given FILETIME.
+ */
+constexpr auto
+FileTimeToUnixEpochDuration(FILETIME ft) noexcept
{
- return (ToInt64(ft) - 116444736000000000) / 10000000;
+ /**
+ * 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 FileTimeToChronoDuration(ft) - windows_unix_delta;
}
inline std::chrono::system_clock::time_point
FileTimeToChrono(FILETIME ft) noexcept
{
- // TODO: eliminate the time_t roundtrip, preserve sub-second resolution
- return std::chrono::system_clock::from_time_t(FileTimeToTimeT(ft));
+ /* this is guaranteed to be 0 in C++20 */
+ const auto unix_epoch = std::chrono::system_clock::from_time_t(0);
+
+ const auto windows_duration = FileTimeToUnixEpochDuration(ft);
+ const auto sys_duration =
+ std::chrono::duration_cast<std::chrono::system_clock::duration>
+ (windows_duration);
+
+ return unix_epoch + sys_duration;
}
constexpr std::chrono::seconds