Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-28 08:27:14

0001 #ifndef TZ_H
0002 #define TZ_H
0003 
0004 // The MIT License (MIT)
0005 //
0006 // Copyright (c) 2015, 2016, 2017 Howard Hinnant
0007 // Copyright (c) 2017 Jiangang Zhuang
0008 // Copyright (c) 2017 Aaron Bishop
0009 // Copyright (c) 2017 Tomasz KamiƄski
0010 //
0011 // Permission is hereby granted, free of charge, to any person obtaining a copy
0012 // of this software and associated documentation files (the "Software"), to deal
0013 // in the Software without restriction, including without limitation the rights
0014 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0015 // copies of the Software, and to permit persons to whom the Software is
0016 // furnished to do so, subject to the following conditions:
0017 //
0018 // The above copyright notice and this permission notice shall be included in all
0019 // copies or substantial portions of the Software.
0020 //
0021 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0022 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0023 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0024 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0025 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0026 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0027 // SOFTWARE.
0028 //
0029 // Our apologies.  When the previous paragraph was written, lowercase had not yet
0030 // been invented (that would involve another several millennia of evolution).
0031 // We did not mean to shout.
0032 
0033 // Get more recent database at http://www.iana.org/time-zones
0034 
0035 // The notion of "current timezone" is something the operating system is expected to "just
0036 // know". How it knows this is system specific. It's often a value set by the user at OS
0037 // installation time and recorded by the OS somewhere. On Linux and Mac systems the current
0038 // timezone name is obtained by looking at the name or contents of a particular file on
0039 // disk. On Windows the current timezone name comes from the registry. In either method,
0040 // there is no guarantee that the "native" current timezone name obtained will match any
0041 // of the "Standard" names in this library's "database". On Linux, the names usually do
0042 // seem to match so mapping functions to map from native to "Standard" are typically not
0043 // required. On Windows, the names are never "Standard" so mapping is always required.
0044 // Technically any OS may use the mapping process but currently only Windows does use it.
0045 
0046 #ifndef USE_OS_TZDB
0047 #  define USE_OS_TZDB 0
0048 #endif
0049 
0050 #ifndef HAS_REMOTE_API
0051 #  if USE_OS_TZDB == 0
0052 #    if defined _WIN32 || defined __ANDROID__
0053 #      define HAS_REMOTE_API 0
0054 #    else
0055 #      define HAS_REMOTE_API 1
0056 #    endif
0057 #  else  // HAS_REMOTE_API makes no sense when using the OS timezone database
0058 #    define HAS_REMOTE_API 0
0059 #  endif
0060 #endif
0061 
0062 #ifdef __clang__
0063 # pragma clang diagnostic push
0064 # pragma clang diagnostic ignored "-Wconstant-logical-operand"
0065 #endif
0066 
0067 static_assert(!(USE_OS_TZDB && HAS_REMOTE_API),
0068               "USE_OS_TZDB and HAS_REMOTE_API can not be used together");
0069 
0070 #ifdef __clang__
0071 # pragma clang diagnostic pop
0072 #endif
0073 
0074 #ifndef AUTO_DOWNLOAD
0075 #  define AUTO_DOWNLOAD HAS_REMOTE_API
0076 #endif
0077 
0078 static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true,
0079               "AUTO_DOWNLOAD can not be turned on without HAS_REMOTE_API");
0080 
0081 #ifndef USE_SHELL_API
0082 #  define USE_SHELL_API 1
0083 #endif
0084 
0085 #if USE_OS_TZDB
0086 #  ifdef _WIN32
0087 #    error "USE_OS_TZDB can not be used on Windows"
0088 #  endif
0089 #endif
0090 
0091 #ifndef HAS_DEDUCTION_GUIDES
0092 #  if __cplusplus >= 201703
0093 #    define HAS_DEDUCTION_GUIDES 1
0094 #  else
0095 #    define HAS_DEDUCTION_GUIDES 0
0096 #  endif
0097 #endif  // HAS_DEDUCTION_GUIDES
0098 
0099 #include "date.h"
0100 
0101 #if defined(_MSC_VER) && (_MSC_VER < 1900)
0102 #include "tz_private.h"
0103 #endif
0104 
0105 #include <algorithm>
0106 #include <atomic>
0107 #include <cassert>
0108 #include <chrono>
0109 #include <istream>
0110 #include <locale>
0111 #include <memory>
0112 #include <mutex>
0113 #include <ostream>
0114 #include <sstream>
0115 #include <stdexcept>
0116 #include <string>
0117 #include <type_traits>
0118 #include <utility>
0119 #include <vector>
0120 
0121 #ifdef _WIN32
0122 #  ifdef DATE_BUILD_DLL
0123 #    define DATE_API __declspec(dllexport)
0124 #  elif defined(DATE_USE_DLL)
0125 #    define DATE_API __declspec(dllimport)
0126 #  else
0127 #    define DATE_API
0128 #  endif
0129 #else
0130 #  ifdef DATE_BUILD_DLL
0131 #    define DATE_API __attribute__ ((visibility ("default")))
0132 #  else
0133 #    define DATE_API
0134 #  endif
0135 #endif
0136 
0137 namespace arrow_vendored::date
0138 {
0139 
0140 enum class choose {earliest, latest};
0141 
0142 #if defined(BUILD_TZ_LIB)
0143 # if defined(ANDROID) || defined(__ANDROID__)
0144 struct tzdb;
0145 static std::unique_ptr<tzdb> init_tzdb();
0146 # endif // defined(ANDROID) || defined(__ANDROID__)
0147 #endif // defined(BUILD_TZ_LIB)
0148 
0149 namespace detail
0150 {
0151     struct undocumented;
0152 
0153     template<typename T>
0154     struct nodeduct
0155     {
0156        using type = T;
0157     };
0158 
0159     template<typename T>
0160     using nodeduct_t = typename nodeduct<T>::type;
0161 }
0162 
0163 struct sys_info
0164 {
0165     sys_seconds          begin;
0166     sys_seconds          end;
0167     std::chrono::seconds offset;
0168     std::chrono::minutes save;
0169     std::string          abbrev;
0170 };
0171 
0172 template<class CharT, class Traits>
0173 std::basic_ostream<CharT, Traits>&
0174 operator<<(std::basic_ostream<CharT, Traits>& os, const sys_info& r)
0175 {
0176     os << r.begin << '\n';
0177     os << r.end << '\n';
0178     os << make_time(r.offset) << "\n";
0179     os << make_time(r.save) << "\n";
0180     os << r.abbrev << '\n';
0181     return os;
0182 }
0183 
0184 struct local_info
0185 {
0186     enum {unique, nonexistent, ambiguous} result;
0187     sys_info first;
0188     sys_info second;
0189 };
0190 
0191 template<class CharT, class Traits>
0192 std::basic_ostream<CharT, Traits>&
0193 operator<<(std::basic_ostream<CharT, Traits>& os, const local_info& r)
0194 {
0195     if (r.result == local_info::nonexistent)
0196         os << "nonexistent between\n";
0197     else if (r.result == local_info::ambiguous)
0198         os << "ambiguous between\n";
0199     os << r.first;
0200     if (r.result != local_info::unique)
0201     {
0202         os << "and\n";
0203         os << r.second;
0204     }
0205     return os;
0206 }
0207 
0208 class nonexistent_local_time
0209     : public std::runtime_error
0210 {
0211 public:
0212     template <class Duration>
0213         nonexistent_local_time(local_time<Duration> tp, const local_info& i);
0214 
0215 private:
0216     template <class Duration>
0217     static
0218     std::string
0219     make_msg(local_time<Duration> tp, const local_info& i);
0220 };
0221 
0222 template <class Duration>
0223 inline
0224 nonexistent_local_time::nonexistent_local_time(local_time<Duration> tp,
0225                                                const local_info& i)
0226     : std::runtime_error(make_msg(tp, i))
0227 {
0228 }
0229 
0230 template <class Duration>
0231 std::string
0232 nonexistent_local_time::make_msg(local_time<Duration> tp, const local_info& i)
0233 {
0234     assert(i.result == local_info::nonexistent);
0235     std::ostringstream os;
0236     os << tp << " is in a gap between\n"
0237        << local_seconds{i.first.end.time_since_epoch()} + i.first.offset << ' '
0238        << i.first.abbrev << " and\n"
0239        << local_seconds{i.second.begin.time_since_epoch()} + i.second.offset << ' '
0240        << i.second.abbrev
0241        << " which are both equivalent to\n";
0242     date::operator<<(os, i.first.end) << " UTC";
0243     return os.str();
0244 }
0245 
0246 class ambiguous_local_time
0247     : public std::runtime_error
0248 {
0249 public:
0250     template <class Duration>
0251         ambiguous_local_time(local_time<Duration> tp, const local_info& i);
0252 
0253 private:
0254     template <class Duration>
0255     static
0256     std::string
0257     make_msg(local_time<Duration> tp, const local_info& i);
0258 };
0259 
0260 template <class Duration>
0261 inline
0262 ambiguous_local_time::ambiguous_local_time(local_time<Duration> tp, const local_info& i)
0263     : std::runtime_error(make_msg(tp, i))
0264 {
0265 }
0266 
0267 template <class Duration>
0268 std::string
0269 ambiguous_local_time::make_msg(local_time<Duration> tp, const local_info& i)
0270 {
0271     assert(i.result == local_info::ambiguous);
0272     std::ostringstream os;
0273     os << tp << " is ambiguous.  It could be\n"
0274        << tp << ' ' << i.first.abbrev << " == "
0275        << tp - i.first.offset << " UTC or\n"
0276        << tp << ' ' << i.second.abbrev  << " == "
0277        << tp - i.second.offset  << " UTC";
0278     return os.str();
0279 }
0280 
0281 class time_zone;
0282 
0283 #if HAS_STRING_VIEW
0284 DATE_API const time_zone* locate_zone(std::string_view tz_name);
0285 #else
0286 DATE_API const time_zone* locate_zone(const std::string& tz_name);
0287 #endif
0288 
0289 DATE_API const time_zone* current_zone();
0290 
0291 template <class T>
0292 struct zoned_traits
0293 {
0294 };
0295 
0296 template <>
0297 struct zoned_traits<const time_zone*>
0298 {
0299     static
0300     const time_zone*
0301     default_zone()
0302     {
0303         return date::locate_zone("Etc/UTC");
0304     }
0305 
0306 #if HAS_STRING_VIEW
0307 
0308     static
0309     const time_zone*
0310     locate_zone(std::string_view name)
0311     {
0312         return date::locate_zone(name);
0313     }
0314 
0315 #else  // !HAS_STRING_VIEW
0316 
0317     static
0318     const time_zone*
0319     locate_zone(const std::string& name)
0320     {
0321         return date::locate_zone(name);
0322     }
0323 
0324     static
0325     const time_zone*
0326     locate_zone(const char* name)
0327     {
0328         return date::locate_zone(name);
0329     }
0330 
0331 #endif  // !HAS_STRING_VIEW
0332 };
0333 
0334 template <class Duration, class TimeZonePtr>
0335 class zoned_time;
0336 
0337 template <class Duration1, class Duration2, class TimeZonePtr>
0338 bool
0339 operator==(const zoned_time<Duration1, TimeZonePtr>& x,
0340            const zoned_time<Duration2, TimeZonePtr>& y);
0341 
0342 template <class Duration, class TimeZonePtr = const time_zone*>
0343 class zoned_time
0344 {
0345 public:
0346     using duration = typename std::common_type<Duration, std::chrono::seconds>::type;
0347 
0348 private:
0349     TimeZonePtr        zone_;
0350     sys_time<duration> tp_;
0351 
0352 public:
0353 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0354     template <class T = TimeZonePtr,
0355               class = decltype(zoned_traits<T>::default_zone())>
0356 #endif
0357         zoned_time();
0358 
0359 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0360     template <class T = TimeZonePtr,
0361               class = decltype(zoned_traits<T>::default_zone())>
0362 #endif
0363         zoned_time(const sys_time<Duration>& st);
0364     explicit zoned_time(TimeZonePtr z);
0365 
0366 #if HAS_STRING_VIEW
0367     template <class T = TimeZonePtr,
0368               class = typename std::enable_if
0369               <
0370                   std::is_constructible
0371                   <
0372                       zoned_time,
0373                       decltype(zoned_traits<T>::locate_zone(std::string_view()))
0374                   >::value
0375               >::type>
0376         explicit zoned_time(std::string_view name);
0377 #else
0378 #  if !defined(_MSC_VER) || (_MSC_VER > 1916)
0379     template <class T = TimeZonePtr,
0380               class = typename std::enable_if
0381               <
0382                   std::is_constructible
0383                   <
0384                       zoned_time,
0385                       decltype(zoned_traits<T>::locate_zone(std::string()))
0386                   >::value
0387               >::type>
0388 #  endif
0389         explicit zoned_time(const std::string& name);
0390 #endif
0391 
0392     template <class Duration2,
0393               class = typename std::enable_if
0394                       <
0395                           std::is_convertible<sys_time<Duration2>,
0396                                               sys_time<Duration>>::value
0397                       >::type>
0398         zoned_time(const zoned_time<Duration2, TimeZonePtr>& zt) NOEXCEPT;
0399 
0400     zoned_time(TimeZonePtr z, const sys_time<Duration>& st);
0401 
0402 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0403     template <class T = TimeZonePtr,
0404               class = typename std::enable_if
0405               <
0406                   std::is_convertible
0407                   <
0408                       decltype(std::declval<T&>()->to_sys(local_time<Duration>{})),
0409                       sys_time<duration>
0410                   >::value
0411               >::type>
0412 #endif
0413         zoned_time(TimeZonePtr z, const local_time<Duration>& tp);
0414 
0415 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0416     template <class T = TimeZonePtr,
0417               class = typename std::enable_if
0418               <
0419                   std::is_convertible
0420                   <
0421                       decltype(std::declval<T&>()->to_sys(local_time<Duration>{},
0422                                                           choose::earliest)),
0423                       sys_time<duration>
0424                   >::value
0425               >::type>
0426 #endif
0427         zoned_time(TimeZonePtr z, const local_time<Duration>& tp, choose c);
0428 
0429     template <class Duration2, class TimeZonePtr2,
0430               class = typename std::enable_if
0431                       <
0432                           std::is_convertible<sys_time<Duration2>,
0433                                               sys_time<Duration>>::value
0434                       >::type>
0435         zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt);
0436 
0437     template <class Duration2, class TimeZonePtr2,
0438               class = typename std::enable_if
0439                       <
0440                           std::is_convertible<sys_time<Duration2>,
0441                                               sys_time<Duration>>::value
0442                       >::type>
0443         zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt, choose);
0444 
0445 #if HAS_STRING_VIEW
0446 
0447     template <class T = TimeZonePtr,
0448               class = typename std::enable_if
0449               <
0450                   std::is_constructible
0451                   <
0452                       zoned_time,
0453                       decltype(zoned_traits<T>::locate_zone(std::string_view())),
0454                       sys_time<Duration>
0455                   >::value
0456               >::type>
0457         zoned_time(std::string_view name, detail::nodeduct_t<const sys_time<Duration>&> st);
0458 
0459     template <class T = TimeZonePtr,
0460               class = typename std::enable_if
0461               <
0462                   std::is_constructible
0463                   <
0464                       zoned_time,
0465                       decltype(zoned_traits<T>::locate_zone(std::string_view())),
0466                       local_time<Duration>
0467                   >::value
0468               >::type>
0469         zoned_time(std::string_view name, detail::nodeduct_t<const local_time<Duration>&> tp);
0470 
0471     template <class T = TimeZonePtr,
0472               class = typename std::enable_if
0473               <
0474                   std::is_constructible
0475                   <
0476                       zoned_time,
0477                       decltype(zoned_traits<T>::locate_zone(std::string_view())),
0478                       local_time<Duration>,
0479                       choose
0480                   >::value
0481               >::type>
0482         zoned_time(std::string_view name, detail::nodeduct_t<const local_time<Duration>&> tp, choose c);
0483 
0484     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
0485               class = typename std::enable_if
0486                       <
0487                           std::is_convertible<sys_time<Duration2>,
0488                                               sys_time<Duration>>::value &&
0489                           std::is_constructible
0490                           <
0491                               zoned_time,
0492                               decltype(zoned_traits<T>::locate_zone(std::string_view())),
0493                               zoned_time
0494                           >::value
0495                       >::type>
0496         zoned_time(std::string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt);
0497 
0498     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
0499               class = typename std::enable_if
0500                       <
0501                           std::is_convertible<sys_time<Duration2>,
0502                                               sys_time<Duration>>::value &&
0503                           std::is_constructible
0504                           <
0505                               zoned_time,
0506                               decltype(zoned_traits<T>::locate_zone(std::string_view())),
0507                               zoned_time,
0508                               choose
0509                           >::value
0510                       >::type>
0511         zoned_time(std::string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt, choose);
0512 
0513 #else  // !HAS_STRING_VIEW
0514 
0515 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0516     template <class T = TimeZonePtr,
0517               class = typename std::enable_if
0518               <
0519                   std::is_constructible
0520                   <
0521                       zoned_time,
0522                       decltype(zoned_traits<T>::locate_zone(std::string())),
0523                       sys_time<Duration>
0524                   >::value
0525               >::type>
0526 #endif
0527         zoned_time(const std::string& name, const sys_time<Duration>& st);
0528 
0529 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0530     template <class T = TimeZonePtr,
0531               class = typename std::enable_if
0532               <
0533                   std::is_constructible
0534                   <
0535                       zoned_time,
0536                       decltype(zoned_traits<T>::locate_zone(std::string())),
0537                       sys_time<Duration>
0538                   >::value
0539               >::type>
0540 #endif
0541         zoned_time(const char* name, const sys_time<Duration>& st);
0542 
0543 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0544     template <class T = TimeZonePtr,
0545               class = typename std::enable_if
0546               <
0547                   std::is_constructible
0548                   <
0549                       zoned_time,
0550                       decltype(zoned_traits<T>::locate_zone(std::string())),
0551                       local_time<Duration>
0552                   >::value
0553               >::type>
0554 #endif
0555         zoned_time(const std::string& name, const local_time<Duration>& tp);
0556 
0557 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0558     template <class T = TimeZonePtr,
0559               class = typename std::enable_if
0560               <
0561                   std::is_constructible
0562                   <
0563                       zoned_time,
0564                       decltype(zoned_traits<T>::locate_zone(std::string())),
0565                       local_time<Duration>
0566                   >::value
0567               >::type>
0568 #endif
0569         zoned_time(const char* name, const local_time<Duration>& tp);
0570 
0571 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0572     template <class T = TimeZonePtr,
0573               class = typename std::enable_if
0574               <
0575                   std::is_constructible
0576                   <
0577                       zoned_time,
0578                       decltype(zoned_traits<T>::locate_zone(std::string())),
0579                       local_time<Duration>,
0580                       choose
0581                   >::value
0582               >::type>
0583 #endif
0584         zoned_time(const std::string& name, const local_time<Duration>& tp, choose c);
0585 
0586 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0587     template <class T = TimeZonePtr,
0588               class = typename std::enable_if
0589               <
0590                   std::is_constructible
0591                   <
0592                       zoned_time,
0593                       decltype(zoned_traits<T>::locate_zone(std::string())),
0594                       local_time<Duration>,
0595                       choose
0596                   >::value
0597               >::type>
0598 #endif
0599         zoned_time(const char* name, const local_time<Duration>& tp, choose c);
0600 
0601 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0602     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
0603               class = typename std::enable_if
0604                       <
0605                           std::is_convertible<sys_time<Duration2>,
0606                                               sys_time<Duration>>::value &&
0607                           std::is_constructible
0608                           <
0609                               zoned_time,
0610                               decltype(zoned_traits<T>::locate_zone(std::string())),
0611                               zoned_time
0612                           >::value
0613                       >::type>
0614 #else
0615     template <class Duration2, class TimeZonePtr2>
0616 #endif
0617         zoned_time(const std::string& name, const zoned_time<Duration2, TimeZonePtr2>& zt);
0618 
0619 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0620     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
0621               class = typename std::enable_if
0622                       <
0623                           std::is_convertible<sys_time<Duration2>,
0624                                               sys_time<Duration>>::value &&
0625                           std::is_constructible
0626                           <
0627                               zoned_time,
0628                               decltype(zoned_traits<T>::locate_zone(std::string())),
0629                               zoned_time
0630                           >::value
0631                       >::type>
0632 #else
0633     template <class Duration2, class TimeZonePtr2>
0634 #endif
0635         zoned_time(const char* name, const zoned_time<Duration2, TimeZonePtr2>& zt);
0636 
0637 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0638     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
0639               class = typename std::enable_if
0640                       <
0641                           std::is_convertible<sys_time<Duration2>,
0642                                               sys_time<Duration>>::value &&
0643                           std::is_constructible
0644                           <
0645                               zoned_time,
0646                               decltype(zoned_traits<T>::locate_zone(std::string())),
0647                               zoned_time,
0648                               choose
0649                           >::value
0650                       >::type>
0651 #else
0652     template <class Duration2, class TimeZonePtr2>
0653 #endif
0654         zoned_time(const std::string& name, const zoned_time<Duration2, TimeZonePtr2>& zt,
0655                    choose);
0656 
0657 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
0658     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
0659               class = typename std::enable_if
0660                       <
0661                           std::is_convertible<sys_time<Duration2>,
0662                                               sys_time<Duration>>::value &&
0663                           std::is_constructible
0664                           <
0665                               zoned_time,
0666                               decltype(zoned_traits<T>::locate_zone(std::string())),
0667                               zoned_time,
0668                               choose
0669                           >::value
0670                       >::type>
0671 #else
0672     template <class Duration2, class TimeZonePtr2>
0673 #endif
0674         zoned_time(const char* name, const zoned_time<Duration2, TimeZonePtr2>& zt,
0675                    choose);
0676 
0677 #endif  // !HAS_STRING_VIEW
0678 
0679     zoned_time& operator=(const sys_time<Duration>& st);
0680     zoned_time& operator=(const local_time<Duration>& ut);
0681 
0682     explicit operator sys_time<duration>() const;
0683     explicit operator local_time<duration>() const;
0684 
0685     TimeZonePtr          get_time_zone() const;
0686     local_time<duration> get_local_time() const;
0687     sys_time<duration>   get_sys_time() const;
0688     sys_info             get_info() const;
0689 
0690     template <class Duration1, class Duration2, class TimeZonePtr1>
0691     friend
0692     bool
0693     operator==(const zoned_time<Duration1, TimeZonePtr1>& x,
0694                const zoned_time<Duration2, TimeZonePtr1>& y);
0695 
0696     template <class CharT, class Traits, class Duration1, class TimeZonePtr1>
0697     friend
0698     std::basic_ostream<CharT, Traits>&
0699     operator<<(std::basic_ostream<CharT, Traits>& os,
0700                const zoned_time<Duration1, TimeZonePtr1>& t);
0701 
0702 private:
0703     template <class D, class T> friend class zoned_time;
0704 
0705     template <class TimeZonePtr2>
0706     static
0707     TimeZonePtr2&&
0708     check(TimeZonePtr2&& p);
0709 };
0710 
0711 using zoned_seconds = zoned_time<std::chrono::seconds>;
0712 
0713 #if HAS_DEDUCTION_GUIDES
0714 
0715 namespace detail
0716 {
0717    template<typename TimeZonePtrOrName>
0718    using time_zone_representation =
0719        std::conditional_t
0720        <
0721            std::is_convertible<TimeZonePtrOrName, std::string_view>::value,
0722            time_zone const*,
0723            std::remove_cv_t<std::remove_reference_t<TimeZonePtrOrName>>
0724        >;
0725 }
0726 
0727 zoned_time()
0728     -> zoned_time<std::chrono::seconds>;
0729 
0730 template <class Duration>
0731 zoned_time(sys_time<Duration>)
0732     -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>>;
0733 
0734 template <class TimeZonePtrOrName>
0735 zoned_time(TimeZonePtrOrName&&)
0736     -> zoned_time<std::chrono::seconds, detail::time_zone_representation<TimeZonePtrOrName>>;
0737 
0738 template <class TimeZonePtrOrName, class Duration>
0739 zoned_time(TimeZonePtrOrName&&, sys_time<Duration>)
0740     -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>, detail::time_zone_representation<TimeZonePtrOrName>>;
0741 
0742 template <class TimeZonePtrOrName, class Duration>
0743 zoned_time(TimeZonePtrOrName&&, local_time<Duration>, choose = choose::earliest)
0744     -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>, detail::time_zone_representation<TimeZonePtrOrName>>;
0745 
0746 template <class Duration, class TimeZonePtrOrName, class TimeZonePtr2>
0747 zoned_time(TimeZonePtrOrName&&, zoned_time<Duration, TimeZonePtr2>, choose = choose::earliest)
0748     -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>, detail::time_zone_representation<TimeZonePtrOrName>>;
0749 
0750 #endif  // HAS_DEDUCTION_GUIDES
0751 
0752 template <class Duration1, class Duration2, class TimeZonePtr>
0753 inline
0754 bool
0755 operator==(const zoned_time<Duration1, TimeZonePtr>& x,
0756            const zoned_time<Duration2, TimeZonePtr>& y)
0757 {
0758     return x.zone_ == y.zone_ && x.tp_ == y.tp_;
0759 }
0760 
0761 template <class Duration1, class Duration2, class TimeZonePtr>
0762 inline
0763 bool
0764 operator!=(const zoned_time<Duration1, TimeZonePtr>& x,
0765            const zoned_time<Duration2, TimeZonePtr>& y)
0766 {
0767     return !(x == y);
0768 }
0769 
0770 #if !defined(_MSC_VER) || (_MSC_VER >= 1900)
0771 
0772 namespace detail
0773 {
0774 #  if USE_OS_TZDB
0775     struct transition;
0776     struct expanded_ttinfo;
0777 #  else  // !USE_OS_TZDB
0778     struct zonelet;
0779     class Rule;
0780 #  endif  // !USE_OS_TZDB
0781 }
0782 
0783 #endif  // !defined(_MSC_VER) || (_MSC_VER >= 1900)
0784 
0785 class time_zone
0786 {
0787 private:
0788     std::string                          name_;
0789 #if USE_OS_TZDB
0790     std::vector<detail::transition>      transitions_;
0791     std::vector<detail::expanded_ttinfo> ttinfos_;
0792 #else  // !USE_OS_TZDB
0793     std::vector<detail::zonelet>         zonelets_;
0794 #endif  // !USE_OS_TZDB
0795     std::unique_ptr<std::once_flag>      adjusted_;
0796 
0797 public:
0798 #if !defined(_MSC_VER) || (_MSC_VER >= 1900)
0799     time_zone(time_zone&&) = default;
0800     time_zone& operator=(time_zone&&) = default;
0801 #else   // defined(_MSC_VER) && (_MSC_VER < 1900)
0802     time_zone(time_zone&& src);
0803     time_zone& operator=(time_zone&& src);
0804 #endif  // defined(_MSC_VER) && (_MSC_VER < 1900)
0805 
0806     DATE_API explicit time_zone(const std::string& s, detail::undocumented);
0807 
0808     const std::string& name() const NOEXCEPT;
0809 
0810     template <class Duration> sys_info   get_info(sys_time<Duration> st) const;
0811     template <class Duration> local_info get_info(local_time<Duration> tp) const;
0812 
0813     template <class Duration>
0814         sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0815         to_sys(local_time<Duration> tp) const;
0816 
0817     template <class Duration>
0818         sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0819         to_sys(local_time<Duration> tp, choose z) const;
0820 
0821     template <class Duration>
0822         local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0823         to_local(sys_time<Duration> tp) const;
0824 
0825     friend bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT;
0826     friend bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT;
0827     friend DATE_API std::ostream& operator<<(std::ostream& os, const time_zone& z);
0828 
0829 #if !USE_OS_TZDB
0830     DATE_API void add(const std::string& s);
0831 #else
0832 # if defined(BUILD_TZ_LIB)
0833 #  if defined(ANDROID) || defined(__ANDROID__)
0834     friend std::unique_ptr<tzdb> init_tzdb();
0835 #  endif // defined(ANDROID) || defined(__ANDROID__)
0836 # endif // defined(BUILD_TZ_LIB)
0837 #endif  // !USE_OS_TZDB
0838 
0839 private:
0840     DATE_API sys_info   get_info_impl(sys_seconds tp) const;
0841     DATE_API local_info get_info_impl(local_seconds tp) const;
0842 
0843     template <class Duration>
0844         sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0845         to_sys_impl(local_time<Duration> tp, choose z, std::false_type) const;
0846     template <class Duration>
0847         sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0848         to_sys_impl(local_time<Duration> tp, choose, std::true_type) const;
0849 
0850 #if USE_OS_TZDB
0851     DATE_API void init() const;
0852     DATE_API void init_impl();
0853     DATE_API sys_info
0854         load_sys_info(std::vector<detail::transition>::const_iterator i) const;
0855 
0856     template <class TimeType>
0857     DATE_API void
0858     load_data(std::istream& inf, std::int32_t tzh_leapcnt, std::int32_t tzh_timecnt,
0859                                  std::int32_t tzh_typecnt, std::int32_t tzh_charcnt);
0860 # if defined(ANDROID) || defined(__ANDROID__)
0861     void parse_from_android_tzdata(std::ifstream& inf, const std::size_t off);
0862 # endif // defined(ANDROID) || defined(__ANDROID__)
0863 #else  // !USE_OS_TZDB
0864     DATE_API sys_info   get_info_impl(sys_seconds tp, int tz_int) const;
0865     DATE_API void adjust_infos(const std::vector<detail::Rule>& rules);
0866     DATE_API void parse_info(std::istream& in);
0867 #endif  // !USE_OS_TZDB
0868 };
0869 
0870 #if defined(_MSC_VER) && (_MSC_VER < 1900)
0871 
0872 inline
0873 time_zone::time_zone(time_zone&& src)
0874     : name_(std::move(src.name_))
0875     , zonelets_(std::move(src.zonelets_))
0876     , adjusted_(std::move(src.adjusted_))
0877     {}
0878 
0879 inline
0880 time_zone&
0881 time_zone::operator=(time_zone&& src)
0882 {
0883     name_ = std::move(src.name_);
0884     zonelets_ = std::move(src.zonelets_);
0885     adjusted_ = std::move(src.adjusted_);
0886     return *this;
0887 }
0888 
0889 #endif  // defined(_MSC_VER) && (_MSC_VER < 1900)
0890 
0891 inline
0892 const std::string&
0893 time_zone::name() const NOEXCEPT
0894 {
0895     return name_;
0896 }
0897 
0898 template <class Duration>
0899 inline
0900 sys_info
0901 time_zone::get_info(sys_time<Duration> st) const
0902 {
0903     return get_info_impl(date::floor<std::chrono::seconds>(st));
0904 }
0905 
0906 template <class Duration>
0907 inline
0908 local_info
0909 time_zone::get_info(local_time<Duration> tp) const
0910 {
0911     return get_info_impl(date::floor<std::chrono::seconds>(tp));
0912 }
0913 
0914 template <class Duration>
0915 inline
0916 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0917 time_zone::to_sys(local_time<Duration> tp) const
0918 {
0919     return to_sys_impl(tp, choose{}, std::true_type{});
0920 }
0921 
0922 template <class Duration>
0923 inline
0924 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0925 time_zone::to_sys(local_time<Duration> tp, choose z) const
0926 {
0927     return to_sys_impl(tp, z, std::false_type{});
0928 }
0929 
0930 template <class Duration>
0931 inline
0932 local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0933 time_zone::to_local(sys_time<Duration> tp) const
0934 {
0935     using LT = local_time<typename std::common_type<Duration, std::chrono::seconds>::type>;
0936     auto i = get_info(tp);
0937     return LT{(tp + i.offset).time_since_epoch()};
0938 }
0939 
0940 inline bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ == y.name_;}
0941 inline bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ < y.name_;}
0942 
0943 inline bool operator!=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x == y);}
0944 inline bool operator> (const time_zone& x, const time_zone& y) NOEXCEPT {return   y < x;}
0945 inline bool operator<=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(y < x);}
0946 inline bool operator>=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x < y);}
0947 
0948 template <class Duration>
0949 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0950 time_zone::to_sys_impl(local_time<Duration> tp, choose z, std::false_type) const
0951 {
0952     auto i = get_info(tp);
0953     if (i.result == local_info::nonexistent)
0954     {
0955         return i.first.end;
0956     }
0957     else if (i.result == local_info::ambiguous)
0958     {
0959         if (z == choose::latest)
0960             return sys_time<Duration>{tp.time_since_epoch()} - i.second.offset;
0961     }
0962     return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
0963 }
0964 
0965 template <class Duration>
0966 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
0967 time_zone::to_sys_impl(local_time<Duration> tp, choose, std::true_type) const
0968 {
0969     auto i = get_info(tp);
0970     if (i.result == local_info::nonexistent)
0971         throw nonexistent_local_time(tp, i);
0972     else if (i.result == local_info::ambiguous)
0973         throw ambiguous_local_time(tp, i);
0974     return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
0975 }
0976 
0977 #if !USE_OS_TZDB
0978 
0979 class time_zone_link
0980 {
0981 private:
0982     std::string name_;
0983     std::string target_;
0984 public:
0985     DATE_API explicit time_zone_link(const std::string& s);
0986 
0987     const std::string& name() const {return name_;}
0988     const std::string& target() const {return target_;}
0989 
0990     friend bool operator==(const time_zone_link& x, const time_zone_link& y) {return x.name_ == y.name_;}
0991     friend bool operator< (const time_zone_link& x, const time_zone_link& y) {return x.name_ < y.name_;}
0992 
0993     friend DATE_API std::ostream& operator<<(std::ostream& os, const time_zone_link& x);
0994 };
0995 
0996 using link = time_zone_link;
0997 
0998 inline bool operator!=(const time_zone_link& x, const time_zone_link& y) {return !(x == y);}
0999 inline bool operator> (const time_zone_link& x, const time_zone_link& y) {return   y < x;}
1000 inline bool operator<=(const time_zone_link& x, const time_zone_link& y) {return !(y < x);}
1001 inline bool operator>=(const time_zone_link& x, const time_zone_link& y) {return !(x < y);}
1002 
1003 #endif  // !USE_OS_TZDB
1004 
1005 class leap_second
1006 {
1007 private:
1008     sys_seconds date_;
1009 
1010 public:
1011 #if USE_OS_TZDB
1012     DATE_API explicit leap_second(const sys_seconds& s, detail::undocumented);
1013 #else
1014     DATE_API explicit leap_second(const std::string& s, detail::undocumented);
1015 #endif
1016 
1017     sys_seconds date() const {return date_;}
1018 
1019     friend bool operator==(const leap_second& x, const leap_second& y) {return x.date_ == y.date_;}
1020     friend bool operator< (const leap_second& x, const leap_second& y) {return x.date_ < y.date_;}
1021 
1022     template <class Duration>
1023     friend
1024     bool
1025     operator==(const leap_second& x, const sys_time<Duration>& y)
1026     {
1027         return x.date_ == y;
1028     }
1029 
1030     template <class Duration>
1031     friend
1032     bool
1033     operator< (const leap_second& x, const sys_time<Duration>& y)
1034     {
1035         return x.date_ < y;
1036     }
1037 
1038     template <class Duration>
1039     friend
1040     bool
1041     operator< (const sys_time<Duration>& x, const leap_second& y)
1042     {
1043         return x < y.date_;
1044     }
1045 
1046     friend DATE_API std::ostream& operator<<(std::ostream& os, const leap_second& x);
1047 };
1048 
1049 inline bool operator!=(const leap_second& x, const leap_second& y) {return !(x == y);}
1050 inline bool operator> (const leap_second& x, const leap_second& y) {return   y < x;}
1051 inline bool operator<=(const leap_second& x, const leap_second& y) {return !(y < x);}
1052 inline bool operator>=(const leap_second& x, const leap_second& y) {return !(x < y);}
1053 
1054 template <class Duration>
1055 inline
1056 bool
1057 operator==(const sys_time<Duration>& x, const leap_second& y)
1058 {
1059     return y == x;
1060 }
1061 
1062 template <class Duration>
1063 inline
1064 bool
1065 operator!=(const leap_second& x, const sys_time<Duration>& y)
1066 {
1067     return !(x == y);
1068 }
1069 
1070 template <class Duration>
1071 inline
1072 bool
1073 operator!=(const sys_time<Duration>& x, const leap_second& y)
1074 {
1075     return !(x == y);
1076 }
1077 
1078 template <class Duration>
1079 inline
1080 bool
1081 operator> (const leap_second& x, const sys_time<Duration>& y)
1082 {
1083     return y < x;
1084 }
1085 
1086 template <class Duration>
1087 inline
1088 bool
1089 operator> (const sys_time<Duration>& x, const leap_second& y)
1090 {
1091     return y < x;
1092 }
1093 
1094 template <class Duration>
1095 inline
1096 bool
1097 operator<=(const leap_second& x, const sys_time<Duration>& y)
1098 {
1099     return !(y < x);
1100 }
1101 
1102 template <class Duration>
1103 inline
1104 bool
1105 operator<=(const sys_time<Duration>& x, const leap_second& y)
1106 {
1107     return !(y < x);
1108 }
1109 
1110 template <class Duration>
1111 inline
1112 bool
1113 operator>=(const leap_second& x, const sys_time<Duration>& y)
1114 {
1115     return !(x < y);
1116 }
1117 
1118 template <class Duration>
1119 inline
1120 bool
1121 operator>=(const sys_time<Duration>& x, const leap_second& y)
1122 {
1123     return !(x < y);
1124 }
1125 
1126 using leap = leap_second;
1127 
1128 #ifdef _WIN32
1129 
1130 namespace detail
1131 {
1132 
1133 // The time zone mapping is modelled after this data file:
1134 // http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml
1135 // and the field names match the element names from the mapZone element
1136 // of windowsZones.xml.
1137 // The website displays this file here:
1138 // http://www.unicode.org/cldr/charts/latest/supplemental/zone_tzid.html
1139 // The html view is sorted before being displayed but is otherwise the same
1140 // There is a mapping between the os centric view (in this case windows)
1141 // the html displays uses and the generic view the xml file.
1142 // That mapping is this:
1143 // display column "windows" -> xml field "other".
1144 // display column "region"  -> xml field "territory".
1145 // display column "tzid"    -> xml field "type".
1146 // This structure uses the generic terminology because it could be
1147 // used to to support other os/native name conversions, not just windows,
1148 // and using the same generic names helps retain the connection to the
1149 // origin of the data that we are using.
1150 struct timezone_mapping
1151 {
1152     timezone_mapping(const char* other, const char* territory, const char* type)
1153         : other(other), territory(territory), type(type)
1154     {
1155     }
1156     timezone_mapping() = default;
1157     std::string other;
1158     std::string territory;
1159     std::string type;
1160 };
1161 
1162 }  // detail
1163 
1164 #endif  // _WIN32
1165 
1166 struct tzdb
1167 {
1168     std::string                 version = "unknown";
1169     std::vector<time_zone>      zones;
1170 #if !USE_OS_TZDB
1171     std::vector<time_zone_link> links;
1172 #endif
1173     std::vector<leap_second>    leap_seconds;
1174 #if !USE_OS_TZDB
1175     std::vector<detail::Rule>   rules;
1176 #endif
1177 #ifdef _WIN32
1178     std::vector<detail::timezone_mapping> mappings;
1179 #endif
1180     tzdb* next = nullptr;
1181 
1182     tzdb() = default;
1183 #if !defined(_MSC_VER) || (_MSC_VER >= 1900)
1184     tzdb(tzdb&&) = default;
1185     tzdb& operator=(tzdb&&) = default;
1186 #else  // defined(_MSC_VER) && (_MSC_VER < 1900)
1187     tzdb(tzdb&& src)
1188         : version(std::move(src.version))
1189         , zones(std::move(src.zones))
1190         , links(std::move(src.links))
1191         , leap_seconds(std::move(src.leap_seconds))
1192         , rules(std::move(src.rules))
1193         , mappings(std::move(src.mappings))
1194     {}
1195 
1196     tzdb& operator=(tzdb&& src)
1197     {
1198         version = std::move(src.version);
1199         zones = std::move(src.zones);
1200         links = std::move(src.links);
1201         leap_seconds = std::move(src.leap_seconds);
1202         rules = std::move(src.rules);
1203         mappings = std::move(src.mappings);
1204         return *this;
1205     }
1206 #endif  // defined(_MSC_VER) && (_MSC_VER < 1900)
1207 
1208 #if HAS_STRING_VIEW
1209     DATE_API const time_zone* locate_zone(std::string_view tz_name) const;
1210 #else
1211     DATE_API const time_zone* locate_zone(const std::string& tz_name) const;
1212 #endif
1213     DATE_API const time_zone* current_zone() const;
1214 };
1215 
1216 using TZ_DB = tzdb;
1217 
1218 DATE_API std::ostream&
1219 operator<<(std::ostream& os, const tzdb& db);
1220 
1221 DATE_API const tzdb& get_tzdb();
1222 
1223 class tzdb_list
1224 {
1225     std::atomic<tzdb*> head_{nullptr};
1226 
1227 public:
1228     DATE_API ~tzdb_list();
1229     tzdb_list() = default;
1230     DATE_API tzdb_list(tzdb_list&& x) NOEXCEPT;
1231 
1232     const tzdb& front() const NOEXCEPT {return *head_;}
1233           tzdb& front()       NOEXCEPT {return *head_;}
1234 
1235     class const_iterator;
1236 
1237     const_iterator begin() const NOEXCEPT;
1238     const_iterator end() const NOEXCEPT;
1239 
1240     const_iterator cbegin() const NOEXCEPT;
1241     const_iterator cend() const NOEXCEPT;
1242 
1243     DATE_API const_iterator erase_after(const_iterator p) NOEXCEPT;
1244 
1245     struct undocumented_helper;
1246 private:
1247     void push_front(tzdb* tzdb) NOEXCEPT;
1248 };
1249 
1250 class tzdb_list::const_iterator
1251 {
1252     tzdb* p_ = nullptr;
1253 
1254     explicit const_iterator(tzdb* p) NOEXCEPT : p_{p} {}
1255 public:
1256     const_iterator() = default;
1257 
1258     using iterator_category = std::forward_iterator_tag;
1259     using value_type        = tzdb;
1260     using reference         = const value_type&;
1261     using pointer           = const value_type*;
1262     using difference_type   = std::ptrdiff_t;
1263 
1264     reference operator*() const NOEXCEPT {return *p_;}
1265     pointer  operator->() const NOEXCEPT {return p_;}
1266 
1267     const_iterator& operator++() NOEXCEPT {p_ = p_->next; return *this;}
1268     const_iterator  operator++(int) NOEXCEPT {auto t = *this; ++(*this); return t;}
1269 
1270     friend
1271     bool
1272     operator==(const const_iterator& x, const const_iterator& y) NOEXCEPT
1273         {return x.p_ == y.p_;}
1274 
1275     friend
1276     bool
1277     operator!=(const const_iterator& x, const const_iterator& y) NOEXCEPT
1278         {return !(x == y);}
1279 
1280     friend class tzdb_list;
1281 };
1282 
1283 inline
1284 tzdb_list::const_iterator
1285 tzdb_list::begin() const NOEXCEPT
1286 {
1287     return const_iterator{head_};
1288 }
1289 
1290 inline
1291 tzdb_list::const_iterator
1292 tzdb_list::end() const NOEXCEPT
1293 {
1294     return const_iterator{nullptr};
1295 }
1296 
1297 inline
1298 tzdb_list::const_iterator
1299 tzdb_list::cbegin() const NOEXCEPT
1300 {
1301     return begin();
1302 }
1303 
1304 inline
1305 tzdb_list::const_iterator
1306 tzdb_list::cend() const NOEXCEPT
1307 {
1308     return end();
1309 }
1310 
1311 DATE_API tzdb_list& get_tzdb_list();
1312 
1313 #if !USE_OS_TZDB
1314 
1315 DATE_API const tzdb& reload_tzdb();
1316 DATE_API void        set_install(const std::string& install);
1317 
1318 #endif  // !USE_OS_TZDB
1319 
1320 #if HAS_REMOTE_API
1321 
1322 DATE_API std::string remote_version();
1323 // if provided error_buffer size should be at least CURL_ERROR_SIZE
1324 DATE_API bool        remote_download(const std::string& version, char* error_buffer = nullptr);
1325 DATE_API bool        remote_install(const std::string& version);
1326 
1327 #endif
1328 
1329 // zoned_time
1330 
1331 namespace detail
1332 {
1333 
1334 template <class T>
1335 inline
1336 T*
1337 to_raw_pointer(T* p) NOEXCEPT
1338 {
1339     return p;
1340 }
1341 
1342 template <class Pointer>
1343 inline
1344 auto
1345 to_raw_pointer(Pointer p) NOEXCEPT
1346     -> decltype(detail::to_raw_pointer(p.operator->()))
1347 {
1348     return detail::to_raw_pointer(p.operator->());
1349 }
1350 
1351 }  // namespace detail
1352 
1353 template <class Duration, class TimeZonePtr>
1354 template <class TimeZonePtr2>
1355 inline
1356 TimeZonePtr2&&
1357 zoned_time<Duration, TimeZonePtr>::check(TimeZonePtr2&& p)
1358 {
1359     if (detail::to_raw_pointer(p) == nullptr)
1360         throw std::runtime_error(
1361             "zoned_time constructed with a time zone pointer == nullptr");
1362     return std::forward<TimeZonePtr2>(p);
1363 }
1364 
1365 template <class Duration, class TimeZonePtr>
1366 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1367 template <class T, class>
1368 #endif
1369 inline
1370 zoned_time<Duration, TimeZonePtr>::zoned_time()
1371     : zone_(check(zoned_traits<TimeZonePtr>::default_zone()))
1372     {}
1373 
1374 template <class Duration, class TimeZonePtr>
1375 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1376 template <class T, class>
1377 #endif
1378 inline
1379 zoned_time<Duration, TimeZonePtr>::zoned_time(const sys_time<Duration>& st)
1380     : zone_(check(zoned_traits<TimeZonePtr>::default_zone()))
1381     , tp_(st)
1382     {}
1383 
1384 template <class Duration, class TimeZonePtr>
1385 inline
1386 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z)
1387     : zone_(check(std::move(z)))
1388     {}
1389 
1390 #if HAS_STRING_VIEW
1391 
1392 template <class Duration, class TimeZonePtr>
1393 template <class T, class>
1394 inline
1395 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name)
1396     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name))
1397     {}
1398 
1399 #else  // !HAS_STRING_VIEW
1400 
1401 template <class Duration, class TimeZonePtr>
1402 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1403 template <class T, class>
1404 #endif
1405 inline
1406 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name)
1407     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name))
1408     {}
1409 
1410 #endif  // !HAS_STRING_VIEW
1411 
1412 template <class Duration, class TimeZonePtr>
1413 template <class Duration2, class>
1414 inline
1415 zoned_time<Duration, TimeZonePtr>::zoned_time(const zoned_time<Duration2, TimeZonePtr>& zt) NOEXCEPT
1416     : zone_(zt.zone_)
1417     , tp_(zt.tp_)
1418     {}
1419 
1420 template <class Duration, class TimeZonePtr>
1421 inline
1422 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const sys_time<Duration>& st)
1423     : zone_(check(std::move(z)))
1424     , tp_(st)
1425     {}
1426 
1427 template <class Duration, class TimeZonePtr>
1428 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1429 template <class T, class>
1430 #endif
1431 inline
1432 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t)
1433     : zone_(check(std::move(z)))
1434     , tp_(zone_->to_sys(t))
1435     {}
1436 
1437 template <class Duration, class TimeZonePtr>
1438 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1439 template <class T, class>
1440 #endif
1441 inline
1442 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t,
1443                                               choose c)
1444     : zone_(check(std::move(z)))
1445     , tp_(zone_->to_sys(t, c))
1446     {}
1447 
1448 template <class Duration, class TimeZonePtr>
1449 template <class Duration2, class TimeZonePtr2, class>
1450 inline
1451 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z,
1452                                               const zoned_time<Duration2, TimeZonePtr2>& zt)
1453     : zone_(check(std::move(z)))
1454     , tp_(zt.tp_)
1455     {}
1456 
1457 template <class Duration, class TimeZonePtr>
1458 template <class Duration2, class TimeZonePtr2, class>
1459 inline
1460 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z,
1461                                       const zoned_time<Duration2, TimeZonePtr2>& zt, choose)
1462     : zoned_time(std::move(z), zt)
1463     {}
1464 
1465 #if HAS_STRING_VIEW
1466 
1467 template <class Duration, class TimeZonePtr>
1468 template <class T, class>
1469 inline
1470 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name,
1471                                               detail::nodeduct_t<const sys_time<Duration>&> st)
1472     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), st)
1473     {}
1474 
1475 template <class Duration, class TimeZonePtr>
1476 template <class T, class>
1477 inline
1478 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name,
1479                                               detail::nodeduct_t<const local_time<Duration>&> t)
1480     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t)
1481     {}
1482 
1483 template <class Duration, class TimeZonePtr>
1484 template <class T, class>
1485 inline
1486 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name,
1487                                               detail::nodeduct_t<const local_time<Duration>&> t, choose c)
1488     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t, c)
1489     {}
1490 
1491 template <class Duration, class TimeZonePtr>
1492 template <class Duration2, class TimeZonePtr2, class, class>
1493 inline
1494 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name,
1495                                               const zoned_time<Duration2, TimeZonePtr2>& zt)
1496     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt)
1497     {}
1498 
1499 template <class Duration, class TimeZonePtr>
1500 template <class Duration2, class TimeZonePtr2, class, class>
1501 inline
1502 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name,
1503                                               const zoned_time<Duration2, TimeZonePtr2>& zt,
1504                                               choose c)
1505     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt, c)
1506     {}
1507 
1508 #else  // !HAS_STRING_VIEW
1509 
1510 template <class Duration, class TimeZonePtr>
1511 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1512 template <class T, class>
1513 #endif
1514 inline
1515 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1516                                               const sys_time<Duration>& st)
1517     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), st)
1518     {}
1519 
1520 template <class Duration, class TimeZonePtr>
1521 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1522 template <class T, class>
1523 #endif
1524 inline
1525 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1526                                               const sys_time<Duration>& st)
1527     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), st)
1528     {}
1529 
1530 template <class Duration, class TimeZonePtr>
1531 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1532 template <class T, class>
1533 #endif
1534 inline
1535 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1536                                               const local_time<Duration>& t)
1537     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t)
1538     {}
1539 
1540 template <class Duration, class TimeZonePtr>
1541 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1542 template <class T, class>
1543 #endif
1544 inline
1545 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1546                                               const local_time<Duration>& t)
1547     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t)
1548     {}
1549 
1550 template <class Duration, class TimeZonePtr>
1551 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1552 template <class T, class>
1553 #endif
1554 inline
1555 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1556                                               const local_time<Duration>& t, choose c)
1557     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t, c)
1558     {}
1559 
1560 template <class Duration, class TimeZonePtr>
1561 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1562 template <class T, class>
1563 #endif
1564 inline
1565 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1566                                               const local_time<Duration>& t, choose c)
1567     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t, c)
1568     {}
1569 
1570 template <class Duration, class TimeZonePtr>
1571 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1572 template <class Duration2, class TimeZonePtr2, class, class>
1573 #else
1574 template <class Duration2, class TimeZonePtr2>
1575 #endif
1576 inline
1577 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1578                                               const zoned_time<Duration2, TimeZonePtr2>& zt)
1579     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt)
1580     {}
1581 
1582 template <class Duration, class TimeZonePtr>
1583 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1584 template <class Duration2, class TimeZonePtr2, class, class>
1585 #else
1586 template <class Duration2, class TimeZonePtr2>
1587 #endif
1588 inline
1589 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1590                                               const zoned_time<Duration2, TimeZonePtr2>& zt)
1591     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt)
1592     {}
1593 
1594 template <class Duration, class TimeZonePtr>
1595 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1596 template <class Duration2, class TimeZonePtr2, class, class>
1597 #else
1598 template <class Duration2, class TimeZonePtr2>
1599 #endif
1600 inline
1601 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1602                                               const zoned_time<Duration2, TimeZonePtr2>& zt,
1603                                               choose c)
1604     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt, c)
1605     {}
1606 
1607 template <class Duration, class TimeZonePtr>
1608 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1609 template <class Duration2, class TimeZonePtr2, class, class>
1610 #else
1611 template <class Duration2, class TimeZonePtr2>
1612 #endif
1613 inline
1614 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1615                                               const zoned_time<Duration2, TimeZonePtr2>& zt,
1616                                               choose c)
1617     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt, c)
1618     {}
1619 
1620 #endif  // HAS_STRING_VIEW
1621 
1622 template <class Duration, class TimeZonePtr>
1623 inline
1624 zoned_time<Duration, TimeZonePtr>&
1625 zoned_time<Duration, TimeZonePtr>::operator=(const sys_time<Duration>& st)
1626 {
1627     tp_ = st;
1628     return *this;
1629 }
1630 
1631 template <class Duration, class TimeZonePtr>
1632 inline
1633 zoned_time<Duration, TimeZonePtr>&
1634 zoned_time<Duration, TimeZonePtr>::operator=(const local_time<Duration>& ut)
1635 {
1636     tp_ = zone_->to_sys(ut);
1637     return *this;
1638 }
1639 
1640 template <class Duration, class TimeZonePtr>
1641 inline
1642 zoned_time<Duration, TimeZonePtr>::operator local_time<typename zoned_time<Duration, TimeZonePtr>::duration>() const
1643 {
1644     return get_local_time();
1645 }
1646 
1647 template <class Duration, class TimeZonePtr>
1648 inline
1649 zoned_time<Duration, TimeZonePtr>::operator sys_time<typename zoned_time<Duration, TimeZonePtr>::duration>() const
1650 {
1651     return get_sys_time();
1652 }
1653 
1654 template <class Duration, class TimeZonePtr>
1655 inline
1656 TimeZonePtr
1657 zoned_time<Duration, TimeZonePtr>::get_time_zone() const
1658 {
1659     return zone_;
1660 }
1661 
1662 template <class Duration, class TimeZonePtr>
1663 inline
1664 local_time<typename zoned_time<Duration, TimeZonePtr>::duration>
1665 zoned_time<Duration, TimeZonePtr>::get_local_time() const
1666 {
1667     return zone_->to_local(tp_);
1668 }
1669 
1670 template <class Duration, class TimeZonePtr>
1671 inline
1672 sys_time<typename zoned_time<Duration, TimeZonePtr>::duration>
1673 zoned_time<Duration, TimeZonePtr>::get_sys_time() const
1674 {
1675     return tp_;
1676 }
1677 
1678 template <class Duration, class TimeZonePtr>
1679 inline
1680 sys_info
1681 zoned_time<Duration, TimeZonePtr>::get_info() const
1682 {
1683     return zone_->get_info(tp_);
1684 }
1685 
1686 // make_zoned_time
1687 
1688 inline
1689 zoned_time<std::chrono::seconds>
1690 make_zoned()
1691 {
1692     return zoned_time<std::chrono::seconds>();
1693 }
1694 
1695 template <class Duration>
1696 inline
1697 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1698 make_zoned(const sys_time<Duration>& tp)
1699 {
1700     return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>(tp);
1701 }
1702 
1703 template <class TimeZonePtr
1704 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1705 #if !defined(__INTEL_COMPILER) || (__INTEL_COMPILER > 1600)
1706           , class = typename std::enable_if
1707           <
1708             std::is_class
1709             <
1710                 typename std::decay
1711                 <
1712                     decltype(*detail::to_raw_pointer(std::declval<TimeZonePtr&>()))
1713                 >::type
1714             >{}
1715           >::type
1716 #endif
1717 #endif
1718          >
1719 inline
1720 zoned_time<std::chrono::seconds, TimeZonePtr>
1721 make_zoned(TimeZonePtr z)
1722 {
1723     return zoned_time<std::chrono::seconds, TimeZonePtr>(std::move(z));
1724 }
1725 
1726 inline
1727 zoned_seconds
1728 make_zoned(const std::string& name)
1729 {
1730     return zoned_seconds(name);
1731 }
1732 
1733 template <class Duration, class TimeZonePtr
1734 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1735 #if !defined(__INTEL_COMPILER) || (__INTEL_COMPILER > 1600)
1736           , class = typename std::enable_if
1737           <
1738             std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{}
1739           >::type
1740 #endif
1741 #endif
1742          >
1743 inline
1744 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr>
1745 make_zoned(TimeZonePtr zone, const local_time<Duration>& tp)
1746 {
1747     return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type,
1748                       TimeZonePtr>(std::move(zone), tp);
1749 }
1750 
1751 template <class Duration, class TimeZonePtr
1752 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1753 #if !defined(__INTEL_COMPILER) || (__INTEL_COMPILER > 1600)
1754           , class = typename std::enable_if
1755           <
1756             std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{}
1757           >::type
1758 #endif
1759 #endif
1760          >
1761 inline
1762 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr>
1763 make_zoned(TimeZonePtr zone, const local_time<Duration>& tp, choose c)
1764 {
1765     return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type,
1766                       TimeZonePtr>(std::move(zone), tp, c);
1767 }
1768 
1769 template <class Duration>
1770 inline
1771 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1772 make_zoned(const std::string& name, const local_time<Duration>& tp)
1773 {
1774     return zoned_time<typename std::common_type<Duration,
1775                       std::chrono::seconds>::type>(name, tp);
1776 }
1777 
1778 template <class Duration>
1779 inline
1780 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1781 make_zoned(const std::string& name, const local_time<Duration>& tp, choose c)
1782 {
1783     return zoned_time<typename std::common_type<Duration,
1784                       std::chrono::seconds>::type>(name, tp, c);
1785 }
1786 
1787 template <class Duration, class TimeZonePtr>
1788 inline
1789 zoned_time<Duration, TimeZonePtr>
1790 make_zoned(TimeZonePtr zone, const zoned_time<Duration, TimeZonePtr>& zt)
1791 {
1792     return zoned_time<Duration, TimeZonePtr>(std::move(zone), zt);
1793 }
1794 
1795 template <class Duration, class TimeZonePtr>
1796 inline
1797 zoned_time<Duration, TimeZonePtr>
1798 make_zoned(const std::string& name, const zoned_time<Duration, TimeZonePtr>& zt)
1799 {
1800     return zoned_time<Duration, TimeZonePtr>(name, zt);
1801 }
1802 
1803 template <class Duration, class TimeZonePtr>
1804 inline
1805 zoned_time<Duration, TimeZonePtr>
1806 make_zoned(TimeZonePtr zone, const zoned_time<Duration, TimeZonePtr>& zt, choose c)
1807 {
1808     return zoned_time<Duration, TimeZonePtr>(std::move(zone), zt, c);
1809 }
1810 
1811 template <class Duration, class TimeZonePtr>
1812 inline
1813 zoned_time<Duration, TimeZonePtr>
1814 make_zoned(const std::string& name, const zoned_time<Duration, TimeZonePtr>& zt, choose c)
1815 {
1816     return zoned_time<Duration, TimeZonePtr>(name, zt, c);
1817 }
1818 
1819 template <class Duration, class TimeZonePtr
1820 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1821 #if !defined(__INTEL_COMPILER) || (__INTEL_COMPILER > 1600)
1822           , class = typename std::enable_if
1823           <
1824             std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{}
1825           >::type
1826 #endif
1827 #endif
1828          >
1829 inline
1830 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr>
1831 make_zoned(TimeZonePtr zone, const sys_time<Duration>& st)
1832 {
1833     return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type,
1834                       TimeZonePtr>(std::move(zone), st);
1835 }
1836 
1837 template <class Duration>
1838 inline
1839 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1840 make_zoned(const std::string& name, const sys_time<Duration>& st)
1841 {
1842     return zoned_time<typename std::common_type<Duration,
1843                       std::chrono::seconds>::type>(name, st);
1844 }
1845 
1846 template <class CharT, class Traits, class Duration, class TimeZonePtr>
1847 std::basic_ostream<CharT, Traits>&
1848 to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
1849           const zoned_time<Duration, TimeZonePtr>& tp)
1850 {
1851     using duration = typename zoned_time<Duration, TimeZonePtr>::duration;
1852     using LT = local_time<duration>;
1853     auto const st = tp.get_sys_time();
1854     auto const info = tp.get_time_zone()->get_info(st);
1855     return to_stream(os, fmt, LT{(st+info.offset).time_since_epoch()},
1856                      &info.abbrev, &info.offset);
1857 }
1858 
1859 template <class CharT, class Traits, class Duration, class TimeZonePtr>
1860 inline
1861 std::basic_ostream<CharT, Traits>&
1862 operator<<(std::basic_ostream<CharT, Traits>& os, const zoned_time<Duration, TimeZonePtr>& t)
1863 {
1864     const CharT fmt[] = {'%', 'F', ' ', '%', 'T', ' ', '%', 'Z', CharT{}};
1865     return to_stream(os, fmt, t);
1866 }
1867 
1868 class utc_clock
1869 {
1870 public:
1871     using duration                  = std::chrono::system_clock::duration;
1872     using rep                       = duration::rep;
1873     using period                    = duration::period;
1874     using time_point                = std::chrono::time_point<utc_clock>;
1875     static CONSTDATA bool is_steady = false;
1876 
1877     static time_point now();
1878 
1879     template<typename Duration>
1880     static
1881     std::chrono::time_point<std::chrono::system_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
1882     to_sys(const std::chrono::time_point<utc_clock, Duration>&);
1883 
1884     template<typename Duration>
1885     static
1886     std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
1887     from_sys(const std::chrono::time_point<std::chrono::system_clock, Duration>&);
1888 
1889     template<typename Duration>
1890     static
1891     std::chrono::time_point<local_t, typename std::common_type<Duration, std::chrono::seconds>::type>
1892     to_local(const std::chrono::time_point<utc_clock, Duration>&);
1893 
1894     template<typename Duration>
1895     static
1896     std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
1897     from_local(const std::chrono::time_point<local_t, Duration>&);
1898 };
1899 
1900 template <class Duration>
1901     using utc_time = std::chrono::time_point<utc_clock, Duration>;
1902 
1903 using utc_seconds = utc_time<std::chrono::seconds>;
1904 
1905 template <class Duration>
1906 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1907 utc_clock::from_sys(const sys_time<Duration>& st)
1908 {
1909     using std::chrono::seconds;
1910     using CD = typename std::common_type<Duration, seconds>::type;
1911     auto const& leaps = get_tzdb().leap_seconds;
1912     auto const lt = std::upper_bound(leaps.begin(), leaps.end(), st);
1913     return utc_time<CD>{st.time_since_epoch() + seconds{lt-leaps.begin()}};
1914 }
1915 
1916 // Return pair<is_leap_second, seconds{number_of_leap_seconds_since_1970}>
1917 // first is true if ut is during a leap second insertion, otherwise false.
1918 // If ut is during a leap second insertion, that leap second is included in the count
1919 template <class Duration>
1920 std::pair<bool, std::chrono::seconds>
1921 is_leap_second(date::utc_time<Duration> const& ut)
1922 {
1923     using std::chrono::seconds;
1924     using duration = typename std::common_type<Duration, seconds>::type;
1925     auto const& leaps = get_tzdb().leap_seconds;
1926     auto tp = sys_time<duration>{ut.time_since_epoch()};
1927     auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp);
1928     auto ds = seconds{lt-leaps.begin()};
1929     tp -= ds;
1930     auto ls = false;
1931     if (lt > leaps.begin())
1932     {
1933         if (tp < lt[-1])
1934         {
1935             if (tp >= lt[-1].date() - seconds{1})
1936                 ls = true;
1937             else
1938                 --ds;
1939         }
1940     }
1941     return {ls, ds};
1942 }
1943 
1944 struct leap_second_info
1945 {
1946     bool is_leap_second;
1947     std::chrono::seconds elapsed;
1948 };
1949 
1950 template <class Duration>
1951 leap_second_info
1952 get_leap_second_info(date::utc_time<Duration> const& ut)
1953 {
1954     auto p = is_leap_second(ut);
1955     return {p.first, p.second};
1956 }
1957 
1958 template <class Duration>
1959 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1960 utc_clock::to_sys(const utc_time<Duration>& ut)
1961 {
1962     using std::chrono::seconds;
1963     using CD = typename std::common_type<Duration, seconds>::type;
1964     auto ls = is_leap_second(ut);
1965     auto tp = sys_time<CD>{ut.time_since_epoch() - ls.second};
1966     if (ls.first)
1967         tp = floor<seconds>(tp) + seconds{1} - CD{1};
1968     return tp;
1969 }
1970 
1971 inline
1972 utc_clock::time_point
1973 utc_clock::now()
1974 {
1975     return from_sys(std::chrono::system_clock::now());
1976 }
1977 
1978 template <class Duration>
1979 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1980 utc_clock::from_local(const local_time<Duration>& st)
1981 {
1982     return from_sys(sys_time<Duration>{st.time_since_epoch()});
1983 }
1984 
1985 template <class Duration>
1986 local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1987 utc_clock::to_local(const utc_time<Duration>& ut)
1988 {
1989     using CD = typename std::common_type<Duration, std::chrono::seconds>::type;
1990     return local_time<CD>{to_sys(ut).time_since_epoch()};
1991 }
1992 
1993 template <class CharT, class Traits, class Duration>
1994 std::basic_ostream<CharT, Traits>&
1995 to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
1996           const utc_time<Duration>& t)
1997 {
1998     using std::chrono::seconds;
1999     using CT = typename std::common_type<Duration, seconds>::type;
2000     const std::string abbrev("UTC");
2001     CONSTDATA seconds offset{0};
2002     auto ls = is_leap_second(t);
2003     auto tp = sys_time<CT>{t.time_since_epoch() - ls.second};
2004     auto const sd = floor<days>(tp);
2005     year_month_day ymd = sd;
2006     auto time = make_time(tp - sys_seconds{sd});
2007     time.seconds(detail::undocumented{}) += seconds{ls.first};
2008     fields<CT> fds{ymd, time};
2009     return to_stream(os, fmt, fds, &abbrev, &offset);
2010 }
2011 
2012 template <class CharT, class Traits, class Duration>
2013 std::basic_ostream<CharT, Traits>&
2014 operator<<(std::basic_ostream<CharT, Traits>& os, const utc_time<Duration>& t)
2015 {
2016     const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}};
2017     return to_stream(os, fmt, t);
2018 }
2019 
2020 template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
2021 std::basic_istream<CharT, Traits>&
2022 from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
2023             utc_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
2024             std::chrono::minutes* offset = nullptr)
2025 {
2026     using std::chrono::seconds;
2027     using std::chrono::minutes;
2028     using CT = typename std::common_type<Duration, seconds>::type;
2029     minutes offset_local{};
2030     auto offptr = offset ? offset : &offset_local;
2031     fields<CT> fds{};
2032     fds.has_tod = true;
2033     from_stream(is, fmt, fds, abbrev, offptr);
2034     if (!fds.ymd.ok())
2035         is.setstate(std::ios::failbit);
2036     if (!is.fail())
2037     {
2038         bool is_60_sec = fds.tod.seconds() == seconds{60};
2039         if (is_60_sec)
2040             fds.tod.seconds(detail::undocumented{}) -= seconds{1};
2041         auto tmp = utc_clock::from_sys(sys_days(fds.ymd) - *offptr + fds.tod.to_duration());
2042         if (is_60_sec)
2043             tmp += seconds{1};
2044         if (is_60_sec != is_leap_second(tmp).first || !fds.tod.in_conventional_range())
2045         {
2046             is.setstate(std::ios::failbit);
2047             return is;
2048         }
2049         tp = std::chrono::time_point_cast<Duration>(tmp);
2050     }
2051     return is;
2052 }
2053 
2054 // tai_clock
2055 
2056 class tai_clock
2057 {
2058 public:
2059     using duration                  = std::chrono::system_clock::duration;
2060     using rep                       = duration::rep;
2061     using period                    = duration::period;
2062     using time_point                = std::chrono::time_point<tai_clock>;
2063     static const bool is_steady     = false;
2064 
2065     static time_point now();
2066 
2067     template<typename Duration>
2068     static
2069     std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
2070     to_utc(const std::chrono::time_point<tai_clock, Duration>&) NOEXCEPT;
2071 
2072     template<typename Duration>
2073     static
2074     std::chrono::time_point<tai_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
2075     from_utc(const std::chrono::time_point<utc_clock, Duration>&) NOEXCEPT;
2076 
2077     template<typename Duration>
2078     static
2079     std::chrono::time_point<local_t, typename std::common_type<Duration, date::days>::type>
2080     to_local(const std::chrono::time_point<tai_clock, Duration>&) NOEXCEPT;
2081 
2082     template<typename Duration>
2083     static
2084     std::chrono::time_point<tai_clock, typename std::common_type<Duration, date::days>::type>
2085     from_local(const std::chrono::time_point<local_t, Duration>&) NOEXCEPT;
2086 };
2087 
2088 template <class Duration>
2089     using tai_time = std::chrono::time_point<tai_clock, Duration>;
2090 
2091 using tai_seconds = tai_time<std::chrono::seconds>;
2092 
2093 template <class Duration>
2094 inline
2095 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2096 tai_clock::to_utc(const tai_time<Duration>& t) NOEXCEPT
2097 {
2098     using std::chrono::seconds;
2099     using CD = typename std::common_type<Duration, seconds>::type;
2100     return utc_time<CD>{t.time_since_epoch()} -
2101             (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10});
2102 }
2103 
2104 template <class Duration>
2105 inline
2106 tai_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2107 tai_clock::from_utc(const utc_time<Duration>& t) NOEXCEPT
2108 {
2109     using std::chrono::seconds;
2110     using CD = typename std::common_type<Duration, seconds>::type;
2111     return tai_time<CD>{t.time_since_epoch()} +
2112             (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10});
2113 }
2114 
2115 inline
2116 tai_clock::time_point
2117 tai_clock::now()
2118 {
2119     return from_utc(utc_clock::now());
2120 }
2121 
2122 template <class Duration>
2123 inline
2124 local_time<typename std::common_type<Duration, date::days>::type>
2125 tai_clock::to_local(const tai_time<Duration>& t) NOEXCEPT
2126 {
2127     using CD = typename std::common_type<Duration, date::days>::type;
2128     return local_time<CD>{t.time_since_epoch()} -
2129            (local_days(year{1970}/January/1) - local_days(year{1958}/January/1));
2130 }
2131 
2132 template <class Duration>
2133 inline
2134 tai_time<typename std::common_type<Duration, date::days>::type>
2135 tai_clock::from_local(const local_time<Duration>& t) NOEXCEPT
2136 {
2137     using CD = typename std::common_type<Duration, date::days>::type;
2138     return tai_time<CD>{t.time_since_epoch()} +
2139             (local_days(year{1970}/January/1) - local_days(year{1958}/January/1));
2140 }
2141 
2142 template <class CharT, class Traits, class Duration>
2143 std::basic_ostream<CharT, Traits>&
2144 to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
2145           const tai_time<Duration>& t)
2146 {
2147     const std::string abbrev("TAI");
2148     CONSTDATA std::chrono::seconds offset{0};
2149     return to_stream(os, fmt, tai_clock::to_local(t), &abbrev, &offset);
2150 }
2151 
2152 template <class CharT, class Traits, class Duration>
2153 std::basic_ostream<CharT, Traits>&
2154 operator<<(std::basic_ostream<CharT, Traits>& os, const tai_time<Duration>& t)
2155 {
2156     const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}};
2157     return to_stream(os, fmt, t);
2158 }
2159 
2160 template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
2161 std::basic_istream<CharT, Traits>&
2162 from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
2163             tai_time<Duration>& tp,
2164             std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
2165             std::chrono::minutes* offset = nullptr)
2166 {
2167     local_time<Duration> lp;
2168     from_stream(is, fmt, lp, abbrev, offset);
2169     if (!is.fail())
2170         tp = tai_clock::from_local(lp);
2171     return is;
2172 }
2173 
2174 // gps_clock
2175 
2176 class gps_clock
2177 {
2178 public:
2179     using duration                  = std::chrono::system_clock::duration;
2180     using rep                       = duration::rep;
2181     using period                    = duration::period;
2182     using time_point                = std::chrono::time_point<gps_clock>;
2183     static const bool is_steady     = false;
2184 
2185     static time_point now();
2186 
2187     template<typename Duration>
2188     static
2189     std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
2190     to_utc(const std::chrono::time_point<gps_clock, Duration>&) NOEXCEPT;
2191 
2192     template<typename Duration>
2193     static
2194     std::chrono::time_point<gps_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
2195     from_utc(const std::chrono::time_point<utc_clock, Duration>&) NOEXCEPT;
2196 
2197     template<typename Duration>
2198     static
2199     std::chrono::time_point<local_t, typename std::common_type<Duration, date::days>::type>
2200     to_local(const std::chrono::time_point<gps_clock, Duration>&) NOEXCEPT;
2201 
2202     template<typename Duration>
2203     static
2204     std::chrono::time_point<gps_clock, typename std::common_type<Duration, date::days>::type>
2205     from_local(const std::chrono::time_point<local_t, Duration>&) NOEXCEPT;
2206 };
2207 
2208 template <class Duration>
2209     using gps_time = std::chrono::time_point<gps_clock, Duration>;
2210 
2211 using gps_seconds = gps_time<std::chrono::seconds>;
2212 
2213 template <class Duration>
2214 inline
2215 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2216 gps_clock::to_utc(const gps_time<Duration>& t) NOEXCEPT
2217 {
2218     using std::chrono::seconds;
2219     using CD = typename std::common_type<Duration, seconds>::type;
2220     return utc_time<CD>{t.time_since_epoch()} +
2221             (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1970}/January/1) +
2222              seconds{9});
2223 }
2224 
2225 template <class Duration>
2226 inline
2227 gps_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2228 gps_clock::from_utc(const utc_time<Duration>& t) NOEXCEPT
2229 {
2230     using std::chrono::seconds;
2231     using CD = typename std::common_type<Duration, seconds>::type;
2232     return gps_time<CD>{t.time_since_epoch()} -
2233             (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1970}/January/1) +
2234              seconds{9});
2235 }
2236 
2237 inline
2238 gps_clock::time_point
2239 gps_clock::now()
2240 {
2241     return from_utc(utc_clock::now());
2242 }
2243 
2244 template <class Duration>
2245 inline
2246 local_time<typename std::common_type<Duration, date::days>::type>
2247 gps_clock::to_local(const gps_time<Duration>& t) NOEXCEPT
2248 {
2249     using CD = typename std::common_type<Duration, date::days>::type;
2250     return local_time<CD>{t.time_since_epoch()} +
2251             (local_days(year{1980}/January/Sunday[1]) - local_days(year{1970}/January/1));
2252 }
2253 
2254 template <class Duration>
2255 inline
2256 gps_time<typename std::common_type<Duration, date::days>::type>
2257 gps_clock::from_local(const local_time<Duration>& t) NOEXCEPT
2258 {
2259     using CD = typename std::common_type<Duration, date::days>::type;
2260     return gps_time<CD>{t.time_since_epoch()} -
2261             (local_days(year{1980}/January/Sunday[1]) - local_days(year{1970}/January/1));
2262 }
2263 
2264 
2265 template <class CharT, class Traits, class Duration>
2266 std::basic_ostream<CharT, Traits>&
2267 to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
2268           const gps_time<Duration>& t)
2269 {
2270     const std::string abbrev("GPS");
2271     CONSTDATA std::chrono::seconds offset{0};
2272     return to_stream(os, fmt, gps_clock::to_local(t), &abbrev, &offset);
2273 }
2274 
2275 template <class CharT, class Traits, class Duration>
2276 std::basic_ostream<CharT, Traits>&
2277 operator<<(std::basic_ostream<CharT, Traits>& os, const gps_time<Duration>& t)
2278 {
2279     const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}};
2280     return to_stream(os, fmt, t);
2281 }
2282 
2283 template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
2284 std::basic_istream<CharT, Traits>&
2285 from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
2286             gps_time<Duration>& tp,
2287             std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
2288             std::chrono::minutes* offset = nullptr)
2289 {
2290     local_time<Duration> lp;
2291     from_stream(is, fmt, lp, abbrev, offset);
2292     if (!is.fail())
2293         tp = gps_clock::from_local(lp);
2294     return is;
2295 }
2296 
2297 // clock_time_conversion
2298 
2299 template <class DstClock, class SrcClock>
2300 struct clock_time_conversion
2301 {};
2302 
2303 template <>
2304 struct clock_time_conversion<std::chrono::system_clock, std::chrono::system_clock>
2305 {
2306     template <class Duration>
2307     CONSTCD14
2308     sys_time<Duration>
2309     operator()(const sys_time<Duration>& st) const
2310     {
2311         return st;
2312     }
2313 };
2314 
2315 template <>
2316 struct clock_time_conversion<utc_clock, utc_clock>
2317 {
2318     template <class Duration>
2319     CONSTCD14
2320     utc_time<Duration>
2321     operator()(const utc_time<Duration>& ut) const
2322     {
2323         return ut;
2324     }
2325 };
2326 
2327 template<>
2328 struct clock_time_conversion<local_t, local_t>
2329 {
2330     template <class Duration>
2331     CONSTCD14
2332     local_time<Duration>
2333     operator()(const local_time<Duration>& lt) const
2334     {
2335         return lt;
2336     }
2337 };
2338 
2339 template <>
2340 struct clock_time_conversion<utc_clock, std::chrono::system_clock>
2341 {
2342     template <class Duration>
2343     utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2344     operator()(const sys_time<Duration>& st) const
2345     {
2346         return utc_clock::from_sys(st);
2347     }
2348 };
2349 
2350 template <>
2351 struct clock_time_conversion<std::chrono::system_clock, utc_clock>
2352 {
2353     template <class Duration>
2354     sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2355     operator()(const utc_time<Duration>& ut) const
2356     {
2357         return utc_clock::to_sys(ut);
2358     }
2359 };
2360 
2361 template<>
2362 struct clock_time_conversion<local_t, std::chrono::system_clock>
2363 {
2364     template <class Duration>
2365     CONSTCD14
2366     local_time<Duration>
2367     operator()(const sys_time<Duration>& st) const
2368     {
2369        return local_time<Duration>{st.time_since_epoch()};
2370     }
2371 };
2372 
2373 template<>
2374 struct clock_time_conversion<std::chrono::system_clock, local_t>
2375 {
2376     template <class Duration>
2377     CONSTCD14
2378     sys_time<Duration>
2379     operator()(const local_time<Duration>& lt) const
2380     {
2381         return sys_time<Duration>{lt.time_since_epoch()};
2382     }
2383 };
2384 
2385 template<>
2386 struct clock_time_conversion<utc_clock, local_t>
2387 {
2388     template <class Duration>
2389     utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2390     operator()(const local_time<Duration>& lt) const
2391     {
2392        return utc_clock::from_local(lt);
2393     }
2394 };
2395 
2396 template<>
2397 struct clock_time_conversion<local_t, utc_clock>
2398 {
2399     template <class Duration>
2400     local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2401     operator()(const utc_time<Duration>& ut) const
2402     {
2403        return utc_clock::to_local(ut);
2404     }
2405 };
2406 
2407 template<typename Clock>
2408 struct clock_time_conversion<Clock, Clock>
2409 {
2410     template <class Duration>
2411     CONSTCD14
2412     std::chrono::time_point<Clock, Duration>
2413     operator()(const std::chrono::time_point<Clock, Duration>& tp) const
2414     {
2415         return tp;
2416     }
2417 };
2418 
2419 namespace ctc_detail
2420 {
2421 
2422 template <class Clock, class Duration>
2423     using time_point = std::chrono::time_point<Clock, Duration>;
2424 
2425 using std::declval;
2426 using std::chrono::system_clock;
2427 
2428 //Check if TimePoint is time for given clock,
2429 //if not emits hard error
2430 template <class Clock, class TimePoint>
2431 struct return_clock_time
2432 {
2433     using clock_time_point = time_point<Clock, typename TimePoint::duration>;
2434     using type             = TimePoint;
2435 
2436     static_assert(std::is_same<TimePoint, clock_time_point>::value,
2437                   "time point with appropariate clock shall be returned");
2438 };
2439 
2440 // Check if Clock has to_sys method accepting TimePoint with given duration const& and
2441 // returning sys_time. If so has nested type member equal to return type to_sys.
2442 template <class Clock, class Duration, class = void>
2443 struct return_to_sys
2444 {};
2445 
2446 template <class Clock, class Duration>
2447 struct return_to_sys
2448        <
2449            Clock, Duration,
2450            decltype(Clock::to_sys(declval<time_point<Clock, Duration> const&>()), void())
2451        >
2452     : return_clock_time
2453       <
2454           system_clock,
2455           decltype(Clock::to_sys(declval<time_point<Clock, Duration> const&>()))
2456       >
2457 {};
2458 
2459 // Similiar to above
2460 template <class Clock, class Duration, class = void>
2461 struct return_from_sys
2462 {};
2463 
2464 template <class Clock, class Duration>
2465 struct return_from_sys
2466        <
2467            Clock, Duration,
2468            decltype(Clock::from_sys(declval<time_point<system_clock, Duration> const&>()),
2469                     void())
2470        >
2471     : return_clock_time
2472       <
2473           Clock,
2474           decltype(Clock::from_sys(declval<time_point<system_clock, Duration> const&>()))
2475       >
2476 {};
2477 
2478 // Similiar to above
2479 template <class Clock, class Duration, class = void>
2480 struct return_to_utc
2481 {};
2482 
2483 template <class Clock, class Duration>
2484 struct return_to_utc
2485        <
2486            Clock, Duration,
2487            decltype(Clock::to_utc(declval<time_point<Clock, Duration> const&>()), void())
2488        >
2489     : return_clock_time
2490       <
2491           utc_clock,
2492           decltype(Clock::to_utc(declval<time_point<Clock, Duration> const&>()))>
2493 {};
2494 
2495 // Similiar to above
2496 template <class Clock, class Duration, class = void>
2497 struct return_from_utc
2498 {};
2499 
2500 template <class Clock, class Duration>
2501 struct return_from_utc
2502        <
2503            Clock, Duration,
2504            decltype(Clock::from_utc(declval<time_point<utc_clock, Duration> const&>()),
2505                     void())
2506        >
2507     : return_clock_time
2508       <
2509           Clock,
2510           decltype(Clock::from_utc(declval<time_point<utc_clock, Duration> const&>()))
2511       >
2512 {};
2513 
2514 // Similiar to above
2515 template<typename Clock, typename Duration, typename = void>
2516 struct return_to_local
2517 {};
2518 
2519 template<typename Clock, typename Duration>
2520 struct return_to_local
2521        <
2522           Clock, Duration,
2523           decltype(Clock::to_local(declval<time_point<Clock, Duration> const&>()),
2524                    void())
2525        >
2526      : return_clock_time
2527        <
2528            local_t,
2529            decltype(Clock::to_local(declval<time_point<Clock, Duration> const&>()))
2530        >
2531 {};
2532 
2533 // Similiar to above
2534 template<typename Clock, typename Duration, typename = void>
2535 struct return_from_local
2536 {};
2537 
2538 template<typename Clock, typename Duration>
2539 struct return_from_local
2540        <
2541            Clock, Duration,
2542            decltype(Clock::from_local(declval<time_point<local_t, Duration> const&>()),
2543                     void())
2544        >
2545      : return_clock_time
2546        <
2547            Clock,
2548            decltype(Clock::from_local(declval<time_point<local_t, Duration> const&>()))
2549        >
2550 {};
2551 
2552 }  // namespace ctc_detail
2553 
2554 template <class SrcClock>
2555 struct clock_time_conversion<std::chrono::system_clock, SrcClock>
2556 {
2557     template <class Duration>
2558     CONSTCD14
2559     typename ctc_detail::return_to_sys<SrcClock, Duration>::type
2560     operator()(const std::chrono::time_point<SrcClock, Duration>& tp) const
2561     {
2562         return SrcClock::to_sys(tp);
2563     }
2564 };
2565 
2566 template <class DstClock>
2567 struct clock_time_conversion<DstClock, std::chrono::system_clock>
2568 {
2569     template <class Duration>
2570     CONSTCD14
2571     typename ctc_detail::return_from_sys<DstClock, Duration>::type
2572     operator()(const sys_time<Duration>& st) const
2573     {
2574         return DstClock::from_sys(st);
2575     }
2576 };
2577 
2578 template <class SrcClock>
2579 struct clock_time_conversion<utc_clock, SrcClock>
2580 {
2581     template <class Duration>
2582     CONSTCD14
2583     typename ctc_detail::return_to_utc<SrcClock, Duration>::type
2584     operator()(const std::chrono::time_point<SrcClock, Duration>& tp) const
2585     {
2586         return SrcClock::to_utc(tp);
2587     }
2588 };
2589 
2590 template <class DstClock>
2591 struct clock_time_conversion<DstClock, utc_clock>
2592 {
2593     template <class Duration>
2594     CONSTCD14
2595     typename ctc_detail::return_from_utc<DstClock, Duration>::type
2596     operator()(const utc_time<Duration>& ut) const
2597     {
2598         return DstClock::from_utc(ut);
2599     }
2600 };
2601 
2602 template<typename SrcClock>
2603 struct clock_time_conversion<local_t, SrcClock>
2604 {
2605     template <class Duration>
2606     CONSTCD14
2607     typename ctc_detail::return_to_local<SrcClock, Duration>::type
2608     operator()(const std::chrono::time_point<SrcClock, Duration>& tp) const
2609     {
2610         return SrcClock::to_local(tp);
2611     }
2612 };
2613 
2614 template<typename DstClock>
2615 struct clock_time_conversion<DstClock, local_t>
2616 {
2617     template <class Duration>
2618     CONSTCD14
2619     typename ctc_detail::return_from_local<DstClock, Duration>::type
2620     operator()(const local_time<Duration>& lt) const
2621     {
2622         return DstClock::from_local(lt);
2623     }
2624 };
2625 
2626 namespace clock_cast_detail
2627 {
2628 
2629 template <class Clock, class Duration>
2630     using time_point = std::chrono::time_point<Clock, Duration>;
2631 using std::chrono::system_clock;
2632 
2633 template <class DstClock, class SrcClock, class Duration>
2634 CONSTCD14
2635 auto
2636 conv_clock(const time_point<SrcClock, Duration>& t)
2637     -> decltype(std::declval<clock_time_conversion<DstClock, SrcClock>>()(t))
2638 {
2639     return clock_time_conversion<DstClock, SrcClock>{}(t);
2640 }
2641 
2642 //direct trait conversion, 1st candidate
2643 template <class DstClock, class SrcClock, class Duration>
2644 CONSTCD14
2645 auto
2646 cc_impl(const time_point<SrcClock, Duration>& t, const time_point<SrcClock, Duration>*)
2647     -> decltype(conv_clock<DstClock>(t))
2648 {
2649     return conv_clock<DstClock>(t);
2650 }
2651 
2652 //conversion through sys, 2nd candidate
2653 template <class DstClock, class SrcClock, class Duration>
2654 CONSTCD14
2655 auto
2656 cc_impl(const time_point<SrcClock, Duration>& t, const void*)
2657     -> decltype(conv_clock<DstClock>(conv_clock<system_clock>(t)))
2658 {
2659     return conv_clock<DstClock>(conv_clock<system_clock>(t));
2660 }
2661 
2662 //conversion through utc, 2nd candidate
2663 template <class DstClock, class SrcClock, class Duration>
2664 CONSTCD14
2665 auto
2666 cc_impl(const time_point<SrcClock, Duration>& t, const void*)
2667     -> decltype(0,  // MSVC_WORKAROUND
2668                 conv_clock<DstClock>(conv_clock<utc_clock>(t)))
2669 {
2670     return conv_clock<DstClock>(conv_clock<utc_clock>(t));
2671 }
2672 
2673 //conversion through sys and utc, 3rd candidate
2674 template <class DstClock, class SrcClock, class Duration>
2675 CONSTCD14
2676 auto
2677 cc_impl(const time_point<SrcClock, Duration>& t, ...)
2678     -> decltype(conv_clock<DstClock>(conv_clock<utc_clock>(conv_clock<system_clock>(t))))
2679 {
2680     return conv_clock<DstClock>(conv_clock<utc_clock>(conv_clock<system_clock>(t)));
2681 }
2682 
2683 //conversion through utc and sys, 3rd candidate
2684 template <class DstClock, class SrcClock, class Duration>
2685 CONSTCD14
2686 auto
2687 cc_impl(const time_point<SrcClock, Duration>& t, ...)
2688     -> decltype(0,  // MSVC_WORKAROUND
2689                 conv_clock<DstClock>(conv_clock<system_clock>(conv_clock<utc_clock>(t))))
2690 {
2691     return conv_clock<DstClock>(conv_clock<system_clock>(conv_clock<utc_clock>(t)));
2692 }
2693 
2694 }  // namespace clock_cast_detail
2695 
2696 template <class DstClock, class SrcClock, class Duration>
2697 CONSTCD14
2698 auto
2699 clock_cast(const std::chrono::time_point<SrcClock, Duration>& tp)
2700     -> decltype(clock_cast_detail::cc_impl<DstClock>(tp, &tp))
2701 {
2702     return clock_cast_detail::cc_impl<DstClock>(tp, &tp);
2703 }
2704 
2705 // Deprecated API
2706 
2707 template <class Duration>
2708 inline
2709 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2710 to_sys_time(const utc_time<Duration>& t)
2711 {
2712     return utc_clock::to_sys(t);
2713 }
2714 
2715 template <class Duration>
2716 inline
2717 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2718 to_sys_time(const tai_time<Duration>& t)
2719 {
2720     return utc_clock::to_sys(tai_clock::to_utc(t));
2721 }
2722 
2723 template <class Duration>
2724 inline
2725 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2726 to_sys_time(const gps_time<Duration>& t)
2727 {
2728     return utc_clock::to_sys(gps_clock::to_utc(t));
2729 }
2730 
2731 
2732 template <class Duration>
2733 inline
2734 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2735 to_utc_time(const sys_time<Duration>& t)
2736 {
2737     return utc_clock::from_sys(t);
2738 }
2739 
2740 template <class Duration>
2741 inline
2742 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2743 to_utc_time(const tai_time<Duration>& t)
2744 {
2745     return tai_clock::to_utc(t);
2746 }
2747 
2748 template <class Duration>
2749 inline
2750 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2751 to_utc_time(const gps_time<Duration>& t)
2752 {
2753     return gps_clock::to_utc(t);
2754 }
2755 
2756 
2757 template <class Duration>
2758 inline
2759 tai_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2760 to_tai_time(const sys_time<Duration>& t)
2761 {
2762     return tai_clock::from_utc(utc_clock::from_sys(t));
2763 }
2764 
2765 template <class Duration>
2766 inline
2767 tai_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2768 to_tai_time(const utc_time<Duration>& t)
2769 {
2770     return tai_clock::from_utc(t);
2771 }
2772 
2773 template <class Duration>
2774 inline
2775 tai_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2776 to_tai_time(const gps_time<Duration>& t)
2777 {
2778     return tai_clock::from_utc(gps_clock::to_utc(t));
2779 }
2780 
2781 
2782 template <class Duration>
2783 inline
2784 gps_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2785 to_gps_time(const sys_time<Duration>& t)
2786 {
2787     return gps_clock::from_utc(utc_clock::from_sys(t));
2788 }
2789 
2790 template <class Duration>
2791 inline
2792 gps_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2793 to_gps_time(const utc_time<Duration>& t)
2794 {
2795     return gps_clock::from_utc(t);
2796 }
2797 
2798 template <class Duration>
2799 inline
2800 gps_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2801 to_gps_time(const tai_time<Duration>& t)
2802 {
2803     return gps_clock::from_utc(tai_clock::to_utc(t));
2804 }
2805 
2806 }  // namespace arrow_vendored::date
2807 
2808 #endif  // TZ_H