Mercurial > thymian
view common/date/tz.h @ 0:a4671277546c tip
created the repository for the thymian project
| author | ferencd |
|---|---|
| date | Tue, 17 Aug 2021 11:19:54 +0200 |
| parents | |
| children |
line wrap: on
line source
#ifndef TZ_H #define TZ_H // The MIT License (MIT) // // 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 // 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. // // Our apologies. When the previous paragraph was written, lowercase had not yet // been invented (that would involve another several millennia of evolution). // We did not mean to shout. // Get more recent database at http://www.iana.org/time-zones // The notion of "current timezone" is something the operating system is expected to "just // know". How it knows this is system specific. It's often a value set by the user at OS // installation time and recorded by the OS somewhere. On Linux and Mac systems the current // timezone name is obtained by looking at the name or contents of a particular file on // disk. On Windows the current timezone name comes from the registry. In either method, // there is no guarantee that the "native" current timezone name obtained will match any // of the "Standard" names in this library's "database". On Linux, the names usually do // seem to match so mapping functions to map from native to "Standard" are typically not // required. On Windows, the names are never "Standard" so mapping is always required. // Technically any OS may use the mapping process but currently only Windows does use it. #ifndef USE_OS_TZDB # define USE_OS_TZDB 0 #endif #ifndef HAS_REMOTE_API # if USE_OS_TZDB == 0 # ifdef _WIN32 # define HAS_REMOTE_API 0 # else # define HAS_REMOTE_API 1 # endif # else // HAS_REMOTE_API makes no since when using the OS timezone database # define HAS_REMOTE_API 0 # endif #endif #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wconstant-logical-operand" #endif static_assert(!(USE_OS_TZDB && HAS_REMOTE_API), "USE_OS_TZDB and HAS_REMOTE_API can not be used together"); #ifdef __clang__ # pragma clang diagnostic pop #endif #ifndef AUTO_DOWNLOAD # define AUTO_DOWNLOAD HAS_REMOTE_API #endif static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true, "AUTO_DOWNLOAD can not be turned on without HAS_REMOTE_API"); #ifndef USE_SHELL_API # define USE_SHELL_API 1 #endif #if USE_OS_TZDB # ifdef _WIN32 # error "USE_OS_TZDB can not be used on Windows" # endif # ifndef MISSING_LEAP_SECONDS # ifdef __APPLE__ # define MISSING_LEAP_SECONDS 1 # else # define MISSING_LEAP_SECONDS 0 # endif # endif #else # define MISSING_LEAP_SECONDS 0 #endif #ifndef HAS_DEDUCTION_GUIDES # if __cplusplus >= 201703 # define HAS_DEDUCTION_GUIDES 1 # else # define HAS_DEDUCTION_GUIDES 0 # endif #endif // HAS_DEDUCTION_GUIDES #include "date.h" #if defined(_MSC_VER) && (_MSC_VER < 1900) #include "tz_private.h" #endif #include <algorithm> #include <atomic> #include <cassert> #include <chrono> #include <istream> #include <locale> #include <memory> #include <mutex> #include <ostream> #include <sstream> #include <stdexcept> #include <string> #include <type_traits> #include <utility> #include <vector> #ifdef _WIN32 # ifdef DATE_BUILD_DLL # define DATE_API __declspec(dllexport) # elif defined(DATE_USE_DLL) # define DATE_API __declspec(dllimport) # else # define DATE_API # endif #else # ifdef DATE_BUILD_DLL # define DATE_API __attribute__ ((visibility ("default"))) # else # define DATE_API # endif #endif namespace date { enum class choose {earliest, latest}; namespace detail { struct undocumented; template<typename T> struct nodeduct { using type = T; }; template<typename T> using nodeduct_t = typename nodeduct<T>::type; } struct sys_info { sys_seconds begin; sys_seconds end; std::chrono::seconds offset; std::chrono::minutes save; std::string abbrev; }; template<class CharT, class Traits> std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const sys_info& r) { os << r.begin << '\n'; os << r.end << '\n'; os << make_time(r.offset) << "\n"; os << make_time(r.save) << "\n"; os << r.abbrev << '\n'; return os; } struct local_info { enum {unique, nonexistent, ambiguous} result; sys_info first; sys_info second; }; template<class CharT, class Traits> std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const local_info& r) { if (r.result == local_info::nonexistent) os << "nonexistent between\n"; else if (r.result == local_info::ambiguous) os << "ambiguous between\n"; os << r.first; if (r.result != local_info::unique) { os << "and\n"; os << r.second; } return os; } class nonexistent_local_time : public std::runtime_error { public: template <class Duration> nonexistent_local_time(local_time<Duration> tp, const local_info& i); private: template <class Duration> static std::string make_msg(local_time<Duration> tp, const local_info& i); }; template <class Duration> inline nonexistent_local_time::nonexistent_local_time(local_time<Duration> tp, const local_info& i) : std::runtime_error(make_msg(tp, i)) { } template <class Duration> std::string nonexistent_local_time::make_msg(local_time<Duration> tp, const local_info& i) { assert(i.result == local_info::nonexistent); std::ostringstream os; os << tp << " is in a gap between\n" << local_seconds{i.first.end.time_since_epoch()} + i.first.offset << ' ' << i.first.abbrev << " and\n" << local_seconds{i.second.begin.time_since_epoch()} + i.second.offset << ' ' << i.second.abbrev << " which are both equivalent to\n" << i.first.end << " UTC"; return os.str(); } class ambiguous_local_time : public std::runtime_error { public: template <class Duration> ambiguous_local_time(local_time<Duration> tp, const local_info& i); private: template <class Duration> static std::string make_msg(local_time<Duration> tp, const local_info& i); }; template <class Duration> inline ambiguous_local_time::ambiguous_local_time(local_time<Duration> tp, const local_info& i) : std::runtime_error(make_msg(tp, i)) { } template <class Duration> std::string ambiguous_local_time::make_msg(local_time<Duration> tp, const local_info& i) { assert(i.result == local_info::ambiguous); std::ostringstream os; os << tp << " is ambiguous. It could be\n" << tp << ' ' << i.first.abbrev << " == " << tp - i.first.offset << " UTC or\n" << tp << ' ' << i.second.abbrev << " == " << tp - i.second.offset << " UTC"; return os.str(); } class time_zone; #if HAS_STRING_VIEW DATE_API const time_zone* locate_zone(std::string_view tz_name); #else DATE_API const time_zone* locate_zone(const std::string& tz_name); #endif DATE_API const time_zone* current_zone(); template <class T> struct zoned_traits { }; template <> struct zoned_traits<const time_zone*> { static const time_zone* default_zone() { return date::locate_zone("Etc/UTC"); } #if HAS_STRING_VIEW static const time_zone* locate_zone(std::string_view name) { return date::locate_zone(name); } #else // !HAS_STRING_VIEW static const time_zone* locate_zone(const std::string& name) { return date::locate_zone(name); } static const time_zone* locate_zone(const char* name) { return date::locate_zone(name); } #endif // !HAS_STRING_VIEW }; template <class Duration, class TimeZonePtr> class zoned_time; template <class Duration1, class Duration2, class TimeZonePtr> bool operator==(const zoned_time<Duration1, TimeZonePtr>& x, const zoned_time<Duration2, TimeZonePtr>& y); template <class Duration, class TimeZonePtr = const time_zone*> class zoned_time { public: using duration = typename std::common_type<Duration, std::chrono::seconds>::type; private: TimeZonePtr zone_; sys_time<duration> tp_; public: #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = decltype(zoned_traits<T>::default_zone())> #endif zoned_time(); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = decltype(zoned_traits<T>::default_zone())> #endif zoned_time(const sys_time<Duration>& st); explicit zoned_time(TimeZonePtr z); #if HAS_STRING_VIEW template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string_view())) >::value >::type> explicit zoned_time(std::string_view name); #else # if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())) >::value >::type> # endif explicit zoned_time(const std::string& name); #endif template <class Duration2, class = typename std::enable_if < std::is_convertible<sys_time<Duration2>, sys_time<Duration>>::value >::type> zoned_time(const zoned_time<Duration2, TimeZonePtr>& zt) NOEXCEPT; zoned_time(TimeZonePtr z, const sys_time<Duration>& st); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = typename std::enable_if < std::is_convertible < decltype(std::declval<T&>()->to_sys(local_time<Duration>{})), sys_time<duration> >::value >::type> #endif zoned_time(TimeZonePtr z, const local_time<Duration>& tp); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = typename std::enable_if < std::is_convertible < decltype(std::declval<T&>()->to_sys(local_time<Duration>{}, choose::earliest)), sys_time<duration> >::value >::type> #endif zoned_time(TimeZonePtr z, const local_time<Duration>& tp, choose c); template <class Duration2, class TimeZonePtr2, class = typename std::enable_if < std::is_convertible<sys_time<Duration2>, sys_time<Duration>>::value >::type> zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt); template <class Duration2, class TimeZonePtr2, class = typename std::enable_if < std::is_convertible<sys_time<Duration2>, sys_time<Duration>>::value >::type> zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt, choose); #if HAS_STRING_VIEW template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string_view())), sys_time<Duration> >::value >::type> zoned_time(std::string_view name, detail::nodeduct_t<const sys_time<Duration>&> st); template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string_view())), local_time<Duration> >::value >::type> zoned_time(std::string_view name, detail::nodeduct_t<const local_time<Duration>&> tp); template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string_view())), local_time<Duration>, choose >::value >::type> zoned_time(std::string_view name, detail::nodeduct_t<const local_time<Duration>&> tp, choose c); template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr, class = typename std::enable_if < std::is_convertible<sys_time<Duration2>, sys_time<Duration>>::value && std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string_view())), zoned_time >::value >::type> zoned_time(std::string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt); template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr, class = typename std::enable_if < std::is_convertible<sys_time<Duration2>, sys_time<Duration>>::value && std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string_view())), zoned_time, choose >::value >::type> zoned_time(std::string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt, choose); #else // !HAS_STRING_VIEW #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), sys_time<Duration> >::value >::type> #endif zoned_time(const std::string& name, const sys_time<Duration>& st); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), sys_time<Duration> >::value >::type> #endif zoned_time(const char* name, const sys_time<Duration>& st); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), local_time<Duration> >::value >::type> #endif zoned_time(const std::string& name, const local_time<Duration>& tp); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), local_time<Duration> >::value >::type> #endif zoned_time(const char* name, const local_time<Duration>& tp); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), local_time<Duration>, choose >::value >::type> #endif zoned_time(const std::string& name, const local_time<Duration>& tp, choose c); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T = TimeZonePtr, class = typename std::enable_if < std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), local_time<Duration>, choose >::value >::type> #endif zoned_time(const char* name, const local_time<Duration>& tp, choose c); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr, class = typename std::enable_if < std::is_convertible<sys_time<Duration2>, sys_time<Duration>>::value && std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), zoned_time >::value >::type> #else template <class Duration2, class TimeZonePtr2> #endif zoned_time(const std::string& name, const zoned_time<Duration2, TimeZonePtr2>& zt); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr, class = typename std::enable_if < std::is_convertible<sys_time<Duration2>, sys_time<Duration>>::value && std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), zoned_time >::value >::type> #else template <class Duration2, class TimeZonePtr2> #endif zoned_time(const char* name, const zoned_time<Duration2, TimeZonePtr2>& zt); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr, class = typename std::enable_if < std::is_convertible<sys_time<Duration2>, sys_time<Duration>>::value && std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), zoned_time, choose >::value >::type> #else template <class Duration2, class TimeZonePtr2> #endif zoned_time(const std::string& name, const zoned_time<Duration2, TimeZonePtr2>& zt, choose); #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr, class = typename std::enable_if < std::is_convertible<sys_time<Duration2>, sys_time<Duration>>::value && std::is_constructible < zoned_time, decltype(zoned_traits<T>::locate_zone(std::string())), zoned_time, choose >::value >::type> #else template <class Duration2, class TimeZonePtr2> #endif zoned_time(const char* name, const zoned_time<Duration2, TimeZonePtr2>& zt, choose); #endif // !HAS_STRING_VIEW zoned_time& operator=(const sys_time<Duration>& st); zoned_time& operator=(const local_time<Duration>& ut); explicit operator sys_time<duration>() const; explicit operator local_time<duration>() const; TimeZonePtr get_time_zone() const; local_time<duration> get_local_time() const; sys_time<duration> get_sys_time() const; sys_info get_info() const; template <class Duration1, class Duration2, class TimeZonePtr1> friend bool operator==(const zoned_time<Duration1, TimeZonePtr1>& x, const zoned_time<Duration2, TimeZonePtr1>& y); template <class CharT, class Traits, class Duration1, class TimeZonePtr1> friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const zoned_time<Duration1, TimeZonePtr1>& t); private: template <class D, class T> friend class zoned_time; }; using zoned_seconds = zoned_time<std::chrono::seconds>; #if HAS_DEDUCTION_GUIDES namespace detail { template<typename TimeZonePtrOrName> using time_zone_representation = std::conditional_t < std::is_convertible<TimeZonePtrOrName, std::string_view>::value, time_zone const*, std::remove_cv_t<std::remove_reference_t<TimeZonePtrOrName>> >; } zoned_time() -> zoned_time<std::chrono::seconds>; template <class Duration> zoned_time(sys_time<Duration>) -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>>; template <class TimeZonePtrOrName> zoned_time(TimeZonePtrOrName&&) -> zoned_time<std::chrono::seconds, detail::time_zone_representation<TimeZonePtrOrName>>; template <class TimeZonePtrOrName, class Duration> zoned_time(TimeZonePtrOrName&&, sys_time<Duration>) -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>, detail::time_zone_representation<TimeZonePtrOrName>>; template <class TimeZonePtrOrName, class Duration> zoned_time(TimeZonePtrOrName&&, local_time<Duration>, choose = choose::earliest) -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>, detail::time_zone_representation<TimeZonePtrOrName>>; template <class Duration, class TimeZonePtrOrName, class TimeZonePtr2> zoned_time(TimeZonePtrOrName&&, zoned_time<Duration, TimeZonePtr2>, choose = choose::earliest) -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>, detail::time_zone_representation<TimeZonePtrOrName>>; #endif // HAS_DEDUCTION_GUIDES template <class Duration1, class Duration2, class TimeZonePtr> inline bool operator==(const zoned_time<Duration1, TimeZonePtr>& x, const zoned_time<Duration2, TimeZonePtr>& y) { return x.zone_ == y.zone_ && x.tp_ == y.tp_; } template <class Duration1, class Duration2, class TimeZonePtr> inline bool operator!=(const zoned_time<Duration1, TimeZonePtr>& x, const zoned_time<Duration2, TimeZonePtr>& y) { return !(x == y); } #if !defined(_MSC_VER) || (_MSC_VER >= 1900) namespace detail { # if USE_OS_TZDB struct transition; struct expanded_ttinfo; # else // !USE_OS_TZDB struct zonelet; class Rule; # endif // !USE_OS_TZDB } #endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) class time_zone { private: std::string name_; #if USE_OS_TZDB std::vector<detail::transition> transitions_; std::vector<detail::expanded_ttinfo> ttinfos_; #else // !USE_OS_TZDB std::vector<detail::zonelet> zonelets_; #endif // !USE_OS_TZDB std::unique_ptr<std::once_flag> adjusted_; public: #if !defined(_MSC_VER) || (_MSC_VER >= 1900) time_zone(time_zone&&) = default; time_zone& operator=(time_zone&&) = default; #else // defined(_MSC_VER) && (_MSC_VER < 1900) time_zone(time_zone&& src); time_zone& operator=(time_zone&& src); #endif // defined(_MSC_VER) && (_MSC_VER < 1900) DATE_API explicit time_zone(const std::string& s, detail::undocumented); const std::string& name() const NOEXCEPT; template <class Duration> sys_info get_info(sys_time<Duration> st) const; template <class Duration> local_info get_info(local_time<Duration> tp) const; template <class Duration> sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_sys(local_time<Duration> tp) const; template <class Duration> sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_sys(local_time<Duration> tp, choose z) const; template <class Duration> local_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_local(sys_time<Duration> tp) const; friend bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT; friend bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT; friend DATE_API std::ostream& operator<<(std::ostream& os, const time_zone& z); #if !USE_OS_TZDB DATE_API void add(const std::string& s); #endif // !USE_OS_TZDB private: DATE_API sys_info get_info_impl(sys_seconds tp) const; DATE_API local_info get_info_impl(local_seconds tp) const; template <class Duration> sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_sys_impl(local_time<Duration> tp, choose z, std::false_type) const; template <class Duration> sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_sys_impl(local_time<Duration> tp, choose, std::true_type) const; #if USE_OS_TZDB DATE_API void init() const; DATE_API void init_impl(); DATE_API sys_info load_sys_info(std::vector<detail::transition>::const_iterator i) const; template <class TimeType> DATE_API void load_data(std::istream& inf, std::int32_t tzh_leapcnt, std::int32_t tzh_timecnt, std::int32_t tzh_typecnt, std::int32_t tzh_charcnt); #else // !USE_OS_TZDB DATE_API sys_info get_info_impl(sys_seconds tp, int timezone) const; DATE_API void adjust_infos(const std::vector<detail::Rule>& rules); DATE_API void parse_info(std::istream& in); #endif // !USE_OS_TZDB }; #if defined(_MSC_VER) && (_MSC_VER < 1900) inline time_zone::time_zone(time_zone&& src) : name_(std::move(src.name_)) , zonelets_(std::move(src.zonelets_)) , adjusted_(std::move(src.adjusted_)) {} inline time_zone& time_zone::operator=(time_zone&& src) { name_ = std::move(src.name_); zonelets_ = std::move(src.zonelets_); adjusted_ = std::move(src.adjusted_); return *this; } #endif // defined(_MSC_VER) && (_MSC_VER < 1900) inline const std::string& time_zone::name() const NOEXCEPT { return name_; } template <class Duration> inline sys_info time_zone::get_info(sys_time<Duration> st) const { return get_info_impl(date::floor<std::chrono::seconds>(st)); } template <class Duration> inline local_info time_zone::get_info(local_time<Duration> tp) const { return get_info_impl(date::floor<std::chrono::seconds>(tp)); } template <class Duration> inline sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> time_zone::to_sys(local_time<Duration> tp) const { return to_sys_impl(tp, choose{}, std::true_type{}); } template <class Duration> inline sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> time_zone::to_sys(local_time<Duration> tp, choose z) const { return to_sys_impl(tp, z, std::false_type{}); } template <class Duration> inline local_time<typename std::common_type<Duration, std::chrono::seconds>::type> time_zone::to_local(sys_time<Duration> tp) const { using LT = local_time<typename std::common_type<Duration, std::chrono::seconds>::type>; auto i = get_info(tp); return LT{(tp + i.offset).time_since_epoch()}; } inline bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ == y.name_;} inline bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ < y.name_;} inline bool operator!=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x == y);} inline bool operator> (const time_zone& x, const time_zone& y) NOEXCEPT {return y < x;} inline bool operator<=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(y < x);} inline bool operator>=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x < y);} template <class Duration> sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> time_zone::to_sys_impl(local_time<Duration> tp, choose z, std::false_type) const { auto i = get_info(tp); if (i.result == local_info::nonexistent) { return i.first.end; } else if (i.result == local_info::ambiguous) { if (z == choose::latest) return sys_time<Duration>{tp.time_since_epoch()} - i.second.offset; } return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset; } template <class Duration> sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> time_zone::to_sys_impl(local_time<Duration> tp, choose, std::true_type) const { auto i = get_info(tp); if (i.result == local_info::nonexistent) throw nonexistent_local_time(tp, i); else if (i.result == local_info::ambiguous) throw ambiguous_local_time(tp, i); return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset; } #if !USE_OS_TZDB class link { private: std::string name_; std::string target_; public: DATE_API explicit link(const std::string& s); const std::string& name() const {return name_;} const std::string& target() const {return target_;} friend bool operator==(const link& x, const link& y) {return x.name_ == y.name_;} friend bool operator< (const link& x, const link& y) {return x.name_ < y.name_;} friend DATE_API std::ostream& operator<<(std::ostream& os, const link& x); }; inline bool operator!=(const link& x, const link& y) {return !(x == y);} inline bool operator> (const link& x, const link& y) {return y < x;} inline bool operator<=(const link& x, const link& y) {return !(y < x);} inline bool operator>=(const link& x, const link& y) {return !(x < y);} #endif // !USE_OS_TZDB #if !MISSING_LEAP_SECONDS class leap { private: sys_seconds date_; public: #if USE_OS_TZDB DATE_API explicit leap(const sys_seconds& s, detail::undocumented); #else DATE_API explicit leap(const std::string& s, detail::undocumented); #endif sys_seconds date() const {return date_;} friend bool operator==(const leap& x, const leap& y) {return x.date_ == y.date_;} friend bool operator< (const leap& x, const leap& y) {return x.date_ < y.date_;} template <class Duration> friend bool operator==(const leap& x, const sys_time<Duration>& y) { return x.date_ == y; } template <class Duration> friend bool operator< (const leap& x, const sys_time<Duration>& y) { return x.date_ < y; } template <class Duration> friend bool operator< (const sys_time<Duration>& x, const leap& y) { return x < y.date_; } friend DATE_API std::ostream& operator<<(std::ostream& os, const leap& x); }; inline bool operator!=(const leap& x, const leap& y) {return !(x == y);} inline bool operator> (const leap& x, const leap& y) {return y < x;} inline bool operator<=(const leap& x, const leap& y) {return !(y < x);} inline bool operator>=(const leap& x, const leap& y) {return !(x < y);} template <class Duration> inline bool operator==(const sys_time<Duration>& x, const leap& y) { return y == x; } template <class Duration> inline bool operator!=(const leap& x, const sys_time<Duration>& y) { return !(x == y); } template <class Duration> inline bool operator!=(const sys_time<Duration>& x, const leap& y) { return !(x == y); } template <class Duration> inline bool operator> (const leap& x, const sys_time<Duration>& y) { return y < x; } template <class Duration> inline bool operator> (const sys_time<Duration>& x, const leap& y) { return y < x; } template <class Duration> inline bool operator<=(const leap& x, const sys_time<Duration>& y) { return !(y < x); } template <class Duration> inline bool operator<=(const sys_time<Duration>& x, const leap& y) { return !(y < x); } template <class Duration> inline bool operator>=(const leap& x, const sys_time<Duration>& y) { return !(x < y); } template <class Duration> inline bool operator>=(const sys_time<Duration>& x, const leap& y) { return !(x < y); } #endif // !MISSING_LEAP_SECONDS #ifdef _WIN32 namespace detail { // The time zone mapping is modelled after this data file: // http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml // and the field names match the element names from the mapZone element // of windowsZones.xml. // The website displays this file here: // http://www.unicode.org/cldr/charts/latest/supplemental/zone_tzid.html // The html view is sorted before being displayed but is otherwise the same // There is a mapping between the os centric view (in this case windows) // the html displays uses and the generic view the xml file. // That mapping is this: // display column "windows" -> xml field "other". // display column "region" -> xml field "territory". // display column "tzid" -> xml field "type". // This structure uses the generic terminology because it could be // used to to support other os/native name conversions, not just windows, // and using the same generic names helps retain the connection to the // origin of the data that we are using. struct timezone_mapping { timezone_mapping(const char* other, const char* territory, const char* type) : other(other), territory(territory), type(type) { } timezone_mapping() = default; std::string other; std::string territory; std::string type; }; } // detail #endif // _WIN32 struct tzdb { std::string version = "unknown"; std::vector<time_zone> zones; #if !USE_OS_TZDB std::vector<link> links; #endif #if !MISSING_LEAP_SECONDS std::vector<leap> leaps; #endif #if !USE_OS_TZDB std::vector<detail::Rule> rules; #endif #ifdef _WIN32 std::vector<detail::timezone_mapping> mappings; #endif tzdb* next = nullptr; tzdb() = default; #if !defined(_MSC_VER) || (_MSC_VER >= 1900) tzdb(tzdb&&) = default; tzdb& operator=(tzdb&&) = default; #else // defined(_MSC_VER) && (_MSC_VER < 1900) tzdb(tzdb&& src) : version(std::move(src.version)) , zones(std::move(src.zones)) , links(std::move(src.links)) , leaps(std::move(src.leaps)) , rules(std::move(src.rules)) , mappings(std::move(src.mappings)) {} tzdb& operator=(tzdb&& src) { version = std::move(src.version); zones = std::move(src.zones); links = std::move(src.links); leaps = std::move(src.leaps); rules = std::move(src.rules); mappings = std::move(src.mappings); return *this; } #endif // defined(_MSC_VER) && (_MSC_VER < 1900) #if HAS_STRING_VIEW const time_zone* locate_zone(std::string_view tz_name) const; #else const time_zone* locate_zone(const std::string& tz_name) const; #endif const time_zone* current_zone() const; }; using TZ_DB = tzdb; DATE_API std::ostream& operator<<(std::ostream& os, const tzdb& db); DATE_API const tzdb& get_tzdb(); class tzdb_list { std::atomic<tzdb*> head_{nullptr}; public: ~tzdb_list(); tzdb_list() = default; tzdb_list(tzdb_list&& x) noexcept; const tzdb& front() const noexcept {return *head_;} tzdb& front() noexcept {return *head_;} class const_iterator; const_iterator begin() const noexcept; const_iterator end() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; const_iterator erase_after(const_iterator p) noexcept; struct undocumented_helper; private: void push_front(tzdb* tzdb) noexcept; }; class tzdb_list::const_iterator { tzdb* p_ = nullptr; explicit const_iterator(tzdb* p) noexcept : p_{p} {} public: const_iterator() = default; using iterator_category = std::forward_iterator_tag; using value_type = tzdb; using reference = const value_type&; using pointer = const value_type*; using difference_type = std::ptrdiff_t; reference operator*() const noexcept {return *p_;} pointer operator->() const noexcept {return p_;} const_iterator& operator++() noexcept {p_ = p_->next; return *this;} const_iterator operator++(int) noexcept {auto t = *this; ++(*this); return t;} friend bool operator==(const const_iterator& x, const const_iterator& y) noexcept {return x.p_ == y.p_;} friend bool operator!=(const const_iterator& x, const const_iterator& y) noexcept {return !(x == y);} friend class tzdb_list; }; inline tzdb_list::const_iterator tzdb_list::begin() const noexcept { return const_iterator{head_}; } inline tzdb_list::const_iterator tzdb_list::end() const noexcept { return const_iterator{nullptr}; } inline tzdb_list::const_iterator tzdb_list::cbegin() const noexcept { return begin(); } inline tzdb_list::const_iterator tzdb_list::cend() const noexcept { return end(); } DATE_API tzdb_list& get_tzdb_list(); #if !USE_OS_TZDB DATE_API const tzdb& reload_tzdb(); DATE_API void set_install(const std::string& install); #endif // !USE_OS_TZDB #if HAS_REMOTE_API DATE_API std::string remote_version(); DATE_API bool remote_download(const std::string& version); DATE_API bool remote_install(const std::string& version); #endif // zoned_time namespace detail { template <class T> inline T* to_raw_pointer(T* p) noexcept { return p; } template <class Pointer> inline auto to_raw_pointer(Pointer p) noexcept -> decltype(detail::to_raw_pointer(p.operator->())) { return detail::to_raw_pointer(p.operator->()); } } // namespace detail template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time() : zone_(zoned_traits<TimeZonePtr>::default_zone()) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const sys_time<Duration>& st) : zone_(zoned_traits<TimeZonePtr>::default_zone()) , tp_(st) {} template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z) : zone_(std::move(z)) {assert(detail::to_raw_pointer(zone_) != nullptr);} #if HAS_STRING_VIEW template <class Duration, class TimeZonePtr> template <class T, class> inline zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name)) {} #else // !HAS_STRING_VIEW template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name)) {} #endif // !HAS_STRING_VIEW template <class Duration, class TimeZonePtr> template <class Duration2, class> inline zoned_time<Duration, TimeZonePtr>::zoned_time(const zoned_time<Duration2, TimeZonePtr>& zt) NOEXCEPT : zone_(zt.zone_) , tp_(zt.tp_) {} template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const sys_time<Duration>& st) : zone_(std::move(z)) , tp_(st) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t) : zone_(std::move(z)) , tp_(zone_->to_sys(t)) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t, choose c) : zone_(std::move(z)) , tp_(zone_->to_sys(t, c)) {} template <class Duration, class TimeZonePtr> template <class Duration2, class TimeZonePtr2, class> inline zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt) : zone_(std::move(z)) , tp_(zt.tp_) {} template <class Duration, class TimeZonePtr> template <class Duration2, class TimeZonePtr2, class> inline zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt, choose) : zoned_time(std::move(z), zt) {} #if HAS_STRING_VIEW template <class Duration, class TimeZonePtr> template <class T, class> inline zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name, detail::nodeduct_t<const sys_time<Duration>&> st) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), st) {} template <class Duration, class TimeZonePtr> template <class T, class> inline zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name, detail::nodeduct_t<const local_time<Duration>&> t) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t) {} template <class Duration, class TimeZonePtr> template <class T, class> inline zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name, detail::nodeduct_t<const local_time<Duration>&> t, choose c) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t, c) {} template <class Duration, class TimeZonePtr> template <class Duration2, class TimeZonePtr2, class, class> inline zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt) {} template <class Duration, class TimeZonePtr> template <class Duration2, class TimeZonePtr2, class, class> inline zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt, choose c) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt, c) {} #else // !HAS_STRING_VIEW template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name, const sys_time<Duration>& st) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), st) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name, const sys_time<Duration>& st) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), st) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name, const local_time<Duration>& t) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name, const local_time<Duration>& t) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name, const local_time<Duration>& t, choose c) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t, c) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class T, class> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name, const local_time<Duration>& t, choose c) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t, c) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class Duration2, class TimeZonePtr2, class, class> #else template <class Duration2, class TimeZonePtr2> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name, const zoned_time<Duration2, TimeZonePtr2>& zt) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class Duration2, class TimeZonePtr2, class, class> #else template <class Duration2, class TimeZonePtr2> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name, const zoned_time<Duration2, TimeZonePtr2>& zt) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class Duration2, class TimeZonePtr2, class, class> #else template <class Duration2, class TimeZonePtr2> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name, const zoned_time<Duration2, TimeZonePtr2>& zt, choose c) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt, c) {} template <class Duration, class TimeZonePtr> #if !defined(_MSC_VER) || (_MSC_VER > 1900) template <class Duration2, class TimeZonePtr2, class, class> #else template <class Duration2, class TimeZonePtr2> #endif inline zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name, const zoned_time<Duration2, TimeZonePtr2>& zt, choose c) : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt, c) {} #endif // HAS_STRING_VIEW template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr>& zoned_time<Duration, TimeZonePtr>::operator=(const sys_time<Duration>& st) { tp_ = st; return *this; } template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr>& zoned_time<Duration, TimeZonePtr>::operator=(const local_time<Duration>& ut) { tp_ = zone_->to_sys(ut); return *this; } template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr>::operator local_time<typename zoned_time<Duration, TimeZonePtr>::duration>() const { return get_local_time(); } template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr>::operator sys_time<typename zoned_time<Duration, TimeZonePtr>::duration>() const { return get_sys_time(); } template <class Duration, class TimeZonePtr> inline TimeZonePtr zoned_time<Duration, TimeZonePtr>::get_time_zone() const { return zone_; } template <class Duration, class TimeZonePtr> inline local_time<typename zoned_time<Duration, TimeZonePtr>::duration> zoned_time<Duration, TimeZonePtr>::get_local_time() const { return zone_->to_local(tp_); } template <class Duration, class TimeZonePtr> inline sys_time<typename zoned_time<Duration, TimeZonePtr>::duration> zoned_time<Duration, TimeZonePtr>::get_sys_time() const { return tp_; } template <class Duration, class TimeZonePtr> inline sys_info zoned_time<Duration, TimeZonePtr>::get_info() const { return zone_->get_info(tp_); } // make_zoned_time inline zoned_time<std::chrono::seconds> make_zoned() { return zoned_time<std::chrono::seconds>(); } template <class Duration> inline zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type> make_zoned(const sys_time<Duration>& tp) { return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>(tp); } template <class TimeZonePtr #if !defined(_MSC_VER) || (_MSC_VER > 1900) , class = typename std::enable_if < std::is_class < typename std::decay < decltype(*detail::to_raw_pointer(std::declval<TimeZonePtr&>())) >::type >{} >::type #endif > inline zoned_time<std::chrono::seconds, TimeZonePtr> make_zoned(TimeZonePtr z) { return zoned_time<std::chrono::seconds, TimeZonePtr>(std::move(z)); } inline zoned_seconds make_zoned(const std::string& name) { return zoned_seconds(name); } template <class Duration, class TimeZonePtr #if !defined(_MSC_VER) || (_MSC_VER > 1900) , class = typename std::enable_if < std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{} >::type #endif > inline zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr> make_zoned(TimeZonePtr zone, const local_time<Duration>& tp) { return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr>(std::move(zone), tp); } template <class Duration, class TimeZonePtr #if !defined(_MSC_VER) || (_MSC_VER > 1900) , class = typename std::enable_if < std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{} >::type #endif > inline zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr> make_zoned(TimeZonePtr zone, const local_time<Duration>& tp, choose c) { return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr>(std::move(zone), tp, c); } template <class Duration> inline zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type> make_zoned(const std::string& name, const local_time<Duration>& tp) { return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>(name, tp); } template <class Duration> inline zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type> make_zoned(const std::string& name, const local_time<Duration>& tp, choose c) { return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>(name, tp, c); } template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr> make_zoned(TimeZonePtr zone, const zoned_time<Duration, TimeZonePtr>& zt) { return zoned_time<Duration, TimeZonePtr>(std::move(zone), zt); } template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr> make_zoned(const std::string& name, const zoned_time<Duration, TimeZonePtr>& zt) { return zoned_time<Duration, TimeZonePtr>(name, zt); } template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr> make_zoned(TimeZonePtr zone, const zoned_time<Duration, TimeZonePtr>& zt, choose c) { return zoned_time<Duration, TimeZonePtr>(std::move(zone), zt, c); } template <class Duration, class TimeZonePtr> inline zoned_time<Duration, TimeZonePtr> make_zoned(const std::string& name, const zoned_time<Duration, TimeZonePtr>& zt, choose c) { return zoned_time<Duration, TimeZonePtr>(name, zt, c); } template <class Duration, class TimeZonePtr #if !defined(_MSC_VER) || (_MSC_VER > 1900) , class = typename std::enable_if < std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{} >::type #endif > inline zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr> make_zoned(TimeZonePtr zone, const sys_time<Duration>& st) { return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr>(std::move(zone), st); } template <class Duration> inline zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type> make_zoned(const std::string& name, const sys_time<Duration>& st) { return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>(name, st); } template <class CharT, class Traits, class Duration, class TimeZonePtr> std::basic_ostream<CharT, Traits>& to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const zoned_time<Duration, TimeZonePtr>& tp) { using duration = typename zoned_time<Duration, TimeZonePtr>::duration; using LT = local_time<duration>; auto const st = tp.get_sys_time(); auto const info = tp.get_time_zone()->get_info(st); return to_stream(os, fmt, LT{(st+info.offset).time_since_epoch()}, &info.abbrev, &info.offset); } template <class CharT, class Traits, class Duration, class TimeZonePtr> inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const zoned_time<Duration, TimeZonePtr>& t) { const CharT fmt[] = {'%', 'F', ' ', '%', 'T', ' ', '%', 'Z', CharT{}}; return to_stream(os, fmt, t); } #if !MISSING_LEAP_SECONDS class utc_clock { public: using duration = std::chrono::system_clock::duration; using rep = duration::rep; using period = duration::period; using time_point = std::chrono::time_point<utc_clock>; static CONSTDATA bool is_steady = false; static time_point now(); template<typename Duration> static std::chrono::time_point<std::chrono::system_clock, typename std::common_type<Duration, std::chrono::seconds>::type> to_sys(const std::chrono::time_point<utc_clock, Duration>&); template<typename Duration> static std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type> from_sys(const std::chrono::time_point<std::chrono::system_clock, Duration>&); template<typename Duration> static std::chrono::time_point<local_t, typename std::common_type<Duration, std::chrono::seconds>::type> to_local(const std::chrono::time_point<utc_clock, Duration>&); template<typename Duration> static std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type> from_local(const std::chrono::time_point<local_t, Duration>&); }; template <class Duration> using utc_time = std::chrono::time_point<utc_clock, Duration>; using utc_seconds = utc_time<std::chrono::seconds>; template <class Duration> utc_time<typename std::common_type<Duration, std::chrono::seconds>::type> utc_clock::from_sys(const sys_time<Duration>& st) { using std::chrono::seconds; using CD = typename std::common_type<Duration, seconds>::type; auto const& leaps = get_tzdb().leaps; auto const lt = std::upper_bound(leaps.begin(), leaps.end(), st); return utc_time<CD>{st.time_since_epoch() + seconds{lt-leaps.begin()}}; } // Return pair<is_leap_second, seconds{number_of_leap_seconds_since_1970}> // first is true if ut is during a leap second insertion, otherwise false. // If ut is during a leap second insertion, that leap second is included in the count template <class Duration> std::pair<bool, std::chrono::seconds> is_leap_second(date::utc_time<Duration> const& ut) { using std::chrono::seconds; using duration = typename std::common_type<Duration, seconds>::type; auto const& leaps = get_tzdb().leaps; auto tp = sys_time<duration>{ut.time_since_epoch()}; auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp); auto ds = seconds{lt-leaps.begin()}; tp -= ds; auto ls = false; if (lt > leaps.begin()) { if (tp < lt[-1]) { if (tp >= lt[-1].date() - seconds{1}) ls = true; else --ds; } } return {ls, ds}; } struct leap_second_info { bool is_leap_second; std::chrono::seconds elapsed; }; template <class Duration> leap_second_info get_leap_second_info(date::utc_time<Duration> const& ut) { auto p = is_leap_second(ut); return {p.first, p.second}; } template <class Duration> sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> utc_clock::to_sys(const utc_time<Duration>& ut) { using std::chrono::seconds; using CD = typename std::common_type<Duration, seconds>::type; auto ls = is_leap_second(ut); auto tp = sys_time<CD>{ut.time_since_epoch() - ls.second}; if (ls.first) tp = floor<seconds>(tp) + seconds{1} - CD{1}; return tp; } inline utc_clock::time_point utc_clock::now() { return from_sys(std::chrono::system_clock::now()); } template <class Duration> utc_time<typename std::common_type<Duration, std::chrono::seconds>::type> utc_clock::from_local(const local_time<Duration>& st) { return from_sys(sys_time<Duration>{st.time_since_epoch()}); } template <class Duration> local_time<typename std::common_type<Duration, std::chrono::seconds>::type> utc_clock::to_local(const utc_time<Duration>& ut) { using CD = typename std::common_type<Duration, std::chrono::seconds>::type; return local_time<CD>{to_sys(ut).time_since_epoch()}; } template <class CharT, class Traits, class Duration> std::basic_ostream<CharT, Traits>& to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const utc_time<Duration>& t) { using std::chrono::seconds; using CT = typename std::common_type<Duration, seconds>::type; const std::string abbrev("UTC"); CONSTDATA seconds offset{0}; auto ls = is_leap_second(t); auto tp = sys_time<CT>{t.time_since_epoch() - ls.second}; auto const sd = floor<days>(tp); year_month_day ymd = sd; auto time = make_time(tp - sys_seconds{sd}); time.seconds(detail::undocumented{}) += seconds{ls.first}; fields<CT> fds{ymd, time}; return to_stream(os, fmt, fds, &abbrev, &offset); } template <class CharT, class Traits, class Duration> std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const utc_time<Duration>& t) { const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; return to_stream(os, fmt, t); } template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>> std::basic_istream<CharT, Traits>& from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, utc_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { using std::chrono::seconds; using std::chrono::minutes; using CT = typename std::common_type<Duration, seconds>::type; minutes offset_local{}; auto offptr = offset ? offset : &offset_local; fields<CT> fds{}; fds.has_tod = true; from_stream(is, fmt, fds, abbrev, offptr); if (!fds.ymd.ok()) is.setstate(std::ios::failbit); if (!is.fail()) { bool is_60_sec = fds.tod.seconds() == seconds{60}; if (is_60_sec) fds.tod.seconds(detail::undocumented{}) -= seconds{1}; auto tmp = utc_clock::from_sys(sys_days(fds.ymd) - *offptr + fds.tod.to_duration()); if (is_60_sec) tmp += seconds{1}; if (is_60_sec != is_leap_second(tmp).first || !fds.tod.in_conventional_range()) { is.setstate(std::ios::failbit); return is; } tp = std::chrono::time_point_cast<Duration>(tmp); } return is; } // tai_clock class tai_clock { public: using duration = std::chrono::system_clock::duration; using rep = duration::rep; using period = duration::period; using time_point = std::chrono::time_point<tai_clock>; static const bool is_steady = false; static time_point now(); template<typename Duration> static std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type> to_utc(const std::chrono::time_point<tai_clock, Duration>&) NOEXCEPT; template<typename Duration> static std::chrono::time_point<tai_clock, typename std::common_type<Duration, std::chrono::seconds>::type> from_utc(const std::chrono::time_point<utc_clock, Duration>&) NOEXCEPT; template<typename Duration> static std::chrono::time_point<local_t, typename std::common_type<Duration, date::days>::type> to_local(const std::chrono::time_point<tai_clock, Duration>&) NOEXCEPT; template<typename Duration> static std::chrono::time_point<tai_clock, typename std::common_type<Duration, date::days>::type> from_local(const std::chrono::time_point<local_t, Duration>&) NOEXCEPT; }; template <class Duration> using tai_time = std::chrono::time_point<tai_clock, Duration>; using tai_seconds = tai_time<std::chrono::seconds>; template <class Duration> inline utc_time<typename std::common_type<Duration, std::chrono::seconds>::type> tai_clock::to_utc(const tai_time<Duration>& t) NOEXCEPT { using std::chrono::seconds; using CD = typename std::common_type<Duration, seconds>::type; return utc_time<CD>{t.time_since_epoch()} - (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10}); } template <class Duration> inline tai_time<typename std::common_type<Duration, std::chrono::seconds>::type> tai_clock::from_utc(const utc_time<Duration>& t) NOEXCEPT { using std::chrono::seconds; using CD = typename std::common_type<Duration, seconds>::type; return tai_time<CD>{t.time_since_epoch()} + (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10}); } inline tai_clock::time_point tai_clock::now() { return from_utc(utc_clock::now()); } template <class Duration> inline local_time<typename std::common_type<Duration, date::days>::type> tai_clock::to_local(const tai_time<Duration>& t) NOEXCEPT { using CD = typename std::common_type<Duration, date::days>::type; return local_time<CD>{t.time_since_epoch()} - (local_days(year{1970}/January/1) - local_days(year{1958}/January/1)); } template <class Duration> inline tai_time<typename std::common_type<Duration, date::days>::type> tai_clock::from_local(const local_time<Duration>& t) NOEXCEPT { using CD = typename std::common_type<Duration, date::days>::type; return tai_time<CD>{t.time_since_epoch()} + (local_days(year{1970}/January/1) - local_days(year{1958}/January/1)); } template <class CharT, class Traits, class Duration> std::basic_ostream<CharT, Traits>& to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const tai_time<Duration>& t) { const std::string abbrev("TAI"); CONSTDATA std::chrono::seconds offset{0}; return to_stream(os, fmt, tai_clock::to_local(t), &abbrev, &offset); } template <class CharT, class Traits, class Duration> std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const tai_time<Duration>& t) { const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; return to_stream(os, fmt, t); } template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>> std::basic_istream<CharT, Traits>& from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, tai_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { local_time<Duration> lp; from_stream(is, fmt, lp, abbrev, offset); if (!is.fail()) tp = tai_clock::from_local(lp); return is; } // gps_clock class gps_clock { public: using duration = std::chrono::system_clock::duration; using rep = duration::rep; using period = duration::period; using time_point = std::chrono::time_point<gps_clock>; static const bool is_steady = false; static time_point now(); template<typename Duration> static std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type> to_utc(const std::chrono::time_point<gps_clock, Duration>&) NOEXCEPT; template<typename Duration> static std::chrono::time_point<gps_clock, typename std::common_type<Duration, std::chrono::seconds>::type> from_utc(const std::chrono::time_point<utc_clock, Duration>&) NOEXCEPT; template<typename Duration> static std::chrono::time_point<local_t, typename std::common_type<Duration, date::days>::type> to_local(const std::chrono::time_point<gps_clock, Duration>&) NOEXCEPT; template<typename Duration> static std::chrono::time_point<gps_clock, typename std::common_type<Duration, date::days>::type> from_local(const std::chrono::time_point<local_t, Duration>&) NOEXCEPT; }; template <class Duration> using gps_time = std::chrono::time_point<gps_clock, Duration>; using gps_seconds = gps_time<std::chrono::seconds>; template <class Duration> inline utc_time<typename std::common_type<Duration, std::chrono::seconds>::type> gps_clock::to_utc(const gps_time<Duration>& t) NOEXCEPT { using std::chrono::seconds; using CD = typename std::common_type<Duration, seconds>::type; return utc_time<CD>{t.time_since_epoch()} + (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1970}/January/1) + seconds{9}); } template <class Duration> inline gps_time<typename std::common_type<Duration, std::chrono::seconds>::type> gps_clock::from_utc(const utc_time<Duration>& t) NOEXCEPT { using std::chrono::seconds; using CD = typename std::common_type<Duration, seconds>::type; return gps_time<CD>{t.time_since_epoch()} - (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1970}/January/1) + seconds{9}); } inline gps_clock::time_point gps_clock::now() { return from_utc(utc_clock::now()); } template <class Duration> inline local_time<typename std::common_type<Duration, date::days>::type> gps_clock::to_local(const gps_time<Duration>& t) NOEXCEPT { using CD = typename std::common_type<Duration, date::days>::type; return local_time<CD>{t.time_since_epoch()} + (local_days(year{1980}/January/Sunday[1]) - local_days(year{1970}/January/1)); } template <class Duration> inline gps_time<typename std::common_type<Duration, date::days>::type> gps_clock::from_local(const local_time<Duration>& t) NOEXCEPT { using CD = typename std::common_type<Duration, date::days>::type; return gps_time<CD>{t.time_since_epoch()} - (local_days(year{1980}/January/Sunday[1]) - local_days(year{1970}/January/1)); } template <class CharT, class Traits, class Duration> std::basic_ostream<CharT, Traits>& to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const gps_time<Duration>& t) { const std::string abbrev("GPS"); CONSTDATA std::chrono::seconds offset{0}; return to_stream(os, fmt, gps_clock::to_local(t), &abbrev, &offset); } template <class CharT, class Traits, class Duration> std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const gps_time<Duration>& t) { const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; return to_stream(os, fmt, t); } template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>> std::basic_istream<CharT, Traits>& from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, gps_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { local_time<Duration> lp; from_stream(is, fmt, lp, abbrev, offset); if (!is.fail()) tp = gps_clock::from_local(lp); return is; } // clock_time_conversion template <class DstClock, class SrcClock> struct clock_time_conversion {}; template <> struct clock_time_conversion<std::chrono::system_clock, std::chrono::system_clock> { template <class Duration> sys_time<Duration> operator()(const sys_time<Duration>& st) const { return st; } }; template <> struct clock_time_conversion<utc_clock, utc_clock> { template <class Duration> utc_time<Duration> operator()(const utc_time<Duration>& ut) const { return ut; } }; template<> struct clock_time_conversion<local_t, local_t> { template <class Duration> local_time<Duration> operator()(const local_time<Duration>& lt) const { return lt; } }; template <> struct clock_time_conversion<utc_clock, std::chrono::system_clock> { template <class Duration> utc_time<typename std::common_type<Duration, std::chrono::seconds>::type> operator()(const sys_time<Duration>& st) const { return utc_clock::from_sys(st); } }; template <> struct clock_time_conversion<std::chrono::system_clock, utc_clock> { template <class Duration> sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> operator()(const utc_time<Duration>& ut) const { return utc_clock::to_sys(ut); } }; template<> struct clock_time_conversion<local_t, std::chrono::system_clock> { template <class Duration> local_time<Duration> operator()(const sys_time<Duration>& st) const { return local_time<Duration>{st.time_since_epoch()}; } }; template<> struct clock_time_conversion<std::chrono::system_clock, local_t> { template <class Duration> sys_time<Duration> operator()(const local_time<Duration>& lt) const { return sys_time<Duration>{lt.time_since_epoch()}; } }; template<> struct clock_time_conversion<utc_clock, local_t> { template <class Duration> utc_time<typename std::common_type<Duration, std::chrono::seconds>::type> operator()(const local_time<Duration>& lt) const { return utc_clock::from_local(lt); } }; template<> struct clock_time_conversion<local_t, utc_clock> { template <class Duration> local_time<typename std::common_type<Duration, std::chrono::seconds>::type> operator()(const utc_time<Duration>& ut) const { return utc_clock::to_local(ut); } }; template<typename Clock> struct clock_time_conversion<Clock, Clock> { template <class Duration> std::chrono::time_point<Clock, Duration> operator()(const std::chrono::time_point<Clock, Duration>& tp) const { return tp; } }; namespace ctc_detail { template <class Clock, class Duration> using time_point = std::chrono::time_point<Clock, Duration>; using std::declval; using std::chrono::system_clock; //Check if TimePoint is time for given clock, //if not emits hard error template <class Clock, class TimePoint> struct return_clock_time { using clock_time_point = time_point<Clock, typename TimePoint::duration>; using type = TimePoint; static_assert(std::is_same<TimePoint, clock_time_point>::value, "time point with appropariate clock shall be returned"); }; // 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 <class Clock, class Duration, class = void> struct return_to_sys {}; template <class Clock, class Duration> struct return_to_sys < Clock, Duration, decltype(Clock::to_sys(declval<time_point<Clock, Duration> const&>()), void()) > : return_clock_time < system_clock, decltype(Clock::to_sys(declval<time_point<Clock, Duration> const&>())) > {}; // Similiar to above template <class Clock, class Duration, class = void> struct return_from_sys {}; template <class Clock, class Duration> struct return_from_sys < Clock, Duration, decltype(Clock::from_sys(declval<time_point<system_clock, Duration> const&>()), void()) > : return_clock_time < Clock, decltype(Clock::from_sys(declval<time_point<system_clock, Duration> const&>())) > {}; // Similiar to above template <class Clock, class Duration, class = void> struct return_to_utc {}; template <class Clock, class Duration> struct return_to_utc < Clock, Duration, decltype(Clock::to_utc(declval<time_point<Clock, Duration> const&>()), void()) > : return_clock_time < utc_clock, decltype(Clock::to_utc(declval<time_point<Clock, Duration> const&>()))> {}; // Similiar to above template <class Clock, class Duration, class = void> struct return_from_utc {}; template <class Clock, class Duration> struct return_from_utc < Clock, Duration, decltype(Clock::from_utc(declval<time_point<utc_clock, Duration> const&>()), void()) > : return_clock_time < Clock, decltype(Clock::from_utc(declval<time_point<utc_clock, Duration> const&>())) > {}; // Similiar to above template<typename Clock, typename Duration, typename = void> struct return_to_local {}; template<typename Clock, typename Duration> struct return_to_local < Clock, Duration, decltype(Clock::to_local(declval<time_point<Clock, Duration> const&>()), void()) > : return_clock_time < local_t, decltype(Clock::to_local(declval<time_point<Clock, Duration> const&>())) > {}; // Similiar to above template<typename Clock, typename Duration, typename = void> struct return_from_local {}; template<typename Clock, typename Duration> struct return_from_local < Clock, Duration, decltype(Clock::from_local(declval<time_point<local_t, Duration> const&>()), void()) > : return_clock_time < Clock, decltype(Clock::from_local(declval<time_point<local_t, Duration> const&>())) > {}; } // namespace ctc_detail template <class SrcClock> struct clock_time_conversion<std::chrono::system_clock, SrcClock> { template <class Duration> typename ctc_detail::return_to_sys<SrcClock, Duration>::type operator()(const std::chrono::time_point<SrcClock, Duration>& tp) const { return SrcClock::to_sys(tp); } }; template <class DstClock> struct clock_time_conversion<DstClock, std::chrono::system_clock> { template <class Duration> typename ctc_detail::return_from_sys<DstClock, Duration>::type operator()(const sys_time<Duration>& st) const { return DstClock::from_sys(st); } }; template <class SrcClock> struct clock_time_conversion<utc_clock, SrcClock> { template <class Duration> typename ctc_detail::return_to_utc<SrcClock, Duration>::type operator()(const std::chrono::time_point<SrcClock, Duration>& tp) const { return SrcClock::to_utc(tp); } }; template <class DstClock> struct clock_time_conversion<DstClock, utc_clock> { template <class Duration> typename ctc_detail::return_from_utc<DstClock, Duration>::type operator()(const utc_time<Duration>& ut) const { return DstClock::from_utc(ut); } }; template<typename SrcClock> struct clock_time_conversion<local_t, SrcClock> { template <class Duration> typename ctc_detail::return_to_local<SrcClock, Duration>::type operator()(const std::chrono::time_point<SrcClock, Duration>& tp) const { return SrcClock::to_local(tp); } }; template<typename DstClock> struct clock_time_conversion<DstClock, local_t> { template <class Duration> typename ctc_detail::return_from_local<DstClock, Duration>::type operator()(const local_time<Duration>& lt) const { return DstClock::from_local(lt); } }; namespace clock_cast_detail { template <class Clock, class Duration> using time_point = std::chrono::time_point<Clock, Duration>; using std::chrono::system_clock; template <class DstClock, class SrcClock, class Duration> auto conv_clock(const time_point<SrcClock, Duration>& t) -> decltype(std::declval<clock_time_conversion<DstClock, SrcClock>>()(t)) { return clock_time_conversion<DstClock, SrcClock>{}(t); } //direct trait conversion, 1st candidate template <class DstClock, class SrcClock, class Duration> auto cc_impl(const time_point<SrcClock, Duration>& t, const time_point<SrcClock, Duration>*) -> decltype(conv_clock<DstClock>(t)) { return conv_clock<DstClock>(t); } //conversion through sys, 2nd candidate template <class DstClock, class SrcClock, class Duration> auto cc_impl(const time_point<SrcClock, Duration>& t, const void*) -> decltype(conv_clock<DstClock>(conv_clock<system_clock>(t))) { return conv_clock<DstClock>(conv_clock<system_clock>(t)); } //conversion through utc, 2nd candidate template <class DstClock, class SrcClock, class Duration> auto cc_impl(const time_point<SrcClock, Duration>& t, const void*) -> decltype(0, // MSVC_WORKAROUND conv_clock<DstClock>(conv_clock<utc_clock>(t))) { return conv_clock<DstClock>(conv_clock<utc_clock>(t)); } //conversion through sys and utc, 3rd candidate template <class DstClock, class SrcClock, class Duration> auto cc_impl(const time_point<SrcClock, Duration>& t, ...) -> decltype(conv_clock<DstClock>(conv_clock<utc_clock>(conv_clock<system_clock>(t)))) { return conv_clock<DstClock>(conv_clock<utc_clock>(conv_clock<system_clock>(t))); } //conversion through utc and sys, 3rd candidate template <class DstClock, class SrcClock, class Duration> auto cc_impl(const time_point<SrcClock, Duration>& t, ...) -> decltype(0, // MSVC_WORKAROUND conv_clock<DstClock>(conv_clock<system_clock>(conv_clock<utc_clock>(t)))) { return conv_clock<DstClock>(conv_clock<system_clock>(conv_clock<utc_clock>(t))); } } // namespace clock_cast_detail template <class DstClock, class SrcClock, class Duration> auto clock_cast(const std::chrono::time_point<SrcClock, Duration>& tp) -> decltype(clock_cast_detail::cc_impl<DstClock>(tp, &tp)) { return clock_cast_detail::cc_impl<DstClock>(tp, &tp); } // Deprecated API template <class Duration> inline sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_sys_time(const utc_time<Duration>& t) { return utc_clock::to_sys(t); } template <class Duration> inline sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_sys_time(const tai_time<Duration>& t) { return utc_clock::to_sys(tai_clock::to_utc(t)); } template <class Duration> inline sys_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_sys_time(const gps_time<Duration>& t) { return utc_clock::to_sys(gps_clock::to_utc(t)); } template <class Duration> inline utc_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_utc_time(const sys_time<Duration>& t) { return utc_clock::from_sys(t); } template <class Duration> inline utc_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_utc_time(const tai_time<Duration>& t) { return tai_clock::to_utc(t); } template <class Duration> inline utc_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_utc_time(const gps_time<Duration>& t) { return gps_clock::to_utc(t); } template <class Duration> inline tai_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_tai_time(const sys_time<Duration>& t) { return tai_clock::from_utc(utc_clock::from_sys(t)); } template <class Duration> inline tai_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_tai_time(const utc_time<Duration>& t) { return tai_clock::from_utc(t); } template <class Duration> inline tai_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_tai_time(const gps_time<Duration>& t) { return tai_clock::from_utc(gps_clock::to_utc(t)); } template <class Duration> inline gps_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_gps_time(const sys_time<Duration>& t) { return gps_clock::from_utc(utc_clock::from_sys(t)); } template <class Duration> inline gps_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_gps_time(const utc_time<Duration>& t) { return gps_clock::from_utc(t); } template <class Duration> inline gps_time<typename std::common_type<Duration, std::chrono::seconds>::type> to_gps_time(const tai_time<Duration>& t) { return gps_clock::from_utc(tai_clock::to_utc(t)); } #endif // !MISSING_LEAP_SECONDS } // namespace date #endif // TZ_H
