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