diff --git a/include/date/tz.h b/include/date/tz.h index 3eefa35..1591f80 100644 --- a/include/date/tz.h +++ b/include/date/tz.h @@ -6,6 +6,7 @@ // Copyright (c) 2015, 2016, 2017 Howard Hinnant // Copyright (c) 2017 Jiangang Zhuang // Copyright (c) 2017 Aaron Bishop +// Copyright (c) 2017 Tomasz KamiƄski // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -1836,6 +1837,16 @@ public: static CONSTDATA bool is_steady = false; static time_point now(); + + template + static + std::chrono::time_point::type> + to_sys(const std::chrono::time_point&); + + template + static + std::chrono::time_point::type> + from_sys(const std::chrono::time_point&); }; template @@ -1844,9 +1855,8 @@ template using utc_seconds = utc_time; template -inline utc_time::type> -to_utc_time(const sys_time& st) +utc_clock::from_sys(const sys_time& st) { using namespace std::chrono; using duration = typename std::common_type::type; @@ -1885,9 +1895,8 @@ is_leap_second(date::utc_time const& ut) } template -inline sys_time::type> -to_sys_time(const utc_time& ut) +utc_clock::to_sys(const utc_time& ut) { using namespace std::chrono; using duration = typename std::common_type::type; @@ -1903,7 +1912,7 @@ utc_clock::time_point utc_clock::now() { using namespace std::chrono; - return to_utc_time(system_clock::now()); + return from_sys(system_clock::now()); } template @@ -1979,6 +1988,16 @@ public: static const bool is_steady = false; static time_point now() NOEXCEPT; + + template + static + std::chrono::time_point::type> + to_utc(const std::chrono::time_point&) NOEXCEPT; + + template + static + std::chrono::time_point::type> + from_utc(const std::chrono::time_point&) NOEXCEPT; }; template @@ -1989,7 +2008,7 @@ using tai_seconds = tai_time; template inline utc_time::type> -to_utc_time(const tai_time& t) NOEXCEPT +tai_clock::to_utc(const tai_time& t) NOEXCEPT { using namespace std::chrono; using duration = typename std::common_type::type; @@ -2000,7 +2019,7 @@ to_utc_time(const tai_time& t) NOEXCEPT template inline tai_time::type> -to_tai_time(const utc_time& t) NOEXCEPT +tai_clock::from_utc(const utc_time& t) NOEXCEPT { using namespace std::chrono; using duration = typename std::common_type::type; @@ -2008,20 +2027,12 @@ to_tai_time(const utc_time& t) NOEXCEPT (sys_days(year{1970}/jan/1) - sys_days(year{1958}/jan/1) + seconds{10}); } -template -inline -tai_time::type> -to_tai_time(const sys_time& t) -{ - return to_tai_time(to_utc_time(t)); -} - inline tai_clock::time_point tai_clock::now() NOEXCEPT { using namespace std::chrono; - return to_tai_time(system_clock::now()); + return from_utc(utc_clock::now()); } template @@ -2087,6 +2098,17 @@ public: static const bool is_steady = false; static time_point now() NOEXCEPT; + + template + static + std::chrono::time_point::type> + to_utc(const std::chrono::time_point&) NOEXCEPT; + + template + static + std::chrono::time_point::type> + from_utc(const std::chrono::time_point&) NOEXCEPT; + }; template @@ -2097,7 +2119,7 @@ using gps_seconds = gps_time; template inline utc_time::type> -to_utc_time(const gps_time& t) NOEXCEPT +gps_clock::to_utc(const gps_time& t) NOEXCEPT { using namespace std::chrono; using duration = typename std::common_type::type; @@ -2108,7 +2130,7 @@ to_utc_time(const gps_time& t) NOEXCEPT template inline gps_time::type> -to_gps_time(const utc_time& t) +gps_clock::from_utc(const utc_time& t) NOEXCEPT { using namespace std::chrono; using duration = typename std::common_type::type; @@ -2116,20 +2138,12 @@ to_gps_time(const utc_time& t) (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1970}/jan/1) + seconds{9}); } -template -inline -gps_time::type> -to_gps_time(const sys_time& t) -{ - return to_gps_time(to_utc_time(t)); -} - inline gps_clock::time_point gps_clock::now() NOEXCEPT { using namespace std::chrono; - return to_gps_time(system_clock::now()); + return from_utc(utc_clock::now()); } template @@ -2183,42 +2197,224 @@ from_stream(std::basic_istream& is, const CharT* fmt, return is; } -template -inline -sys_time::type> -to_sys_time(const tai_time& t) +template +struct clock_time_conversion +{}; + +template<> +struct clock_time_conversion { - return to_sys_time(to_utc_time(t)); + template + auto operator()(const std::chrono::time_point& st) + -> std::chrono::time_point + { + return st; + } +}; + +template<> +struct clock_time_conversion +{ + template + auto operator()(const std::chrono::time_point& st) + -> std::chrono::time_point + { + return st; + } +}; + +template<> +struct clock_time_conversion +{ + template + utc_time::type> + operator()(const sys_time& st) const + { + return utc_clock::from_sys(st); + } +}; + +template<> +struct clock_time_conversion +{ + template + sys_time::type> + operator()(const utc_time& ut) const + { + return utc_clock::to_sys(ut); + } +}; + +template +struct clock_time_conversion +{ + template + auto operator()(const std::chrono::time_point& st) + -> std::chrono::time_point + { + return st; + } +}; + +namespace ctc_detail +{ + //Check if TimePoint is time for given clock, + //if so exposes it as type typedef + template + struct return_clock_time + : std::enable_if< + std::is_same::value, + TimePoint + > + {}; + + // Check if Clock has to_sys method accepting TimePoint with given duration const& and returning sys_time + // If so has nested type member equal to return type to_sys. + template + struct return_to_sys + {}; + + template + struct return_to_sys const&>()), void())> + : return_clock_time const&>()))>::type> + {}; + + // Similiar to above + template + struct return_from_sys + {}; + + template + struct return_from_sys const&>()), void())> + : return_clock_time const&>()))>::type> + {}; + + // Similiar to above + template + struct return_to_utc + {}; + + template + struct return_to_utc const&>()), void())> + : return_clock_time const&>()))>::type> + {}; + + // Similiar to above + template + struct return_from_utc + {}; + + template + struct return_from_utc const&>()), void())> + : return_clock_time const&>()))>::type> + {}; } -template -inline -sys_time::type> -to_sys_time(const gps_time& t) +template +struct clock_time_conversion { - return to_sys_time(to_utc_time(t)); + template + auto operator()(const std::chrono::time_point& st) + -> typename ctc_detail::return_to_sys::type + { + return SourceClock::to_sys(st); + } +}; + +template +struct clock_time_conversion +{ + template + auto operator()(const std::chrono::time_point& st) + -> typename ctc_detail::return_from_sys::type + { + return DestClock::from_sys(st); + } +}; + +template +struct clock_time_conversion +{ + template + auto operator()(const std::chrono::time_point& st) + -> typename ctc_detail::return_to_utc::type + { + return SourceClock::to_utc(st); + } +}; + +template +struct clock_time_conversion +{ + template + auto operator()(const std::chrono::time_point& ut) + -> typename ctc_detail::return_from_utc::type + { + return DestClock::from_utc(ut); + } +}; + +namespace clock_cast_detail +{ + template + auto conv_clock(const std::chrono::time_point& st) + -> decltype(std::declval&>()(st)) + { + clock_time_conversion converter; + return converter(st); + } + + //direct triat conversion, 2nd candidate + template + auto cc_impl(const std::chrono::time_point& st, + const std::chrono::time_point* /* 1st */) + -> decltype(conv_clock(st)) + { + return conv_clock(st); + } + + //conversion trought sys, 3rd candidate + template + auto cc_impl(const std::chrono::time_point& st, + const void* /* 2nd */) + -> decltype(conv_clock(conv_clock(st))) + { + return conv_clock(conv_clock(st)); + } + + //conversion trought utc, 3rd candidate + template + auto cc_impl(const std::chrono::time_point& st, + const void* /* 2nd */) + -> decltype(conv_clock(conv_clock(st))) + { + return conv_clock(conv_clock(st)); + } + + //conversion trought sys and utc, 4th candidate + template + auto cc_impl(const std::chrono::time_point& st, + ... /* 3rd */) + -> decltype(conv_clock(conv_clock(conv_clock(st)))) + { + return conv_clock(conv_clock(conv_clock(st))); + } + + //conversion trought utc and sys, 4th candidate + template + auto cc_impl(const std::chrono::time_point& st, + ... /* 3rd */) + -> decltype(conv_clock(conv_clock(conv_clock(st)))) + { + return conv_clock(conv_clock(conv_clock(st))); + } } -template -inline -tai_time::type> -to_tai_time(const gps_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return tai_time{t.time_since_epoch()} + - (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1958}/jan/1) + seconds{19}); -} - -template -inline -gps_time::type> -to_gps_time(const tai_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return gps_time{t.time_since_epoch()} - - (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1958}/jan/1) + seconds{19}); +template +auto clock_cast(const std::chrono::time_point& st) + -> decltype(clock_cast_detail::cc_impl(st, &st)) +{ + return clock_cast_detail::cc_impl(st, &st); } #endif // !MISSING_LEAP_SECONDS