comparison common/date/tz.h @ 0:a4671277546c tip

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