229 lines · c
1// -*- C++ -*-2//===----------------------------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html11 12#ifndef _LIBCPP___CHRONO_ZONED_TIME_H13#define _LIBCPP___CHRONO_ZONED_TIME_H14 15#include <version>16// Enable the contents of the header only when libc++ was built with experimental features enabled.17#if _LIBCPP_HAS_EXPERIMENTAL_TZDB18 19# include <__chrono/calendar.h>20# include <__chrono/duration.h>21# include <__chrono/sys_info.h>22# include <__chrono/system_clock.h>23# include <__chrono/time_zone.h>24# include <__chrono/tzdb_list.h>25# include <__concepts/constructible.h>26# include <__config>27# include <__type_traits/common_type.h>28# include <__type_traits/conditional.h>29# include <__type_traits/remove_cvref.h>30# include <__utility/declval.h>31# include <__utility/move.h>32# include <string_view>33 34# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)35# pragma GCC system_header36# endif37 38_LIBCPP_PUSH_MACROS39# include <__undef_macros>40 41_LIBCPP_BEGIN_NAMESPACE_STD42 43# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION44 45namespace chrono {46 47template <class>48struct zoned_traits {};49 50template <>51struct zoned_traits<const time_zone*> {52 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static const time_zone* default_zone() { return chrono::locate_zone("UTC"); }53 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static const time_zone* locate_zone(string_view __name) {54 return chrono::locate_zone(__name);55 }56};57 58template <class _Duration, class _TimeZonePtr = const time_zone*>59class zoned_time {60 // [time.zone.zonedtime.ctor]/261 static_assert(__is_duration_v<_Duration>,62 "the program is ill-formed since _Duration is not a specialization of std::chrono::duration");63 64 // The wording uses the constraints like65 // constructible_from<zoned_time, decltype(__traits::locate_zone(string_view{}))>66 // Using these constraints in the code causes the compiler to give an67 // error that the constraint depends on itself. To avoid that issue use68 // the fact it is possible to create this object from a _TimeZonePtr.69 using __traits _LIBCPP_NODEBUG = zoned_traits<_TimeZonePtr>;70 71public:72 using duration = common_type_t<_Duration, seconds>;73 74 _LIBCPP_HIDE_FROM_ABI zoned_time()75 requires requires { __traits::default_zone(); }76 : __zone_{__traits::default_zone()}, __tp_{} {}77 78 _LIBCPP_HIDE_FROM_ABI zoned_time(const zoned_time&) = default;79 _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const zoned_time&) = default;80 81 _LIBCPP_HIDE_FROM_ABI zoned_time(const sys_time<_Duration>& __tp)82 requires requires { __traits::default_zone(); }83 : __zone_{__traits::default_zone()}, __tp_{__tp} {}84 85 _LIBCPP_HIDE_FROM_ABI explicit zoned_time(_TimeZonePtr __zone) : __zone_{std::move(__zone)}, __tp_{} {}86 87 _LIBCPP_HIDE_FROM_ABI explicit zoned_time(string_view __name)88 requires(requires { __traits::locate_zone(string_view{}); } &&89 constructible_from<_TimeZonePtr, decltype(__traits::locate_zone(string_view{}))>)90 : __zone_{__traits::locate_zone(__name)}, __tp_{} {}91 92 template <class _Duration2>93 _LIBCPP_HIDE_FROM_ABI zoned_time(const zoned_time<_Duration2, _TimeZonePtr>& __zt)94 requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>95 : __zone_{__zt.get_time_zone()}, __tp_{__zt.get_sys_time()} {}96 97 _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const sys_time<_Duration>& __tp)98 : __zone_{std::move(__zone)}, __tp_{__tp} {}99 100 _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const sys_time<_Duration>& __tp)101 requires requires { _TimeZonePtr{__traits::locate_zone(string_view{})}; }102 : zoned_time{__traits::locate_zone(__name), __tp} {}103 104 _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const local_time<_Duration>& __tp)105 requires(is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{})),106 sys_time<duration>>)107 : __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp)} {}108 109 _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp)110 requires(requires {111 _TimeZonePtr{__traits::locate_zone(string_view{})};112 } && is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{})),113 sys_time<duration>>)114 : zoned_time{__traits::locate_zone(__name), __tp} {}115 116 _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const local_time<_Duration>& __tp, choose __c)117 requires(is_convertible_v<118 decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{}, choose::earliest)),119 sys_time<duration>>)120 : __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp, __c)} {}121 122 _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp, choose __c)123 requires(requires {124 _TimeZonePtr{__traits::locate_zone(string_view{})};125 } && is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{}, choose::earliest)),126 sys_time<duration>>)127 : zoned_time{__traits::locate_zone(__name), __tp, __c} {}128 129 template <class _Duration2, class _TimeZonePtr2>130 _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const zoned_time<_Duration2, _TimeZonePtr2>& __zt)131 requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>132 : __zone_{std::move(__zone)}, __tp_{__zt.get_sys_time()} {}133 134 // per wording choose has no effect135 template <class _Duration2, class _TimeZonePtr2>136 _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, choose)137 requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>138 : __zone_{std::move(__zone)}, __tp_{__zt.get_sys_time()} {}139 140 template <class _Duration2, class _TimeZonePtr2>141 _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt)142 requires(requires {143 _TimeZonePtr{__traits::locate_zone(string_view{})};144 } && is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>)145 : zoned_time{__traits::locate_zone(__name), __zt} {}146 147 template <class _Duration2, class _TimeZonePtr2>148 _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, choose __c)149 requires(requires {150 _TimeZonePtr{__traits::locate_zone(string_view{})};151 } && is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>)152 : zoned_time{__traits::locate_zone(__name), __zt, __c} {}153 154 _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const sys_time<_Duration>& __tp) {155 __tp_ = __tp;156 return *this;157 }158 159 _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const local_time<_Duration>& __tp) {160 // TODO TZDB This seems wrong.161 // Assigning a non-existent or ambiguous time will throw and not satisfy162 // the post condition. This seems quite odd; I constructed an object with163 // choose::earliest and that choice is not respected.164 // what did LEWG do with this.165 // MSVC STL and libstdc++ behave the same166 __tp_ = __zone_->to_sys(__tp);167 return *this;168 }169 170 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI operator sys_time<duration>() const { return get_sys_time(); }171 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit operator local_time<duration>() const { return get_local_time(); }172 173 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _TimeZonePtr get_time_zone() const { return __zone_; }174 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_time<duration> get_local_time() const { return __zone_->to_local(__tp_); }175 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time<duration> get_sys_time() const { return __tp_; }176 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_info get_info() const { return __zone_->get_info(__tp_); }177 178private:179 _TimeZonePtr __zone_;180 sys_time<duration> __tp_;181};182 183zoned_time() -> zoned_time<seconds>;184 185template <class _Duration>186zoned_time(sys_time<_Duration>) -> zoned_time<common_type_t<_Duration, seconds>>;187 188template <class _TimeZonePtrOrName>189using __time_zone_representation _LIBCPP_NODEBUG =190 conditional_t<is_convertible_v<_TimeZonePtrOrName, string_view>,191 const time_zone*,192 remove_cvref_t<_TimeZonePtrOrName>>;193 194template <class _TimeZonePtrOrName>195zoned_time(_TimeZonePtrOrName&&) -> zoned_time<seconds, __time_zone_representation<_TimeZonePtrOrName>>;196 197template <class _TimeZonePtrOrName, class _Duration>198zoned_time(_TimeZonePtrOrName&&, sys_time<_Duration>)199 -> zoned_time<common_type_t<_Duration, seconds>, __time_zone_representation<_TimeZonePtrOrName>>;200 201template <class _TimeZonePtrOrName, class _Duration>202zoned_time(_TimeZonePtrOrName&&, local_time<_Duration>, choose = choose::earliest)203 -> zoned_time<common_type_t<_Duration, seconds>, __time_zone_representation<_TimeZonePtrOrName>>;204 205template <class _Duration, class _TimeZonePtrOrName, class _TimeZonePtr2>206zoned_time(_TimeZonePtrOrName&&, zoned_time<_Duration, _TimeZonePtr2>, choose = choose::earliest)207 -> zoned_time<common_type_t<_Duration, seconds>, __time_zone_representation<_TimeZonePtrOrName>>;208 209using zoned_seconds = zoned_time<seconds>;210 211template <class _Duration1, class _Duration2, class _TimeZonePtr>212_LIBCPP_HIDE_FROM_ABI bool213operator==(const zoned_time<_Duration1, _TimeZonePtr>& __lhs, const zoned_time<_Duration2, _TimeZonePtr>& __rhs) {214 return __lhs.get_time_zone() == __rhs.get_time_zone() && __lhs.get_sys_time() == __rhs.get_sys_time();215}216 217} // namespace chrono218 219# endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM &&220 // _LIBCPP_HAS_LOCALIZATION221 222_LIBCPP_END_NAMESPACE_STD223 224_LIBCPP_POP_MACROS225 226#endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB227 228#endif // _LIBCPP___CHRONO_ZONED_TIME_H229