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