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
37namespace chrono {
38
39class nonexistent_local_time : public runtime_error {
40public:
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
56private:
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
73template <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
83class ambiguous_local_time : public runtime_error {
84public:
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
100private:
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
117template <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