// The MIT License (MIT) // // Copyright (c) 2017, 2018 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 // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #include "tz.h" #include #include template struct is_clock_castable : std::false_type {}; template struct is_clock_castable(typename SourceClock::time_point()), void())> : std::true_type {}; //Clock based on steady clock, not related to wall time (sys_clock/utc_clock) struct steady_based_clock { using duration = std::chrono::steady_clock::duration; using rep = duration::rep; using period = duration::period; using time_point = std::chrono::time_point; static time_point now() { return time_point(std::chrono::steady_clock::now().time_since_epoch()); } }; //Traits that allow conversion between steady_clock and steady_based clock //Does not use wall-time clocks as rally (sys/utc) namespace date { template<> struct clock_time_conversion { template std::chrono::time_point operator()(std::chrono::time_point const& tp) const { using res = std::chrono::time_point; return res(tp.time_since_epoch()); } }; template<> struct clock_time_conversion { template std::chrono::time_point operator()(std::chrono::time_point const& tp) const { using res = std::chrono::time_point; return res(tp.time_since_epoch()); } }; } //Ambigous clocks both providing to/from_sys and to/from_utc //They are mock_ups just returning zero time_point struct amb1_clock { using duration = std::chrono::seconds; using rep = duration::rep; using period = duration::period; using time_point = std::chrono::time_point; static time_point now() { return {}; } template static std::chrono::time_point to_sys(std::chrono::time_point const&) { return {}; } template static std::chrono::time_point from_sys(std::chrono::time_point const&) { return {}; } template static std::chrono::time_point to_utc(std::chrono::time_point const&) { return {}; } template static std::chrono::time_point from_utc(std::chrono::time_point const&) { return {}; } }; struct amb2_clock { using duration = std::chrono::seconds; using rep = duration::rep; using period = duration::period; using time_point = std::chrono::time_point; static time_point now() { return {}; } template static std::chrono::time_point to_sys(std::chrono::time_point const&) { return {}; } template static std::chrono::time_point from_sys(std::chrono::time_point const&) { return {}; } template static std::chrono::time_point to_utc(std::chrono::time_point const&) { return {}; } template static std::chrono::time_point from_utc(std::chrono::time_point const&) { return {}; } }; namespace date { //Disambiguates that sys_clock is preffered template<> struct clock_time_conversion { template std::chrono::time_point operator()(std::chrono::time_point const& tp) const { return amb1_clock::from_sys(amb2_clock::to_sys(tp)); } }; } int main() { using namespace date; using namespace std::chrono; using sys_clock = std::chrono::system_clock; using local_t = date::local_t; //steady_clock (must be different that sys_clock) static_assert(is_clock_castable::value, "steady_clock -> steady_clock"); static_assert(!is_clock_castable::value, "steady_clock -> local_t"); static_assert(!is_clock_castable::value, "local_t -> steady_clock"); static_assert(!is_clock_castable::value, "steady_clock -> sys_clock"); static_assert(!is_clock_castable::value, "sys_clock -> steady_clock"); static_assert(!is_clock_castable::value, "steady_clock -> utc_clock"); static_assert(!is_clock_castable::value, "utc_clock -> steady_clock"); static_assert(!is_clock_castable::value, "steady_clock -> tai_clock"); static_assert(!is_clock_castable::value, "tai_clock -> steady_clock"); //steady_based_clock (unrelated to sys_clock and utc_clocks) static_assert(is_clock_castable::value, "steady_based_clock -> steady_based_clock"); static_assert(!is_clock_castable::value, "steady_based_clock -> local_t"); static_assert(!is_clock_castable::value, "local_t -> steady_based_clock"); static_assert(!is_clock_castable::value, "steady_based_clock -> sys_clock"); static_assert(!is_clock_castable::value, "sys_clock -> steady_based_clock"); static_assert(!is_clock_castable::value, "steady_based_clock -> utc_clock"); static_assert(!is_clock_castable::value, "utc_clock -> steady_based_clock"); static_assert(!is_clock_castable::value, "steady_based_clock -> tai_clock"); static_assert(!is_clock_castable::value, "tai_clock -> steady_based_clock"); //steady_based <-> steady_clock { auto s1 = steady_clock::time_point(steady_clock::duration(200)); auto s2 = steady_based_clock::time_point(steady_based_clock::duration(200)); assert(clock_cast(s1) == s2); assert(clock_cast(s2) == s1); } //ambX <-> sys/utc works as one rally can be used in each case, or one lead to quicker conversione static_assert(is_clock_castable::value, "amb1_clock -> amb1_clock"); static_assert(is_clock_castable::value, "amb1_clock -> sys_clock"); static_assert(is_clock_castable::value, "sys_clock -> amb1_clock"); static_assert(is_clock_castable::value, "amb1_clock -> utc_clock"); static_assert(is_clock_castable::value, "utc_clock -> amb1_clock"); static_assert(is_clock_castable::value, "amb1_clock -> tai_clock"); static_assert(is_clock_castable::value, "tai_clock -> amb1_clock"); static_assert(is_clock_castable::value, "amb1_clock -> tai_clock"); static_assert(is_clock_castable::value, "gps_clock -> amb1_clock"); static_assert(is_clock_castable::value, "amb2_clock -> amb2_clock"); static_assert(is_clock_castable::value, "amb2_clock -> sys_clock"); static_assert(is_clock_castable::value, "sys_clock -> amb2_clock"); static_assert(is_clock_castable::value, "amb2_clock -> utc_clock"); static_assert(is_clock_castable::value, "utc_clock -> amb2_clock"); static_assert(is_clock_castable::value, "amb2_clock -> tai_clock"); static_assert(is_clock_castable::value, "tai_clock -> amb2_clock"); static_assert(is_clock_castable::value, "amb2_clock -> tai_clock"); static_assert(is_clock_castable::value, "gps_clock -> amb2_clock"); //amb1 -> amb2: ambigous because can either go trough sys_clock or utc_clock static_assert(!is_clock_castable::value, "amb1_clock -> amb2_clock"); //amb2 -> amb1: disambiguated via trait specialization static_assert(is_clock_castable::value, "amb2_clock -> amb1_clock"); }