From 7ccfc0d88631a3080c910a4d4f2f1b6ca5be45e8 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Mon, 20 Jul 2020 16:52:37 -0700 Subject: [PATCH] Enable conversion between winrt::clock and std::chrono::system_clock --- strings/base_chrono.h | 25 +++++++++++++++---- test/old_tests/UnitTests/clock.cpp | 40 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/strings/base_chrono.h b/strings/base_chrono.h index 1a6236b5b..35eee33fd 100644 --- a/strings/base_chrono.h +++ b/strings/base_chrono.h @@ -42,12 +42,12 @@ WINRT_EXPORT namespace winrt static time_t to_time_t(time_point const& time) noexcept { - return std::chrono::duration_cast(time - time_t_epoch).count(); + return std::chrono::system_clock::to_time_t(to_sys(time)); } static time_point from_time_t(time_t time) noexcept { - return time_t_epoch + time_t_duration{ time }; + return from_sys(std::chrono::system_clock::from_time_t(time)); } static file_time to_file_time(time_point const& time) noexcept @@ -70,10 +70,25 @@ WINRT_EXPORT namespace winrt return from_file_time(time); } + template + static std::chrono::time_point> + to_sys(std::chrono::time_point const& tp) + { + return epoch + tp.time_since_epoch(); + } + + template + static std::chrono::time_point> + from_sys(std::chrono::time_point const& tp) + { + using result_t = std::chrono::time_point>; + return result_t{ tp - epoch }; + } + private: - // Define 00:00:00, Jan 1 1970 UTC in FILETIME units. - static constexpr time_point time_t_epoch{ duration{ 0x019DB1DED53E8000 } }; - using time_t_duration = std::chrono::duration; + // system_clock epoch is 00:00:00, Jan 1 1970. + // This is 11644473600 seconds after Windows FILETIME epoch of 00:00:00, Jan 1 1601. + static constexpr std::chrono::time_point epoch{ std::chrono::seconds{ -11644473600 } }; }; } diff --git a/test/old_tests/UnitTests/clock.cpp b/test/old_tests/UnitTests/clock.cpp index 1ac633d88..c18b5431a 100644 --- a/test/old_tests/UnitTests/clock.cpp +++ b/test/old_tests/UnitTests/clock.cpp @@ -95,3 +95,43 @@ TEST_CASE("clock, FILETIME") const auto diff = abs(clock::now() - clock::from_file_time(now_ft)); REQUIRE(diff < milliseconds{ 100 }); } + +TEST_CASE("clock, system_clock") +{ + DateTime const now_dt = clock::now(); + auto const now_sys = system_clock::now(); + + // Round trip DateTime to std::chrono::system_clock::time_point and back + REQUIRE(clock::from_sys(clock::to_sys(now_dt)) == now_dt); + + // Round trip other direction + REQUIRE(clock::to_sys(clock::from_sys(now_sys)) == now_sys); + + // Round trip with custom resolution + { + auto const now_dt_sec = time_point_cast(now_dt); + REQUIRE(clock::from_sys(clock::to_sys(now_dt_sec)) == now_dt_sec); + } + { + auto const now_dt_mins = time_point_cast(now_dt); + REQUIRE(clock::from_sys(clock::to_sys(now_dt_mins)) == now_dt_mins); + } + { + auto const now_sys_sec = time_point_cast(now_sys); + REQUIRE(clock::to_sys(clock::from_sys(now_sys_sec)) == now_sys_sec); + } + { + auto const now_sys_mins = time_point_cast(now_sys); + REQUIRE(clock::to_sys(clock::from_sys(now_sys_mins)) == now_sys_mins); + } + + // Verify that the epoch calculations are correct. + { + auto const diff = now_dt - clock::from_sys(now_sys); + REQUIRE(abs(diff) < milliseconds{ 100 }); + } + { + auto const diff = now_sys - clock::to_sys(now_dt); + REQUIRE(abs(diff) < milliseconds{ 100 }); + } +}