ferencd@0: #ifndef TZ_H ferencd@0: #define TZ_H ferencd@0: ferencd@0: // The MIT License (MIT) ferencd@0: // ferencd@0: // Copyright (c) 2015, 2016, 2017 Howard Hinnant ferencd@0: // Copyright (c) 2017 Jiangang Zhuang ferencd@0: // Copyright (c) 2017 Aaron Bishop ferencd@0: // Copyright (c) 2017 Tomasz KamiƄski ferencd@0: // ferencd@0: // Permission is hereby granted, free of charge, to any person obtaining a copy ferencd@0: // of this software and associated documentation files (the "Software"), to deal ferencd@0: // in the Software without restriction, including without limitation the rights ferencd@0: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ferencd@0: // copies of the Software, and to permit persons to whom the Software is ferencd@0: // furnished to do so, subject to the following conditions: ferencd@0: // ferencd@0: // The above copyright notice and this permission notice shall be included in all ferencd@0: // copies or substantial portions of the Software. ferencd@0: // ferencd@0: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ferencd@0: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ferencd@0: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ferencd@0: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ferencd@0: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ferencd@0: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ferencd@0: // SOFTWARE. ferencd@0: // ferencd@0: // Our apologies. When the previous paragraph was written, lowercase had not yet ferencd@0: // been invented (that would involve another several millennia of evolution). ferencd@0: // We did not mean to shout. ferencd@0: ferencd@0: // Get more recent database at http://www.iana.org/time-zones ferencd@0: ferencd@0: // The notion of "current timezone" is something the operating system is expected to "just ferencd@0: // know". How it knows this is system specific. It's often a value set by the user at OS ferencd@0: // installation time and recorded by the OS somewhere. On Linux and Mac systems the current ferencd@0: // timezone name is obtained by looking at the name or contents of a particular file on ferencd@0: // disk. On Windows the current timezone name comes from the registry. In either method, ferencd@0: // there is no guarantee that the "native" current timezone name obtained will match any ferencd@0: // of the "Standard" names in this library's "database". On Linux, the names usually do ferencd@0: // seem to match so mapping functions to map from native to "Standard" are typically not ferencd@0: // required. On Windows, the names are never "Standard" so mapping is always required. ferencd@0: // Technically any OS may use the mapping process but currently only Windows does use it. ferencd@0: ferencd@0: #ifndef USE_OS_TZDB ferencd@0: # define USE_OS_TZDB 0 ferencd@0: #endif ferencd@0: ferencd@0: #ifndef HAS_REMOTE_API ferencd@0: # if USE_OS_TZDB == 0 ferencd@0: # ifdef _WIN32 ferencd@0: # define HAS_REMOTE_API 0 ferencd@0: # else ferencd@0: # define HAS_REMOTE_API 1 ferencd@0: # endif ferencd@0: # else // HAS_REMOTE_API makes no since when using the OS timezone database ferencd@0: # define HAS_REMOTE_API 0 ferencd@0: # endif ferencd@0: #endif ferencd@0: ferencd@0: #ifdef __clang__ ferencd@0: # pragma clang diagnostic push ferencd@0: # pragma clang diagnostic ignored "-Wconstant-logical-operand" ferencd@0: #endif ferencd@0: ferencd@0: static_assert(!(USE_OS_TZDB && HAS_REMOTE_API), ferencd@0: "USE_OS_TZDB and HAS_REMOTE_API can not be used together"); ferencd@0: ferencd@0: #ifdef __clang__ ferencd@0: # pragma clang diagnostic pop ferencd@0: #endif ferencd@0: ferencd@0: #ifndef AUTO_DOWNLOAD ferencd@0: # define AUTO_DOWNLOAD HAS_REMOTE_API ferencd@0: #endif ferencd@0: ferencd@0: static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true, ferencd@0: "AUTO_DOWNLOAD can not be turned on without HAS_REMOTE_API"); ferencd@0: ferencd@0: #ifndef USE_SHELL_API ferencd@0: # define USE_SHELL_API 1 ferencd@0: #endif ferencd@0: ferencd@0: #if USE_OS_TZDB ferencd@0: # ifdef _WIN32 ferencd@0: # error "USE_OS_TZDB can not be used on Windows" ferencd@0: # endif ferencd@0: # ifndef MISSING_LEAP_SECONDS ferencd@0: # ifdef __APPLE__ ferencd@0: # define MISSING_LEAP_SECONDS 1 ferencd@0: # else ferencd@0: # define MISSING_LEAP_SECONDS 0 ferencd@0: # endif ferencd@0: # endif ferencd@0: #else ferencd@0: # define MISSING_LEAP_SECONDS 0 ferencd@0: #endif ferencd@0: ferencd@0: #ifndef HAS_DEDUCTION_GUIDES ferencd@0: # if __cplusplus >= 201703 ferencd@0: # define HAS_DEDUCTION_GUIDES 1 ferencd@0: # else ferencd@0: # define HAS_DEDUCTION_GUIDES 0 ferencd@0: # endif ferencd@0: #endif // HAS_DEDUCTION_GUIDES ferencd@0: ferencd@0: #include "date.h" ferencd@0: ferencd@0: #if defined(_MSC_VER) && (_MSC_VER < 1900) ferencd@0: #include "tz_private.h" ferencd@0: #endif ferencd@0: ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: ferencd@0: #ifdef _WIN32 ferencd@0: # ifdef DATE_BUILD_DLL ferencd@0: # define DATE_API __declspec(dllexport) ferencd@0: # elif defined(DATE_USE_DLL) ferencd@0: # define DATE_API __declspec(dllimport) ferencd@0: # else ferencd@0: # define DATE_API ferencd@0: # endif ferencd@0: #else ferencd@0: # ifdef DATE_BUILD_DLL ferencd@0: # define DATE_API __attribute__ ((visibility ("default"))) ferencd@0: # else ferencd@0: # define DATE_API ferencd@0: # endif ferencd@0: #endif ferencd@0: ferencd@0: namespace date ferencd@0: { ferencd@0: ferencd@0: enum class choose {earliest, latest}; ferencd@0: ferencd@0: namespace detail ferencd@0: { ferencd@0: struct undocumented; ferencd@0: ferencd@0: template ferencd@0: struct nodeduct ferencd@0: { ferencd@0: using type = T; ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: using nodeduct_t = typename nodeduct::type; ferencd@0: } ferencd@0: ferencd@0: struct sys_info ferencd@0: { ferencd@0: sys_seconds begin; ferencd@0: sys_seconds end; ferencd@0: std::chrono::seconds offset; ferencd@0: std::chrono::minutes save; ferencd@0: std::string abbrev; ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: std::basic_ostream& ferencd@0: operator<<(std::basic_ostream& os, const sys_info& r) ferencd@0: { ferencd@0: os << r.begin << '\n'; ferencd@0: os << r.end << '\n'; ferencd@0: os << make_time(r.offset) << "\n"; ferencd@0: os << make_time(r.save) << "\n"; ferencd@0: os << r.abbrev << '\n'; ferencd@0: return os; ferencd@0: } ferencd@0: ferencd@0: struct local_info ferencd@0: { ferencd@0: enum {unique, nonexistent, ambiguous} result; ferencd@0: sys_info first; ferencd@0: sys_info second; ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: std::basic_ostream& ferencd@0: operator<<(std::basic_ostream& os, const local_info& r) ferencd@0: { ferencd@0: if (r.result == local_info::nonexistent) ferencd@0: os << "nonexistent between\n"; ferencd@0: else if (r.result == local_info::ambiguous) ferencd@0: os << "ambiguous between\n"; ferencd@0: os << r.first; ferencd@0: if (r.result != local_info::unique) ferencd@0: { ferencd@0: os << "and\n"; ferencd@0: os << r.second; ferencd@0: } ferencd@0: return os; ferencd@0: } ferencd@0: ferencd@0: class nonexistent_local_time ferencd@0: : public std::runtime_error ferencd@0: { ferencd@0: public: ferencd@0: template ferencd@0: nonexistent_local_time(local_time tp, const local_info& i); ferencd@0: ferencd@0: private: ferencd@0: template ferencd@0: static ferencd@0: std::string ferencd@0: make_msg(local_time tp, const local_info& i); ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: nonexistent_local_time::nonexistent_local_time(local_time tp, ferencd@0: const local_info& i) ferencd@0: : std::runtime_error(make_msg(tp, i)) ferencd@0: { ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: std::string ferencd@0: nonexistent_local_time::make_msg(local_time tp, const local_info& i) ferencd@0: { ferencd@0: assert(i.result == local_info::nonexistent); ferencd@0: std::ostringstream os; ferencd@0: os << tp << " is in a gap between\n" ferencd@0: << local_seconds{i.first.end.time_since_epoch()} + i.first.offset << ' ' ferencd@0: << i.first.abbrev << " and\n" ferencd@0: << local_seconds{i.second.begin.time_since_epoch()} + i.second.offset << ' ' ferencd@0: << i.second.abbrev ferencd@0: << " which are both equivalent to\n" ferencd@0: << i.first.end << " UTC"; ferencd@0: return os.str(); ferencd@0: } ferencd@0: ferencd@0: class ambiguous_local_time ferencd@0: : public std::runtime_error ferencd@0: { ferencd@0: public: ferencd@0: template ferencd@0: ambiguous_local_time(local_time tp, const local_info& i); ferencd@0: ferencd@0: private: ferencd@0: template ferencd@0: static ferencd@0: std::string ferencd@0: make_msg(local_time tp, const local_info& i); ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: ambiguous_local_time::ambiguous_local_time(local_time tp, const local_info& i) ferencd@0: : std::runtime_error(make_msg(tp, i)) ferencd@0: { ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: std::string ferencd@0: ambiguous_local_time::make_msg(local_time tp, const local_info& i) ferencd@0: { ferencd@0: assert(i.result == local_info::ambiguous); ferencd@0: std::ostringstream os; ferencd@0: os << tp << " is ambiguous. It could be\n" ferencd@0: << tp << ' ' << i.first.abbrev << " == " ferencd@0: << tp - i.first.offset << " UTC or\n" ferencd@0: << tp << ' ' << i.second.abbrev << " == " ferencd@0: << tp - i.second.offset << " UTC"; ferencd@0: return os.str(); ferencd@0: } ferencd@0: ferencd@0: class time_zone; ferencd@0: ferencd@0: #if HAS_STRING_VIEW ferencd@0: DATE_API const time_zone* locate_zone(std::string_view tz_name); ferencd@0: #else ferencd@0: DATE_API const time_zone* locate_zone(const std::string& tz_name); ferencd@0: #endif ferencd@0: ferencd@0: DATE_API const time_zone* current_zone(); ferencd@0: ferencd@0: template ferencd@0: struct zoned_traits ferencd@0: { ferencd@0: }; ferencd@0: ferencd@0: template <> ferencd@0: struct zoned_traits ferencd@0: { ferencd@0: static ferencd@0: const time_zone* ferencd@0: default_zone() ferencd@0: { ferencd@0: return date::locate_zone("Etc/UTC"); ferencd@0: } ferencd@0: ferencd@0: #if HAS_STRING_VIEW ferencd@0: ferencd@0: static ferencd@0: const time_zone* ferencd@0: locate_zone(std::string_view name) ferencd@0: { ferencd@0: return date::locate_zone(name); ferencd@0: } ferencd@0: ferencd@0: #else // !HAS_STRING_VIEW ferencd@0: ferencd@0: static ferencd@0: const time_zone* ferencd@0: locate_zone(const std::string& name) ferencd@0: { ferencd@0: return date::locate_zone(name); ferencd@0: } ferencd@0: ferencd@0: static ferencd@0: const time_zone* ferencd@0: locate_zone(const char* name) ferencd@0: { ferencd@0: return date::locate_zone(name); ferencd@0: } ferencd@0: ferencd@0: #endif // !HAS_STRING_VIEW ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: class zoned_time; ferencd@0: ferencd@0: template ferencd@0: bool ferencd@0: operator==(const zoned_time& x, ferencd@0: const zoned_time& y); ferencd@0: ferencd@0: template ferencd@0: class zoned_time ferencd@0: { ferencd@0: public: ferencd@0: using duration = typename std::common_type::type; ferencd@0: ferencd@0: private: ferencd@0: TimeZonePtr zone_; ferencd@0: sys_time tp_; ferencd@0: ferencd@0: public: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ::default_zone())> ferencd@0: #endif ferencd@0: zoned_time(); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ::default_zone())> ferencd@0: #endif ferencd@0: zoned_time(const sys_time& st); ferencd@0: explicit zoned_time(TimeZonePtr z); ferencd@0: ferencd@0: #if HAS_STRING_VIEW ferencd@0: template ::locate_zone(std::string_view())) ferencd@0: >::value ferencd@0: >::type> ferencd@0: explicit zoned_time(std::string_view name); ferencd@0: #else ferencd@0: # if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ::locate_zone(std::string())) ferencd@0: >::value ferencd@0: >::type> ferencd@0: # endif ferencd@0: explicit zoned_time(const std::string& name); ferencd@0: #endif ferencd@0: ferencd@0: template , ferencd@0: sys_time>::value ferencd@0: >::type> ferencd@0: zoned_time(const zoned_time& zt) NOEXCEPT; ferencd@0: ferencd@0: zoned_time(TimeZonePtr z, const sys_time& st); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ()->to_sys(local_time{})), ferencd@0: sys_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: #endif ferencd@0: zoned_time(TimeZonePtr z, const local_time& tp); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ()->to_sys(local_time{}, ferencd@0: choose::earliest)), ferencd@0: sys_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: #endif ferencd@0: zoned_time(TimeZonePtr z, const local_time& tp, choose c); ferencd@0: ferencd@0: template , ferencd@0: sys_time>::value ferencd@0: >::type> ferencd@0: zoned_time(TimeZonePtr z, const zoned_time& zt); ferencd@0: ferencd@0: template , ferencd@0: sys_time>::value ferencd@0: >::type> ferencd@0: zoned_time(TimeZonePtr z, const zoned_time& zt, choose); ferencd@0: ferencd@0: #if HAS_STRING_VIEW ferencd@0: ferencd@0: template ::locate_zone(std::string_view())), ferencd@0: sys_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: zoned_time(std::string_view name, detail::nodeduct_t&> st); ferencd@0: ferencd@0: template ::locate_zone(std::string_view())), ferencd@0: local_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: zoned_time(std::string_view name, detail::nodeduct_t&> tp); ferencd@0: ferencd@0: template ::locate_zone(std::string_view())), ferencd@0: local_time, ferencd@0: choose ferencd@0: >::value ferencd@0: >::type> ferencd@0: zoned_time(std::string_view name, detail::nodeduct_t&> tp, choose c); ferencd@0: ferencd@0: template , ferencd@0: sys_time>::value && ferencd@0: std::is_constructible ferencd@0: < ferencd@0: zoned_time, ferencd@0: decltype(zoned_traits::locate_zone(std::string_view())), ferencd@0: zoned_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: zoned_time(std::string_view name, const zoned_time& zt); ferencd@0: ferencd@0: template , ferencd@0: sys_time>::value && ferencd@0: std::is_constructible ferencd@0: < ferencd@0: zoned_time, ferencd@0: decltype(zoned_traits::locate_zone(std::string_view())), ferencd@0: zoned_time, ferencd@0: choose ferencd@0: >::value ferencd@0: >::type> ferencd@0: zoned_time(std::string_view name, const zoned_time& zt, choose); ferencd@0: ferencd@0: #else // !HAS_STRING_VIEW ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ::locate_zone(std::string())), ferencd@0: sys_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: #endif ferencd@0: zoned_time(const std::string& name, const sys_time& st); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ::locate_zone(std::string())), ferencd@0: sys_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: #endif ferencd@0: zoned_time(const char* name, const sys_time& st); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ::locate_zone(std::string())), ferencd@0: local_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: #endif ferencd@0: zoned_time(const std::string& name, const local_time& tp); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ::locate_zone(std::string())), ferencd@0: local_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: #endif ferencd@0: zoned_time(const char* name, const local_time& tp); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ::locate_zone(std::string())), ferencd@0: local_time, ferencd@0: choose ferencd@0: >::value ferencd@0: >::type> ferencd@0: #endif ferencd@0: zoned_time(const std::string& name, const local_time& tp, choose c); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ::locate_zone(std::string())), ferencd@0: local_time, ferencd@0: choose ferencd@0: >::value ferencd@0: >::type> ferencd@0: #endif ferencd@0: zoned_time(const char* name, const local_time& tp, choose c); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template , ferencd@0: sys_time>::value && ferencd@0: std::is_constructible ferencd@0: < ferencd@0: zoned_time, ferencd@0: decltype(zoned_traits::locate_zone(std::string())), ferencd@0: zoned_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: #else ferencd@0: template ferencd@0: #endif ferencd@0: zoned_time(const std::string& name, const zoned_time& zt); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template , ferencd@0: sys_time>::value && ferencd@0: std::is_constructible ferencd@0: < ferencd@0: zoned_time, ferencd@0: decltype(zoned_traits::locate_zone(std::string())), ferencd@0: zoned_time ferencd@0: >::value ferencd@0: >::type> ferencd@0: #else ferencd@0: template ferencd@0: #endif ferencd@0: zoned_time(const char* name, const zoned_time& zt); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template , ferencd@0: sys_time>::value && ferencd@0: std::is_constructible ferencd@0: < ferencd@0: zoned_time, ferencd@0: decltype(zoned_traits::locate_zone(std::string())), ferencd@0: zoned_time, ferencd@0: choose ferencd@0: >::value ferencd@0: >::type> ferencd@0: #else ferencd@0: template ferencd@0: #endif ferencd@0: zoned_time(const std::string& name, const zoned_time& zt, ferencd@0: choose); ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template , ferencd@0: sys_time>::value && ferencd@0: std::is_constructible ferencd@0: < ferencd@0: zoned_time, ferencd@0: decltype(zoned_traits::locate_zone(std::string())), ferencd@0: zoned_time, ferencd@0: choose ferencd@0: >::value ferencd@0: >::type> ferencd@0: #else ferencd@0: template ferencd@0: #endif ferencd@0: zoned_time(const char* name, const zoned_time& zt, ferencd@0: choose); ferencd@0: ferencd@0: #endif // !HAS_STRING_VIEW ferencd@0: ferencd@0: zoned_time& operator=(const sys_time& st); ferencd@0: zoned_time& operator=(const local_time& ut); ferencd@0: ferencd@0: explicit operator sys_time() const; ferencd@0: explicit operator local_time() const; ferencd@0: ferencd@0: TimeZonePtr get_time_zone() const; ferencd@0: local_time get_local_time() const; ferencd@0: sys_time get_sys_time() const; ferencd@0: sys_info get_info() const; ferencd@0: ferencd@0: template ferencd@0: friend ferencd@0: bool ferencd@0: operator==(const zoned_time& x, ferencd@0: const zoned_time& y); ferencd@0: ferencd@0: template ferencd@0: friend ferencd@0: std::basic_ostream& ferencd@0: operator<<(std::basic_ostream& os, ferencd@0: const zoned_time& t); ferencd@0: ferencd@0: private: ferencd@0: template friend class zoned_time; ferencd@0: }; ferencd@0: ferencd@0: using zoned_seconds = zoned_time; ferencd@0: ferencd@0: #if HAS_DEDUCTION_GUIDES ferencd@0: ferencd@0: namespace detail ferencd@0: { ferencd@0: template ferencd@0: using time_zone_representation = ferencd@0: std::conditional_t ferencd@0: < ferencd@0: std::is_convertible::value, ferencd@0: time_zone const*, ferencd@0: std::remove_cv_t> ferencd@0: >; ferencd@0: } ferencd@0: ferencd@0: zoned_time() ferencd@0: -> zoned_time; ferencd@0: ferencd@0: template ferencd@0: zoned_time(sys_time) ferencd@0: -> zoned_time>; ferencd@0: ferencd@0: template ferencd@0: zoned_time(TimeZonePtrOrName&&) ferencd@0: -> zoned_time>; ferencd@0: ferencd@0: template ferencd@0: zoned_time(TimeZonePtrOrName&&, sys_time) ferencd@0: -> zoned_time, detail::time_zone_representation>; ferencd@0: ferencd@0: template ferencd@0: zoned_time(TimeZonePtrOrName&&, local_time, choose = choose::earliest) ferencd@0: -> zoned_time, detail::time_zone_representation>; ferencd@0: ferencd@0: template ferencd@0: zoned_time(TimeZonePtrOrName&&, zoned_time, choose = choose::earliest) ferencd@0: -> zoned_time, detail::time_zone_representation>; ferencd@0: ferencd@0: #endif // HAS_DEDUCTION_GUIDES ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator==(const zoned_time& x, ferencd@0: const zoned_time& y) ferencd@0: { ferencd@0: return x.zone_ == y.zone_ && x.tp_ == y.tp_; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator!=(const zoned_time& x, ferencd@0: const zoned_time& y) ferencd@0: { ferencd@0: return !(x == y); ferencd@0: } ferencd@0: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER >= 1900) ferencd@0: ferencd@0: namespace detail ferencd@0: { ferencd@0: # if USE_OS_TZDB ferencd@0: struct transition; ferencd@0: struct expanded_ttinfo; ferencd@0: # else // !USE_OS_TZDB ferencd@0: struct zonelet; ferencd@0: class Rule; ferencd@0: # endif // !USE_OS_TZDB ferencd@0: } ferencd@0: ferencd@0: #endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) ferencd@0: ferencd@0: class time_zone ferencd@0: { ferencd@0: private: ferencd@0: std::string name_; ferencd@0: #if USE_OS_TZDB ferencd@0: std::vector transitions_; ferencd@0: std::vector ttinfos_; ferencd@0: #else // !USE_OS_TZDB ferencd@0: std::vector zonelets_; ferencd@0: #endif // !USE_OS_TZDB ferencd@0: std::unique_ptr adjusted_; ferencd@0: ferencd@0: public: ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER >= 1900) ferencd@0: time_zone(time_zone&&) = default; ferencd@0: time_zone& operator=(time_zone&&) = default; ferencd@0: #else // defined(_MSC_VER) && (_MSC_VER < 1900) ferencd@0: time_zone(time_zone&& src); ferencd@0: time_zone& operator=(time_zone&& src); ferencd@0: #endif // defined(_MSC_VER) && (_MSC_VER < 1900) ferencd@0: ferencd@0: DATE_API explicit time_zone(const std::string& s, detail::undocumented); ferencd@0: ferencd@0: const std::string& name() const NOEXCEPT; ferencd@0: ferencd@0: template sys_info get_info(sys_time st) const; ferencd@0: template local_info get_info(local_time tp) const; ferencd@0: ferencd@0: template ferencd@0: sys_time::type> ferencd@0: to_sys(local_time tp) const; ferencd@0: ferencd@0: template ferencd@0: sys_time::type> ferencd@0: to_sys(local_time tp, choose z) const; ferencd@0: ferencd@0: template ferencd@0: local_time::type> ferencd@0: to_local(sys_time tp) const; ferencd@0: ferencd@0: friend bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT; ferencd@0: friend bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT; ferencd@0: friend DATE_API std::ostream& operator<<(std::ostream& os, const time_zone& z); ferencd@0: ferencd@0: #if !USE_OS_TZDB ferencd@0: DATE_API void add(const std::string& s); ferencd@0: #endif // !USE_OS_TZDB ferencd@0: ferencd@0: private: ferencd@0: DATE_API sys_info get_info_impl(sys_seconds tp) const; ferencd@0: DATE_API local_info get_info_impl(local_seconds tp) const; ferencd@0: ferencd@0: template ferencd@0: sys_time::type> ferencd@0: to_sys_impl(local_time tp, choose z, std::false_type) const; ferencd@0: template ferencd@0: sys_time::type> ferencd@0: to_sys_impl(local_time tp, choose, std::true_type) const; ferencd@0: ferencd@0: #if USE_OS_TZDB ferencd@0: DATE_API void init() const; ferencd@0: DATE_API void init_impl(); ferencd@0: DATE_API sys_info ferencd@0: load_sys_info(std::vector::const_iterator i) const; ferencd@0: ferencd@0: template ferencd@0: DATE_API void ferencd@0: load_data(std::istream& inf, std::int32_t tzh_leapcnt, std::int32_t tzh_timecnt, ferencd@0: std::int32_t tzh_typecnt, std::int32_t tzh_charcnt); ferencd@0: #else // !USE_OS_TZDB ferencd@0: DATE_API sys_info get_info_impl(sys_seconds tp, int timezone) const; ferencd@0: DATE_API void adjust_infos(const std::vector& rules); ferencd@0: DATE_API void parse_info(std::istream& in); ferencd@0: #endif // !USE_OS_TZDB ferencd@0: }; ferencd@0: ferencd@0: #if defined(_MSC_VER) && (_MSC_VER < 1900) ferencd@0: ferencd@0: inline ferencd@0: time_zone::time_zone(time_zone&& src) ferencd@0: : name_(std::move(src.name_)) ferencd@0: , zonelets_(std::move(src.zonelets_)) ferencd@0: , adjusted_(std::move(src.adjusted_)) ferencd@0: {} ferencd@0: ferencd@0: inline ferencd@0: time_zone& ferencd@0: time_zone::operator=(time_zone&& src) ferencd@0: { ferencd@0: name_ = std::move(src.name_); ferencd@0: zonelets_ = std::move(src.zonelets_); ferencd@0: adjusted_ = std::move(src.adjusted_); ferencd@0: return *this; ferencd@0: } ferencd@0: ferencd@0: #endif // defined(_MSC_VER) && (_MSC_VER < 1900) ferencd@0: ferencd@0: inline ferencd@0: const std::string& ferencd@0: time_zone::name() const NOEXCEPT ferencd@0: { ferencd@0: return name_; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: sys_info ferencd@0: time_zone::get_info(sys_time st) const ferencd@0: { ferencd@0: return get_info_impl(date::floor(st)); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: local_info ferencd@0: time_zone::get_info(local_time tp) const ferencd@0: { ferencd@0: return get_info_impl(date::floor(tp)); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: sys_time::type> ferencd@0: time_zone::to_sys(local_time tp) const ferencd@0: { ferencd@0: return to_sys_impl(tp, choose{}, std::true_type{}); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: sys_time::type> ferencd@0: time_zone::to_sys(local_time tp, choose z) const ferencd@0: { ferencd@0: return to_sys_impl(tp, z, std::false_type{}); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: local_time::type> ferencd@0: time_zone::to_local(sys_time tp) const ferencd@0: { ferencd@0: using LT = local_time::type>; ferencd@0: auto i = get_info(tp); ferencd@0: return LT{(tp + i.offset).time_since_epoch()}; ferencd@0: } ferencd@0: ferencd@0: inline bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ == y.name_;} ferencd@0: inline bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ < y.name_;} ferencd@0: ferencd@0: inline bool operator!=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x == y);} ferencd@0: inline bool operator> (const time_zone& x, const time_zone& y) NOEXCEPT {return y < x;} ferencd@0: inline bool operator<=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(y < x);} ferencd@0: inline bool operator>=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x < y);} ferencd@0: ferencd@0: template ferencd@0: sys_time::type> ferencd@0: time_zone::to_sys_impl(local_time tp, choose z, std::false_type) const ferencd@0: { ferencd@0: auto i = get_info(tp); ferencd@0: if (i.result == local_info::nonexistent) ferencd@0: { ferencd@0: return i.first.end; ferencd@0: } ferencd@0: else if (i.result == local_info::ambiguous) ferencd@0: { ferencd@0: if (z == choose::latest) ferencd@0: return sys_time{tp.time_since_epoch()} - i.second.offset; ferencd@0: } ferencd@0: return sys_time{tp.time_since_epoch()} - i.first.offset; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: sys_time::type> ferencd@0: time_zone::to_sys_impl(local_time tp, choose, std::true_type) const ferencd@0: { ferencd@0: auto i = get_info(tp); ferencd@0: if (i.result == local_info::nonexistent) ferencd@0: throw nonexistent_local_time(tp, i); ferencd@0: else if (i.result == local_info::ambiguous) ferencd@0: throw ambiguous_local_time(tp, i); ferencd@0: return sys_time{tp.time_since_epoch()} - i.first.offset; ferencd@0: } ferencd@0: ferencd@0: #if !USE_OS_TZDB ferencd@0: ferencd@0: class link ferencd@0: { ferencd@0: private: ferencd@0: std::string name_; ferencd@0: std::string target_; ferencd@0: public: ferencd@0: DATE_API explicit link(const std::string& s); ferencd@0: ferencd@0: const std::string& name() const {return name_;} ferencd@0: const std::string& target() const {return target_;} ferencd@0: ferencd@0: friend bool operator==(const link& x, const link& y) {return x.name_ == y.name_;} ferencd@0: friend bool operator< (const link& x, const link& y) {return x.name_ < y.name_;} ferencd@0: ferencd@0: friend DATE_API std::ostream& operator<<(std::ostream& os, const link& x); ferencd@0: }; ferencd@0: ferencd@0: inline bool operator!=(const link& x, const link& y) {return !(x == y);} ferencd@0: inline bool operator> (const link& x, const link& y) {return y < x;} ferencd@0: inline bool operator<=(const link& x, const link& y) {return !(y < x);} ferencd@0: inline bool operator>=(const link& x, const link& y) {return !(x < y);} ferencd@0: ferencd@0: #endif // !USE_OS_TZDB ferencd@0: ferencd@0: #if !MISSING_LEAP_SECONDS ferencd@0: ferencd@0: class leap ferencd@0: { ferencd@0: private: ferencd@0: sys_seconds date_; ferencd@0: ferencd@0: public: ferencd@0: #if USE_OS_TZDB ferencd@0: DATE_API explicit leap(const sys_seconds& s, detail::undocumented); ferencd@0: #else ferencd@0: DATE_API explicit leap(const std::string& s, detail::undocumented); ferencd@0: #endif ferencd@0: ferencd@0: sys_seconds date() const {return date_;} ferencd@0: ferencd@0: friend bool operator==(const leap& x, const leap& y) {return x.date_ == y.date_;} ferencd@0: friend bool operator< (const leap& x, const leap& y) {return x.date_ < y.date_;} ferencd@0: ferencd@0: template ferencd@0: friend ferencd@0: bool ferencd@0: operator==(const leap& x, const sys_time& y) ferencd@0: { ferencd@0: return x.date_ == y; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: friend ferencd@0: bool ferencd@0: operator< (const leap& x, const sys_time& y) ferencd@0: { ferencd@0: return x.date_ < y; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: friend ferencd@0: bool ferencd@0: operator< (const sys_time& x, const leap& y) ferencd@0: { ferencd@0: return x < y.date_; ferencd@0: } ferencd@0: ferencd@0: friend DATE_API std::ostream& operator<<(std::ostream& os, const leap& x); ferencd@0: }; ferencd@0: ferencd@0: inline bool operator!=(const leap& x, const leap& y) {return !(x == y);} ferencd@0: inline bool operator> (const leap& x, const leap& y) {return y < x;} ferencd@0: inline bool operator<=(const leap& x, const leap& y) {return !(y < x);} ferencd@0: inline bool operator>=(const leap& x, const leap& y) {return !(x < y);} ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator==(const sys_time& x, const leap& y) ferencd@0: { ferencd@0: return y == x; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator!=(const leap& x, const sys_time& y) ferencd@0: { ferencd@0: return !(x == y); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator!=(const sys_time& x, const leap& y) ferencd@0: { ferencd@0: return !(x == y); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator> (const leap& x, const sys_time& y) ferencd@0: { ferencd@0: return y < x; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator> (const sys_time& x, const leap& y) ferencd@0: { ferencd@0: return y < x; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator<=(const leap& x, const sys_time& y) ferencd@0: { ferencd@0: return !(y < x); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator<=(const sys_time& x, const leap& y) ferencd@0: { ferencd@0: return !(y < x); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator>=(const leap& x, const sys_time& y) ferencd@0: { ferencd@0: return !(x < y); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: bool ferencd@0: operator>=(const sys_time& x, const leap& y) ferencd@0: { ferencd@0: return !(x < y); ferencd@0: } ferencd@0: ferencd@0: #endif // !MISSING_LEAP_SECONDS ferencd@0: ferencd@0: #ifdef _WIN32 ferencd@0: ferencd@0: namespace detail ferencd@0: { ferencd@0: ferencd@0: // The time zone mapping is modelled after this data file: ferencd@0: // http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml ferencd@0: // and the field names match the element names from the mapZone element ferencd@0: // of windowsZones.xml. ferencd@0: // The website displays this file here: ferencd@0: // http://www.unicode.org/cldr/charts/latest/supplemental/zone_tzid.html ferencd@0: // The html view is sorted before being displayed but is otherwise the same ferencd@0: // There is a mapping between the os centric view (in this case windows) ferencd@0: // the html displays uses and the generic view the xml file. ferencd@0: // That mapping is this: ferencd@0: // display column "windows" -> xml field "other". ferencd@0: // display column "region" -> xml field "territory". ferencd@0: // display column "tzid" -> xml field "type". ferencd@0: // This structure uses the generic terminology because it could be ferencd@0: // used to to support other os/native name conversions, not just windows, ferencd@0: // and using the same generic names helps retain the connection to the ferencd@0: // origin of the data that we are using. ferencd@0: struct timezone_mapping ferencd@0: { ferencd@0: timezone_mapping(const char* other, const char* territory, const char* type) ferencd@0: : other(other), territory(territory), type(type) ferencd@0: { ferencd@0: } ferencd@0: timezone_mapping() = default; ferencd@0: std::string other; ferencd@0: std::string territory; ferencd@0: std::string type; ferencd@0: }; ferencd@0: ferencd@0: } // detail ferencd@0: ferencd@0: #endif // _WIN32 ferencd@0: ferencd@0: struct tzdb ferencd@0: { ferencd@0: std::string version = "unknown"; ferencd@0: std::vector zones; ferencd@0: #if !USE_OS_TZDB ferencd@0: std::vector links; ferencd@0: #endif ferencd@0: #if !MISSING_LEAP_SECONDS ferencd@0: std::vector leaps; ferencd@0: #endif ferencd@0: #if !USE_OS_TZDB ferencd@0: std::vector rules; ferencd@0: #endif ferencd@0: #ifdef _WIN32 ferencd@0: std::vector mappings; ferencd@0: #endif ferencd@0: tzdb* next = nullptr; ferencd@0: ferencd@0: tzdb() = default; ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER >= 1900) ferencd@0: tzdb(tzdb&&) = default; ferencd@0: tzdb& operator=(tzdb&&) = default; ferencd@0: #else // defined(_MSC_VER) && (_MSC_VER < 1900) ferencd@0: tzdb(tzdb&& src) ferencd@0: : version(std::move(src.version)) ferencd@0: , zones(std::move(src.zones)) ferencd@0: , links(std::move(src.links)) ferencd@0: , leaps(std::move(src.leaps)) ferencd@0: , rules(std::move(src.rules)) ferencd@0: , mappings(std::move(src.mappings)) ferencd@0: {} ferencd@0: ferencd@0: tzdb& operator=(tzdb&& src) ferencd@0: { ferencd@0: version = std::move(src.version); ferencd@0: zones = std::move(src.zones); ferencd@0: links = std::move(src.links); ferencd@0: leaps = std::move(src.leaps); ferencd@0: rules = std::move(src.rules); ferencd@0: mappings = std::move(src.mappings); ferencd@0: return *this; ferencd@0: } ferencd@0: #endif // defined(_MSC_VER) && (_MSC_VER < 1900) ferencd@0: ferencd@0: #if HAS_STRING_VIEW ferencd@0: const time_zone* locate_zone(std::string_view tz_name) const; ferencd@0: #else ferencd@0: const time_zone* locate_zone(const std::string& tz_name) const; ferencd@0: #endif ferencd@0: const time_zone* current_zone() const; ferencd@0: }; ferencd@0: ferencd@0: using TZ_DB = tzdb; ferencd@0: ferencd@0: DATE_API std::ostream& ferencd@0: operator<<(std::ostream& os, const tzdb& db); ferencd@0: ferencd@0: DATE_API const tzdb& get_tzdb(); ferencd@0: ferencd@0: class tzdb_list ferencd@0: { ferencd@0: std::atomic head_{nullptr}; ferencd@0: ferencd@0: public: ferencd@0: ~tzdb_list(); ferencd@0: tzdb_list() = default; ferencd@0: tzdb_list(tzdb_list&& x) noexcept; ferencd@0: ferencd@0: const tzdb& front() const noexcept {return *head_;} ferencd@0: tzdb& front() noexcept {return *head_;} ferencd@0: ferencd@0: class const_iterator; ferencd@0: ferencd@0: const_iterator begin() const noexcept; ferencd@0: const_iterator end() const noexcept; ferencd@0: ferencd@0: const_iterator cbegin() const noexcept; ferencd@0: const_iterator cend() const noexcept; ferencd@0: ferencd@0: const_iterator erase_after(const_iterator p) noexcept; ferencd@0: ferencd@0: struct undocumented_helper; ferencd@0: private: ferencd@0: void push_front(tzdb* tzdb) noexcept; ferencd@0: }; ferencd@0: ferencd@0: class tzdb_list::const_iterator ferencd@0: { ferencd@0: tzdb* p_ = nullptr; ferencd@0: ferencd@0: explicit const_iterator(tzdb* p) noexcept : p_{p} {} ferencd@0: public: ferencd@0: const_iterator() = default; ferencd@0: ferencd@0: using iterator_category = std::forward_iterator_tag; ferencd@0: using value_type = tzdb; ferencd@0: using reference = const value_type&; ferencd@0: using pointer = const value_type*; ferencd@0: using difference_type = std::ptrdiff_t; ferencd@0: ferencd@0: reference operator*() const noexcept {return *p_;} ferencd@0: pointer operator->() const noexcept {return p_;} ferencd@0: ferencd@0: const_iterator& operator++() noexcept {p_ = p_->next; return *this;} ferencd@0: const_iterator operator++(int) noexcept {auto t = *this; ++(*this); return t;} ferencd@0: ferencd@0: friend ferencd@0: bool ferencd@0: operator==(const const_iterator& x, const const_iterator& y) noexcept ferencd@0: {return x.p_ == y.p_;} ferencd@0: ferencd@0: friend ferencd@0: bool ferencd@0: operator!=(const const_iterator& x, const const_iterator& y) noexcept ferencd@0: {return !(x == y);} ferencd@0: ferencd@0: friend class tzdb_list; ferencd@0: }; ferencd@0: ferencd@0: inline ferencd@0: tzdb_list::const_iterator ferencd@0: tzdb_list::begin() const noexcept ferencd@0: { ferencd@0: return const_iterator{head_}; ferencd@0: } ferencd@0: ferencd@0: inline ferencd@0: tzdb_list::const_iterator ferencd@0: tzdb_list::end() const noexcept ferencd@0: { ferencd@0: return const_iterator{nullptr}; ferencd@0: } ferencd@0: ferencd@0: inline ferencd@0: tzdb_list::const_iterator ferencd@0: tzdb_list::cbegin() const noexcept ferencd@0: { ferencd@0: return begin(); ferencd@0: } ferencd@0: ferencd@0: inline ferencd@0: tzdb_list::const_iterator ferencd@0: tzdb_list::cend() const noexcept ferencd@0: { ferencd@0: return end(); ferencd@0: } ferencd@0: ferencd@0: DATE_API tzdb_list& get_tzdb_list(); ferencd@0: ferencd@0: #if !USE_OS_TZDB ferencd@0: ferencd@0: DATE_API const tzdb& reload_tzdb(); ferencd@0: DATE_API void set_install(const std::string& install); ferencd@0: ferencd@0: #endif // !USE_OS_TZDB ferencd@0: ferencd@0: #if HAS_REMOTE_API ferencd@0: ferencd@0: DATE_API std::string remote_version(); ferencd@0: DATE_API bool remote_download(const std::string& version); ferencd@0: DATE_API bool remote_install(const std::string& version); ferencd@0: ferencd@0: #endif ferencd@0: ferencd@0: // zoned_time ferencd@0: ferencd@0: namespace detail ferencd@0: { ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: T* ferencd@0: to_raw_pointer(T* p) noexcept ferencd@0: { ferencd@0: return p; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: auto ferencd@0: to_raw_pointer(Pointer p) noexcept ferencd@0: -> decltype(detail::to_raw_pointer(p.operator->())) ferencd@0: { ferencd@0: return detail::to_raw_pointer(p.operator->()); ferencd@0: } ferencd@0: ferencd@0: } // namespace detail ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time() ferencd@0: : zone_(zoned_traits::default_zone()) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const sys_time& st) ferencd@0: : zone_(zoned_traits::default_zone()) ferencd@0: , tp_(st) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(TimeZonePtr z) ferencd@0: : zone_(std::move(z)) ferencd@0: {assert(detail::to_raw_pointer(zone_) != nullptr);} ferencd@0: ferencd@0: #if HAS_STRING_VIEW ferencd@0: ferencd@0: template ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(std::string_view name) ferencd@0: : zoned_time(zoned_traits::locate_zone(name)) ferencd@0: {} ferencd@0: ferencd@0: #else // !HAS_STRING_VIEW ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const std::string& name) ferencd@0: : zoned_time(zoned_traits::locate_zone(name)) ferencd@0: {} ferencd@0: ferencd@0: #endif // !HAS_STRING_VIEW ferencd@0: ferencd@0: template ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(const zoned_time& zt) NOEXCEPT ferencd@0: : zone_(zt.zone_) ferencd@0: , tp_(zt.tp_) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(TimeZonePtr z, const sys_time& st) ferencd@0: : zone_(std::move(z)) ferencd@0: , tp_(st) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(TimeZonePtr z, const local_time& t) ferencd@0: : zone_(std::move(z)) ferencd@0: , tp_(zone_->to_sys(t)) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(TimeZonePtr z, const local_time& t, ferencd@0: choose c) ferencd@0: : zone_(std::move(z)) ferencd@0: , tp_(zone_->to_sys(t, c)) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(TimeZonePtr z, ferencd@0: const zoned_time& zt) ferencd@0: : zone_(std::move(z)) ferencd@0: , tp_(zt.tp_) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(TimeZonePtr z, ferencd@0: const zoned_time& zt, choose) ferencd@0: : zoned_time(std::move(z), zt) ferencd@0: {} ferencd@0: ferencd@0: #if HAS_STRING_VIEW ferencd@0: ferencd@0: template ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(std::string_view name, ferencd@0: detail::nodeduct_t&> st) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), st) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(std::string_view name, ferencd@0: detail::nodeduct_t&> t) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), t) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(std::string_view name, ferencd@0: detail::nodeduct_t&> t, choose c) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), t, c) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(std::string_view name, ferencd@0: const zoned_time& zt) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), zt) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::zoned_time(std::string_view name, ferencd@0: const zoned_time& zt, ferencd@0: choose c) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), zt, c) ferencd@0: {} ferencd@0: ferencd@0: #else // !HAS_STRING_VIEW ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const std::string& name, ferencd@0: const sys_time& st) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), st) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const char* name, ferencd@0: const sys_time& st) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), st) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const std::string& name, ferencd@0: const local_time& t) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), t) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const char* name, ferencd@0: const local_time& t) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), t) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const std::string& name, ferencd@0: const local_time& t, choose c) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), t, c) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const char* name, ferencd@0: const local_time& t, choose c) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), t, c) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #else ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const std::string& name, ferencd@0: const zoned_time& zt) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), zt) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #else ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const char* name, ferencd@0: const zoned_time& zt) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), zt) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #else ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const std::string& name, ferencd@0: const zoned_time& zt, ferencd@0: choose c) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), zt, c) ferencd@0: {} ferencd@0: ferencd@0: template ferencd@0: #if !defined(_MSC_VER) || (_MSC_VER > 1900) ferencd@0: template ferencd@0: #else ferencd@0: template ferencd@0: #endif ferencd@0: inline ferencd@0: zoned_time::zoned_time(const char* name, ferencd@0: const zoned_time& zt, ferencd@0: choose c) ferencd@0: : zoned_time(zoned_traits::locate_zone(name), zt, c) ferencd@0: {} ferencd@0: ferencd@0: #endif // HAS_STRING_VIEW ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time& ferencd@0: zoned_time::operator=(const sys_time& st) ferencd@0: { ferencd@0: tp_ = st; ferencd@0: return *this; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time& ferencd@0: zoned_time::operator=(const local_time& ut) ferencd@0: { ferencd@0: tp_ = zone_->to_sys(ut); ferencd@0: return *this; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::operator local_time::duration>() const ferencd@0: { ferencd@0: return get_local_time(); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::operator sys_time::duration>() const ferencd@0: { ferencd@0: return get_sys_time(); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: TimeZonePtr ferencd@0: zoned_time::get_time_zone() const ferencd@0: { ferencd@0: return zone_; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: local_time::duration> ferencd@0: zoned_time::get_local_time() const ferencd@0: { ferencd@0: return zone_->to_local(tp_); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: sys_time::duration> ferencd@0: zoned_time::get_sys_time() const ferencd@0: { ferencd@0: return tp_; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: sys_info ferencd@0: zoned_time::get_info() const ferencd@0: { ferencd@0: return zone_->get_info(tp_); ferencd@0: } ferencd@0: ferencd@0: // make_zoned_time ferencd@0: ferencd@0: inline ferencd@0: zoned_time ferencd@0: make_zoned() ferencd@0: { ferencd@0: return zoned_time(); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::type> ferencd@0: make_zoned(const sys_time& tp) ferencd@0: { ferencd@0: return zoned_time::type>(tp); ferencd@0: } ferencd@0: ferencd@0: template 1900) ferencd@0: , class = typename std::enable_if ferencd@0: < ferencd@0: std::is_class ferencd@0: < ferencd@0: typename std::decay ferencd@0: < ferencd@0: decltype(*detail::to_raw_pointer(std::declval())) ferencd@0: >::type ferencd@0: >{} ferencd@0: >::type ferencd@0: #endif ferencd@0: > ferencd@0: inline ferencd@0: zoned_time ferencd@0: make_zoned(TimeZonePtr z) ferencd@0: { ferencd@0: return zoned_time(std::move(z)); ferencd@0: } ferencd@0: ferencd@0: inline ferencd@0: zoned_seconds ferencd@0: make_zoned(const std::string& name) ferencd@0: { ferencd@0: return zoned_seconds(name); ferencd@0: } ferencd@0: ferencd@0: template 1900) ferencd@0: , class = typename std::enable_if ferencd@0: < ferencd@0: std::is_class())>::type>{} ferencd@0: >::type ferencd@0: #endif ferencd@0: > ferencd@0: inline ferencd@0: zoned_time::type, TimeZonePtr> ferencd@0: make_zoned(TimeZonePtr zone, const local_time& tp) ferencd@0: { ferencd@0: return zoned_time::type, ferencd@0: TimeZonePtr>(std::move(zone), tp); ferencd@0: } ferencd@0: ferencd@0: template 1900) ferencd@0: , class = typename std::enable_if ferencd@0: < ferencd@0: std::is_class())>::type>{} ferencd@0: >::type ferencd@0: #endif ferencd@0: > ferencd@0: inline ferencd@0: zoned_time::type, TimeZonePtr> ferencd@0: make_zoned(TimeZonePtr zone, const local_time& tp, choose c) ferencd@0: { ferencd@0: return zoned_time::type, ferencd@0: TimeZonePtr>(std::move(zone), tp, c); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::type> ferencd@0: make_zoned(const std::string& name, const local_time& tp) ferencd@0: { ferencd@0: return zoned_time::type>(name, tp); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::type> ferencd@0: make_zoned(const std::string& name, const local_time& tp, choose c) ferencd@0: { ferencd@0: return zoned_time::type>(name, tp, c); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time ferencd@0: make_zoned(TimeZonePtr zone, const zoned_time& zt) ferencd@0: { ferencd@0: return zoned_time(std::move(zone), zt); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time ferencd@0: make_zoned(const std::string& name, const zoned_time& zt) ferencd@0: { ferencd@0: return zoned_time(name, zt); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time ferencd@0: make_zoned(TimeZonePtr zone, const zoned_time& zt, choose c) ferencd@0: { ferencd@0: return zoned_time(std::move(zone), zt, c); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time ferencd@0: make_zoned(const std::string& name, const zoned_time& zt, choose c) ferencd@0: { ferencd@0: return zoned_time(name, zt, c); ferencd@0: } ferencd@0: ferencd@0: template 1900) ferencd@0: , class = typename std::enable_if ferencd@0: < ferencd@0: std::is_class())>::type>{} ferencd@0: >::type ferencd@0: #endif ferencd@0: > ferencd@0: inline ferencd@0: zoned_time::type, TimeZonePtr> ferencd@0: make_zoned(TimeZonePtr zone, const sys_time& st) ferencd@0: { ferencd@0: return zoned_time::type, ferencd@0: TimeZonePtr>(std::move(zone), st); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: zoned_time::type> ferencd@0: make_zoned(const std::string& name, const sys_time& st) ferencd@0: { ferencd@0: return zoned_time::type>(name, st); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: std::basic_ostream& ferencd@0: to_stream(std::basic_ostream& os, const CharT* fmt, ferencd@0: const zoned_time& tp) ferencd@0: { ferencd@0: using duration = typename zoned_time::duration; ferencd@0: using LT = local_time; ferencd@0: auto const st = tp.get_sys_time(); ferencd@0: auto const info = tp.get_time_zone()->get_info(st); ferencd@0: return to_stream(os, fmt, LT{(st+info.offset).time_since_epoch()}, ferencd@0: &info.abbrev, &info.offset); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: std::basic_ostream& ferencd@0: operator<<(std::basic_ostream& os, const zoned_time& t) ferencd@0: { ferencd@0: const CharT fmt[] = {'%', 'F', ' ', '%', 'T', ' ', '%', 'Z', CharT{}}; ferencd@0: return to_stream(os, fmt, t); ferencd@0: } ferencd@0: ferencd@0: #if !MISSING_LEAP_SECONDS ferencd@0: ferencd@0: class utc_clock ferencd@0: { ferencd@0: public: ferencd@0: using duration = std::chrono::system_clock::duration; ferencd@0: using rep = duration::rep; ferencd@0: using period = duration::period; ferencd@0: using time_point = std::chrono::time_point; ferencd@0: static CONSTDATA bool is_steady = false; ferencd@0: ferencd@0: static time_point now(); ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: to_sys(const std::chrono::time_point&); ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: from_sys(const std::chrono::time_point&); ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: to_local(const std::chrono::time_point&); ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: from_local(const std::chrono::time_point&); ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: using utc_time = std::chrono::time_point; ferencd@0: ferencd@0: using utc_seconds = utc_time; ferencd@0: ferencd@0: template ferencd@0: utc_time::type> ferencd@0: utc_clock::from_sys(const sys_time& st) ferencd@0: { ferencd@0: using std::chrono::seconds; ferencd@0: using CD = typename std::common_type::type; ferencd@0: auto const& leaps = get_tzdb().leaps; ferencd@0: auto const lt = std::upper_bound(leaps.begin(), leaps.end(), st); ferencd@0: return utc_time{st.time_since_epoch() + seconds{lt-leaps.begin()}}; ferencd@0: } ferencd@0: ferencd@0: // Return pair ferencd@0: // first is true if ut is during a leap second insertion, otherwise false. ferencd@0: // If ut is during a leap second insertion, that leap second is included in the count ferencd@0: template ferencd@0: std::pair ferencd@0: is_leap_second(date::utc_time const& ut) ferencd@0: { ferencd@0: using std::chrono::seconds; ferencd@0: using duration = typename std::common_type::type; ferencd@0: auto const& leaps = get_tzdb().leaps; ferencd@0: auto tp = sys_time{ut.time_since_epoch()}; ferencd@0: auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp); ferencd@0: auto ds = seconds{lt-leaps.begin()}; ferencd@0: tp -= ds; ferencd@0: auto ls = false; ferencd@0: if (lt > leaps.begin()) ferencd@0: { ferencd@0: if (tp < lt[-1]) ferencd@0: { ferencd@0: if (tp >= lt[-1].date() - seconds{1}) ferencd@0: ls = true; ferencd@0: else ferencd@0: --ds; ferencd@0: } ferencd@0: } ferencd@0: return {ls, ds}; ferencd@0: } ferencd@0: ferencd@0: struct leap_second_info ferencd@0: { ferencd@0: bool is_leap_second; ferencd@0: std::chrono::seconds elapsed; ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: leap_second_info ferencd@0: get_leap_second_info(date::utc_time const& ut) ferencd@0: { ferencd@0: auto p = is_leap_second(ut); ferencd@0: return {p.first, p.second}; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: sys_time::type> ferencd@0: utc_clock::to_sys(const utc_time& ut) ferencd@0: { ferencd@0: using std::chrono::seconds; ferencd@0: using CD = typename std::common_type::type; ferencd@0: auto ls = is_leap_second(ut); ferencd@0: auto tp = sys_time{ut.time_since_epoch() - ls.second}; ferencd@0: if (ls.first) ferencd@0: tp = floor(tp) + seconds{1} - CD{1}; ferencd@0: return tp; ferencd@0: } ferencd@0: ferencd@0: inline ferencd@0: utc_clock::time_point ferencd@0: utc_clock::now() ferencd@0: { ferencd@0: return from_sys(std::chrono::system_clock::now()); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: utc_time::type> ferencd@0: utc_clock::from_local(const local_time& st) ferencd@0: { ferencd@0: return from_sys(sys_time{st.time_since_epoch()}); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: local_time::type> ferencd@0: utc_clock::to_local(const utc_time& ut) ferencd@0: { ferencd@0: using CD = typename std::common_type::type; ferencd@0: return local_time{to_sys(ut).time_since_epoch()}; ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: std::basic_ostream& ferencd@0: to_stream(std::basic_ostream& os, const CharT* fmt, ferencd@0: const utc_time& t) ferencd@0: { ferencd@0: using std::chrono::seconds; ferencd@0: using CT = typename std::common_type::type; ferencd@0: const std::string abbrev("UTC"); ferencd@0: CONSTDATA seconds offset{0}; ferencd@0: auto ls = is_leap_second(t); ferencd@0: auto tp = sys_time{t.time_since_epoch() - ls.second}; ferencd@0: auto const sd = floor(tp); ferencd@0: year_month_day ymd = sd; ferencd@0: auto time = make_time(tp - sys_seconds{sd}); ferencd@0: time.seconds(detail::undocumented{}) += seconds{ls.first}; ferencd@0: fields fds{ymd, time}; ferencd@0: return to_stream(os, fmt, fds, &abbrev, &offset); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: std::basic_ostream& ferencd@0: operator<<(std::basic_ostream& os, const utc_time& t) ferencd@0: { ferencd@0: const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; ferencd@0: return to_stream(os, fmt, t); ferencd@0: } ferencd@0: ferencd@0: template > ferencd@0: std::basic_istream& ferencd@0: from_stream(std::basic_istream& is, const CharT* fmt, ferencd@0: utc_time& tp, std::basic_string* abbrev = nullptr, ferencd@0: std::chrono::minutes* offset = nullptr) ferencd@0: { ferencd@0: using std::chrono::seconds; ferencd@0: using std::chrono::minutes; ferencd@0: using CT = typename std::common_type::type; ferencd@0: minutes offset_local{}; ferencd@0: auto offptr = offset ? offset : &offset_local; ferencd@0: fields fds{}; ferencd@0: fds.has_tod = true; ferencd@0: from_stream(is, fmt, fds, abbrev, offptr); ferencd@0: if (!fds.ymd.ok()) ferencd@0: is.setstate(std::ios::failbit); ferencd@0: if (!is.fail()) ferencd@0: { ferencd@0: bool is_60_sec = fds.tod.seconds() == seconds{60}; ferencd@0: if (is_60_sec) ferencd@0: fds.tod.seconds(detail::undocumented{}) -= seconds{1}; ferencd@0: auto tmp = utc_clock::from_sys(sys_days(fds.ymd) - *offptr + fds.tod.to_duration()); ferencd@0: if (is_60_sec) ferencd@0: tmp += seconds{1}; ferencd@0: if (is_60_sec != is_leap_second(tmp).first || !fds.tod.in_conventional_range()) ferencd@0: { ferencd@0: is.setstate(std::ios::failbit); ferencd@0: return is; ferencd@0: } ferencd@0: tp = std::chrono::time_point_cast(tmp); ferencd@0: } ferencd@0: return is; ferencd@0: } ferencd@0: ferencd@0: // tai_clock ferencd@0: ferencd@0: class tai_clock ferencd@0: { ferencd@0: public: ferencd@0: using duration = std::chrono::system_clock::duration; ferencd@0: using rep = duration::rep; ferencd@0: using period = duration::period; ferencd@0: using time_point = std::chrono::time_point; ferencd@0: static const bool is_steady = false; ferencd@0: ferencd@0: static time_point now(); ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: to_utc(const std::chrono::time_point&) NOEXCEPT; ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: from_utc(const std::chrono::time_point&) NOEXCEPT; ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: to_local(const std::chrono::time_point&) NOEXCEPT; ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: from_local(const std::chrono::time_point&) NOEXCEPT; ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: using tai_time = std::chrono::time_point; ferencd@0: ferencd@0: using tai_seconds = tai_time; ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: utc_time::type> ferencd@0: tai_clock::to_utc(const tai_time& t) NOEXCEPT ferencd@0: { ferencd@0: using std::chrono::seconds; ferencd@0: using CD = typename std::common_type::type; ferencd@0: return utc_time{t.time_since_epoch()} - ferencd@0: (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10}); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: tai_time::type> ferencd@0: tai_clock::from_utc(const utc_time& t) NOEXCEPT ferencd@0: { ferencd@0: using std::chrono::seconds; ferencd@0: using CD = typename std::common_type::type; ferencd@0: return tai_time{t.time_since_epoch()} + ferencd@0: (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10}); ferencd@0: } ferencd@0: ferencd@0: inline ferencd@0: tai_clock::time_point ferencd@0: tai_clock::now() ferencd@0: { ferencd@0: return from_utc(utc_clock::now()); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: local_time::type> ferencd@0: tai_clock::to_local(const tai_time& t) NOEXCEPT ferencd@0: { ferencd@0: using CD = typename std::common_type::type; ferencd@0: return local_time{t.time_since_epoch()} - ferencd@0: (local_days(year{1970}/January/1) - local_days(year{1958}/January/1)); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: tai_time::type> ferencd@0: tai_clock::from_local(const local_time& t) NOEXCEPT ferencd@0: { ferencd@0: using CD = typename std::common_type::type; ferencd@0: return tai_time{t.time_since_epoch()} + ferencd@0: (local_days(year{1970}/January/1) - local_days(year{1958}/January/1)); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: std::basic_ostream& ferencd@0: to_stream(std::basic_ostream& os, const CharT* fmt, ferencd@0: const tai_time& t) ferencd@0: { ferencd@0: const std::string abbrev("TAI"); ferencd@0: CONSTDATA std::chrono::seconds offset{0}; ferencd@0: return to_stream(os, fmt, tai_clock::to_local(t), &abbrev, &offset); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: std::basic_ostream& ferencd@0: operator<<(std::basic_ostream& os, const tai_time& t) ferencd@0: { ferencd@0: const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; ferencd@0: return to_stream(os, fmt, t); ferencd@0: } ferencd@0: ferencd@0: template > ferencd@0: std::basic_istream& ferencd@0: from_stream(std::basic_istream& is, const CharT* fmt, ferencd@0: tai_time& tp, ferencd@0: std::basic_string* abbrev = nullptr, ferencd@0: std::chrono::minutes* offset = nullptr) ferencd@0: { ferencd@0: local_time lp; ferencd@0: from_stream(is, fmt, lp, abbrev, offset); ferencd@0: if (!is.fail()) ferencd@0: tp = tai_clock::from_local(lp); ferencd@0: return is; ferencd@0: } ferencd@0: ferencd@0: // gps_clock ferencd@0: ferencd@0: class gps_clock ferencd@0: { ferencd@0: public: ferencd@0: using duration = std::chrono::system_clock::duration; ferencd@0: using rep = duration::rep; ferencd@0: using period = duration::period; ferencd@0: using time_point = std::chrono::time_point; ferencd@0: static const bool is_steady = false; ferencd@0: ferencd@0: static time_point now(); ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: to_utc(const std::chrono::time_point&) NOEXCEPT; ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: from_utc(const std::chrono::time_point&) NOEXCEPT; ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: to_local(const std::chrono::time_point&) NOEXCEPT; ferencd@0: ferencd@0: template ferencd@0: static ferencd@0: std::chrono::time_point::type> ferencd@0: from_local(const std::chrono::time_point&) NOEXCEPT; ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: using gps_time = std::chrono::time_point; ferencd@0: ferencd@0: using gps_seconds = gps_time; ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: utc_time::type> ferencd@0: gps_clock::to_utc(const gps_time& t) NOEXCEPT ferencd@0: { ferencd@0: using std::chrono::seconds; ferencd@0: using CD = typename std::common_type::type; ferencd@0: return utc_time{t.time_since_epoch()} + ferencd@0: (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1970}/January/1) + ferencd@0: seconds{9}); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: gps_time::type> ferencd@0: gps_clock::from_utc(const utc_time& t) NOEXCEPT ferencd@0: { ferencd@0: using std::chrono::seconds; ferencd@0: using CD = typename std::common_type::type; ferencd@0: return gps_time{t.time_since_epoch()} - ferencd@0: (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1970}/January/1) + ferencd@0: seconds{9}); ferencd@0: } ferencd@0: ferencd@0: inline ferencd@0: gps_clock::time_point ferencd@0: gps_clock::now() ferencd@0: { ferencd@0: return from_utc(utc_clock::now()); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: local_time::type> ferencd@0: gps_clock::to_local(const gps_time& t) NOEXCEPT ferencd@0: { ferencd@0: using CD = typename std::common_type::type; ferencd@0: return local_time{t.time_since_epoch()} + ferencd@0: (local_days(year{1980}/January/Sunday[1]) - local_days(year{1970}/January/1)); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: gps_time::type> ferencd@0: gps_clock::from_local(const local_time& t) NOEXCEPT ferencd@0: { ferencd@0: using CD = typename std::common_type::type; ferencd@0: return gps_time{t.time_since_epoch()} - ferencd@0: (local_days(year{1980}/January/Sunday[1]) - local_days(year{1970}/January/1)); ferencd@0: } ferencd@0: ferencd@0: ferencd@0: template ferencd@0: std::basic_ostream& ferencd@0: to_stream(std::basic_ostream& os, const CharT* fmt, ferencd@0: const gps_time& t) ferencd@0: { ferencd@0: const std::string abbrev("GPS"); ferencd@0: CONSTDATA std::chrono::seconds offset{0}; ferencd@0: return to_stream(os, fmt, gps_clock::to_local(t), &abbrev, &offset); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: std::basic_ostream& ferencd@0: operator<<(std::basic_ostream& os, const gps_time& t) ferencd@0: { ferencd@0: const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; ferencd@0: return to_stream(os, fmt, t); ferencd@0: } ferencd@0: ferencd@0: template > ferencd@0: std::basic_istream& ferencd@0: from_stream(std::basic_istream& is, const CharT* fmt, ferencd@0: gps_time& tp, ferencd@0: std::basic_string* abbrev = nullptr, ferencd@0: std::chrono::minutes* offset = nullptr) ferencd@0: { ferencd@0: local_time lp; ferencd@0: from_stream(is, fmt, lp, abbrev, offset); ferencd@0: if (!is.fail()) ferencd@0: tp = gps_clock::from_local(lp); ferencd@0: return is; ferencd@0: } ferencd@0: ferencd@0: // clock_time_conversion ferencd@0: ferencd@0: template ferencd@0: struct clock_time_conversion ferencd@0: {}; ferencd@0: ferencd@0: template <> ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: sys_time ferencd@0: operator()(const sys_time& st) const ferencd@0: { ferencd@0: return st; ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template <> ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: utc_time ferencd@0: operator()(const utc_time& ut) const ferencd@0: { ferencd@0: return ut; ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template<> ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: local_time ferencd@0: operator()(const local_time& lt) const ferencd@0: { ferencd@0: return lt; ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template <> ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: utc_time::type> ferencd@0: operator()(const sys_time& st) const ferencd@0: { ferencd@0: return utc_clock::from_sys(st); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template <> ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: sys_time::type> ferencd@0: operator()(const utc_time& ut) const ferencd@0: { ferencd@0: return utc_clock::to_sys(ut); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template<> ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: local_time ferencd@0: operator()(const sys_time& st) const ferencd@0: { ferencd@0: return local_time{st.time_since_epoch()}; ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template<> ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: sys_time ferencd@0: operator()(const local_time& lt) const ferencd@0: { ferencd@0: return sys_time{lt.time_since_epoch()}; ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template<> ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: utc_time::type> ferencd@0: operator()(const local_time& lt) const ferencd@0: { ferencd@0: return utc_clock::from_local(lt); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template<> ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: local_time::type> ferencd@0: operator()(const utc_time& ut) const ferencd@0: { ferencd@0: return utc_clock::to_local(ut); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: std::chrono::time_point ferencd@0: operator()(const std::chrono::time_point& tp) const ferencd@0: { ferencd@0: return tp; ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: namespace ctc_detail ferencd@0: { ferencd@0: ferencd@0: template ferencd@0: using time_point = std::chrono::time_point; ferencd@0: ferencd@0: using std::declval; ferencd@0: using std::chrono::system_clock; ferencd@0: ferencd@0: //Check if TimePoint is time for given clock, ferencd@0: //if not emits hard error ferencd@0: template ferencd@0: struct return_clock_time ferencd@0: { ferencd@0: using clock_time_point = time_point; ferencd@0: using type = TimePoint; ferencd@0: ferencd@0: static_assert(std::is_same::value, ferencd@0: "time point with appropariate clock shall be returned"); ferencd@0: }; ferencd@0: ferencd@0: // Check if Clock has to_sys method accepting TimePoint with given duration const& and ferencd@0: // returning sys_time. If so has nested type member equal to return type to_sys. ferencd@0: template ferencd@0: struct return_to_sys ferencd@0: {}; ferencd@0: ferencd@0: template ferencd@0: struct return_to_sys ferencd@0: < ferencd@0: Clock, Duration, ferencd@0: decltype(Clock::to_sys(declval const&>()), void()) ferencd@0: > ferencd@0: : return_clock_time ferencd@0: < ferencd@0: system_clock, ferencd@0: decltype(Clock::to_sys(declval const&>())) ferencd@0: > ferencd@0: {}; ferencd@0: ferencd@0: // Similiar to above ferencd@0: template ferencd@0: struct return_from_sys ferencd@0: {}; ferencd@0: ferencd@0: template ferencd@0: struct return_from_sys ferencd@0: < ferencd@0: Clock, Duration, ferencd@0: decltype(Clock::from_sys(declval const&>()), ferencd@0: void()) ferencd@0: > ferencd@0: : return_clock_time ferencd@0: < ferencd@0: Clock, ferencd@0: decltype(Clock::from_sys(declval const&>())) ferencd@0: > ferencd@0: {}; ferencd@0: ferencd@0: // Similiar to above ferencd@0: template ferencd@0: struct return_to_utc ferencd@0: {}; ferencd@0: ferencd@0: template ferencd@0: struct return_to_utc ferencd@0: < ferencd@0: Clock, Duration, ferencd@0: decltype(Clock::to_utc(declval const&>()), void()) ferencd@0: > ferencd@0: : return_clock_time ferencd@0: < ferencd@0: utc_clock, ferencd@0: decltype(Clock::to_utc(declval const&>()))> ferencd@0: {}; ferencd@0: ferencd@0: // Similiar to above ferencd@0: template ferencd@0: struct return_from_utc ferencd@0: {}; ferencd@0: ferencd@0: template ferencd@0: struct return_from_utc ferencd@0: < ferencd@0: Clock, Duration, ferencd@0: decltype(Clock::from_utc(declval const&>()), ferencd@0: void()) ferencd@0: > ferencd@0: : return_clock_time ferencd@0: < ferencd@0: Clock, ferencd@0: decltype(Clock::from_utc(declval const&>())) ferencd@0: > ferencd@0: {}; ferencd@0: ferencd@0: // Similiar to above ferencd@0: template ferencd@0: struct return_to_local ferencd@0: {}; ferencd@0: ferencd@0: template ferencd@0: struct return_to_local ferencd@0: < ferencd@0: Clock, Duration, ferencd@0: decltype(Clock::to_local(declval const&>()), ferencd@0: void()) ferencd@0: > ferencd@0: : return_clock_time ferencd@0: < ferencd@0: local_t, ferencd@0: decltype(Clock::to_local(declval const&>())) ferencd@0: > ferencd@0: {}; ferencd@0: ferencd@0: // Similiar to above ferencd@0: template ferencd@0: struct return_from_local ferencd@0: {}; ferencd@0: ferencd@0: template ferencd@0: struct return_from_local ferencd@0: < ferencd@0: Clock, Duration, ferencd@0: decltype(Clock::from_local(declval const&>()), ferencd@0: void()) ferencd@0: > ferencd@0: : return_clock_time ferencd@0: < ferencd@0: Clock, ferencd@0: decltype(Clock::from_local(declval const&>())) ferencd@0: > ferencd@0: {}; ferencd@0: ferencd@0: } // namespace ctc_detail ferencd@0: ferencd@0: template ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: typename ctc_detail::return_to_sys::type ferencd@0: operator()(const std::chrono::time_point& tp) const ferencd@0: { ferencd@0: return SrcClock::to_sys(tp); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: typename ctc_detail::return_from_sys::type ferencd@0: operator()(const sys_time& st) const ferencd@0: { ferencd@0: return DstClock::from_sys(st); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: typename ctc_detail::return_to_utc::type ferencd@0: operator()(const std::chrono::time_point& tp) const ferencd@0: { ferencd@0: return SrcClock::to_utc(tp); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: typename ctc_detail::return_from_utc::type ferencd@0: operator()(const utc_time& ut) const ferencd@0: { ferencd@0: return DstClock::from_utc(ut); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: typename ctc_detail::return_to_local::type ferencd@0: operator()(const std::chrono::time_point& tp) const ferencd@0: { ferencd@0: return SrcClock::to_local(tp); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: template ferencd@0: struct clock_time_conversion ferencd@0: { ferencd@0: template ferencd@0: typename ctc_detail::return_from_local::type ferencd@0: operator()(const local_time& lt) const ferencd@0: { ferencd@0: return DstClock::from_local(lt); ferencd@0: } ferencd@0: }; ferencd@0: ferencd@0: namespace clock_cast_detail ferencd@0: { ferencd@0: ferencd@0: template ferencd@0: using time_point = std::chrono::time_point; ferencd@0: using std::chrono::system_clock; ferencd@0: ferencd@0: template ferencd@0: auto ferencd@0: conv_clock(const time_point& t) ferencd@0: -> decltype(std::declval>()(t)) ferencd@0: { ferencd@0: return clock_time_conversion{}(t); ferencd@0: } ferencd@0: ferencd@0: //direct trait conversion, 1st candidate ferencd@0: template ferencd@0: auto ferencd@0: cc_impl(const time_point& t, const time_point*) ferencd@0: -> decltype(conv_clock(t)) ferencd@0: { ferencd@0: return conv_clock(t); ferencd@0: } ferencd@0: ferencd@0: //conversion through sys, 2nd candidate ferencd@0: template ferencd@0: auto ferencd@0: cc_impl(const time_point& t, const void*) ferencd@0: -> decltype(conv_clock(conv_clock(t))) ferencd@0: { ferencd@0: return conv_clock(conv_clock(t)); ferencd@0: } ferencd@0: ferencd@0: //conversion through utc, 2nd candidate ferencd@0: template ferencd@0: auto ferencd@0: cc_impl(const time_point& t, const void*) ferencd@0: -> decltype(0, // MSVC_WORKAROUND ferencd@0: conv_clock(conv_clock(t))) ferencd@0: { ferencd@0: return conv_clock(conv_clock(t)); ferencd@0: } ferencd@0: ferencd@0: //conversion through sys and utc, 3rd candidate ferencd@0: template ferencd@0: auto ferencd@0: cc_impl(const time_point& t, ...) ferencd@0: -> decltype(conv_clock(conv_clock(conv_clock(t)))) ferencd@0: { ferencd@0: return conv_clock(conv_clock(conv_clock(t))); ferencd@0: } ferencd@0: ferencd@0: //conversion through utc and sys, 3rd candidate ferencd@0: template ferencd@0: auto ferencd@0: cc_impl(const time_point& t, ...) ferencd@0: -> decltype(0, // MSVC_WORKAROUND ferencd@0: conv_clock(conv_clock(conv_clock(t)))) ferencd@0: { ferencd@0: return conv_clock(conv_clock(conv_clock(t))); ferencd@0: } ferencd@0: ferencd@0: } // namespace clock_cast_detail ferencd@0: ferencd@0: template ferencd@0: auto ferencd@0: clock_cast(const std::chrono::time_point& tp) ferencd@0: -> decltype(clock_cast_detail::cc_impl(tp, &tp)) ferencd@0: { ferencd@0: return clock_cast_detail::cc_impl(tp, &tp); ferencd@0: } ferencd@0: ferencd@0: // Deprecated API ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: sys_time::type> ferencd@0: to_sys_time(const utc_time& t) ferencd@0: { ferencd@0: return utc_clock::to_sys(t); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: sys_time::type> ferencd@0: to_sys_time(const tai_time& t) ferencd@0: { ferencd@0: return utc_clock::to_sys(tai_clock::to_utc(t)); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: sys_time::type> ferencd@0: to_sys_time(const gps_time& t) ferencd@0: { ferencd@0: return utc_clock::to_sys(gps_clock::to_utc(t)); ferencd@0: } ferencd@0: ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: utc_time::type> ferencd@0: to_utc_time(const sys_time& t) ferencd@0: { ferencd@0: return utc_clock::from_sys(t); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: utc_time::type> ferencd@0: to_utc_time(const tai_time& t) ferencd@0: { ferencd@0: return tai_clock::to_utc(t); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: utc_time::type> ferencd@0: to_utc_time(const gps_time& t) ferencd@0: { ferencd@0: return gps_clock::to_utc(t); ferencd@0: } ferencd@0: ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: tai_time::type> ferencd@0: to_tai_time(const sys_time& t) ferencd@0: { ferencd@0: return tai_clock::from_utc(utc_clock::from_sys(t)); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: tai_time::type> ferencd@0: to_tai_time(const utc_time& t) ferencd@0: { ferencd@0: return tai_clock::from_utc(t); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: tai_time::type> ferencd@0: to_tai_time(const gps_time& t) ferencd@0: { ferencd@0: return tai_clock::from_utc(gps_clock::to_utc(t)); ferencd@0: } ferencd@0: ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: gps_time::type> ferencd@0: to_gps_time(const sys_time& t) ferencd@0: { ferencd@0: return gps_clock::from_utc(utc_clock::from_sys(t)); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: gps_time::type> ferencd@0: to_gps_time(const utc_time& t) ferencd@0: { ferencd@0: return gps_clock::from_utc(t); ferencd@0: } ferencd@0: ferencd@0: template ferencd@0: inline ferencd@0: gps_time::type> ferencd@0: to_gps_time(const tai_time& t) ferencd@0: { ferencd@0: return gps_clock::from_utc(tai_clock::to_utc(t)); ferencd@0: } ferencd@0: ferencd@0: #endif // !MISSING_LEAP_SECONDS ferencd@0: ferencd@0: } // namespace date ferencd@0: ferencd@0: #endif // TZ_H