master
  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 _LIBCPP_HAS_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[[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#    if _LIBCPP_HAS_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[[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#    if _LIBCPP_HAS_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 // _LIBCPP_HAS_EXPERIMENTAL_TZDB
134
135#endif // _LIBCPP___CHRONO_EXCEPTION_H