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-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 // For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html 11 12 #ifndef _LIBCPP___CHRONO_EXCEPTION_H 13 #define _LIBCPP___CHRONO_EXCEPTION_H 14 15 #include <version> 16 // Enable the contents of the header only when libc++ was built with experimental features enabled. 17 #if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) 18 19 # include <__chrono/calendar.h> 20 # include <__chrono/local_info.h> 21 # include <__chrono/time_point.h> 22 # include <__config> 23 # include <__configuration/availability.h> 24 # include <__verbose_abort> 25 # include <format> 26 # include <stdexcept> 27 # include <string> 28 29 # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 30 # pragma GCC system_header 31 # endif 32 33 _LIBCPP_BEGIN_NAMESPACE_STD 34 35 # if _LIBCPP_STD_VER >= 20 36 37 namespace chrono { 38 39 class nonexistent_local_time : public runtime_error { 40 public: 41 template <class _Duration> 42 _LIBCPP_HIDE_FROM_ABI nonexistent_local_time(const local_time<_Duration>& __time, const local_info& __info) 43 : runtime_error{__create_message(__time, __info)} { 44 // [time.zone.exception.nonexist]/2 45 // Preconditions: i.result == local_info::nonexistent is true. 46 // The value of __info.result is not used. 47 _LIBCPP_ASSERT_PEDANTIC(__info.result == local_info::nonexistent, 48 "creating an nonexistent_local_time from a local_info that is not non-existent"); 49 } 50 51 _LIBCPP_HIDE_FROM_ABI nonexistent_local_time(const nonexistent_local_time&) = default; 52 _LIBCPP_HIDE_FROM_ABI nonexistent_local_time& operator=(const nonexistent_local_time&) = default; 53 54 _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI ~nonexistent_local_time() override; // exported as key function 55 56 private: 57 template <class _Duration> 58 _LIBCPP_HIDE_FROM_ABI string __create_message(const local_time<_Duration>& __time, const local_info& __info) { 59 return std::format( 60 R"({} is in a gap between 61 {} {} and 62 {} {} which are both equivalent to 63 {} UTC)", 64 __time, 65 local_seconds{__info.first.end.time_since_epoch()} + __info.first.offset, 66 __info.first.abbrev, 67 local_seconds{__info.second.begin.time_since_epoch()} + __info.second.offset, 68 __info.second.abbrev, 69 __info.first.end); 70 } 71 }; 72 73 template <class _Duration> 74 _LIBCPP_NORETURN _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI void __throw_nonexistent_local_time( 75 [[maybe_unused]] const local_time<_Duration>& __time, [[maybe_unused]] const local_info& __info) { 76 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 77 throw nonexistent_local_time(__time, __info); 78 # else 79 _LIBCPP_VERBOSE_ABORT("nonexistent_local_time was thrown in -fno-exceptions mode"); 80 # endif 81 } 82 83 class ambiguous_local_time : public runtime_error { 84 public: 85 template <class _Duration> 86 _LIBCPP_HIDE_FROM_ABI ambiguous_local_time(const local_time<_Duration>& __time, const local_info& __info) 87 : runtime_error{__create_message(__time, __info)} { 88 // [time.zone.exception.ambig]/2 89 // Preconditions: i.result == local_info::ambiguous is true. 90 // The value of __info.result is not used. 91 _LIBCPP_ASSERT_PEDANTIC(__info.result == local_info::ambiguous, 92 "creating an ambiguous_local_time from a local_info that is not ambiguous"); 93 } 94 95 _LIBCPP_HIDE_FROM_ABI ambiguous_local_time(const ambiguous_local_time&) = default; 96 _LIBCPP_HIDE_FROM_ABI ambiguous_local_time& operator=(const ambiguous_local_time&) = default; 97 98 _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI ~ambiguous_local_time() override; // exported as key function 99 100 private: 101 template <class _Duration> 102 _LIBCPP_HIDE_FROM_ABI string __create_message(const local_time<_Duration>& __time, const local_info& __info) { 103 return std::format( 104 // There are two spaces after the full-stop; this has been verified 105 // in the sources of the Standard. 106 R"({0} is ambiguous. It could be 107 {0} {1} == {2} UTC or 108 {0} {3} == {4} UTC)", 109 __time, 110 __info.first.abbrev, 111 __time - __info.first.offset, 112 __info.second.abbrev, 113 __time - __info.second.offset); 114 } 115 }; 116 117 template <class _Duration> 118 _LIBCPP_NORETURN _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI void __throw_ambiguous_local_time( 119 [[maybe_unused]] const local_time<_Duration>& __time, [[maybe_unused]] const local_info& __info) { 120 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 121 throw ambiguous_local_time(__time, __info); 122 # else 123 _LIBCPP_VERBOSE_ABORT("ambiguous_local_time was thrown in -fno-exceptions mode"); 124 # endif 125 } 126 127 } // namespace chrono 128 129 # endif // _LIBCPP_STD_VER >= 20 130 131 _LIBCPP_END_NAMESPACE_STD 132 133 #endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) 134 135 #endif // _LIBCPP___CHRONO_EXCEPTION_H 136