1 #ifndef TZ_H
2 #define TZ_H
3 
4 // The MIT License (MIT)
5 //
6 // Copyright (c) 2015, 2016, 2017 Howard Hinnant
7 // Copyright (c) 2017 Jiangang Zhuang
8 // Copyright (c) 2017 Aaron Bishop
9 // Copyright (c) 2017 Tomasz Kamiński
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in all
19 // copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 // SOFTWARE.
28 //
29 // Our apologies.  When the previous paragraph was written, lowercase had not yet
30 // been invented (that would involve another several millennia of evolution).
31 // We did not mean to shout.
32 
33 // Get more recent database at http://www.iana.org/time-zones
34 
35 // The notion of "current timezone" is something the operating system is expected to "just
36 // know". How it knows this is system specific. It's often a value set by the user at OS
37 // installation time and recorded by the OS somewhere. On Linux and Mac systems the current
38 // timezone name is obtained by looking at the name or contents of a particular file on
39 // disk. On Windows the current timezone name comes from the registry. In either method,
40 // there is no guarantee that the "native" current timezone name obtained will match any
41 // of the "Standard" names in this library's "database". On Linux, the names usually do
42 // seem to match so mapping functions to map from native to "Standard" are typically not
43 // required. On Windows, the names are never "Standard" so mapping is always required.
44 // Technically any OS may use the mapping process but currently only Windows does use it.
45 
46 #ifndef USE_OS_TZDB
47 #  define USE_OS_TZDB 0
48 #endif
49 
50 #ifndef HAS_REMOTE_API
51 #  if USE_OS_TZDB == 0
52 #    ifdef _WIN32
53 #      define HAS_REMOTE_API 0
54 #    else
55 #      define HAS_REMOTE_API 1
56 #    endif
57 #  else  // HAS_REMOTE_API makes no since when using the OS timezone database
58 #    define HAS_REMOTE_API 0
59 #  endif
60 #endif
61 
62 #ifdef __clang__
63 # pragma clang diagnostic push
64 # pragma clang diagnostic ignored "-Wconstant-logical-operand"
65 #endif
66 
67 static_assert(!(USE_OS_TZDB && HAS_REMOTE_API),
68               "USE_OS_TZDB and HAS_REMOTE_API can not be used together");
69 
70 #ifdef __clang__
71 # pragma clang diagnostic pop
72 #endif
73 
74 #ifndef AUTO_DOWNLOAD
75 #  define AUTO_DOWNLOAD HAS_REMOTE_API
76 #endif
77 
78 static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true,
79               "AUTO_DOWNLOAD can not be turned on without HAS_REMOTE_API");
80 
81 #ifndef USE_SHELL_API
82 #  define USE_SHELL_API 1
83 #endif
84 
85 #if USE_OS_TZDB
86 #  ifdef _WIN32
87 #    error "USE_OS_TZDB can not be used on Windows"
88 #  endif
89 #endif
90 
91 #ifndef HAS_DEDUCTION_GUIDES
92 #  if __cplusplus >= 201703
93 #    define HAS_DEDUCTION_GUIDES 1
94 #  else
95 #    define HAS_DEDUCTION_GUIDES 0
96 #  endif
97 #endif  // HAS_DEDUCTION_GUIDES
98 
99 #include "date.h"
100 
101 #if defined(_MSC_VER) && (_MSC_VER < 1900)
102 #include "tz_private.h"
103 #endif
104 
105 #include <algorithm>
106 #include <atomic>
107 #include <cassert>
108 #include <chrono>
109 #include <istream>
110 #include <locale>
111 #include <memory>
112 #include <mutex>
113 #include <ostream>
114 #include <sstream>
115 #include <stdexcept>
116 #include <string>
117 #include <type_traits>
118 #include <utility>
119 #include <vector>
120 
121 #ifdef _WIN32
122 #  ifdef DATE_BUILD_DLL
123 #    define DATE_API __declspec(dllexport)
124 #  elif defined(DATE_USE_DLL)
125 #    define DATE_API __declspec(dllimport)
126 #  else
127 #    define DATE_API
128 #  endif
129 #else
130 #  ifdef DATE_BUILD_DLL
131 #    define DATE_API __attribute__ ((visibility ("default")))
132 #  else
133 #    define DATE_API
134 #  endif
135 #endif
136 
137 namespace date
138 {
139 
140 enum class choose {earliest, latest};
141 
142 namespace detail
143 {
144     struct undocumented;
145 
146     template<typename T>
147     struct nodeduct
148     {
149        using type = T;
150     };
151 
152     template<typename T>
153     using nodeduct_t = typename nodeduct<T>::type;
154 }
155 
156 struct sys_info
157 {
158     sys_seconds          begin;
159     sys_seconds          end;
160     std::chrono::seconds offset;
161     std::chrono::minutes save;
162     std::string          abbrev;
163 };
164 
165 template<class CharT, class Traits>
166 std::basic_ostream<CharT, Traits>&
167 operator<<(std::basic_ostream<CharT, Traits>& os, const sys_info& r)
168 {
169     os << r.begin << '\n';
170     os << r.end << '\n';
171     os << make_time(r.offset) << "\n";
172     os << make_time(r.save) << "\n";
173     os << r.abbrev << '\n';
174     return os;
175 }
176 
177 struct local_info
178 {
179     enum {unique, nonexistent, ambiguous} result;
180     sys_info first;
181     sys_info second;
182 };
183 
184 template<class CharT, class Traits>
185 std::basic_ostream<CharT, Traits>&
186 operator<<(std::basic_ostream<CharT, Traits>& os, const local_info& r)
187 {
188     if (r.result == local_info::nonexistent)
189         os << "nonexistent between\n";
190     else if (r.result == local_info::ambiguous)
191         os << "ambiguous between\n";
192     os << r.first;
193     if (r.result != local_info::unique)
194     {
195         os << "and\n";
196         os << r.second;
197     }
198     return os;
199 }
200 
201 class nonexistent_local_time
202     : public std::runtime_error
203 {
204 public:
205     template <class Duration>
206         nonexistent_local_time(local_time<Duration> tp, const local_info& i);
207 
208 private:
209     template <class Duration>
210     static
211     std::string
212     make_msg(local_time<Duration> tp, const local_info& i);
213 };
214 
215 template <class Duration>
216 inline
nonexistent_local_time(local_time<Duration> tp,const local_info & i)217 nonexistent_local_time::nonexistent_local_time(local_time<Duration> tp,
218                                                const local_info& i)
219     : std::runtime_error(make_msg(tp, i))
220 {
221 }
222 
223 template <class Duration>
224 std::string
make_msg(local_time<Duration> tp,const local_info & i)225 nonexistent_local_time::make_msg(local_time<Duration> tp, const local_info& i)
226 {
227     assert(i.result == local_info::nonexistent);
228     std::ostringstream os;
229     os << tp << " is in a gap between\n"
230        << local_seconds{i.first.end.time_since_epoch()} + i.first.offset << ' '
231        << i.first.abbrev << " and\n"
232        << local_seconds{i.second.begin.time_since_epoch()} + i.second.offset << ' '
233        << i.second.abbrev
234        << " which are both equivalent to\n"
235        << i.first.end << " UTC";
236     return os.str();
237 }
238 
239 class ambiguous_local_time
240     : public std::runtime_error
241 {
242 public:
243     template <class Duration>
244         ambiguous_local_time(local_time<Duration> tp, const local_info& i);
245 
246 private:
247     template <class Duration>
248     static
249     std::string
250     make_msg(local_time<Duration> tp, const local_info& i);
251 };
252 
253 template <class Duration>
254 inline
ambiguous_local_time(local_time<Duration> tp,const local_info & i)255 ambiguous_local_time::ambiguous_local_time(local_time<Duration> tp, const local_info& i)
256     : std::runtime_error(make_msg(tp, i))
257 {
258 }
259 
260 template <class Duration>
261 std::string
make_msg(local_time<Duration> tp,const local_info & i)262 ambiguous_local_time::make_msg(local_time<Duration> tp, const local_info& i)
263 {
264     assert(i.result == local_info::ambiguous);
265     std::ostringstream os;
266     os << tp << " is ambiguous.  It could be\n"
267        << tp << ' ' << i.first.abbrev << " == "
268        << tp - i.first.offset << " UTC or\n"
269        << tp << ' ' << i.second.abbrev  << " == "
270        << tp - i.second.offset  << " UTC";
271     return os.str();
272 }
273 
274 class time_zone;
275 
276 #if HAS_STRING_VIEW
277 DATE_API const time_zone* locate_zone(std::string_view tz_name);
278 #else
279 DATE_API const time_zone* locate_zone(const std::string& tz_name);
280 #endif
281 
282 DATE_API const time_zone* current_zone();
283 
284 template <class T>
285 struct zoned_traits
286 {
287 };
288 
289 template <>
290 struct zoned_traits<const time_zone*>
291 {
292     static
293     const time_zone*
294     default_zone()
295     {
296         return date::locate_zone("Etc/UTC");
297     }
298 
299 #if HAS_STRING_VIEW
300 
301     static
302     const time_zone*
303     locate_zone(std::string_view name)
304     {
305         return date::locate_zone(name);
306     }
307 
308 #else  // !HAS_STRING_VIEW
309 
310     static
311     const time_zone*
312     locate_zone(const std::string& name)
313     {
314         return date::locate_zone(name);
315     }
316 
317     static
318     const time_zone*
319     locate_zone(const char* name)
320     {
321         return date::locate_zone(name);
322     }
323 
324 #endif  // !HAS_STRING_VIEW
325 };
326 
327 template <class Duration, class TimeZonePtr>
328 class zoned_time;
329 
330 template <class Duration1, class Duration2, class TimeZonePtr>
331 bool
332 operator==(const zoned_time<Duration1, TimeZonePtr>& x,
333            const zoned_time<Duration2, TimeZonePtr>& y);
334 
335 template <class Duration, class TimeZonePtr = const time_zone*>
336 class zoned_time
337 {
338 public:
339     using duration = typename std::common_type<Duration, std::chrono::seconds>::type;
340 
341 private:
342     TimeZonePtr        zone_;
343     sys_time<duration> tp_;
344 
345 public:
346 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
347     template <class T = TimeZonePtr,
348               class = decltype(zoned_traits<T>::default_zone())>
349 #endif
350         zoned_time();
351 
352 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
353     template <class T = TimeZonePtr,
354               class = decltype(zoned_traits<T>::default_zone())>
355 #endif
356         zoned_time(const sys_time<Duration>& st);
357     explicit zoned_time(TimeZonePtr z);
358 
359 #if HAS_STRING_VIEW
360     template <class T = TimeZonePtr,
361               class = typename std::enable_if
362               <
363                   std::is_constructible
364                   <
365                       zoned_time,
366                       decltype(zoned_traits<T>::locate_zone(std::string_view()))
367                   >::value
368               >::type>
369         explicit zoned_time(std::string_view name);
370 #else
371 #  if !defined(_MSC_VER) || (_MSC_VER > 1916)
372     template <class T = TimeZonePtr,
373               class = typename std::enable_if
374               <
375                   std::is_constructible
376                   <
377                       zoned_time,
378                       decltype(zoned_traits<T>::locate_zone(std::string()))
379                   >::value
380               >::type>
381 #  endif
382         explicit zoned_time(const std::string& name);
383 #endif
384 
385     template <class Duration2,
386               class = typename std::enable_if
387                       <
388                           std::is_convertible<sys_time<Duration2>,
389                                               sys_time<Duration>>::value
390                       >::type>
391         zoned_time(const zoned_time<Duration2, TimeZonePtr>& zt) NOEXCEPT;
392 
393     zoned_time(TimeZonePtr z, const sys_time<Duration>& st);
394 
395 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
396     template <class T = TimeZonePtr,
397               class = typename std::enable_if
398               <
399                   std::is_convertible
400                   <
401                       decltype(std::declval<T&>()->to_sys(local_time<Duration>{})),
402                       sys_time<duration>
403                   >::value
404               >::type>
405 #endif
406         zoned_time(TimeZonePtr z, const local_time<Duration>& tp);
407 
408 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
409     template <class T = TimeZonePtr,
410               class = typename std::enable_if
411               <
412                   std::is_convertible
413                   <
414                       decltype(std::declval<T&>()->to_sys(local_time<Duration>{},
415                                                           choose::earliest)),
416                       sys_time<duration>
417                   >::value
418               >::type>
419 #endif
420         zoned_time(TimeZonePtr z, const local_time<Duration>& tp, choose c);
421 
422     template <class Duration2, class TimeZonePtr2,
423               class = typename std::enable_if
424                       <
425                           std::is_convertible<sys_time<Duration2>,
426                                               sys_time<Duration>>::value
427                       >::type>
428         zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt);
429 
430     template <class Duration2, class TimeZonePtr2,
431               class = typename std::enable_if
432                       <
433                           std::is_convertible<sys_time<Duration2>,
434                                               sys_time<Duration>>::value
435                       >::type>
436         zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt, choose);
437 
438 #if HAS_STRING_VIEW
439 
440     template <class T = TimeZonePtr,
441               class = typename std::enable_if
442               <
443                   std::is_constructible
444                   <
445                       zoned_time,
446                       decltype(zoned_traits<T>::locate_zone(std::string_view())),
447                       sys_time<Duration>
448                   >::value
449               >::type>
450         zoned_time(std::string_view name, detail::nodeduct_t<const sys_time<Duration>&> st);
451 
452     template <class T = TimeZonePtr,
453               class = typename std::enable_if
454               <
455                   std::is_constructible
456                   <
457                       zoned_time,
458                       decltype(zoned_traits<T>::locate_zone(std::string_view())),
459                       local_time<Duration>
460                   >::value
461               >::type>
462         zoned_time(std::string_view name, detail::nodeduct_t<const local_time<Duration>&> tp);
463 
464     template <class T = TimeZonePtr,
465               class = typename std::enable_if
466               <
467                   std::is_constructible
468                   <
469                       zoned_time,
470                       decltype(zoned_traits<T>::locate_zone(std::string_view())),
471                       local_time<Duration>,
472                       choose
473                   >::value
474               >::type>
475         zoned_time(std::string_view name, detail::nodeduct_t<const local_time<Duration>&> tp, choose c);
476 
477     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
478               class = typename std::enable_if
479                       <
480                           std::is_convertible<sys_time<Duration2>,
481                                               sys_time<Duration>>::value &&
482                           std::is_constructible
483                           <
484                               zoned_time,
485                               decltype(zoned_traits<T>::locate_zone(std::string_view())),
486                               zoned_time
487                           >::value
488                       >::type>
489         zoned_time(std::string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt);
490 
491     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
492               class = typename std::enable_if
493                       <
494                           std::is_convertible<sys_time<Duration2>,
495                                               sys_time<Duration>>::value &&
496                           std::is_constructible
497                           <
498                               zoned_time,
499                               decltype(zoned_traits<T>::locate_zone(std::string_view())),
500                               zoned_time,
501                               choose
502                           >::value
503                       >::type>
504         zoned_time(std::string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt, choose);
505 
506 #else  // !HAS_STRING_VIEW
507 
508 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
509     template <class T = TimeZonePtr,
510               class = typename std::enable_if
511               <
512                   std::is_constructible
513                   <
514                       zoned_time,
515                       decltype(zoned_traits<T>::locate_zone(std::string())),
516                       sys_time<Duration>
517                   >::value
518               >::type>
519 #endif
520         zoned_time(const std::string& name, const sys_time<Duration>& st);
521 
522 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
523     template <class T = TimeZonePtr,
524               class = typename std::enable_if
525               <
526                   std::is_constructible
527                   <
528                       zoned_time,
529                       decltype(zoned_traits<T>::locate_zone(std::string())),
530                       sys_time<Duration>
531                   >::value
532               >::type>
533 #endif
534         zoned_time(const char* name, const sys_time<Duration>& st);
535 
536 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
537     template <class T = TimeZonePtr,
538               class = typename std::enable_if
539               <
540                   std::is_constructible
541                   <
542                       zoned_time,
543                       decltype(zoned_traits<T>::locate_zone(std::string())),
544                       local_time<Duration>
545                   >::value
546               >::type>
547 #endif
548         zoned_time(const std::string& name, const local_time<Duration>& tp);
549 
550 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
551     template <class T = TimeZonePtr,
552               class = typename std::enable_if
553               <
554                   std::is_constructible
555                   <
556                       zoned_time,
557                       decltype(zoned_traits<T>::locate_zone(std::string())),
558                       local_time<Duration>
559                   >::value
560               >::type>
561 #endif
562         zoned_time(const char* name, const local_time<Duration>& tp);
563 
564 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
565     template <class T = TimeZonePtr,
566               class = typename std::enable_if
567               <
568                   std::is_constructible
569                   <
570                       zoned_time,
571                       decltype(zoned_traits<T>::locate_zone(std::string())),
572                       local_time<Duration>,
573                       choose
574                   >::value
575               >::type>
576 #endif
577         zoned_time(const std::string& name, const local_time<Duration>& tp, choose c);
578 
579 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
580     template <class T = TimeZonePtr,
581               class = typename std::enable_if
582               <
583                   std::is_constructible
584                   <
585                       zoned_time,
586                       decltype(zoned_traits<T>::locate_zone(std::string())),
587                       local_time<Duration>,
588                       choose
589                   >::value
590               >::type>
591 #endif
592         zoned_time(const char* name, const local_time<Duration>& tp, choose c);
593 
594 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
595     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
596               class = typename std::enable_if
597                       <
598                           std::is_convertible<sys_time<Duration2>,
599                                               sys_time<Duration>>::value &&
600                           std::is_constructible
601                           <
602                               zoned_time,
603                               decltype(zoned_traits<T>::locate_zone(std::string())),
604                               zoned_time
605                           >::value
606                       >::type>
607 #else
608     template <class Duration2, class TimeZonePtr2>
609 #endif
610         zoned_time(const std::string& name, const zoned_time<Duration2, TimeZonePtr2>& zt);
611 
612 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
613     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
614               class = typename std::enable_if
615                       <
616                           std::is_convertible<sys_time<Duration2>,
617                                               sys_time<Duration>>::value &&
618                           std::is_constructible
619                           <
620                               zoned_time,
621                               decltype(zoned_traits<T>::locate_zone(std::string())),
622                               zoned_time
623                           >::value
624                       >::type>
625 #else
626     template <class Duration2, class TimeZonePtr2>
627 #endif
628         zoned_time(const char* name, const zoned_time<Duration2, TimeZonePtr2>& zt);
629 
630 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
631     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
632               class = typename std::enable_if
633                       <
634                           std::is_convertible<sys_time<Duration2>,
635                                               sys_time<Duration>>::value &&
636                           std::is_constructible
637                           <
638                               zoned_time,
639                               decltype(zoned_traits<T>::locate_zone(std::string())),
640                               zoned_time,
641                               choose
642                           >::value
643                       >::type>
644 #else
645     template <class Duration2, class TimeZonePtr2>
646 #endif
647         zoned_time(const std::string& name, const zoned_time<Duration2, TimeZonePtr2>& zt,
648                    choose);
649 
650 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
651     template <class Duration2, class TimeZonePtr2, class T = TimeZonePtr,
652               class = typename std::enable_if
653                       <
654                           std::is_convertible<sys_time<Duration2>,
655                                               sys_time<Duration>>::value &&
656                           std::is_constructible
657                           <
658                               zoned_time,
659                               decltype(zoned_traits<T>::locate_zone(std::string())),
660                               zoned_time,
661                               choose
662                           >::value
663                       >::type>
664 #else
665     template <class Duration2, class TimeZonePtr2>
666 #endif
667         zoned_time(const char* name, const zoned_time<Duration2, TimeZonePtr2>& zt,
668                    choose);
669 
670 #endif  // !HAS_STRING_VIEW
671 
672     zoned_time& operator=(const sys_time<Duration>& st);
673     zoned_time& operator=(const local_time<Duration>& ut);
674 
675     explicit operator sys_time<duration>() const;
676     explicit operator local_time<duration>() const;
677 
678     TimeZonePtr          get_time_zone() const;
679     local_time<duration> get_local_time() const;
680     sys_time<duration>   get_sys_time() const;
681     sys_info             get_info() const;
682 
683     template <class Duration1, class Duration2, class TimeZonePtr1>
684     friend
685     bool
686     operator==(const zoned_time<Duration1, TimeZonePtr1>& x,
687                const zoned_time<Duration2, TimeZonePtr1>& y);
688 
689     template <class CharT, class Traits, class Duration1, class TimeZonePtr1>
690     friend
691     std::basic_ostream<CharT, Traits>&
692     operator<<(std::basic_ostream<CharT, Traits>& os,
693                const zoned_time<Duration1, TimeZonePtr1>& t);
694 
695 private:
696     template <class D, class T> friend class zoned_time;
697 
698     template <class TimeZonePtr2>
699     static
700     TimeZonePtr2&&
701     check(TimeZonePtr2&& p);
702 };
703 
704 using zoned_seconds = zoned_time<std::chrono::seconds>;
705 
706 #if HAS_DEDUCTION_GUIDES
707 
708 namespace detail
709 {
710    template<typename TimeZonePtrOrName>
711    using time_zone_representation =
712        std::conditional_t
713        <
714            std::is_convertible<TimeZonePtrOrName, std::string_view>::value,
715            time_zone const*,
716            std::remove_cv_t<std::remove_reference_t<TimeZonePtrOrName>>
717        >;
718 }
719 
720 zoned_time()
721     -> zoned_time<std::chrono::seconds>;
722 
723 template <class Duration>
724 zoned_time(sys_time<Duration>)
725     -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>>;
726 
727 template <class TimeZonePtrOrName>
728 zoned_time(TimeZonePtrOrName&&)
729     -> zoned_time<std::chrono::seconds, detail::time_zone_representation<TimeZonePtrOrName>>;
730 
731 template <class TimeZonePtrOrName, class Duration>
732 zoned_time(TimeZonePtrOrName&&, sys_time<Duration>)
733     -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>, detail::time_zone_representation<TimeZonePtrOrName>>;
734 
735 template <class TimeZonePtrOrName, class Duration>
736 zoned_time(TimeZonePtrOrName&&, local_time<Duration>, choose = choose::earliest)
737     -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>, detail::time_zone_representation<TimeZonePtrOrName>>;
738 
739 template <class Duration, class TimeZonePtrOrName, class TimeZonePtr2>
740 zoned_time(TimeZonePtrOrName&&, zoned_time<Duration, TimeZonePtr2>, choose = choose::earliest)
741     -> zoned_time<std::common_type_t<Duration, std::chrono::seconds>, detail::time_zone_representation<TimeZonePtrOrName>>;
742 
743 #endif  // HAS_DEDUCTION_GUIDES
744 
745 template <class Duration1, class Duration2, class TimeZonePtr>
746 inline
747 bool
748 operator==(const zoned_time<Duration1, TimeZonePtr>& x,
749            const zoned_time<Duration2, TimeZonePtr>& y)
750 {
751     return x.zone_ == y.zone_ && x.tp_ == y.tp_;
752 }
753 
754 template <class Duration1, class Duration2, class TimeZonePtr>
755 inline
756 bool
757 operator!=(const zoned_time<Duration1, TimeZonePtr>& x,
758            const zoned_time<Duration2, TimeZonePtr>& y)
759 {
760     return !(x == y);
761 }
762 
763 #if !defined(_MSC_VER) || (_MSC_VER >= 1900)
764 
765 namespace detail
766 {
767 #  if USE_OS_TZDB
768     struct transition;
769     struct expanded_ttinfo;
770 #  else  // !USE_OS_TZDB
771     struct zonelet;
772     class Rule;
773 #  endif  // !USE_OS_TZDB
774 }
775 
776 #endif  // !defined(_MSC_VER) || (_MSC_VER >= 1900)
777 
778 class time_zone
779 {
780 private:
781     std::string                          name_;
782 #if USE_OS_TZDB
783     std::vector<detail::transition>      transitions_;
784     std::vector<detail::expanded_ttinfo> ttinfos_;
785 #else  // !USE_OS_TZDB
786     std::vector<detail::zonelet>         zonelets_;
787 #endif  // !USE_OS_TZDB
788     std::unique_ptr<std::once_flag>      adjusted_;
789 
790 public:
791 #if !defined(_MSC_VER) || (_MSC_VER >= 1900)
792     time_zone(time_zone&&) = default;
793     time_zone& operator=(time_zone&&) = default;
794 #else   // defined(_MSC_VER) && (_MSC_VER < 1900)
795     time_zone(time_zone&& src);
796     time_zone& operator=(time_zone&& src);
797 #endif  // defined(_MSC_VER) && (_MSC_VER < 1900)
798 
799     DATE_API explicit time_zone(const std::string& s, detail::undocumented);
800 
801     const std::string& name() const NOEXCEPT;
802 
803     template <class Duration> sys_info   get_info(sys_time<Duration> st) const;
804     template <class Duration> local_info get_info(local_time<Duration> tp) const;
805 
806     template <class Duration>
807         sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
808         to_sys(local_time<Duration> tp) const;
809 
810     template <class Duration>
811         sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
812         to_sys(local_time<Duration> tp, choose z) const;
813 
814     template <class Duration>
815         local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
816         to_local(sys_time<Duration> tp) const;
817 
818     friend bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT;
819     friend bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT;
820     friend DATE_API std::ostream& operator<<(std::ostream& os, const time_zone& z);
821 
822 #if !USE_OS_TZDB
823     DATE_API void add(const std::string& s);
824 #endif  // !USE_OS_TZDB
825 
826 private:
827     DATE_API sys_info   get_info_impl(sys_seconds tp) const;
828     DATE_API local_info get_info_impl(local_seconds tp) const;
829 
830     template <class Duration>
831         sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
832         to_sys_impl(local_time<Duration> tp, choose z, std::false_type) const;
833     template <class Duration>
834         sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
835         to_sys_impl(local_time<Duration> tp, choose, std::true_type) const;
836 
837 #if USE_OS_TZDB
838     DATE_API void init() const;
839     DATE_API void init_impl();
840     DATE_API sys_info
841         load_sys_info(std::vector<detail::transition>::const_iterator i) const;
842 
843     template <class TimeType>
844     DATE_API void
845     load_data(std::istream& inf, std::int32_t tzh_leapcnt, std::int32_t tzh_timecnt,
846                                  std::int32_t tzh_typecnt, std::int32_t tzh_charcnt);
847 #else  // !USE_OS_TZDB
848     DATE_API sys_info   get_info_impl(sys_seconds tp, int timezone) const;
849     DATE_API void adjust_infos(const std::vector<detail::Rule>& rules);
850     DATE_API void parse_info(std::istream& in);
851 #endif  // !USE_OS_TZDB
852 };
853 
854 #if defined(_MSC_VER) && (_MSC_VER < 1900)
855 
856 inline
857 time_zone::time_zone(time_zone&& src)
858     : name_(std::move(src.name_))
859     , zonelets_(std::move(src.zonelets_))
860     , adjusted_(std::move(src.adjusted_))
861     {}
862 
863 inline
864 time_zone&
865 time_zone::operator=(time_zone&& src)
866 {
867     name_ = std::move(src.name_);
868     zonelets_ = std::move(src.zonelets_);
869     adjusted_ = std::move(src.adjusted_);
870     return *this;
871 }
872 
873 #endif  // defined(_MSC_VER) && (_MSC_VER < 1900)
874 
875 inline
876 const std::string&
877 time_zone::name() const NOEXCEPT
878 {
879     return name_;
880 }
881 
882 template <class Duration>
883 inline
884 sys_info
885 time_zone::get_info(sys_time<Duration> st) const
886 {
887     return get_info_impl(date::floor<std::chrono::seconds>(st));
888 }
889 
890 template <class Duration>
891 inline
892 local_info
893 time_zone::get_info(local_time<Duration> tp) const
894 {
895     return get_info_impl(date::floor<std::chrono::seconds>(tp));
896 }
897 
898 template <class Duration>
899 inline
900 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
901 time_zone::to_sys(local_time<Duration> tp) const
902 {
903     return to_sys_impl(tp, choose{}, std::true_type{});
904 }
905 
906 template <class Duration>
907 inline
908 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
909 time_zone::to_sys(local_time<Duration> tp, choose z) const
910 {
911     return to_sys_impl(tp, z, std::false_type{});
912 }
913 
914 template <class Duration>
915 inline
916 local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
917 time_zone::to_local(sys_time<Duration> tp) const
918 {
919     using LT = local_time<typename std::common_type<Duration, std::chrono::seconds>::type>;
920     auto i = get_info(tp);
921     return LT{(tp + i.offset).time_since_epoch()};
922 }
923 
924 inline bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ == y.name_;}
925 inline bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ < y.name_;}
926 
927 inline bool operator!=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x == y);}
928 inline bool operator> (const time_zone& x, const time_zone& y) NOEXCEPT {return   y < x;}
929 inline bool operator<=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(y < x);}
930 inline bool operator>=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x < y);}
931 
932 template <class Duration>
933 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
934 time_zone::to_sys_impl(local_time<Duration> tp, choose z, std::false_type) const
935 {
936     auto i = get_info(tp);
937     if (i.result == local_info::nonexistent)
938     {
939         return i.first.end;
940     }
941     else if (i.result == local_info::ambiguous)
942     {
943         if (z == choose::latest)
944             return sys_time<Duration>{tp.time_since_epoch()} - i.second.offset;
945     }
946     return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
947 }
948 
949 template <class Duration>
950 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
951 time_zone::to_sys_impl(local_time<Duration> tp, choose, std::true_type) const
952 {
953     auto i = get_info(tp);
954     if (i.result == local_info::nonexistent)
955         throw nonexistent_local_time(tp, i);
956     else if (i.result == local_info::ambiguous)
957         throw ambiguous_local_time(tp, i);
958     return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
959 }
960 
961 #if !USE_OS_TZDB
962 
963 class time_zone_link
964 {
965 private:
966     std::string name_;
967     std::string target_;
968 public:
969     DATE_API explicit time_zone_link(const std::string& s);
970 
971     const std::string& name() const {return name_;}
972     const std::string& target() const {return target_;}
973 
974     friend bool operator==(const time_zone_link& x, const time_zone_link& y) {return x.name_ == y.name_;}
975     friend bool operator< (const time_zone_link& x, const time_zone_link& y) {return x.name_ < y.name_;}
976 
977     friend DATE_API std::ostream& operator<<(std::ostream& os, const time_zone_link& x);
978 };
979 
980 using link = time_zone_link;
981 
982 inline bool operator!=(const time_zone_link& x, const time_zone_link& y) {return !(x == y);}
983 inline bool operator> (const time_zone_link& x, const time_zone_link& y) {return   y < x;}
984 inline bool operator<=(const time_zone_link& x, const time_zone_link& y) {return !(y < x);}
985 inline bool operator>=(const time_zone_link& x, const time_zone_link& y) {return !(x < y);}
986 
987 #endif  // !USE_OS_TZDB
988 
989 class leap_second
990 {
991 private:
992     sys_seconds date_;
993 
994 public:
995 #if USE_OS_TZDB
996     DATE_API explicit leap_second(const sys_seconds& s, detail::undocumented);
997 #else
998     DATE_API explicit leap_second(const std::string& s, detail::undocumented);
999 #endif
1000 
1001     sys_seconds date() const {return date_;}
1002 
1003     friend bool operator==(const leap_second& x, const leap_second& y) {return x.date_ == y.date_;}
1004     friend bool operator< (const leap_second& x, const leap_second& y) {return x.date_ < y.date_;}
1005 
1006     template <class Duration>
1007     friend
1008     bool
1009     operator==(const leap_second& x, const sys_time<Duration>& y)
1010     {
1011         return x.date_ == y;
1012     }
1013 
1014     template <class Duration>
1015     friend
1016     bool
1017     operator< (const leap_second& x, const sys_time<Duration>& y)
1018     {
1019         return x.date_ < y;
1020     }
1021 
1022     template <class Duration>
1023     friend
1024     bool
1025     operator< (const sys_time<Duration>& x, const leap_second& y)
1026     {
1027         return x < y.date_;
1028     }
1029 
1030     friend DATE_API std::ostream& operator<<(std::ostream& os, const leap_second& x);
1031 };
1032 
1033 inline bool operator!=(const leap_second& x, const leap_second& y) {return !(x == y);}
1034 inline bool operator> (const leap_second& x, const leap_second& y) {return   y < x;}
1035 inline bool operator<=(const leap_second& x, const leap_second& y) {return !(y < x);}
1036 inline bool operator>=(const leap_second& x, const leap_second& y) {return !(x < y);}
1037 
1038 template <class Duration>
1039 inline
1040 bool
1041 operator==(const sys_time<Duration>& x, const leap_second& y)
1042 {
1043     return y == x;
1044 }
1045 
1046 template <class Duration>
1047 inline
1048 bool
1049 operator!=(const leap_second& x, const sys_time<Duration>& y)
1050 {
1051     return !(x == y);
1052 }
1053 
1054 template <class Duration>
1055 inline
1056 bool
1057 operator!=(const sys_time<Duration>& x, const leap_second& y)
1058 {
1059     return !(x == y);
1060 }
1061 
1062 template <class Duration>
1063 inline
1064 bool
1065 operator> (const leap_second& x, const sys_time<Duration>& y)
1066 {
1067     return y < x;
1068 }
1069 
1070 template <class Duration>
1071 inline
1072 bool
1073 operator> (const sys_time<Duration>& x, const leap_second& y)
1074 {
1075     return y < x;
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 !(x < y);
1100 }
1101 
1102 template <class Duration>
1103 inline
1104 bool
1105 operator>=(const sys_time<Duration>& x, const leap_second& y)
1106 {
1107     return !(x < y);
1108 }
1109 
1110 using leap = leap_second;
1111 
1112 #ifdef _WIN32
1113 
1114 namespace detail
1115 {
1116 
1117 // The time zone mapping is modelled after this data file:
1118 // http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml
1119 // and the field names match the element names from the mapZone element
1120 // of windowsZones.xml.
1121 // The website displays this file here:
1122 // http://www.unicode.org/cldr/charts/latest/supplemental/zone_tzid.html
1123 // The html view is sorted before being displayed but is otherwise the same
1124 // There is a mapping between the os centric view (in this case windows)
1125 // the html displays uses and the generic view the xml file.
1126 // That mapping is this:
1127 // display column "windows" -> xml field "other".
1128 // display column "region"  -> xml field "territory".
1129 // display column "tzid"    -> xml field "type".
1130 // This structure uses the generic terminology because it could be
1131 // used to to support other os/native name conversions, not just windows,
1132 // and using the same generic names helps retain the connection to the
1133 // origin of the data that we are using.
1134 struct timezone_mapping
1135 {
1136     timezone_mapping(const char* other, const char* territory, const char* type)
1137         : other(other), territory(territory), type(type)
1138     {
1139     }
1140     timezone_mapping() = default;
1141     std::string other;
1142     std::string territory;
1143     std::string type;
1144 };
1145 
1146 }  // detail
1147 
1148 #endif  // _WIN32
1149 
1150 struct tzdb
1151 {
1152     std::string                 version = "unknown";
1153     std::vector<time_zone>      zones;
1154 #if !USE_OS_TZDB
1155     std::vector<time_zone_link> links;
1156 #endif
1157     std::vector<leap_second>    leap_seconds;
1158 #if !USE_OS_TZDB
1159     std::vector<detail::Rule>   rules;
1160 #endif
1161 #ifdef _WIN32
1162     std::vector<detail::timezone_mapping> mappings;
1163 #endif
1164     tzdb* next = nullptr;
1165 
1166     tzdb() = default;
1167 #if !defined(_MSC_VER) || (_MSC_VER >= 1900)
1168     tzdb(tzdb&&) = default;
1169     tzdb& operator=(tzdb&&) = default;
1170 #else  // defined(_MSC_VER) && (_MSC_VER < 1900)
1171     tzdb(tzdb&& src)
1172         : version(std::move(src.version))
1173         , zones(std::move(src.zones))
1174         , links(std::move(src.links))
1175         , leap_seconds(std::move(src.leap_seconds))
1176         , rules(std::move(src.rules))
1177         , mappings(std::move(src.mappings))
1178     {}
1179 
1180     tzdb& operator=(tzdb&& src)
1181     {
1182         version = std::move(src.version);
1183         zones = std::move(src.zones);
1184         links = std::move(src.links);
1185         leap_seconds = std::move(src.leap_seconds);
1186         rules = std::move(src.rules);
1187         mappings = std::move(src.mappings);
1188         return *this;
1189     }
1190 #endif  // defined(_MSC_VER) && (_MSC_VER < 1900)
1191 
1192 #if HAS_STRING_VIEW
1193     const time_zone* locate_zone(std::string_view tz_name) const;
1194 #else
1195     const time_zone* locate_zone(const std::string& tz_name) const;
1196 #endif
1197     const time_zone* current_zone() const;
1198 };
1199 
1200 using TZ_DB = tzdb;
1201 
1202 DATE_API std::ostream&
1203 operator<<(std::ostream& os, const tzdb& db);
1204 
1205 DATE_API const tzdb& get_tzdb();
1206 
1207 class tzdb_list
1208 {
1209     std::atomic<tzdb*> head_{nullptr};
1210 
1211 public:
1212     ~tzdb_list();
1213     tzdb_list() = default;
1214     tzdb_list(tzdb_list&& x) NOEXCEPT;
1215 
1216     const tzdb& front() const NOEXCEPT {return *head_;}
1217           tzdb& front()       NOEXCEPT {return *head_;}
1218 
1219     class const_iterator;
1220 
1221     const_iterator begin() const NOEXCEPT;
1222     const_iterator end() const NOEXCEPT;
1223 
1224     const_iterator cbegin() const NOEXCEPT;
1225     const_iterator cend() const NOEXCEPT;
1226 
1227     const_iterator erase_after(const_iterator p) NOEXCEPT;
1228 
1229     struct undocumented_helper;
1230 private:
1231     void push_front(tzdb* tzdb) NOEXCEPT;
1232 };
1233 
1234 class tzdb_list::const_iterator
1235 {
1236     tzdb* p_ = nullptr;
1237 
1238     explicit const_iterator(tzdb* p) NOEXCEPT : p_{p} {}
1239 public:
1240     const_iterator() = default;
1241 
1242     using iterator_category = std::forward_iterator_tag;
1243     using value_type        = tzdb;
1244     using reference         = const value_type&;
1245     using pointer           = const value_type*;
1246     using difference_type   = std::ptrdiff_t;
1247 
1248     reference operator*() const NOEXCEPT {return *p_;}
1249     pointer  operator->() const NOEXCEPT {return p_;}
1250 
1251     const_iterator& operator++() NOEXCEPT {p_ = p_->next; return *this;}
1252     const_iterator  operator++(int) NOEXCEPT {auto t = *this; ++(*this); return t;}
1253 
1254     friend
1255     bool
1256     operator==(const const_iterator& x, const const_iterator& y) NOEXCEPT
1257         {return x.p_ == y.p_;}
1258 
1259     friend
1260     bool
1261     operator!=(const const_iterator& x, const const_iterator& y) NOEXCEPT
1262         {return !(x == y);}
1263 
1264     friend class tzdb_list;
1265 };
1266 
1267 inline
1268 tzdb_list::const_iterator
1269 tzdb_list::begin() const NOEXCEPT
1270 {
1271     return const_iterator{head_};
1272 }
1273 
1274 inline
1275 tzdb_list::const_iterator
1276 tzdb_list::end() const NOEXCEPT
1277 {
1278     return const_iterator{nullptr};
1279 }
1280 
1281 inline
1282 tzdb_list::const_iterator
1283 tzdb_list::cbegin() const NOEXCEPT
1284 {
1285     return begin();
1286 }
1287 
1288 inline
1289 tzdb_list::const_iterator
1290 tzdb_list::cend() const NOEXCEPT
1291 {
1292     return end();
1293 }
1294 
1295 DATE_API tzdb_list& get_tzdb_list();
1296 
1297 #if !USE_OS_TZDB
1298 
1299 DATE_API const tzdb& reload_tzdb();
1300 DATE_API void        set_install(const std::string& install);
1301 
1302 #endif  // !USE_OS_TZDB
1303 
1304 #if HAS_REMOTE_API
1305 
1306 DATE_API std::string remote_version();
1307 // if provided error_buffer size should be at least CURL_ERROR_SIZE
1308 DATE_API bool        remote_download(const std::string& version, char* error_buffer = nullptr);
1309 DATE_API bool        remote_install(const std::string& version);
1310 
1311 #endif
1312 
1313 // zoned_time
1314 
1315 namespace detail
1316 {
1317 
1318 template <class T>
1319 inline
1320 T*
1321 to_raw_pointer(T* p) NOEXCEPT
1322 {
1323     return p;
1324 }
1325 
1326 template <class Pointer>
1327 inline
1328 auto
1329 to_raw_pointer(Pointer p) NOEXCEPT
1330     -> decltype(detail::to_raw_pointer(p.operator->()))
1331 {
1332     return detail::to_raw_pointer(p.operator->());
1333 }
1334 
1335 }  // namespace detail
1336 
1337 template <class Duration, class TimeZonePtr>
1338 template <class TimeZonePtr2>
1339 inline
1340 TimeZonePtr2&&
1341 zoned_time<Duration, TimeZonePtr>::check(TimeZonePtr2&& p)
1342 {
1343     if (detail::to_raw_pointer(p) == nullptr)
1344         throw std::runtime_error(
1345             "zoned_time constructed with a time zone pointer == nullptr");
1346     return std::forward<TimeZonePtr2>(p);
1347 }
1348 
1349 template <class Duration, class TimeZonePtr>
1350 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1351 template <class T, class>
1352 #endif
1353 inline
1354 zoned_time<Duration, TimeZonePtr>::zoned_time()
1355     : zone_(check(zoned_traits<TimeZonePtr>::default_zone()))
1356     {}
1357 
1358 template <class Duration, class TimeZonePtr>
1359 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1360 template <class T, class>
1361 #endif
1362 inline
1363 zoned_time<Duration, TimeZonePtr>::zoned_time(const sys_time<Duration>& st)
1364     : zone_(check(zoned_traits<TimeZonePtr>::default_zone()))
1365     , tp_(st)
1366     {}
1367 
1368 template <class Duration, class TimeZonePtr>
1369 inline
1370 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z)
1371     : zone_(check(std::move(z)))
1372     {}
1373 
1374 #if HAS_STRING_VIEW
1375 
1376 template <class Duration, class TimeZonePtr>
1377 template <class T, class>
1378 inline
1379 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name)
1380     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name))
1381     {}
1382 
1383 #else  // !HAS_STRING_VIEW
1384 
1385 template <class Duration, class TimeZonePtr>
1386 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1387 template <class T, class>
1388 #endif
1389 inline
1390 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name)
1391     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name))
1392     {}
1393 
1394 #endif  // !HAS_STRING_VIEW
1395 
1396 template <class Duration, class TimeZonePtr>
1397 template <class Duration2, class>
1398 inline
1399 zoned_time<Duration, TimeZonePtr>::zoned_time(const zoned_time<Duration2, TimeZonePtr>& zt) NOEXCEPT
1400     : zone_(zt.zone_)
1401     , tp_(zt.tp_)
1402     {}
1403 
1404 template <class Duration, class TimeZonePtr>
1405 inline
1406 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const sys_time<Duration>& st)
1407     : zone_(check(std::move(z)))
1408     , tp_(st)
1409     {}
1410 
1411 template <class Duration, class TimeZonePtr>
1412 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1413 template <class T, class>
1414 #endif
1415 inline
1416 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t)
1417     : zone_(check(std::move(z)))
1418     , tp_(zone_->to_sys(t))
1419     {}
1420 
1421 template <class Duration, class TimeZonePtr>
1422 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1423 template <class T, class>
1424 #endif
1425 inline
1426 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t,
1427                                               choose c)
1428     : zone_(check(std::move(z)))
1429     , tp_(zone_->to_sys(t, c))
1430     {}
1431 
1432 template <class Duration, class TimeZonePtr>
1433 template <class Duration2, class TimeZonePtr2, class>
1434 inline
1435 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z,
1436                                               const zoned_time<Duration2, TimeZonePtr2>& zt)
1437     : zone_(check(std::move(z)))
1438     , tp_(zt.tp_)
1439     {}
1440 
1441 template <class Duration, class TimeZonePtr>
1442 template <class Duration2, class TimeZonePtr2, class>
1443 inline
1444 zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z,
1445                                       const zoned_time<Duration2, TimeZonePtr2>& zt, choose)
1446     : zoned_time(std::move(z), zt)
1447     {}
1448 
1449 #if HAS_STRING_VIEW
1450 
1451 template <class Duration, class TimeZonePtr>
1452 template <class T, class>
1453 inline
1454 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name,
1455                                               detail::nodeduct_t<const sys_time<Duration>&> st)
1456     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), st)
1457     {}
1458 
1459 template <class Duration, class TimeZonePtr>
1460 template <class T, class>
1461 inline
1462 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name,
1463                                               detail::nodeduct_t<const local_time<Duration>&> t)
1464     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t)
1465     {}
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 local_time<Duration>&> t, choose c)
1472     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t, c)
1473     {}
1474 
1475 template <class Duration, class TimeZonePtr>
1476 template <class Duration2, class TimeZonePtr2, class, class>
1477 inline
1478 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name,
1479                                               const zoned_time<Duration2, TimeZonePtr2>& zt)
1480     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt)
1481     {}
1482 
1483 template <class Duration, class TimeZonePtr>
1484 template <class Duration2, class TimeZonePtr2, class, class>
1485 inline
1486 zoned_time<Duration, TimeZonePtr>::zoned_time(std::string_view name,
1487                                               const zoned_time<Duration2, TimeZonePtr2>& zt,
1488                                               choose c)
1489     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt, c)
1490     {}
1491 
1492 #else  // !HAS_STRING_VIEW
1493 
1494 template <class Duration, class TimeZonePtr>
1495 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1496 template <class T, class>
1497 #endif
1498 inline
1499 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1500                                               const sys_time<Duration>& st)
1501     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), st)
1502     {}
1503 
1504 template <class Duration, class TimeZonePtr>
1505 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1506 template <class T, class>
1507 #endif
1508 inline
1509 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1510                                               const sys_time<Duration>& st)
1511     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), st)
1512     {}
1513 
1514 template <class Duration, class TimeZonePtr>
1515 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1516 template <class T, class>
1517 #endif
1518 inline
1519 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1520                                               const local_time<Duration>& t)
1521     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t)
1522     {}
1523 
1524 template <class Duration, class TimeZonePtr>
1525 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1526 template <class T, class>
1527 #endif
1528 inline
1529 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1530                                               const local_time<Duration>& t)
1531     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t)
1532     {}
1533 
1534 template <class Duration, class TimeZonePtr>
1535 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1536 template <class T, class>
1537 #endif
1538 inline
1539 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1540                                               const local_time<Duration>& t, choose c)
1541     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t, c)
1542     {}
1543 
1544 template <class Duration, class TimeZonePtr>
1545 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1546 template <class T, class>
1547 #endif
1548 inline
1549 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1550                                               const local_time<Duration>& t, choose c)
1551     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), t, c)
1552     {}
1553 
1554 template <class Duration, class TimeZonePtr>
1555 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1556 template <class Duration2, class TimeZonePtr2, class, class>
1557 #else
1558 template <class Duration2, class TimeZonePtr2>
1559 #endif
1560 inline
1561 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1562                                               const zoned_time<Duration2, TimeZonePtr2>& zt)
1563     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt)
1564     {}
1565 
1566 template <class Duration, class TimeZonePtr>
1567 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1568 template <class Duration2, class TimeZonePtr2, class, class>
1569 #else
1570 template <class Duration2, class TimeZonePtr2>
1571 #endif
1572 inline
1573 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1574                                               const zoned_time<Duration2, TimeZonePtr2>& zt)
1575     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt)
1576     {}
1577 
1578 template <class Duration, class TimeZonePtr>
1579 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1580 template <class Duration2, class TimeZonePtr2, class, class>
1581 #else
1582 template <class Duration2, class TimeZonePtr2>
1583 #endif
1584 inline
1585 zoned_time<Duration, TimeZonePtr>::zoned_time(const std::string& name,
1586                                               const zoned_time<Duration2, TimeZonePtr2>& zt,
1587                                               choose c)
1588     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt, c)
1589     {}
1590 
1591 template <class Duration, class TimeZonePtr>
1592 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1593 template <class Duration2, class TimeZonePtr2, class, class>
1594 #else
1595 template <class Duration2, class TimeZonePtr2>
1596 #endif
1597 inline
1598 zoned_time<Duration, TimeZonePtr>::zoned_time(const char* name,
1599                                               const zoned_time<Duration2, TimeZonePtr2>& zt,
1600                                               choose c)
1601     : zoned_time(zoned_traits<TimeZonePtr>::locate_zone(name), zt, c)
1602     {}
1603 
1604 #endif  // HAS_STRING_VIEW
1605 
1606 template <class Duration, class TimeZonePtr>
1607 inline
1608 zoned_time<Duration, TimeZonePtr>&
1609 zoned_time<Duration, TimeZonePtr>::operator=(const sys_time<Duration>& st)
1610 {
1611     tp_ = st;
1612     return *this;
1613 }
1614 
1615 template <class Duration, class TimeZonePtr>
1616 inline
1617 zoned_time<Duration, TimeZonePtr>&
1618 zoned_time<Duration, TimeZonePtr>::operator=(const local_time<Duration>& ut)
1619 {
1620     tp_ = zone_->to_sys(ut);
1621     return *this;
1622 }
1623 
1624 template <class Duration, class TimeZonePtr>
1625 inline
1626 zoned_time<Duration, TimeZonePtr>::operator local_time<typename zoned_time<Duration, TimeZonePtr>::duration>() const
1627 {
1628     return get_local_time();
1629 }
1630 
1631 template <class Duration, class TimeZonePtr>
1632 inline
1633 zoned_time<Duration, TimeZonePtr>::operator sys_time<typename zoned_time<Duration, TimeZonePtr>::duration>() const
1634 {
1635     return get_sys_time();
1636 }
1637 
1638 template <class Duration, class TimeZonePtr>
1639 inline
1640 TimeZonePtr
1641 zoned_time<Duration, TimeZonePtr>::get_time_zone() const
1642 {
1643     return zone_;
1644 }
1645 
1646 template <class Duration, class TimeZonePtr>
1647 inline
1648 local_time<typename zoned_time<Duration, TimeZonePtr>::duration>
1649 zoned_time<Duration, TimeZonePtr>::get_local_time() const
1650 {
1651     return zone_->to_local(tp_);
1652 }
1653 
1654 template <class Duration, class TimeZonePtr>
1655 inline
1656 sys_time<typename zoned_time<Duration, TimeZonePtr>::duration>
1657 zoned_time<Duration, TimeZonePtr>::get_sys_time() const
1658 {
1659     return tp_;
1660 }
1661 
1662 template <class Duration, class TimeZonePtr>
1663 inline
1664 sys_info
1665 zoned_time<Duration, TimeZonePtr>::get_info() const
1666 {
1667     return zone_->get_info(tp_);
1668 }
1669 
1670 // make_zoned_time
1671 
1672 inline
1673 zoned_time<std::chrono::seconds>
1674 make_zoned()
1675 {
1676     return zoned_time<std::chrono::seconds>();
1677 }
1678 
1679 template <class Duration>
1680 inline
1681 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1682 make_zoned(const sys_time<Duration>& tp)
1683 {
1684     return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>(tp);
1685 }
1686 
1687 template <class TimeZonePtr
1688 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1689 #if !defined(__INTEL_COMPILER) || (__INTEL_COMPILER > 1600)
1690           , class = typename std::enable_if
1691           <
1692             std::is_class
1693             <
1694                 typename std::decay
1695                 <
1696                     decltype(*detail::to_raw_pointer(std::declval<TimeZonePtr&>()))
1697                 >::type
1698             >{}
1699           >::type
1700 #endif
1701 #endif
1702          >
1703 inline
1704 zoned_time<std::chrono::seconds, TimeZonePtr>
1705 make_zoned(TimeZonePtr z)
1706 {
1707     return zoned_time<std::chrono::seconds, TimeZonePtr>(std::move(z));
1708 }
1709 
1710 inline
1711 zoned_seconds
1712 make_zoned(const std::string& name)
1713 {
1714     return zoned_seconds(name);
1715 }
1716 
1717 template <class Duration, class TimeZonePtr
1718 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1719 #if !defined(__INTEL_COMPILER) || (__INTEL_COMPILER > 1600)
1720           , class = typename std::enable_if
1721           <
1722             std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{}
1723           >::type
1724 #endif
1725 #endif
1726          >
1727 inline
1728 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr>
1729 make_zoned(TimeZonePtr zone, const local_time<Duration>& tp)
1730 {
1731     return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type,
1732                       TimeZonePtr>(std::move(zone), tp);
1733 }
1734 
1735 template <class Duration, class TimeZonePtr
1736 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1737 #if !defined(__INTEL_COMPILER) || (__INTEL_COMPILER > 1600)
1738           , class = typename std::enable_if
1739           <
1740             std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{}
1741           >::type
1742 #endif
1743 #endif
1744          >
1745 inline
1746 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr>
1747 make_zoned(TimeZonePtr zone, const local_time<Duration>& tp, choose c)
1748 {
1749     return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type,
1750                       TimeZonePtr>(std::move(zone), tp, c);
1751 }
1752 
1753 template <class Duration>
1754 inline
1755 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1756 make_zoned(const std::string& name, const local_time<Duration>& tp)
1757 {
1758     return zoned_time<typename std::common_type<Duration,
1759                       std::chrono::seconds>::type>(name, tp);
1760 }
1761 
1762 template <class Duration>
1763 inline
1764 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1765 make_zoned(const std::string& name, const local_time<Duration>& tp, choose c)
1766 {
1767     return zoned_time<typename std::common_type<Duration,
1768                       std::chrono::seconds>::type>(name, tp, c);
1769 }
1770 
1771 template <class Duration, class TimeZonePtr>
1772 inline
1773 zoned_time<Duration, TimeZonePtr>
1774 make_zoned(TimeZonePtr zone, const zoned_time<Duration, TimeZonePtr>& zt)
1775 {
1776     return zoned_time<Duration, TimeZonePtr>(std::move(zone), zt);
1777 }
1778 
1779 template <class Duration, class TimeZonePtr>
1780 inline
1781 zoned_time<Duration, TimeZonePtr>
1782 make_zoned(const std::string& name, const zoned_time<Duration, TimeZonePtr>& zt)
1783 {
1784     return zoned_time<Duration, TimeZonePtr>(name, zt);
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, choose c)
1791 {
1792     return zoned_time<Duration, TimeZonePtr>(std::move(zone), zt, c);
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, choose c)
1799 {
1800     return zoned_time<Duration, TimeZonePtr>(name, zt, c);
1801 }
1802 
1803 template <class Duration, class TimeZonePtr
1804 #if !defined(_MSC_VER) || (_MSC_VER > 1916)
1805 #if !defined(__INTEL_COMPILER) || (__INTEL_COMPILER > 1600)
1806           , class = typename std::enable_if
1807           <
1808             std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{}
1809           >::type
1810 #endif
1811 #endif
1812          >
1813 inline
1814 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type, TimeZonePtr>
1815 make_zoned(TimeZonePtr zone, const sys_time<Duration>& st)
1816 {
1817     return zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type,
1818                       TimeZonePtr>(std::move(zone), st);
1819 }
1820 
1821 template <class Duration>
1822 inline
1823 zoned_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1824 make_zoned(const std::string& name, const sys_time<Duration>& st)
1825 {
1826     return zoned_time<typename std::common_type<Duration,
1827                       std::chrono::seconds>::type>(name, st);
1828 }
1829 
1830 template <class CharT, class Traits, class Duration, class TimeZonePtr>
1831 std::basic_ostream<CharT, Traits>&
1832 to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
1833           const zoned_time<Duration, TimeZonePtr>& tp)
1834 {
1835     using duration = typename zoned_time<Duration, TimeZonePtr>::duration;
1836     using LT = local_time<duration>;
1837     auto const st = tp.get_sys_time();
1838     auto const info = tp.get_time_zone()->get_info(st);
1839     return to_stream(os, fmt, LT{(st+info.offset).time_since_epoch()},
1840                      &info.abbrev, &info.offset);
1841 }
1842 
1843 template <class CharT, class Traits, class Duration, class TimeZonePtr>
1844 inline
1845 std::basic_ostream<CharT, Traits>&
1846 operator<<(std::basic_ostream<CharT, Traits>& os, const zoned_time<Duration, TimeZonePtr>& t)
1847 {
1848     const CharT fmt[] = {'%', 'F', ' ', '%', 'T', ' ', '%', 'Z', CharT{}};
1849     return to_stream(os, fmt, t);
1850 }
1851 
1852 class utc_clock
1853 {
1854 public:
1855     using duration                  = std::chrono::system_clock::duration;
1856     using rep                       = duration::rep;
1857     using period                    = duration::period;
1858     using time_point                = std::chrono::time_point<utc_clock>;
1859     static CONSTDATA bool is_steady = false;
1860 
1861     static time_point now();
1862 
1863     template<typename Duration>
1864     static
1865     std::chrono::time_point<std::chrono::system_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
1866     to_sys(const std::chrono::time_point<utc_clock, Duration>&);
1867 
1868     template<typename Duration>
1869     static
1870     std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
1871     from_sys(const std::chrono::time_point<std::chrono::system_clock, Duration>&);
1872 
1873     template<typename Duration>
1874     static
1875     std::chrono::time_point<local_t, typename std::common_type<Duration, std::chrono::seconds>::type>
1876     to_local(const std::chrono::time_point<utc_clock, Duration>&);
1877 
1878     template<typename Duration>
1879     static
1880     std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
1881     from_local(const std::chrono::time_point<local_t, Duration>&);
1882 };
1883 
1884 template <class Duration>
1885     using utc_time = std::chrono::time_point<utc_clock, Duration>;
1886 
1887 using utc_seconds = utc_time<std::chrono::seconds>;
1888 
1889 template <class Duration>
1890 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1891 utc_clock::from_sys(const sys_time<Duration>& st)
1892 {
1893     using std::chrono::seconds;
1894     using CD = typename std::common_type<Duration, seconds>::type;
1895     auto const& leaps = get_tzdb().leap_seconds;
1896     auto const lt = std::upper_bound(leaps.begin(), leaps.end(), st);
1897     return utc_time<CD>{st.time_since_epoch() + seconds{lt-leaps.begin()}};
1898 }
1899 
1900 // Return pair<is_leap_second, seconds{number_of_leap_seconds_since_1970}>
1901 // first is true if ut is during a leap second insertion, otherwise false.
1902 // If ut is during a leap second insertion, that leap second is included in the count
1903 template <class Duration>
1904 std::pair<bool, std::chrono::seconds>
1905 is_leap_second(date::utc_time<Duration> const& ut)
1906 {
1907     using std::chrono::seconds;
1908     using duration = typename std::common_type<Duration, seconds>::type;
1909     auto const& leaps = get_tzdb().leap_seconds;
1910     auto tp = sys_time<duration>{ut.time_since_epoch()};
1911     auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp);
1912     auto ds = seconds{lt-leaps.begin()};
1913     tp -= ds;
1914     auto ls = false;
1915     if (lt > leaps.begin())
1916     {
1917         if (tp < lt[-1])
1918         {
1919             if (tp >= lt[-1].date() - seconds{1})
1920                 ls = true;
1921             else
1922                 --ds;
1923         }
1924     }
1925     return {ls, ds};
1926 }
1927 
1928 struct leap_second_info
1929 {
1930     bool is_leap_second;
1931     std::chrono::seconds elapsed;
1932 };
1933 
1934 template <class Duration>
1935 leap_second_info
1936 get_leap_second_info(date::utc_time<Duration> const& ut)
1937 {
1938     auto p = is_leap_second(ut);
1939     return {p.first, p.second};
1940 }
1941 
1942 template <class Duration>
1943 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1944 utc_clock::to_sys(const utc_time<Duration>& ut)
1945 {
1946     using std::chrono::seconds;
1947     using CD = typename std::common_type<Duration, seconds>::type;
1948     auto ls = is_leap_second(ut);
1949     auto tp = sys_time<CD>{ut.time_since_epoch() - ls.second};
1950     if (ls.first)
1951         tp = floor<seconds>(tp) + seconds{1} - CD{1};
1952     return tp;
1953 }
1954 
1955 inline
1956 utc_clock::time_point
1957 utc_clock::now()
1958 {
1959     return from_sys(std::chrono::system_clock::now());
1960 }
1961 
1962 template <class Duration>
1963 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1964 utc_clock::from_local(const local_time<Duration>& st)
1965 {
1966     return from_sys(sys_time<Duration>{st.time_since_epoch()});
1967 }
1968 
1969 template <class Duration>
1970 local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
1971 utc_clock::to_local(const utc_time<Duration>& ut)
1972 {
1973     using CD = typename std::common_type<Duration, std::chrono::seconds>::type;
1974     return local_time<CD>{to_sys(ut).time_since_epoch()};
1975 }
1976 
1977 template <class CharT, class Traits, class Duration>
1978 std::basic_ostream<CharT, Traits>&
1979 to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
1980           const utc_time<Duration>& t)
1981 {
1982     using std::chrono::seconds;
1983     using CT = typename std::common_type<Duration, seconds>::type;
1984     const std::string abbrev("UTC");
1985     CONSTDATA seconds offset{0};
1986     auto ls = is_leap_second(t);
1987     auto tp = sys_time<CT>{t.time_since_epoch() - ls.second};
1988     auto const sd = floor<days>(tp);
1989     year_month_day ymd = sd;
1990     auto time = make_time(tp - sys_seconds{sd});
1991     time.seconds(detail::undocumented{}) += seconds{ls.first};
1992     fields<CT> fds{ymd, time};
1993     return to_stream(os, fmt, fds, &abbrev, &offset);
1994 }
1995 
1996 template <class CharT, class Traits, class Duration>
1997 std::basic_ostream<CharT, Traits>&
1998 operator<<(std::basic_ostream<CharT, Traits>& os, const utc_time<Duration>& t)
1999 {
2000     const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}};
2001     return to_stream(os, fmt, t);
2002 }
2003 
2004 template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
2005 std::basic_istream<CharT, Traits>&
2006 from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
2007             utc_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
2008             std::chrono::minutes* offset = nullptr)
2009 {
2010     using std::chrono::seconds;
2011     using std::chrono::minutes;
2012     using CT = typename std::common_type<Duration, seconds>::type;
2013     minutes offset_local{};
2014     auto offptr = offset ? offset : &offset_local;
2015     fields<CT> fds{};
2016     fds.has_tod = true;
2017     from_stream(is, fmt, fds, abbrev, offptr);
2018     if (!fds.ymd.ok())
2019         is.setstate(std::ios::failbit);
2020     if (!is.fail())
2021     {
2022         bool is_60_sec = fds.tod.seconds() == seconds{60};
2023         if (is_60_sec)
2024             fds.tod.seconds(detail::undocumented{}) -= seconds{1};
2025         auto tmp = utc_clock::from_sys(sys_days(fds.ymd) - *offptr + fds.tod.to_duration());
2026         if (is_60_sec)
2027             tmp += seconds{1};
2028         if (is_60_sec != is_leap_second(tmp).first || !fds.tod.in_conventional_range())
2029         {
2030             is.setstate(std::ios::failbit);
2031             return is;
2032         }
2033         tp = std::chrono::time_point_cast<Duration>(tmp);
2034     }
2035     return is;
2036 }
2037 
2038 // tai_clock
2039 
2040 class tai_clock
2041 {
2042 public:
2043     using duration                  = std::chrono::system_clock::duration;
2044     using rep                       = duration::rep;
2045     using period                    = duration::period;
2046     using time_point                = std::chrono::time_point<tai_clock>;
2047     static const bool is_steady     = false;
2048 
2049     static time_point now();
2050 
2051     template<typename Duration>
2052     static
2053     std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
2054     to_utc(const std::chrono::time_point<tai_clock, Duration>&) NOEXCEPT;
2055 
2056     template<typename Duration>
2057     static
2058     std::chrono::time_point<tai_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
2059     from_utc(const std::chrono::time_point<utc_clock, Duration>&) NOEXCEPT;
2060 
2061     template<typename Duration>
2062     static
2063     std::chrono::time_point<local_t, typename std::common_type<Duration, date::days>::type>
2064     to_local(const std::chrono::time_point<tai_clock, Duration>&) NOEXCEPT;
2065 
2066     template<typename Duration>
2067     static
2068     std::chrono::time_point<tai_clock, typename std::common_type<Duration, date::days>::type>
2069     from_local(const std::chrono::time_point<local_t, Duration>&) NOEXCEPT;
2070 };
2071 
2072 template <class Duration>
2073     using tai_time = std::chrono::time_point<tai_clock, Duration>;
2074 
2075 using tai_seconds = tai_time<std::chrono::seconds>;
2076 
2077 template <class Duration>
2078 inline
2079 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2080 tai_clock::to_utc(const tai_time<Duration>& t) NOEXCEPT
2081 {
2082     using std::chrono::seconds;
2083     using CD = typename std::common_type<Duration, seconds>::type;
2084     return utc_time<CD>{t.time_since_epoch()} -
2085             (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10});
2086 }
2087 
2088 template <class Duration>
2089 inline
2090 tai_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2091 tai_clock::from_utc(const utc_time<Duration>& t) NOEXCEPT
2092 {
2093     using std::chrono::seconds;
2094     using CD = typename std::common_type<Duration, seconds>::type;
2095     return tai_time<CD>{t.time_since_epoch()} +
2096             (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10});
2097 }
2098 
2099 inline
2100 tai_clock::time_point
2101 tai_clock::now()
2102 {
2103     return from_utc(utc_clock::now());
2104 }
2105 
2106 template <class Duration>
2107 inline
2108 local_time<typename std::common_type<Duration, date::days>::type>
2109 tai_clock::to_local(const tai_time<Duration>& t) NOEXCEPT
2110 {
2111     using CD = typename std::common_type<Duration, date::days>::type;
2112     return local_time<CD>{t.time_since_epoch()} -
2113            (local_days(year{1970}/January/1) - local_days(year{1958}/January/1));
2114 }
2115 
2116 template <class Duration>
2117 inline
2118 tai_time<typename std::common_type<Duration, date::days>::type>
2119 tai_clock::from_local(const local_time<Duration>& t) NOEXCEPT
2120 {
2121     using CD = typename std::common_type<Duration, date::days>::type;
2122     return tai_time<CD>{t.time_since_epoch()} +
2123             (local_days(year{1970}/January/1) - local_days(year{1958}/January/1));
2124 }
2125 
2126 template <class CharT, class Traits, class Duration>
2127 std::basic_ostream<CharT, Traits>&
2128 to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
2129           const tai_time<Duration>& t)
2130 {
2131     const std::string abbrev("TAI");
2132     CONSTDATA std::chrono::seconds offset{0};
2133     return to_stream(os, fmt, tai_clock::to_local(t), &abbrev, &offset);
2134 }
2135 
2136 template <class CharT, class Traits, class Duration>
2137 std::basic_ostream<CharT, Traits>&
2138 operator<<(std::basic_ostream<CharT, Traits>& os, const tai_time<Duration>& t)
2139 {
2140     const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}};
2141     return to_stream(os, fmt, t);
2142 }
2143 
2144 template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
2145 std::basic_istream<CharT, Traits>&
2146 from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
2147             tai_time<Duration>& tp,
2148             std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
2149             std::chrono::minutes* offset = nullptr)
2150 {
2151     local_time<Duration> lp;
2152     from_stream(is, fmt, lp, abbrev, offset);
2153     if (!is.fail())
2154         tp = tai_clock::from_local(lp);
2155     return is;
2156 }
2157 
2158 // gps_clock
2159 
2160 class gps_clock
2161 {
2162 public:
2163     using duration                  = std::chrono::system_clock::duration;
2164     using rep                       = duration::rep;
2165     using period                    = duration::period;
2166     using time_point                = std::chrono::time_point<gps_clock>;
2167     static const bool is_steady     = false;
2168 
2169     static time_point now();
2170 
2171     template<typename Duration>
2172     static
2173     std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
2174     to_utc(const std::chrono::time_point<gps_clock, Duration>&) NOEXCEPT;
2175 
2176     template<typename Duration>
2177     static
2178     std::chrono::time_point<gps_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
2179     from_utc(const std::chrono::time_point<utc_clock, Duration>&) NOEXCEPT;
2180 
2181     template<typename Duration>
2182     static
2183     std::chrono::time_point<local_t, typename std::common_type<Duration, date::days>::type>
2184     to_local(const std::chrono::time_point<gps_clock, Duration>&) NOEXCEPT;
2185 
2186     template<typename Duration>
2187     static
2188     std::chrono::time_point<gps_clock, typename std::common_type<Duration, date::days>::type>
2189     from_local(const std::chrono::time_point<local_t, Duration>&) NOEXCEPT;
2190 };
2191 
2192 template <class Duration>
2193     using gps_time = std::chrono::time_point<gps_clock, Duration>;
2194 
2195 using gps_seconds = gps_time<std::chrono::seconds>;
2196 
2197 template <class Duration>
2198 inline
2199 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2200 gps_clock::to_utc(const gps_time<Duration>& t) NOEXCEPT
2201 {
2202     using std::chrono::seconds;
2203     using CD = typename std::common_type<Duration, seconds>::type;
2204     return utc_time<CD>{t.time_since_epoch()} +
2205             (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1970}/January/1) +
2206              seconds{9});
2207 }
2208 
2209 template <class Duration>
2210 inline
2211 gps_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2212 gps_clock::from_utc(const utc_time<Duration>& t) NOEXCEPT
2213 {
2214     using std::chrono::seconds;
2215     using CD = typename std::common_type<Duration, seconds>::type;
2216     return gps_time<CD>{t.time_since_epoch()} -
2217             (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1970}/January/1) +
2218              seconds{9});
2219 }
2220 
2221 inline
2222 gps_clock::time_point
2223 gps_clock::now()
2224 {
2225     return from_utc(utc_clock::now());
2226 }
2227 
2228 template <class Duration>
2229 inline
2230 local_time<typename std::common_type<Duration, date::days>::type>
2231 gps_clock::to_local(const gps_time<Duration>& t) NOEXCEPT
2232 {
2233     using CD = typename std::common_type<Duration, date::days>::type;
2234     return local_time<CD>{t.time_since_epoch()} +
2235             (local_days(year{1980}/January/Sunday[1]) - local_days(year{1970}/January/1));
2236 }
2237 
2238 template <class Duration>
2239 inline
2240 gps_time<typename std::common_type<Duration, date::days>::type>
2241 gps_clock::from_local(const local_time<Duration>& t) NOEXCEPT
2242 {
2243     using CD = typename std::common_type<Duration, date::days>::type;
2244     return gps_time<CD>{t.time_since_epoch()} -
2245             (local_days(year{1980}/January/Sunday[1]) - local_days(year{1970}/January/1));
2246 }
2247 
2248 
2249 template <class CharT, class Traits, class Duration>
2250 std::basic_ostream<CharT, Traits>&
2251 to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
2252           const gps_time<Duration>& t)
2253 {
2254     const std::string abbrev("GPS");
2255     CONSTDATA std::chrono::seconds offset{0};
2256     return to_stream(os, fmt, gps_clock::to_local(t), &abbrev, &offset);
2257 }
2258 
2259 template <class CharT, class Traits, class Duration>
2260 std::basic_ostream<CharT, Traits>&
2261 operator<<(std::basic_ostream<CharT, Traits>& os, const gps_time<Duration>& t)
2262 {
2263     const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}};
2264     return to_stream(os, fmt, t);
2265 }
2266 
2267 template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
2268 std::basic_istream<CharT, Traits>&
2269 from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
2270             gps_time<Duration>& tp,
2271             std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
2272             std::chrono::minutes* offset = nullptr)
2273 {
2274     local_time<Duration> lp;
2275     from_stream(is, fmt, lp, abbrev, offset);
2276     if (!is.fail())
2277         tp = gps_clock::from_local(lp);
2278     return is;
2279 }
2280 
2281 // clock_time_conversion
2282 
2283 template <class DstClock, class SrcClock>
2284 struct clock_time_conversion
2285 {};
2286 
2287 template <>
2288 struct clock_time_conversion<std::chrono::system_clock, std::chrono::system_clock>
2289 {
2290     template <class Duration>
2291     CONSTCD14
2292     sys_time<Duration>
2293     operator()(const sys_time<Duration>& st) const
2294     {
2295         return st;
2296     }
2297 };
2298 
2299 template <>
2300 struct clock_time_conversion<utc_clock, utc_clock>
2301 {
2302     template <class Duration>
2303     CONSTCD14
2304     utc_time<Duration>
2305     operator()(const utc_time<Duration>& ut) const
2306     {
2307         return ut;
2308     }
2309 };
2310 
2311 template<>
2312 struct clock_time_conversion<local_t, local_t>
2313 {
2314     template <class Duration>
2315     CONSTCD14
2316     local_time<Duration>
2317     operator()(const local_time<Duration>& lt) const
2318     {
2319         return lt;
2320     }
2321 };
2322 
2323 template <>
2324 struct clock_time_conversion<utc_clock, std::chrono::system_clock>
2325 {
2326     template <class Duration>
2327     utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2328     operator()(const sys_time<Duration>& st) const
2329     {
2330         return utc_clock::from_sys(st);
2331     }
2332 };
2333 
2334 template <>
2335 struct clock_time_conversion<std::chrono::system_clock, utc_clock>
2336 {
2337     template <class Duration>
2338     sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2339     operator()(const utc_time<Duration>& ut) const
2340     {
2341         return utc_clock::to_sys(ut);
2342     }
2343 };
2344 
2345 template<>
2346 struct clock_time_conversion<local_t, std::chrono::system_clock>
2347 {
2348     template <class Duration>
2349     CONSTCD14
2350     local_time<Duration>
2351     operator()(const sys_time<Duration>& st) const
2352     {
2353        return local_time<Duration>{st.time_since_epoch()};
2354     }
2355 };
2356 
2357 template<>
2358 struct clock_time_conversion<std::chrono::system_clock, local_t>
2359 {
2360     template <class Duration>
2361     CONSTCD14
2362     sys_time<Duration>
2363     operator()(const local_time<Duration>& lt) const
2364     {
2365         return sys_time<Duration>{lt.time_since_epoch()};
2366     }
2367 };
2368 
2369 template<>
2370 struct clock_time_conversion<utc_clock, local_t>
2371 {
2372     template <class Duration>
2373     utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2374     operator()(const local_time<Duration>& lt) const
2375     {
2376        return utc_clock::from_local(lt);
2377     }
2378 };
2379 
2380 template<>
2381 struct clock_time_conversion<local_t, utc_clock>
2382 {
2383     template <class Duration>
2384     local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2385     operator()(const utc_time<Duration>& ut) const
2386     {
2387        return utc_clock::to_local(ut);
2388     }
2389 };
2390 
2391 template<typename Clock>
2392 struct clock_time_conversion<Clock, Clock>
2393 {
2394     template <class Duration>
2395     CONSTCD14
2396     std::chrono::time_point<Clock, Duration>
2397     operator()(const std::chrono::time_point<Clock, Duration>& tp) const
2398     {
2399         return tp;
2400     }
2401 };
2402 
2403 namespace ctc_detail
2404 {
2405 
2406 template <class Clock, class Duration>
2407     using time_point = std::chrono::time_point<Clock, Duration>;
2408 
2409 using std::declval;
2410 using std::chrono::system_clock;
2411 
2412 //Check if TimePoint is time for given clock,
2413 //if not emits hard error
2414 template <class Clock, class TimePoint>
2415 struct return_clock_time
2416 {
2417     using clock_time_point = time_point<Clock, typename TimePoint::duration>;
2418     using type             = TimePoint;
2419 
2420     static_assert(std::is_same<TimePoint, clock_time_point>::value,
2421                   "time point with appropariate clock shall be returned");
2422 };
2423 
2424 // Check if Clock has to_sys method accepting TimePoint with given duration const& and
2425 // returning sys_time. If so has nested type member equal to return type to_sys.
2426 template <class Clock, class Duration, class = void>
2427 struct return_to_sys
2428 {};
2429 
2430 template <class Clock, class Duration>
2431 struct return_to_sys
2432        <
2433            Clock, Duration,
2434            decltype(Clock::to_sys(declval<time_point<Clock, Duration> const&>()), void())
2435        >
2436     : return_clock_time
2437       <
2438           system_clock,
2439           decltype(Clock::to_sys(declval<time_point<Clock, Duration> const&>()))
2440       >
2441 {};
2442 
2443 // Similiar to above
2444 template <class Clock, class Duration, class = void>
2445 struct return_from_sys
2446 {};
2447 
2448 template <class Clock, class Duration>
2449 struct return_from_sys
2450        <
2451            Clock, Duration,
2452            decltype(Clock::from_sys(declval<time_point<system_clock, Duration> const&>()),
2453                     void())
2454        >
2455     : return_clock_time
2456       <
2457           Clock,
2458           decltype(Clock::from_sys(declval<time_point<system_clock, Duration> const&>()))
2459       >
2460 {};
2461 
2462 // Similiar to above
2463 template <class Clock, class Duration, class = void>
2464 struct return_to_utc
2465 {};
2466 
2467 template <class Clock, class Duration>
2468 struct return_to_utc
2469        <
2470            Clock, Duration,
2471            decltype(Clock::to_utc(declval<time_point<Clock, Duration> const&>()), void())
2472        >
2473     : return_clock_time
2474       <
2475           utc_clock,
2476           decltype(Clock::to_utc(declval<time_point<Clock, Duration> const&>()))>
2477 {};
2478 
2479 // Similiar to above
2480 template <class Clock, class Duration, class = void>
2481 struct return_from_utc
2482 {};
2483 
2484 template <class Clock, class Duration>
2485 struct return_from_utc
2486        <
2487            Clock, Duration,
2488            decltype(Clock::from_utc(declval<time_point<utc_clock, Duration> const&>()),
2489                     void())
2490        >
2491     : return_clock_time
2492       <
2493           Clock,
2494           decltype(Clock::from_utc(declval<time_point<utc_clock, Duration> const&>()))
2495       >
2496 {};
2497 
2498 // Similiar to above
2499 template<typename Clock, typename Duration, typename = void>
2500 struct return_to_local
2501 {};
2502 
2503 template<typename Clock, typename Duration>
2504 struct return_to_local
2505        <
2506           Clock, Duration,
2507           decltype(Clock::to_local(declval<time_point<Clock, Duration> const&>()),
2508                    void())
2509        >
2510      : return_clock_time
2511        <
2512            local_t,
2513            decltype(Clock::to_local(declval<time_point<Clock, Duration> const&>()))
2514        >
2515 {};
2516 
2517 // Similiar to above
2518 template<typename Clock, typename Duration, typename = void>
2519 struct return_from_local
2520 {};
2521 
2522 template<typename Clock, typename Duration>
2523 struct return_from_local
2524        <
2525            Clock, Duration,
2526            decltype(Clock::from_local(declval<time_point<local_t, Duration> const&>()),
2527                     void())
2528        >
2529      : return_clock_time
2530        <
2531            Clock,
2532            decltype(Clock::from_local(declval<time_point<local_t, Duration> const&>()))
2533        >
2534 {};
2535 
2536 }  // namespace ctc_detail
2537 
2538 template <class SrcClock>
2539 struct clock_time_conversion<std::chrono::system_clock, SrcClock>
2540 {
2541     template <class Duration>
2542     CONSTCD14
2543     typename ctc_detail::return_to_sys<SrcClock, Duration>::type
2544     operator()(const std::chrono::time_point<SrcClock, Duration>& tp) const
2545     {
2546         return SrcClock::to_sys(tp);
2547     }
2548 };
2549 
2550 template <class DstClock>
2551 struct clock_time_conversion<DstClock, std::chrono::system_clock>
2552 {
2553     template <class Duration>
2554     CONSTCD14
2555     typename ctc_detail::return_from_sys<DstClock, Duration>::type
2556     operator()(const sys_time<Duration>& st) const
2557     {
2558         return DstClock::from_sys(st);
2559     }
2560 };
2561 
2562 template <class SrcClock>
2563 struct clock_time_conversion<utc_clock, SrcClock>
2564 {
2565     template <class Duration>
2566     CONSTCD14
2567     typename ctc_detail::return_to_utc<SrcClock, Duration>::type
2568     operator()(const std::chrono::time_point<SrcClock, Duration>& tp) const
2569     {
2570         return SrcClock::to_utc(tp);
2571     }
2572 };
2573 
2574 template <class DstClock>
2575 struct clock_time_conversion<DstClock, utc_clock>
2576 {
2577     template <class Duration>
2578     CONSTCD14
2579     typename ctc_detail::return_from_utc<DstClock, Duration>::type
2580     operator()(const utc_time<Duration>& ut) const
2581     {
2582         return DstClock::from_utc(ut);
2583     }
2584 };
2585 
2586 template<typename SrcClock>
2587 struct clock_time_conversion<local_t, SrcClock>
2588 {
2589     template <class Duration>
2590     CONSTCD14
2591     typename ctc_detail::return_to_local<SrcClock, Duration>::type
2592     operator()(const std::chrono::time_point<SrcClock, Duration>& tp) const
2593     {
2594         return SrcClock::to_local(tp);
2595     }
2596 };
2597 
2598 template<typename DstClock>
2599 struct clock_time_conversion<DstClock, local_t>
2600 {
2601     template <class Duration>
2602     CONSTCD14
2603     typename ctc_detail::return_from_local<DstClock, Duration>::type
2604     operator()(const local_time<Duration>& lt) const
2605     {
2606         return DstClock::from_local(lt);
2607     }
2608 };
2609 
2610 namespace clock_cast_detail
2611 {
2612 
2613 template <class Clock, class Duration>
2614     using time_point = std::chrono::time_point<Clock, Duration>;
2615 using std::chrono::system_clock;
2616 
2617 template <class DstClock, class SrcClock, class Duration>
2618 CONSTCD14
2619 auto
2620 conv_clock(const time_point<SrcClock, Duration>& t)
2621     -> decltype(std::declval<clock_time_conversion<DstClock, SrcClock>>()(t))
2622 {
2623     return clock_time_conversion<DstClock, SrcClock>{}(t);
2624 }
2625 
2626 //direct trait conversion, 1st candidate
2627 template <class DstClock, class SrcClock, class Duration>
2628 CONSTCD14
2629 auto
2630 cc_impl(const time_point<SrcClock, Duration>& t, const time_point<SrcClock, Duration>*)
2631     -> decltype(conv_clock<DstClock>(t))
2632 {
2633     return conv_clock<DstClock>(t);
2634 }
2635 
2636 //conversion through sys, 2nd candidate
2637 template <class DstClock, class SrcClock, class Duration>
2638 CONSTCD14
2639 auto
2640 cc_impl(const time_point<SrcClock, Duration>& t, const void*)
2641     -> decltype(conv_clock<DstClock>(conv_clock<system_clock>(t)))
2642 {
2643     return conv_clock<DstClock>(conv_clock<system_clock>(t));
2644 }
2645 
2646 //conversion through utc, 2nd candidate
2647 template <class DstClock, class SrcClock, class Duration>
2648 CONSTCD14
2649 auto
2650 cc_impl(const time_point<SrcClock, Duration>& t, const void*)
2651     -> decltype(0,  // MSVC_WORKAROUND
2652                 conv_clock<DstClock>(conv_clock<utc_clock>(t)))
2653 {
2654     return conv_clock<DstClock>(conv_clock<utc_clock>(t));
2655 }
2656 
2657 //conversion through sys and utc, 3rd candidate
2658 template <class DstClock, class SrcClock, class Duration>
2659 CONSTCD14
2660 auto
2661 cc_impl(const time_point<SrcClock, Duration>& t, ...)
2662     -> decltype(conv_clock<DstClock>(conv_clock<utc_clock>(conv_clock<system_clock>(t))))
2663 {
2664     return conv_clock<DstClock>(conv_clock<utc_clock>(conv_clock<system_clock>(t)));
2665 }
2666 
2667 //conversion through utc and sys, 3rd candidate
2668 template <class DstClock, class SrcClock, class Duration>
2669 CONSTCD14
2670 auto
2671 cc_impl(const time_point<SrcClock, Duration>& t, ...)
2672     -> decltype(0,  // MSVC_WORKAROUND
2673                 conv_clock<DstClock>(conv_clock<system_clock>(conv_clock<utc_clock>(t))))
2674 {
2675     return conv_clock<DstClock>(conv_clock<system_clock>(conv_clock<utc_clock>(t)));
2676 }
2677 
2678 }  // namespace clock_cast_detail
2679 
2680 template <class DstClock, class SrcClock, class Duration>
2681 CONSTCD14
2682 auto
2683 clock_cast(const std::chrono::time_point<SrcClock, Duration>& tp)
2684     -> decltype(clock_cast_detail::cc_impl<DstClock>(tp, &tp))
2685 {
2686     return clock_cast_detail::cc_impl<DstClock>(tp, &tp);
2687 }
2688 
2689 // Deprecated API
2690 
2691 template <class Duration>
2692 inline
2693 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2694 to_sys_time(const utc_time<Duration>& t)
2695 {
2696     return utc_clock::to_sys(t);
2697 }
2698 
2699 template <class Duration>
2700 inline
2701 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2702 to_sys_time(const tai_time<Duration>& t)
2703 {
2704     return utc_clock::to_sys(tai_clock::to_utc(t));
2705 }
2706 
2707 template <class Duration>
2708 inline
2709 sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2710 to_sys_time(const gps_time<Duration>& t)
2711 {
2712     return utc_clock::to_sys(gps_clock::to_utc(t));
2713 }
2714 
2715 
2716 template <class Duration>
2717 inline
2718 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2719 to_utc_time(const sys_time<Duration>& t)
2720 {
2721     return utc_clock::from_sys(t);
2722 }
2723 
2724 template <class Duration>
2725 inline
2726 utc_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2727 to_utc_time(const tai_time<Duration>& t)
2728 {
2729     return tai_clock::to_utc(t);
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 gps_time<Duration>& t)
2736 {
2737     return gps_clock::to_utc(t);
2738 }
2739 
2740 
2741 template <class Duration>
2742 inline
2743 tai_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2744 to_tai_time(const sys_time<Duration>& t)
2745 {
2746     return tai_clock::from_utc(utc_clock::from_sys(t));
2747 }
2748 
2749 template <class Duration>
2750 inline
2751 tai_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2752 to_tai_time(const utc_time<Duration>& t)
2753 {
2754     return tai_clock::from_utc(t);
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 gps_time<Duration>& t)
2761 {
2762     return tai_clock::from_utc(gps_clock::to_utc(t));
2763 }
2764 
2765 
2766 template <class Duration>
2767 inline
2768 gps_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2769 to_gps_time(const sys_time<Duration>& t)
2770 {
2771     return gps_clock::from_utc(utc_clock::from_sys(t));
2772 }
2773 
2774 template <class Duration>
2775 inline
2776 gps_time<typename std::common_type<Duration, std::chrono::seconds>::type>
2777 to_gps_time(const utc_time<Duration>& t)
2778 {
2779     return gps_clock::from_utc(t);
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 tai_time<Duration>& t)
2786 {
2787     return gps_clock::from_utc(tai_clock::to_utc(t));
2788 }
2789 
2790 }  // namespace date
2791 
2792 #endif  // TZ_H
2793