git repos / blockattack-game

blame: source/misc/embedded_libs/fmt-11.0.2/include/fmt/chrono.h

normal view · raw

f8deb5b9 Poul Sander 2022-01-15 13:55 1
// Formatting library for C++ - chrono support
f8deb5b9 Poul Sander 2022-01-15 13:55 2
//
f8deb5b9 Poul Sander 2022-01-15 13:55 3
// Copyright (c) 2012 - present, Victor Zverovich
f8deb5b9 Poul Sander 2022-01-15 13:55 4
// All rights reserved.
f8deb5b9 Poul Sander 2022-01-15 13:55 5
//
f8deb5b9 Poul Sander 2022-01-15 13:55 6
// For the license information refer to format.h.
f8deb5b9 Poul Sander 2022-01-15 13:55 7
f8deb5b9 Poul Sander 2022-01-15 13:55 8
#ifndef FMT_CHRONO_H_
f8deb5b9 Poul Sander 2022-01-15 13:55 9
#define FMT_CHRONO_H_
f8deb5b9 Poul Sander 2022-01-15 13:55 10
47fd5c32 Poul Sander 2024-10-05 08:44 11
#ifndef FMT_MODULE
47fd5c32 Poul Sander 2024-10-05 08:44 12
#  include <algorithm>
47fd5c32 Poul Sander 2024-10-05 08:44 13
#  include <chrono>
47fd5c32 Poul Sander 2024-10-05 08:44 14
#  include <cmath>    // std::isfinite
47fd5c32 Poul Sander 2024-10-05 08:44 15
#  include <cstring>  // std::memcpy
47fd5c32 Poul Sander 2024-10-05 08:44 16
#  include <ctime>
47fd5c32 Poul Sander 2024-10-05 08:44 17
#  include <iterator>
47fd5c32 Poul Sander 2024-10-05 08:44 18
#  include <locale>
47fd5c32 Poul Sander 2024-10-05 08:44 19
#  include <ostream>
47fd5c32 Poul Sander 2024-10-05 08:44 20
#  include <type_traits>
47fd5c32 Poul Sander 2024-10-05 08:44 21
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 22
f8deb5b9 Poul Sander 2022-01-15 13:55 23
#include "format.h"
f8deb5b9 Poul Sander 2022-01-15 13:55 24
f8deb5b9 Poul Sander 2022-01-15 13:55 25
FMT_BEGIN_NAMESPACE
f8deb5b9 Poul Sander 2022-01-15 13:55 26
47fd5c32 Poul Sander 2024-10-05 08:44 27
// Check if std::chrono::local_t is available.
47fd5c32 Poul Sander 2024-10-05 08:44 28
#ifndef FMT_USE_LOCAL_TIME
47fd5c32 Poul Sander 2024-10-05 08:44 29
#  ifdef __cpp_lib_chrono
47fd5c32 Poul Sander 2024-10-05 08:44 30
#    define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L)
47fd5c32 Poul Sander 2024-10-05 08:44 31
#  else
47fd5c32 Poul Sander 2024-10-05 08:44 32
#    define FMT_USE_LOCAL_TIME 0
47fd5c32 Poul Sander 2024-10-05 08:44 33
#  endif
47fd5c32 Poul Sander 2024-10-05 08:44 34
#endif
47fd5c32 Poul Sander 2024-10-05 08:44 35
47fd5c32 Poul Sander 2024-10-05 08:44 36
// Check if std::chrono::utc_timestamp is available.
47fd5c32 Poul Sander 2024-10-05 08:44 37
#ifndef FMT_USE_UTC_TIME
47fd5c32 Poul Sander 2024-10-05 08:44 38
#  ifdef __cpp_lib_chrono
47fd5c32 Poul Sander 2024-10-05 08:44 39
#    define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L)
47fd5c32 Poul Sander 2024-10-05 08:44 40
#  else
47fd5c32 Poul Sander 2024-10-05 08:44 41
#    define FMT_USE_UTC_TIME 0
47fd5c32 Poul Sander 2024-10-05 08:44 42
#  endif
47fd5c32 Poul Sander 2024-10-05 08:44 43
#endif
47fd5c32 Poul Sander 2024-10-05 08:44 44
f8deb5b9 Poul Sander 2022-01-15 13:55 45
// Enable tzset.
f8deb5b9 Poul Sander 2022-01-15 13:55 46
#ifndef FMT_USE_TZSET
f8deb5b9 Poul Sander 2022-01-15 13:55 47
// UWP doesn't provide _tzset.
f8deb5b9 Poul Sander 2022-01-15 13:55 48
#  if FMT_HAS_INCLUDE("winapifamily.h")
f8deb5b9 Poul Sander 2022-01-15 13:55 49
#    include <winapifamily.h>
f8deb5b9 Poul Sander 2022-01-15 13:55 50
#  endif
f8deb5b9 Poul Sander 2022-01-15 13:55 51
#  if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \
f8deb5b9 Poul Sander 2022-01-15 13:55 52
                          (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
f8deb5b9 Poul Sander 2022-01-15 13:55 53
#    define FMT_USE_TZSET 1
f8deb5b9 Poul Sander 2022-01-15 13:55 54
#  else
f8deb5b9 Poul Sander 2022-01-15 13:55 55
#    define FMT_USE_TZSET 0
f8deb5b9 Poul Sander 2022-01-15 13:55 56
#  endif
f8deb5b9 Poul Sander 2022-01-15 13:55 57
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 58
f8deb5b9 Poul Sander 2022-01-15 13:55 59
// Enable safe chrono durations, unless explicitly disabled.
f8deb5b9 Poul Sander 2022-01-15 13:55 60
#ifndef FMT_SAFE_DURATION_CAST
f8deb5b9 Poul Sander 2022-01-15 13:55 61
#  define FMT_SAFE_DURATION_CAST 1
f8deb5b9 Poul Sander 2022-01-15 13:55 62
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 63
#if FMT_SAFE_DURATION_CAST
f8deb5b9 Poul Sander 2022-01-15 13:55 64
f8deb5b9 Poul Sander 2022-01-15 13:55 65
// For conversion between std::chrono::durations without undefined
f8deb5b9 Poul Sander 2022-01-15 13:55 66
// behaviour or erroneous results.
f8deb5b9 Poul Sander 2022-01-15 13:55 67
// This is a stripped down version of duration_cast, for inclusion in fmt.
f8deb5b9 Poul Sander 2022-01-15 13:55 68
// See https://github.com/pauldreik/safe_duration_cast
f8deb5b9 Poul Sander 2022-01-15 13:55 69
//
f8deb5b9 Poul Sander 2022-01-15 13:55 70
// Copyright Paul Dreik 2019
f8deb5b9 Poul Sander 2022-01-15 13:55 71
namespace safe_duration_cast {
f8deb5b9 Poul Sander 2022-01-15 13:55 72
f8deb5b9 Poul Sander 2022-01-15 13:55 73
template <typename To, typename From,
f8deb5b9 Poul Sander 2022-01-15 13:55 74
          FMT_ENABLE_IF(!std::is_same<From, To>::value &&
f8deb5b9 Poul Sander 2022-01-15 13:55 75
                        std::numeric_limits<From>::is_signed ==
f8deb5b9 Poul Sander 2022-01-15 13:55 76
                            std::numeric_limits<To>::is_signed)>
47fd5c32 Poul Sander 2024-10-05 08:44 77
FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec)
47fd5c32 Poul Sander 2024-10-05 08:44 78
    -> To {
f8deb5b9 Poul Sander 2022-01-15 13:55 79
  ec = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 80
  using F = std::numeric_limits<From>;
f8deb5b9 Poul Sander 2022-01-15 13:55 81
  using T = std::numeric_limits<To>;
f8deb5b9 Poul Sander 2022-01-15 13:55 82
  static_assert(F::is_integer, "From must be integral");
f8deb5b9 Poul Sander 2022-01-15 13:55 83
  static_assert(T::is_integer, "To must be integral");
f8deb5b9 Poul Sander 2022-01-15 13:55 84
f8deb5b9 Poul Sander 2022-01-15 13:55 85
  // A and B are both signed, or both unsigned.
f8deb5b9 Poul Sander 2022-01-15 13:55 86
  if (detail::const_check(F::digits <= T::digits)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 87
    // From fits in To without any problem.
f8deb5b9 Poul Sander 2022-01-15 13:55 88
  } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 89
    // From does not always fit in To, resort to a dynamic check.
f8deb5b9 Poul Sander 2022-01-15 13:55 90
    if (from < (T::min)() || from > (T::max)()) {
f8deb5b9 Poul Sander 2022-01-15 13:55 91
      // outside range.
f8deb5b9 Poul Sander 2022-01-15 13:55 92
      ec = 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 93
      return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 94
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 95
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 96
  return static_cast<To>(from);
f8deb5b9 Poul Sander 2022-01-15 13:55 97
}
f8deb5b9 Poul Sander 2022-01-15 13:55 98
47fd5c32 Poul Sander 2024-10-05 08:44 99
/// Converts From to To, without loss. If the dynamic value of from
47fd5c32 Poul Sander 2024-10-05 08:44 100
/// can't be converted to To without loss, ec is set.
f8deb5b9 Poul Sander 2022-01-15 13:55 101
template <typename To, typename From,
f8deb5b9 Poul Sander 2022-01-15 13:55 102
          FMT_ENABLE_IF(!std::is_same<From, To>::value &&
f8deb5b9 Poul Sander 2022-01-15 13:55 103
                        std::numeric_limits<From>::is_signed !=
f8deb5b9 Poul Sander 2022-01-15 13:55 104
                            std::numeric_limits<To>::is_signed)>
47fd5c32 Poul Sander 2024-10-05 08:44 105
FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec)
47fd5c32 Poul Sander 2024-10-05 08:44 106
    -> To {
f8deb5b9 Poul Sander 2022-01-15 13:55 107
  ec = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 108
  using F = std::numeric_limits<From>;
f8deb5b9 Poul Sander 2022-01-15 13:55 109
  using T = std::numeric_limits<To>;
f8deb5b9 Poul Sander 2022-01-15 13:55 110
  static_assert(F::is_integer, "From must be integral");
f8deb5b9 Poul Sander 2022-01-15 13:55 111
  static_assert(T::is_integer, "To must be integral");
f8deb5b9 Poul Sander 2022-01-15 13:55 112
f8deb5b9 Poul Sander 2022-01-15 13:55 113
  if (detail::const_check(F::is_signed && !T::is_signed)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 114
    // From may be negative, not allowed!
f8deb5b9 Poul Sander 2022-01-15 13:55 115
    if (fmt::detail::is_negative(from)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 116
      ec = 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 117
      return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 118
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 119
    // From is positive. Can it always fit in To?
f8deb5b9 Poul Sander 2022-01-15 13:55 120
    if (detail::const_check(F::digits > T::digits) &&
f8deb5b9 Poul Sander 2022-01-15 13:55 121
        from > static_cast<From>(detail::max_value<To>())) {
f8deb5b9 Poul Sander 2022-01-15 13:55 122
      ec = 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 123
      return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 124
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 125
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 126
f8deb5b9 Poul Sander 2022-01-15 13:55 127
  if (detail::const_check(!F::is_signed && T::is_signed &&
f8deb5b9 Poul Sander 2022-01-15 13:55 128
                          F::digits >= T::digits) &&
f8deb5b9 Poul Sander 2022-01-15 13:55 129
      from > static_cast<From>(detail::max_value<To>())) {
f8deb5b9 Poul Sander 2022-01-15 13:55 130
    ec = 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 131
    return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 132
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 133
  return static_cast<To>(from);  // Lossless conversion.
f8deb5b9 Poul Sander 2022-01-15 13:55 134
}
f8deb5b9 Poul Sander 2022-01-15 13:55 135
f8deb5b9 Poul Sander 2022-01-15 13:55 136
template <typename To, typename From,
f8deb5b9 Poul Sander 2022-01-15 13:55 137
          FMT_ENABLE_IF(std::is_same<From, To>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 138
FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec)
47fd5c32 Poul Sander 2024-10-05 08:44 139
    -> To {
f8deb5b9 Poul Sander 2022-01-15 13:55 140
  ec = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 141
  return from;
f8deb5b9 Poul Sander 2022-01-15 13:55 142
}  // function
f8deb5b9 Poul Sander 2022-01-15 13:55 143
f8deb5b9 Poul Sander 2022-01-15 13:55 144
// clang-format off
f8deb5b9 Poul Sander 2022-01-15 13:55 145
/**
f8deb5b9 Poul Sander 2022-01-15 13:55 146
 * converts From to To if possible, otherwise ec is set.
f8deb5b9 Poul Sander 2022-01-15 13:55 147
 *
f8deb5b9 Poul Sander 2022-01-15 13:55 148
 * input                            |    output
f8deb5b9 Poul Sander 2022-01-15 13:55 149
 * ---------------------------------|---------------
f8deb5b9 Poul Sander 2022-01-15 13:55 150
 * NaN                              | NaN
f8deb5b9 Poul Sander 2022-01-15 13:55 151
 * Inf                              | Inf
f8deb5b9 Poul Sander 2022-01-15 13:55 152
 * normal, fits in output           | converted (possibly lossy)
f8deb5b9 Poul Sander 2022-01-15 13:55 153
 * normal, does not fit in output   | ec is set
f8deb5b9 Poul Sander 2022-01-15 13:55 154
 * subnormal                        | best effort
f8deb5b9 Poul Sander 2022-01-15 13:55 155
 * -Inf                             | -Inf
f8deb5b9 Poul Sander 2022-01-15 13:55 156
 */
f8deb5b9 Poul Sander 2022-01-15 13:55 157
// clang-format on
f8deb5b9 Poul Sander 2022-01-15 13:55 158
template <typename To, typename From,
f8deb5b9 Poul Sander 2022-01-15 13:55 159
          FMT_ENABLE_IF(!std::is_same<From, To>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 160
FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To {
f8deb5b9 Poul Sander 2022-01-15 13:55 161
  ec = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 162
  using T = std::numeric_limits<To>;
f8deb5b9 Poul Sander 2022-01-15 13:55 163
  static_assert(std::is_floating_point<From>::value, "From must be floating");
f8deb5b9 Poul Sander 2022-01-15 13:55 164
  static_assert(std::is_floating_point<To>::value, "To must be floating");
f8deb5b9 Poul Sander 2022-01-15 13:55 165
f8deb5b9 Poul Sander 2022-01-15 13:55 166
  // catch the only happy case
f8deb5b9 Poul Sander 2022-01-15 13:55 167
  if (std::isfinite(from)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 168
    if (from >= T::lowest() && from <= (T::max)()) {
f8deb5b9 Poul Sander 2022-01-15 13:55 169
      return static_cast<To>(from);
f8deb5b9 Poul Sander 2022-01-15 13:55 170
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 171
    // not within range.
f8deb5b9 Poul Sander 2022-01-15 13:55 172
    ec = 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 173
    return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 174
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 175
f8deb5b9 Poul Sander 2022-01-15 13:55 176
  // nan and inf will be preserved
f8deb5b9 Poul Sander 2022-01-15 13:55 177
  return static_cast<To>(from);
f8deb5b9 Poul Sander 2022-01-15 13:55 178
}  // function
f8deb5b9 Poul Sander 2022-01-15 13:55 179
f8deb5b9 Poul Sander 2022-01-15 13:55 180
template <typename To, typename From,
f8deb5b9 Poul Sander 2022-01-15 13:55 181
          FMT_ENABLE_IF(std::is_same<From, To>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 182
FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To {
f8deb5b9 Poul Sander 2022-01-15 13:55 183
  ec = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 184
  static_assert(std::is_floating_point<From>::value, "From must be floating");
f8deb5b9 Poul Sander 2022-01-15 13:55 185
  return from;
f8deb5b9 Poul Sander 2022-01-15 13:55 186
}
f8deb5b9 Poul Sander 2022-01-15 13:55 187
47fd5c32 Poul Sander 2024-10-05 08:44 188
/// Safe duration cast between integral durations
f8deb5b9 Poul Sander 2022-01-15 13:55 189
template <typename To, typename FromRep, typename FromPeriod,
f8deb5b9 Poul Sander 2022-01-15 13:55 190
          FMT_ENABLE_IF(std::is_integral<FromRep>::value),
f8deb5b9 Poul Sander 2022-01-15 13:55 191
          FMT_ENABLE_IF(std::is_integral<typename To::rep>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 192
auto safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
47fd5c32 Poul Sander 2024-10-05 08:44 193
                        int& ec) -> To {
f8deb5b9 Poul Sander 2022-01-15 13:55 194
  using From = std::chrono::duration<FromRep, FromPeriod>;
f8deb5b9 Poul Sander 2022-01-15 13:55 195
  ec = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 196
  // the basic idea is that we need to convert from count() in the from type
f8deb5b9 Poul Sander 2022-01-15 13:55 197
  // to count() in the To type, by multiplying it with this:
f8deb5b9 Poul Sander 2022-01-15 13:55 198
  struct Factor
f8deb5b9 Poul Sander 2022-01-15 13:55 199
      : std::ratio_divide<typename From::period, typename To::period> {};
f8deb5b9 Poul Sander 2022-01-15 13:55 200
f8deb5b9 Poul Sander 2022-01-15 13:55 201
  static_assert(Factor::num > 0, "num must be positive");
f8deb5b9 Poul Sander 2022-01-15 13:55 202
  static_assert(Factor::den > 0, "den must be positive");
f8deb5b9 Poul Sander 2022-01-15 13:55 203
f8deb5b9 Poul Sander 2022-01-15 13:55 204
  // the conversion is like this: multiply from.count() with Factor::num
f8deb5b9 Poul Sander 2022-01-15 13:55 205
  // /Factor::den and convert it to To::rep, all this without
f8deb5b9 Poul Sander 2022-01-15 13:55 206
  // overflow/underflow. let's start by finding a suitable type that can hold
f8deb5b9 Poul Sander 2022-01-15 13:55 207
  // both To, From and Factor::num
f8deb5b9 Poul Sander 2022-01-15 13:55 208
  using IntermediateRep =
f8deb5b9 Poul Sander 2022-01-15 13:55 209
      typename std::common_type<typename From::rep, typename To::rep,
f8deb5b9 Poul Sander 2022-01-15 13:55 210
                                decltype(Factor::num)>::type;
f8deb5b9 Poul Sander 2022-01-15 13:55 211
f8deb5b9 Poul Sander 2022-01-15 13:55 212
  // safe conversion to IntermediateRep
f8deb5b9 Poul Sander 2022-01-15 13:55 213
  IntermediateRep count =
f8deb5b9 Poul Sander 2022-01-15 13:55 214
      lossless_integral_conversion<IntermediateRep>(from.count(), ec);
f8deb5b9 Poul Sander 2022-01-15 13:55 215
  if (ec) return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 216
  // multiply with Factor::num without overflow or underflow
f8deb5b9 Poul Sander 2022-01-15 13:55 217
  if (detail::const_check(Factor::num != 1)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 218
    const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
f8deb5b9 Poul Sander 2022-01-15 13:55 219
    if (count > max1) {
f8deb5b9 Poul Sander 2022-01-15 13:55 220
      ec = 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 221
      return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 222
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 223
    const auto min1 =
f8deb5b9 Poul Sander 2022-01-15 13:55 224
        (std::numeric_limits<IntermediateRep>::min)() / Factor::num;
47fd5c32 Poul Sander 2024-10-05 08:44 225
    if (detail::const_check(!std::is_unsigned<IntermediateRep>::value) &&
47fd5c32 Poul Sander 2024-10-05 08:44 226
        count < min1) {
f8deb5b9 Poul Sander 2022-01-15 13:55 227
      ec = 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 228
      return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 229
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 230
    count *= Factor::num;
f8deb5b9 Poul Sander 2022-01-15 13:55 231
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 232
f8deb5b9 Poul Sander 2022-01-15 13:55 233
  if (detail::const_check(Factor::den != 1)) count /= Factor::den;
f8deb5b9 Poul Sander 2022-01-15 13:55 234
  auto tocount = lossless_integral_conversion<typename To::rep>(count, ec);
f8deb5b9 Poul Sander 2022-01-15 13:55 235
  return ec ? To() : To(tocount);
f8deb5b9 Poul Sander 2022-01-15 13:55 236
}
f8deb5b9 Poul Sander 2022-01-15 13:55 237
47fd5c32 Poul Sander 2024-10-05 08:44 238
/// Safe duration_cast between floating point durations
f8deb5b9 Poul Sander 2022-01-15 13:55 239
template <typename To, typename FromRep, typename FromPeriod,
f8deb5b9 Poul Sander 2022-01-15 13:55 240
          FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
f8deb5b9 Poul Sander 2022-01-15 13:55 241
          FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 242
auto safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
47fd5c32 Poul Sander 2024-10-05 08:44 243
                        int& ec) -> To {
f8deb5b9 Poul Sander 2022-01-15 13:55 244
  using From = std::chrono::duration<FromRep, FromPeriod>;
f8deb5b9 Poul Sander 2022-01-15 13:55 245
  ec = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 246
  if (std::isnan(from.count())) {
f8deb5b9 Poul Sander 2022-01-15 13:55 247
    // nan in, gives nan out. easy.
f8deb5b9 Poul Sander 2022-01-15 13:55 248
    return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
f8deb5b9 Poul Sander 2022-01-15 13:55 249
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 250
  // maybe we should also check if from is denormal, and decide what to do about
f8deb5b9 Poul Sander 2022-01-15 13:55 251
  // it.
f8deb5b9 Poul Sander 2022-01-15 13:55 252
f8deb5b9 Poul Sander 2022-01-15 13:55 253
  // +-inf should be preserved.
f8deb5b9 Poul Sander 2022-01-15 13:55 254
  if (std::isinf(from.count())) {
f8deb5b9 Poul Sander 2022-01-15 13:55 255
    return To{from.count()};
f8deb5b9 Poul Sander 2022-01-15 13:55 256
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 257
f8deb5b9 Poul Sander 2022-01-15 13:55 258
  // the basic idea is that we need to convert from count() in the from type
f8deb5b9 Poul Sander 2022-01-15 13:55 259
  // to count() in the To type, by multiplying it with this:
f8deb5b9 Poul Sander 2022-01-15 13:55 260
  struct Factor
f8deb5b9 Poul Sander 2022-01-15 13:55 261
      : std::ratio_divide<typename From::period, typename To::period> {};
f8deb5b9 Poul Sander 2022-01-15 13:55 262
f8deb5b9 Poul Sander 2022-01-15 13:55 263
  static_assert(Factor::num > 0, "num must be positive");
f8deb5b9 Poul Sander 2022-01-15 13:55 264
  static_assert(Factor::den > 0, "den must be positive");
f8deb5b9 Poul Sander 2022-01-15 13:55 265
f8deb5b9 Poul Sander 2022-01-15 13:55 266
  // the conversion is like this: multiply from.count() with Factor::num
f8deb5b9 Poul Sander 2022-01-15 13:55 267
  // /Factor::den and convert it to To::rep, all this without
f8deb5b9 Poul Sander 2022-01-15 13:55 268
  // overflow/underflow. let's start by finding a suitable type that can hold
f8deb5b9 Poul Sander 2022-01-15 13:55 269
  // both To, From and Factor::num
f8deb5b9 Poul Sander 2022-01-15 13:55 270
  using IntermediateRep =
f8deb5b9 Poul Sander 2022-01-15 13:55 271
      typename std::common_type<typename From::rep, typename To::rep,
f8deb5b9 Poul Sander 2022-01-15 13:55 272
                                decltype(Factor::num)>::type;
f8deb5b9 Poul Sander 2022-01-15 13:55 273
f8deb5b9 Poul Sander 2022-01-15 13:55 274
  // force conversion of From::rep -> IntermediateRep to be safe,
f8deb5b9 Poul Sander 2022-01-15 13:55 275
  // even if it will never happen be narrowing in this context.
f8deb5b9 Poul Sander 2022-01-15 13:55 276
  IntermediateRep count =
f8deb5b9 Poul Sander 2022-01-15 13:55 277
      safe_float_conversion<IntermediateRep>(from.count(), ec);
f8deb5b9 Poul Sander 2022-01-15 13:55 278
  if (ec) {
f8deb5b9 Poul Sander 2022-01-15 13:55 279
    return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 280
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 281
f8deb5b9 Poul Sander 2022-01-15 13:55 282
  // multiply with Factor::num without overflow or underflow
f8deb5b9 Poul Sander 2022-01-15 13:55 283
  if (detail::const_check(Factor::num != 1)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 284
    constexpr auto max1 = detail::max_value<IntermediateRep>() /
f8deb5b9 Poul Sander 2022-01-15 13:55 285
                          static_cast<IntermediateRep>(Factor::num);
f8deb5b9 Poul Sander 2022-01-15 13:55 286
    if (count > max1) {
f8deb5b9 Poul Sander 2022-01-15 13:55 287
      ec = 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 288
      return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 289
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 290
    constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
f8deb5b9 Poul Sander 2022-01-15 13:55 291
                          static_cast<IntermediateRep>(Factor::num);
f8deb5b9 Poul Sander 2022-01-15 13:55 292
    if (count < min1) {
f8deb5b9 Poul Sander 2022-01-15 13:55 293
      ec = 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 294
      return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 295
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 296
    count *= static_cast<IntermediateRep>(Factor::num);
f8deb5b9 Poul Sander 2022-01-15 13:55 297
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 298
f8deb5b9 Poul Sander 2022-01-15 13:55 299
  // this can't go wrong, right? den>0 is checked earlier.
f8deb5b9 Poul Sander 2022-01-15 13:55 300
  if (detail::const_check(Factor::den != 1)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 301
    using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
f8deb5b9 Poul Sander 2022-01-15 13:55 302
    count /= static_cast<common_t>(Factor::den);
f8deb5b9 Poul Sander 2022-01-15 13:55 303
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 304
f8deb5b9 Poul Sander 2022-01-15 13:55 305
  // convert to the to type, safely
f8deb5b9 Poul Sander 2022-01-15 13:55 306
  using ToRep = typename To::rep;
f8deb5b9 Poul Sander 2022-01-15 13:55 307
f8deb5b9 Poul Sander 2022-01-15 13:55 308
  const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
f8deb5b9 Poul Sander 2022-01-15 13:55 309
  if (ec) {
f8deb5b9 Poul Sander 2022-01-15 13:55 310
    return {};
f8deb5b9 Poul Sander 2022-01-15 13:55 311
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 312
  return To{tocount};
f8deb5b9 Poul Sander 2022-01-15 13:55 313
}
f8deb5b9 Poul Sander 2022-01-15 13:55 314
}  // namespace safe_duration_cast
f8deb5b9 Poul Sander 2022-01-15 13:55 315
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 316
f8deb5b9 Poul Sander 2022-01-15 13:55 317
// Prevents expansion of a preceding token as a function-style macro.
f8deb5b9 Poul Sander 2022-01-15 13:55 318
// Usage: f FMT_NOMACRO()
f8deb5b9 Poul Sander 2022-01-15 13:55 319
#define FMT_NOMACRO
f8deb5b9 Poul Sander 2022-01-15 13:55 320
f8deb5b9 Poul Sander 2022-01-15 13:55 321
namespace detail {
f8deb5b9 Poul Sander 2022-01-15 13:55 322
template <typename T = void> struct null {};
47fd5c32 Poul Sander 2024-10-05 08:44 323
inline auto localtime_r FMT_NOMACRO(...) -> null<> { return null<>(); }
47fd5c32 Poul Sander 2024-10-05 08:44 324
inline auto localtime_s(...) -> null<> { return null<>(); }
47fd5c32 Poul Sander 2024-10-05 08:44 325
inline auto gmtime_r(...) -> null<> { return null<>(); }
47fd5c32 Poul Sander 2024-10-05 08:44 326
inline auto gmtime_s(...) -> null<> { return null<>(); }
47fd5c32 Poul Sander 2024-10-05 08:44 327
47fd5c32 Poul Sander 2024-10-05 08:44 328
// It is defined here and not in ostream.h because the latter has expensive
47fd5c32 Poul Sander 2024-10-05 08:44 329
// includes.
47fd5c32 Poul Sander 2024-10-05 08:44 330
template <typename Streambuf> class formatbuf : public Streambuf {
47fd5c32 Poul Sander 2024-10-05 08:44 331
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 332
  using char_type = typename Streambuf::char_type;
47fd5c32 Poul Sander 2024-10-05 08:44 333
  using streamsize = decltype(std::declval<Streambuf>().sputn(nullptr, 0));
47fd5c32 Poul Sander 2024-10-05 08:44 334
  using int_type = typename Streambuf::int_type;
47fd5c32 Poul Sander 2024-10-05 08:44 335
  using traits_type = typename Streambuf::traits_type;
47fd5c32 Poul Sander 2024-10-05 08:44 336
47fd5c32 Poul Sander 2024-10-05 08:44 337
  buffer<char_type>& buffer_;
47fd5c32 Poul Sander 2024-10-05 08:44 338
47fd5c32 Poul Sander 2024-10-05 08:44 339
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 340
  explicit formatbuf(buffer<char_type>& buf) : buffer_(buf) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 341
47fd5c32 Poul Sander 2024-10-05 08:44 342
 protected:
47fd5c32 Poul Sander 2024-10-05 08:44 343
  // The put area is always empty. This makes the implementation simpler and has
47fd5c32 Poul Sander 2024-10-05 08:44 344
  // the advantage that the streambuf and the buffer are always in sync and
47fd5c32 Poul Sander 2024-10-05 08:44 345
  // sputc never writes into uninitialized memory. A disadvantage is that each
47fd5c32 Poul Sander 2024-10-05 08:44 346
  // call to sputc always results in a (virtual) call to overflow. There is no
47fd5c32 Poul Sander 2024-10-05 08:44 347
  // disadvantage here for sputn since this always results in a call to xsputn.
47fd5c32 Poul Sander 2024-10-05 08:44 348
47fd5c32 Poul Sander 2024-10-05 08:44 349
  auto overflow(int_type ch) -> int_type override {
47fd5c32 Poul Sander 2024-10-05 08:44 350
    if (!traits_type::eq_int_type(ch, traits_type::eof()))
47fd5c32 Poul Sander 2024-10-05 08:44 351
      buffer_.push_back(static_cast<char_type>(ch));
47fd5c32 Poul Sander 2024-10-05 08:44 352
    return ch;
47fd5c32 Poul Sander 2024-10-05 08:44 353
  }
47fd5c32 Poul Sander 2024-10-05 08:44 354
47fd5c32 Poul Sander 2024-10-05 08:44 355
  auto xsputn(const char_type* s, streamsize count) -> streamsize override {
47fd5c32 Poul Sander 2024-10-05 08:44 356
    buffer_.append(s, s + count);
47fd5c32 Poul Sander 2024-10-05 08:44 357
    return count;
47fd5c32 Poul Sander 2024-10-05 08:44 358
  }
47fd5c32 Poul Sander 2024-10-05 08:44 359
};
47fd5c32 Poul Sander 2024-10-05 08:44 360
47fd5c32 Poul Sander 2024-10-05 08:44 361
inline auto get_classic_locale() -> const std::locale& {
f8deb5b9 Poul Sander 2022-01-15 13:55 362
  static const auto& locale = std::locale::classic();
f8deb5b9 Poul Sander 2022-01-15 13:55 363
  return locale;
f8deb5b9 Poul Sander 2022-01-15 13:55 364
}
f8deb5b9 Poul Sander 2022-01-15 13:55 365
f8deb5b9 Poul Sander 2022-01-15 13:55 366
template <typename CodeUnit> struct codecvt_result {
f8deb5b9 Poul Sander 2022-01-15 13:55 367
  static constexpr const size_t max_size = 32;
f8deb5b9 Poul Sander 2022-01-15 13:55 368
  CodeUnit buf[max_size];
f8deb5b9 Poul Sander 2022-01-15 13:55 369
  CodeUnit* end;
f8deb5b9 Poul Sander 2022-01-15 13:55 370
};
f8deb5b9 Poul Sander 2022-01-15 13:55 371
f8deb5b9 Poul Sander 2022-01-15 13:55 372
template <typename CodeUnit>
f8deb5b9 Poul Sander 2022-01-15 13:55 373
void write_codecvt(codecvt_result<CodeUnit>& out, string_view in_buf,
f8deb5b9 Poul Sander 2022-01-15 13:55 374
                   const std::locale& loc) {
f8deb5b9 Poul Sander 2022-01-15 13:55 375
#if FMT_CLANG_VERSION
f8deb5b9 Poul Sander 2022-01-15 13:55 376
#  pragma clang diagnostic push
f8deb5b9 Poul Sander 2022-01-15 13:55 377
#  pragma clang diagnostic ignored "-Wdeprecated"
47fd5c32 Poul Sander 2024-10-05 08:44 378
  auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
f8deb5b9 Poul Sander 2022-01-15 13:55 379
#  pragma clang diagnostic pop
f8deb5b9 Poul Sander 2022-01-15 13:55 380
#else
47fd5c32 Poul Sander 2024-10-05 08:44 381
  auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
f8deb5b9 Poul Sander 2022-01-15 13:55 382
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 383
  auto mb = std::mbstate_t();
f8deb5b9 Poul Sander 2022-01-15 13:55 384
  const char* from_next = nullptr;
f8deb5b9 Poul Sander 2022-01-15 13:55 385
  auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next,
f8deb5b9 Poul Sander 2022-01-15 13:55 386
                     std::begin(out.buf), std::end(out.buf), out.end);
f8deb5b9 Poul Sander 2022-01-15 13:55 387
  if (result != std::codecvt_base::ok)
f8deb5b9 Poul Sander 2022-01-15 13:55 388
    FMT_THROW(format_error("failed to format time"));
f8deb5b9 Poul Sander 2022-01-15 13:55 389
}
f8deb5b9 Poul Sander 2022-01-15 13:55 390
f8deb5b9 Poul Sander 2022-01-15 13:55 391
template <typename OutputIt>
f8deb5b9 Poul Sander 2022-01-15 13:55 392
auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc)
f8deb5b9 Poul Sander 2022-01-15 13:55 393
    -> OutputIt {
47fd5c32 Poul Sander 2024-10-05 08:44 394
  if (detail::use_utf8() && loc != get_classic_locale()) {
f8deb5b9 Poul Sander 2022-01-15 13:55 395
    // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
f8deb5b9 Poul Sander 2022-01-15 13:55 396
    // gcc-4.
47fd5c32 Poul Sander 2024-10-05 08:44 397
#if FMT_MSC_VERSION != 0 ||  \
47fd5c32 Poul Sander 2024-10-05 08:44 398
    (defined(__GLIBCXX__) && \
47fd5c32 Poul Sander 2024-10-05 08:44 399
     (!defined(_GLIBCXX_USE_DUAL_ABI) || _GLIBCXX_USE_DUAL_ABI == 0))
f8deb5b9 Poul Sander 2022-01-15 13:55 400
    // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
f8deb5b9 Poul Sander 2022-01-15 13:55 401
    // and newer.
f8deb5b9 Poul Sander 2022-01-15 13:55 402
    using code_unit = wchar_t;
f8deb5b9 Poul Sander 2022-01-15 13:55 403
#else
f8deb5b9 Poul Sander 2022-01-15 13:55 404
    using code_unit = char32_t;
f8deb5b9 Poul Sander 2022-01-15 13:55 405
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 406
f8deb5b9 Poul Sander 2022-01-15 13:55 407
    using unit_t = codecvt_result<code_unit>;
f8deb5b9 Poul Sander 2022-01-15 13:55 408
    unit_t unit;
f8deb5b9 Poul Sander 2022-01-15 13:55 409
    write_codecvt(unit, in, loc);
f8deb5b9 Poul Sander 2022-01-15 13:55 410
    // In UTF-8 is used one to four one-byte code units.
47fd5c32 Poul Sander 2024-10-05 08:44 411
    auto u =
47fd5c32 Poul Sander 2024-10-05 08:44 412
        to_utf8<code_unit, basic_memory_buffer<char, unit_t::max_size * 4>>();
47fd5c32 Poul Sander 2024-10-05 08:44 413
    if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)}))
47fd5c32 Poul Sander 2024-10-05 08:44 414
      FMT_THROW(format_error("failed to format time"));
47fd5c32 Poul Sander 2024-10-05 08:44 415
    return copy<char>(u.c_str(), u.c_str() + u.size(), out);
f8deb5b9 Poul Sander 2022-01-15 13:55 416
  }
47fd5c32 Poul Sander 2024-10-05 08:44 417
  return copy<char>(in.data(), in.data() + in.size(), out);
f8deb5b9 Poul Sander 2022-01-15 13:55 418
}
f8deb5b9 Poul Sander 2022-01-15 13:55 419
f8deb5b9 Poul Sander 2022-01-15 13:55 420
template <typename Char, typename OutputIt,
f8deb5b9 Poul Sander 2022-01-15 13:55 421
          FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
f8deb5b9 Poul Sander 2022-01-15 13:55 422
auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc)
f8deb5b9 Poul Sander 2022-01-15 13:55 423
    -> OutputIt {
f8deb5b9 Poul Sander 2022-01-15 13:55 424
  codecvt_result<Char> unit;
f8deb5b9 Poul Sander 2022-01-15 13:55 425
  write_codecvt(unit, sv, loc);
47fd5c32 Poul Sander 2024-10-05 08:44 426
  return copy<Char>(unit.buf, unit.end, out);
f8deb5b9 Poul Sander 2022-01-15 13:55 427
}
f8deb5b9 Poul Sander 2022-01-15 13:55 428
f8deb5b9 Poul Sander 2022-01-15 13:55 429
template <typename Char, typename OutputIt,
f8deb5b9 Poul Sander 2022-01-15 13:55 430
          FMT_ENABLE_IF(std::is_same<Char, char>::value)>
f8deb5b9 Poul Sander 2022-01-15 13:55 431
auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc)
f8deb5b9 Poul Sander 2022-01-15 13:55 432
    -> OutputIt {
f8deb5b9 Poul Sander 2022-01-15 13:55 433
  return write_encoded_tm_str(out, sv, loc);
f8deb5b9 Poul Sander 2022-01-15 13:55 434
}
f8deb5b9 Poul Sander 2022-01-15 13:55 435
f8deb5b9 Poul Sander 2022-01-15 13:55 436
template <typename Char>
f8deb5b9 Poul Sander 2022-01-15 13:55 437
inline void do_write(buffer<Char>& buf, const std::tm& time,
f8deb5b9 Poul Sander 2022-01-15 13:55 438
                     const std::locale& loc, char format, char modifier) {
f8deb5b9 Poul Sander 2022-01-15 13:55 439
  auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
f8deb5b9 Poul Sander 2022-01-15 13:55 440
  auto&& os = std::basic_ostream<Char>(&format_buf);
f8deb5b9 Poul Sander 2022-01-15 13:55 441
  os.imbue(loc);
47fd5c32 Poul Sander 2024-10-05 08:44 442
  const auto& facet = std::use_facet<std::time_put<Char>>(loc);
f8deb5b9 Poul Sander 2022-01-15 13:55 443
  auto end = facet.put(os, os, Char(' '), &time, format, modifier);
f8deb5b9 Poul Sander 2022-01-15 13:55 444
  if (end.failed()) FMT_THROW(format_error("failed to format time"));
f8deb5b9 Poul Sander 2022-01-15 13:55 445
}
f8deb5b9 Poul Sander 2022-01-15 13:55 446
f8deb5b9 Poul Sander 2022-01-15 13:55 447
template <typename Char, typename OutputIt,
f8deb5b9 Poul Sander 2022-01-15 13:55 448
          FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
f8deb5b9 Poul Sander 2022-01-15 13:55 449
auto write(OutputIt out, const std::tm& time, const std::locale& loc,
f8deb5b9 Poul Sander 2022-01-15 13:55 450
           char format, char modifier = 0) -> OutputIt {
f8deb5b9 Poul Sander 2022-01-15 13:55 451
  auto&& buf = get_buffer<Char>(out);
f8deb5b9 Poul Sander 2022-01-15 13:55 452
  do_write<Char>(buf, time, loc, format, modifier);
47fd5c32 Poul Sander 2024-10-05 08:44 453
  return get_iterator(buf, out);
f8deb5b9 Poul Sander 2022-01-15 13:55 454
}
f8deb5b9 Poul Sander 2022-01-15 13:55 455
f8deb5b9 Poul Sander 2022-01-15 13:55 456
template <typename Char, typename OutputIt,
f8deb5b9 Poul Sander 2022-01-15 13:55 457
          FMT_ENABLE_IF(std::is_same<Char, char>::value)>
f8deb5b9 Poul Sander 2022-01-15 13:55 458
auto write(OutputIt out, const std::tm& time, const std::locale& loc,
f8deb5b9 Poul Sander 2022-01-15 13:55 459
           char format, char modifier = 0) -> OutputIt {
f8deb5b9 Poul Sander 2022-01-15 13:55 460
  auto&& buf = basic_memory_buffer<Char>();
f8deb5b9 Poul Sander 2022-01-15 13:55 461
  do_write<char>(buf, time, loc, format, modifier);
f8deb5b9 Poul Sander 2022-01-15 13:55 462
  return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc);
f8deb5b9 Poul Sander 2022-01-15 13:55 463
}
f8deb5b9 Poul Sander 2022-01-15 13:55 464
47fd5c32 Poul Sander 2024-10-05 08:44 465
template <typename Rep1, typename Rep2>
47fd5c32 Poul Sander 2024-10-05 08:44 466
struct is_same_arithmetic_type
47fd5c32 Poul Sander 2024-10-05 08:44 467
    : public std::integral_constant<bool,
47fd5c32 Poul Sander 2024-10-05 08:44 468
                                    (std::is_integral<Rep1>::value &&
47fd5c32 Poul Sander 2024-10-05 08:44 469
                                     std::is_integral<Rep2>::value) ||
47fd5c32 Poul Sander 2024-10-05 08:44 470
                                        (std::is_floating_point<Rep1>::value &&
47fd5c32 Poul Sander 2024-10-05 08:44 471
                                         std::is_floating_point<Rep2>::value)> {
47fd5c32 Poul Sander 2024-10-05 08:44 472
};
47fd5c32 Poul Sander 2024-10-05 08:44 473
47fd5c32 Poul Sander 2024-10-05 08:44 474
template <
47fd5c32 Poul Sander 2024-10-05 08:44 475
    typename To, typename FromRep, typename FromPeriod,
47fd5c32 Poul Sander 2024-10-05 08:44 476
    FMT_ENABLE_IF(is_same_arithmetic_type<FromRep, typename To::rep>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 477
auto fmt_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
47fd5c32 Poul Sander 2024-10-05 08:44 478
#if FMT_SAFE_DURATION_CAST
47fd5c32 Poul Sander 2024-10-05 08:44 479
  // Throwing version of safe_duration_cast is only available for
47fd5c32 Poul Sander 2024-10-05 08:44 480
  // integer to integer or float to float casts.
47fd5c32 Poul Sander 2024-10-05 08:44 481
  int ec;
47fd5c32 Poul Sander 2024-10-05 08:44 482
  To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
47fd5c32 Poul Sander 2024-10-05 08:44 483
  if (ec) FMT_THROW(format_error("cannot format duration"));
47fd5c32 Poul Sander 2024-10-05 08:44 484
  return to;
47fd5c32 Poul Sander 2024-10-05 08:44 485
#else
47fd5c32 Poul Sander 2024-10-05 08:44 486
  // Standard duration cast, may overflow.
47fd5c32 Poul Sander 2024-10-05 08:44 487
  return std::chrono::duration_cast<To>(from);
47fd5c32 Poul Sander 2024-10-05 08:44 488
#endif
47fd5c32 Poul Sander 2024-10-05 08:44 489
}
47fd5c32 Poul Sander 2024-10-05 08:44 490
47fd5c32 Poul Sander 2024-10-05 08:44 491
template <
47fd5c32 Poul Sander 2024-10-05 08:44 492
    typename To, typename FromRep, typename FromPeriod,
47fd5c32 Poul Sander 2024-10-05 08:44 493
    FMT_ENABLE_IF(!is_same_arithmetic_type<FromRep, typename To::rep>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 494
auto fmt_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
47fd5c32 Poul Sander 2024-10-05 08:44 495
  // Mixed integer <-> float cast is not supported by safe_duration_cast.
47fd5c32 Poul Sander 2024-10-05 08:44 496
  return std::chrono::duration_cast<To>(from);
47fd5c32 Poul Sander 2024-10-05 08:44 497
}
47fd5c32 Poul Sander 2024-10-05 08:44 498
47fd5c32 Poul Sander 2024-10-05 08:44 499
template <typename Duration>
47fd5c32 Poul Sander 2024-10-05 08:44 500
auto to_time_t(
47fd5c32 Poul Sander 2024-10-05 08:44 501
    std::chrono::time_point<std::chrono::system_clock, Duration> time_point)
47fd5c32 Poul Sander 2024-10-05 08:44 502
    -> std::time_t {
47fd5c32 Poul Sander 2024-10-05 08:44 503
  // Cannot use std::chrono::system_clock::to_time_t since this would first
47fd5c32 Poul Sander 2024-10-05 08:44 504
  // require a cast to std::chrono::system_clock::time_point, which could
47fd5c32 Poul Sander 2024-10-05 08:44 505
  // overflow.
47fd5c32 Poul Sander 2024-10-05 08:44 506
  return fmt_duration_cast<std::chrono::duration<std::time_t>>(
47fd5c32 Poul Sander 2024-10-05 08:44 507
             time_point.time_since_epoch())
47fd5c32 Poul Sander 2024-10-05 08:44 508
      .count();
47fd5c32 Poul Sander 2024-10-05 08:44 509
}
f8deb5b9 Poul Sander 2022-01-15 13:55 510
}  // namespace detail
f8deb5b9 Poul Sander 2022-01-15 13:55 511
47fd5c32 Poul Sander 2024-10-05 08:44 512
FMT_BEGIN_EXPORT
f8deb5b9 Poul Sander 2022-01-15 13:55 513
f8deb5b9 Poul Sander 2022-01-15 13:55 514
/**
47fd5c32 Poul Sander 2024-10-05 08:44 515
 * Converts given time since epoch as `std::time_t` value into calendar time,
47fd5c32 Poul Sander 2024-10-05 08:44 516
 * expressed in local time. Unlike `std::localtime`, this function is
47fd5c32 Poul Sander 2024-10-05 08:44 517
 * thread-safe on most platforms.
f8deb5b9 Poul Sander 2022-01-15 13:55 518
 */
47fd5c32 Poul Sander 2024-10-05 08:44 519
inline auto localtime(std::time_t time) -> std::tm {
f8deb5b9 Poul Sander 2022-01-15 13:55 520
  struct dispatcher {
f8deb5b9 Poul Sander 2022-01-15 13:55 521
    std::time_t time_;
f8deb5b9 Poul Sander 2022-01-15 13:55 522
    std::tm tm_;
f8deb5b9 Poul Sander 2022-01-15 13:55 523
f8deb5b9 Poul Sander 2022-01-15 13:55 524
    dispatcher(std::time_t t) : time_(t) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 525
47fd5c32 Poul Sander 2024-10-05 08:44 526
    auto run() -> bool {
f8deb5b9 Poul Sander 2022-01-15 13:55 527
      using namespace fmt::detail;
f8deb5b9 Poul Sander 2022-01-15 13:55 528
      return handle(localtime_r(&time_, &tm_));
f8deb5b9 Poul Sander 2022-01-15 13:55 529
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 530
47fd5c32 Poul Sander 2024-10-05 08:44 531
    auto handle(std::tm* tm) -> bool { return tm != nullptr; }
f8deb5b9 Poul Sander 2022-01-15 13:55 532
47fd5c32 Poul Sander 2024-10-05 08:44 533
    auto handle(detail::null<>) -> bool {
f8deb5b9 Poul Sander 2022-01-15 13:55 534
      using namespace fmt::detail;
f8deb5b9 Poul Sander 2022-01-15 13:55 535
      return fallback(localtime_s(&tm_, &time_));
f8deb5b9 Poul Sander 2022-01-15 13:55 536
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 537
47fd5c32 Poul Sander 2024-10-05 08:44 538
    auto fallback(int res) -> bool { return res == 0; }
f8deb5b9 Poul Sander 2022-01-15 13:55 539
47fd5c32 Poul Sander 2024-10-05 08:44 540
#if !FMT_MSC_VERSION
47fd5c32 Poul Sander 2024-10-05 08:44 541
    auto fallback(detail::null<>) -> bool {
f8deb5b9 Poul Sander 2022-01-15 13:55 542
      using namespace fmt::detail;
f8deb5b9 Poul Sander 2022-01-15 13:55 543
      std::tm* tm = std::localtime(&time_);
f8deb5b9 Poul Sander 2022-01-15 13:55 544
      if (tm) tm_ = *tm;
f8deb5b9 Poul Sander 2022-01-15 13:55 545
      return tm != nullptr;
f8deb5b9 Poul Sander 2022-01-15 13:55 546
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 547
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 548
  };
f8deb5b9 Poul Sander 2022-01-15 13:55 549
  dispatcher lt(time);
f8deb5b9 Poul Sander 2022-01-15 13:55 550
  // Too big time values may be unsupported.
f8deb5b9 Poul Sander 2022-01-15 13:55 551
  if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
f8deb5b9 Poul Sander 2022-01-15 13:55 552
  return lt.tm_;
f8deb5b9 Poul Sander 2022-01-15 13:55 553
}
f8deb5b9 Poul Sander 2022-01-15 13:55 554
47fd5c32 Poul Sander 2024-10-05 08:44 555
#if FMT_USE_LOCAL_TIME
47fd5c32 Poul Sander 2024-10-05 08:44 556
template <typename Duration>
47fd5c32 Poul Sander 2024-10-05 08:44 557
inline auto localtime(std::chrono::local_time<Duration> time) -> std::tm {
47fd5c32 Poul Sander 2024-10-05 08:44 558
  return localtime(
47fd5c32 Poul Sander 2024-10-05 08:44 559
      detail::to_time_t(std::chrono::current_zone()->to_sys(time)));
f8deb5b9 Poul Sander 2022-01-15 13:55 560
}
47fd5c32 Poul Sander 2024-10-05 08:44 561
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 562
f8deb5b9 Poul Sander 2022-01-15 13:55 563
/**
47fd5c32 Poul Sander 2024-10-05 08:44 564
 * Converts given time since epoch as `std::time_t` value into calendar time,
47fd5c32 Poul Sander 2024-10-05 08:44 565
 * expressed in Coordinated Universal Time (UTC). Unlike `std::gmtime`, this
47fd5c32 Poul Sander 2024-10-05 08:44 566
 * function is thread-safe on most platforms.
f8deb5b9 Poul Sander 2022-01-15 13:55 567
 */
47fd5c32 Poul Sander 2024-10-05 08:44 568
inline auto gmtime(std::time_t time) -> std::tm {
f8deb5b9 Poul Sander 2022-01-15 13:55 569
  struct dispatcher {
f8deb5b9 Poul Sander 2022-01-15 13:55 570
    std::time_t time_;
f8deb5b9 Poul Sander 2022-01-15 13:55 571
    std::tm tm_;
f8deb5b9 Poul Sander 2022-01-15 13:55 572
f8deb5b9 Poul Sander 2022-01-15 13:55 573
    dispatcher(std::time_t t) : time_(t) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 574
47fd5c32 Poul Sander 2024-10-05 08:44 575
    auto run() -> bool {
f8deb5b9 Poul Sander 2022-01-15 13:55 576
      using namespace fmt::detail;
f8deb5b9 Poul Sander 2022-01-15 13:55 577
      return handle(gmtime_r(&time_, &tm_));
f8deb5b9 Poul Sander 2022-01-15 13:55 578
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 579
47fd5c32 Poul Sander 2024-10-05 08:44 580
    auto handle(std::tm* tm) -> bool { return tm != nullptr; }
f8deb5b9 Poul Sander 2022-01-15 13:55 581
47fd5c32 Poul Sander 2024-10-05 08:44 582
    auto handle(detail::null<>) -> bool {
f8deb5b9 Poul Sander 2022-01-15 13:55 583
      using namespace fmt::detail;
f8deb5b9 Poul Sander 2022-01-15 13:55 584
      return fallback(gmtime_s(&tm_, &time_));
f8deb5b9 Poul Sander 2022-01-15 13:55 585
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 586
47fd5c32 Poul Sander 2024-10-05 08:44 587
    auto fallback(int res) -> bool { return res == 0; }
f8deb5b9 Poul Sander 2022-01-15 13:55 588
47fd5c32 Poul Sander 2024-10-05 08:44 589
#if !FMT_MSC_VERSION
47fd5c32 Poul Sander 2024-10-05 08:44 590
    auto fallback(detail::null<>) -> bool {
f8deb5b9 Poul Sander 2022-01-15 13:55 591
      std::tm* tm = std::gmtime(&time_);
f8deb5b9 Poul Sander 2022-01-15 13:55 592
      if (tm) tm_ = *tm;
f8deb5b9 Poul Sander 2022-01-15 13:55 593
      return tm != nullptr;
f8deb5b9 Poul Sander 2022-01-15 13:55 594
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 595
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 596
  };
47fd5c32 Poul Sander 2024-10-05 08:44 597
  auto gt = dispatcher(time);
f8deb5b9 Poul Sander 2022-01-15 13:55 598
  // Too big time values may be unsupported.
f8deb5b9 Poul Sander 2022-01-15 13:55 599
  if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
f8deb5b9 Poul Sander 2022-01-15 13:55 600
  return gt.tm_;
f8deb5b9 Poul Sander 2022-01-15 13:55 601
}
f8deb5b9 Poul Sander 2022-01-15 13:55 602
47fd5c32 Poul Sander 2024-10-05 08:44 603
template <typename Duration>
47fd5c32 Poul Sander 2024-10-05 08:44 604
inline auto gmtime(
47fd5c32 Poul Sander 2024-10-05 08:44 605
    std::chrono::time_point<std::chrono::system_clock, Duration> time_point)
47fd5c32 Poul Sander 2024-10-05 08:44 606
    -> std::tm {
47fd5c32 Poul Sander 2024-10-05 08:44 607
  return gmtime(detail::to_time_t(time_point));
f8deb5b9 Poul Sander 2022-01-15 13:55 608
}
f8deb5b9 Poul Sander 2022-01-15 13:55 609
47fd5c32 Poul Sander 2024-10-05 08:44 610
namespace detail {
f8deb5b9 Poul Sander 2022-01-15 13:55 611
f8deb5b9 Poul Sander 2022-01-15 13:55 612
// Writes two-digit numbers a, b and c separated by sep to buf.
f8deb5b9 Poul Sander 2022-01-15 13:55 613
// The method by Pavel Novikov based on
f8deb5b9 Poul Sander 2022-01-15 13:55 614
// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/.
f8deb5b9 Poul Sander 2022-01-15 13:55 615
inline void write_digit2_separated(char* buf, unsigned a, unsigned b,
f8deb5b9 Poul Sander 2022-01-15 13:55 616
                                   unsigned c, char sep) {
f8deb5b9 Poul Sander 2022-01-15 13:55 617
  unsigned long long digits =
f8deb5b9 Poul Sander 2022-01-15 13:55 618
      a | (b << 24) | (static_cast<unsigned long long>(c) << 48);
f8deb5b9 Poul Sander 2022-01-15 13:55 619
  // Convert each value to BCD.
f8deb5b9 Poul Sander 2022-01-15 13:55 620
  // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b.
f8deb5b9 Poul Sander 2022-01-15 13:55 621
  // The difference is
f8deb5b9 Poul Sander 2022-01-15 13:55 622
  //   y - x = a * 6
f8deb5b9 Poul Sander 2022-01-15 13:55 623
  // a can be found from x:
f8deb5b9 Poul Sander 2022-01-15 13:55 624
  //   a = floor(x / 10)
f8deb5b9 Poul Sander 2022-01-15 13:55 625
  // then
f8deb5b9 Poul Sander 2022-01-15 13:55 626
  //   y = x + a * 6 = x + floor(x / 10) * 6
f8deb5b9 Poul Sander 2022-01-15 13:55 627
  // floor(x / 10) is (x * 205) >> 11 (needs 16 bits).
f8deb5b9 Poul Sander 2022-01-15 13:55 628
  digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6;
f8deb5b9 Poul Sander 2022-01-15 13:55 629
  // Put low nibbles to high bytes and high nibbles to low bytes.
f8deb5b9 Poul Sander 2022-01-15 13:55 630
  digits = ((digits & 0x00f00000f00000f0) >> 4) |
f8deb5b9 Poul Sander 2022-01-15 13:55 631
           ((digits & 0x000f00000f00000f) << 8);
f8deb5b9 Poul Sander 2022-01-15 13:55 632
  auto usep = static_cast<unsigned long long>(sep);
f8deb5b9 Poul Sander 2022-01-15 13:55 633
  // Add ASCII '0' to each digit byte and insert separators.
f8deb5b9 Poul Sander 2022-01-15 13:55 634
  digits |= 0x3030003030003030 | (usep << 16) | (usep << 40);
f8deb5b9 Poul Sander 2022-01-15 13:55 635
f8deb5b9 Poul Sander 2022-01-15 13:55 636
  constexpr const size_t len = 8;
f8deb5b9 Poul Sander 2022-01-15 13:55 637
  if (const_check(is_big_endian())) {
f8deb5b9 Poul Sander 2022-01-15 13:55 638
    char tmp[len];
47fd5c32 Poul Sander 2024-10-05 08:44 639
    std::memcpy(tmp, &digits, len);
f8deb5b9 Poul Sander 2022-01-15 13:55 640
    std::reverse_copy(tmp, tmp + len, buf);
f8deb5b9 Poul Sander 2022-01-15 13:55 641
  } else {
47fd5c32 Poul Sander 2024-10-05 08:44 642
    std::memcpy(buf, &digits, len);
f8deb5b9 Poul Sander 2022-01-15 13:55 643
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 644
}
f8deb5b9 Poul Sander 2022-01-15 13:55 645
47fd5c32 Poul Sander 2024-10-05 08:44 646
template <typename Period>
47fd5c32 Poul Sander 2024-10-05 08:44 647
FMT_CONSTEXPR inline auto get_units() -> const char* {
f8deb5b9 Poul Sander 2022-01-15 13:55 648
  if (std::is_same<Period, std::atto>::value) return "as";
f8deb5b9 Poul Sander 2022-01-15 13:55 649
  if (std::is_same<Period, std::femto>::value) return "fs";
f8deb5b9 Poul Sander 2022-01-15 13:55 650
  if (std::is_same<Period, std::pico>::value) return "ps";
f8deb5b9 Poul Sander 2022-01-15 13:55 651
  if (std::is_same<Period, std::nano>::value) return "ns";
f8deb5b9 Poul Sander 2022-01-15 13:55 652
  if (std::is_same<Period, std::micro>::value) return "µs";
f8deb5b9 Poul Sander 2022-01-15 13:55 653
  if (std::is_same<Period, std::milli>::value) return "ms";
f8deb5b9 Poul Sander 2022-01-15 13:55 654
  if (std::is_same<Period, std::centi>::value) return "cs";
f8deb5b9 Poul Sander 2022-01-15 13:55 655
  if (std::is_same<Period, std::deci>::value) return "ds";
f8deb5b9 Poul Sander 2022-01-15 13:55 656
  if (std::is_same<Period, std::ratio<1>>::value) return "s";
f8deb5b9 Poul Sander 2022-01-15 13:55 657
  if (std::is_same<Period, std::deca>::value) return "das";
f8deb5b9 Poul Sander 2022-01-15 13:55 658
  if (std::is_same<Period, std::hecto>::value) return "hs";
f8deb5b9 Poul Sander 2022-01-15 13:55 659
  if (std::is_same<Period, std::kilo>::value) return "ks";
f8deb5b9 Poul Sander 2022-01-15 13:55 660
  if (std::is_same<Period, std::mega>::value) return "Ms";
f8deb5b9 Poul Sander 2022-01-15 13:55 661
  if (std::is_same<Period, std::giga>::value) return "Gs";
f8deb5b9 Poul Sander 2022-01-15 13:55 662
  if (std::is_same<Period, std::tera>::value) return "Ts";
f8deb5b9 Poul Sander 2022-01-15 13:55 663
  if (std::is_same<Period, std::peta>::value) return "Ps";
f8deb5b9 Poul Sander 2022-01-15 13:55 664
  if (std::is_same<Period, std::exa>::value) return "Es";
47fd5c32 Poul Sander 2024-10-05 08:44 665
  if (std::is_same<Period, std::ratio<60>>::value) return "min";
f8deb5b9 Poul Sander 2022-01-15 13:55 666
  if (std::is_same<Period, std::ratio<3600>>::value) return "h";
47fd5c32 Poul Sander 2024-10-05 08:44 667
  if (std::is_same<Period, std::ratio<86400>>::value) return "d";
f8deb5b9 Poul Sander 2022-01-15 13:55 668
  return nullptr;
f8deb5b9 Poul Sander 2022-01-15 13:55 669
}
f8deb5b9 Poul Sander 2022-01-15 13:55 670
f8deb5b9 Poul Sander 2022-01-15 13:55 671
enum class numeric_system {
f8deb5b9 Poul Sander 2022-01-15 13:55 672
  standard,
f8deb5b9 Poul Sander 2022-01-15 13:55 673
  // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
f8deb5b9 Poul Sander 2022-01-15 13:55 674
  alternative
f8deb5b9 Poul Sander 2022-01-15 13:55 675
};
f8deb5b9 Poul Sander 2022-01-15 13:55 676
47fd5c32 Poul Sander 2024-10-05 08:44 677
// Glibc extensions for formatting numeric values.
47fd5c32 Poul Sander 2024-10-05 08:44 678
enum class pad_type {
47fd5c32 Poul Sander 2024-10-05 08:44 679
  // Pad a numeric result string with zeros (the default).
47fd5c32 Poul Sander 2024-10-05 08:44 680
  zero,
47fd5c32 Poul Sander 2024-10-05 08:44 681
  // Do not pad a numeric result string.
47fd5c32 Poul Sander 2024-10-05 08:44 682
  none,
47fd5c32 Poul Sander 2024-10-05 08:44 683
  // Pad a numeric result string with spaces.
47fd5c32 Poul Sander 2024-10-05 08:44 684
  space,
47fd5c32 Poul Sander 2024-10-05 08:44 685
};
47fd5c32 Poul Sander 2024-10-05 08:44 686
47fd5c32 Poul Sander 2024-10-05 08:44 687
template <typename OutputIt>
47fd5c32 Poul Sander 2024-10-05 08:44 688
auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt {
47fd5c32 Poul Sander 2024-10-05 08:44 689
  if (pad == pad_type::none) return out;
47fd5c32 Poul Sander 2024-10-05 08:44 690
  return detail::fill_n(out, width, pad == pad_type::space ? ' ' : '0');
47fd5c32 Poul Sander 2024-10-05 08:44 691
}
47fd5c32 Poul Sander 2024-10-05 08:44 692
47fd5c32 Poul Sander 2024-10-05 08:44 693
template <typename OutputIt>
47fd5c32 Poul Sander 2024-10-05 08:44 694
auto write_padding(OutputIt out, pad_type pad) -> OutputIt {
47fd5c32 Poul Sander 2024-10-05 08:44 695
  if (pad != pad_type::none) *out++ = pad == pad_type::space ? ' ' : '0';
47fd5c32 Poul Sander 2024-10-05 08:44 696
  return out;
47fd5c32 Poul Sander 2024-10-05 08:44 697
}
47fd5c32 Poul Sander 2024-10-05 08:44 698
f8deb5b9 Poul Sander 2022-01-15 13:55 699
// Parses a put_time-like format string and invokes handler actions.
f8deb5b9 Poul Sander 2022-01-15 13:55 700
template <typename Char, typename Handler>
47fd5c32 Poul Sander 2024-10-05 08:44 701
FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end,
47fd5c32 Poul Sander 2024-10-05 08:44 702
                                       Handler&& handler) -> const Char* {
47fd5c32 Poul Sander 2024-10-05 08:44 703
  if (begin == end || *begin == '}') return begin;
47fd5c32 Poul Sander 2024-10-05 08:44 704
  if (*begin != '%') FMT_THROW(format_error("invalid format"));
f8deb5b9 Poul Sander 2022-01-15 13:55 705
  auto ptr = begin;
f8deb5b9 Poul Sander 2022-01-15 13:55 706
  while (ptr != end) {
47fd5c32 Poul Sander 2024-10-05 08:44 707
    pad_type pad = pad_type::zero;
f8deb5b9 Poul Sander 2022-01-15 13:55 708
    auto c = *ptr;
f8deb5b9 Poul Sander 2022-01-15 13:55 709
    if (c == '}') break;
f8deb5b9 Poul Sander 2022-01-15 13:55 710
    if (c != '%') {
f8deb5b9 Poul Sander 2022-01-15 13:55 711
      ++ptr;
f8deb5b9 Poul Sander 2022-01-15 13:55 712
      continue;
f8deb5b9 Poul Sander 2022-01-15 13:55 713
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 714
    if (begin != ptr) handler.on_text(begin, ptr);
f8deb5b9 Poul Sander 2022-01-15 13:55 715
    ++ptr;  // consume '%'
f8deb5b9 Poul Sander 2022-01-15 13:55 716
    if (ptr == end) FMT_THROW(format_error("invalid format"));
47fd5c32 Poul Sander 2024-10-05 08:44 717
    c = *ptr;
47fd5c32 Poul Sander 2024-10-05 08:44 718
    switch (c) {
47fd5c32 Poul Sander 2024-10-05 08:44 719
    case '_':
47fd5c32 Poul Sander 2024-10-05 08:44 720
      pad = pad_type::space;
47fd5c32 Poul Sander 2024-10-05 08:44 721
      ++ptr;
47fd5c32 Poul Sander 2024-10-05 08:44 722
      break;
47fd5c32 Poul Sander 2024-10-05 08:44 723
    case '-':
47fd5c32 Poul Sander 2024-10-05 08:44 724
      pad = pad_type::none;
47fd5c32 Poul Sander 2024-10-05 08:44 725
      ++ptr;
47fd5c32 Poul Sander 2024-10-05 08:44 726
      break;
47fd5c32 Poul Sander 2024-10-05 08:44 727
    }
47fd5c32 Poul Sander 2024-10-05 08:44 728
    if (ptr == end) FMT_THROW(format_error("invalid format"));
f8deb5b9 Poul Sander 2022-01-15 13:55 729
    c = *ptr++;
f8deb5b9 Poul Sander 2022-01-15 13:55 730
    switch (c) {
f8deb5b9 Poul Sander 2022-01-15 13:55 731
    case '%':
f8deb5b9 Poul Sander 2022-01-15 13:55 732
      handler.on_text(ptr - 1, ptr);
f8deb5b9 Poul Sander 2022-01-15 13:55 733
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 734
    case 'n': {
f8deb5b9 Poul Sander 2022-01-15 13:55 735
      const Char newline[] = {'\n'};
f8deb5b9 Poul Sander 2022-01-15 13:55 736
      handler.on_text(newline, newline + 1);
f8deb5b9 Poul Sander 2022-01-15 13:55 737
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 738
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 739
    case 't': {
f8deb5b9 Poul Sander 2022-01-15 13:55 740
      const Char tab[] = {'\t'};
f8deb5b9 Poul Sander 2022-01-15 13:55 741
      handler.on_text(tab, tab + 1);
f8deb5b9 Poul Sander 2022-01-15 13:55 742
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 743
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 744
    // Year:
f8deb5b9 Poul Sander 2022-01-15 13:55 745
    case 'Y':
f8deb5b9 Poul Sander 2022-01-15 13:55 746
      handler.on_year(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 747
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 748
    case 'y':
f8deb5b9 Poul Sander 2022-01-15 13:55 749
      handler.on_short_year(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 750
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 751
    case 'C':
f8deb5b9 Poul Sander 2022-01-15 13:55 752
      handler.on_century(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 753
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 754
    case 'G':
f8deb5b9 Poul Sander 2022-01-15 13:55 755
      handler.on_iso_week_based_year();
f8deb5b9 Poul Sander 2022-01-15 13:55 756
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 757
    case 'g':
f8deb5b9 Poul Sander 2022-01-15 13:55 758
      handler.on_iso_week_based_short_year();
f8deb5b9 Poul Sander 2022-01-15 13:55 759
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 760
    // Day of the week:
f8deb5b9 Poul Sander 2022-01-15 13:55 761
    case 'a':
f8deb5b9 Poul Sander 2022-01-15 13:55 762
      handler.on_abbr_weekday();
f8deb5b9 Poul Sander 2022-01-15 13:55 763
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 764
    case 'A':
f8deb5b9 Poul Sander 2022-01-15 13:55 765
      handler.on_full_weekday();
f8deb5b9 Poul Sander 2022-01-15 13:55 766
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 767
    case 'w':
f8deb5b9 Poul Sander 2022-01-15 13:55 768
      handler.on_dec0_weekday(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 769
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 770
    case 'u':
f8deb5b9 Poul Sander 2022-01-15 13:55 771
      handler.on_dec1_weekday(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 772
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 773
    // Month:
f8deb5b9 Poul Sander 2022-01-15 13:55 774
    case 'b':
f8deb5b9 Poul Sander 2022-01-15 13:55 775
    case 'h':
f8deb5b9 Poul Sander 2022-01-15 13:55 776
      handler.on_abbr_month();
f8deb5b9 Poul Sander 2022-01-15 13:55 777
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 778
    case 'B':
f8deb5b9 Poul Sander 2022-01-15 13:55 779
      handler.on_full_month();
f8deb5b9 Poul Sander 2022-01-15 13:55 780
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 781
    case 'm':
f8deb5b9 Poul Sander 2022-01-15 13:55 782
      handler.on_dec_month(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 783
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 784
    // Day of the year/month:
f8deb5b9 Poul Sander 2022-01-15 13:55 785
    case 'U':
47fd5c32 Poul Sander 2024-10-05 08:44 786
      handler.on_dec0_week_of_year(numeric_system::standard, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 787
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 788
    case 'W':
47fd5c32 Poul Sander 2024-10-05 08:44 789
      handler.on_dec1_week_of_year(numeric_system::standard, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 790
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 791
    case 'V':
47fd5c32 Poul Sander 2024-10-05 08:44 792
      handler.on_iso_week_of_year(numeric_system::standard, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 793
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 794
    case 'j':
f8deb5b9 Poul Sander 2022-01-15 13:55 795
      handler.on_day_of_year();
f8deb5b9 Poul Sander 2022-01-15 13:55 796
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 797
    case 'd':
47fd5c32 Poul Sander 2024-10-05 08:44 798
      handler.on_day_of_month(numeric_system::standard, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 799
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 800
    case 'e':
47fd5c32 Poul Sander 2024-10-05 08:44 801
      handler.on_day_of_month(numeric_system::standard, pad_type::space);
f8deb5b9 Poul Sander 2022-01-15 13:55 802
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 803
    // Hour, minute, second:
f8deb5b9 Poul Sander 2022-01-15 13:55 804
    case 'H':
47fd5c32 Poul Sander 2024-10-05 08:44 805
      handler.on_24_hour(numeric_system::standard, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 806
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 807
    case 'I':
47fd5c32 Poul Sander 2024-10-05 08:44 808
      handler.on_12_hour(numeric_system::standard, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 809
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 810
    case 'M':
47fd5c32 Poul Sander 2024-10-05 08:44 811
      handler.on_minute(numeric_system::standard, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 812
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 813
    case 'S':
47fd5c32 Poul Sander 2024-10-05 08:44 814
      handler.on_second(numeric_system::standard, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 815
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 816
    // Other:
f8deb5b9 Poul Sander 2022-01-15 13:55 817
    case 'c':
f8deb5b9 Poul Sander 2022-01-15 13:55 818
      handler.on_datetime(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 819
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 820
    case 'x':
f8deb5b9 Poul Sander 2022-01-15 13:55 821
      handler.on_loc_date(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 822
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 823
    case 'X':
f8deb5b9 Poul Sander 2022-01-15 13:55 824
      handler.on_loc_time(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 825
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 826
    case 'D':
f8deb5b9 Poul Sander 2022-01-15 13:55 827
      handler.on_us_date();
f8deb5b9 Poul Sander 2022-01-15 13:55 828
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 829
    case 'F':
f8deb5b9 Poul Sander 2022-01-15 13:55 830
      handler.on_iso_date();
f8deb5b9 Poul Sander 2022-01-15 13:55 831
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 832
    case 'r':
f8deb5b9 Poul Sander 2022-01-15 13:55 833
      handler.on_12_hour_time();
f8deb5b9 Poul Sander 2022-01-15 13:55 834
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 835
    case 'R':
f8deb5b9 Poul Sander 2022-01-15 13:55 836
      handler.on_24_hour_time();
f8deb5b9 Poul Sander 2022-01-15 13:55 837
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 838
    case 'T':
f8deb5b9 Poul Sander 2022-01-15 13:55 839
      handler.on_iso_time();
f8deb5b9 Poul Sander 2022-01-15 13:55 840
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 841
    case 'p':
f8deb5b9 Poul Sander 2022-01-15 13:55 842
      handler.on_am_pm();
f8deb5b9 Poul Sander 2022-01-15 13:55 843
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 844
    case 'Q':
f8deb5b9 Poul Sander 2022-01-15 13:55 845
      handler.on_duration_value();
f8deb5b9 Poul Sander 2022-01-15 13:55 846
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 847
    case 'q':
f8deb5b9 Poul Sander 2022-01-15 13:55 848
      handler.on_duration_unit();
f8deb5b9 Poul Sander 2022-01-15 13:55 849
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 850
    case 'z':
47fd5c32 Poul Sander 2024-10-05 08:44 851
      handler.on_utc_offset(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 852
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 853
    case 'Z':
f8deb5b9 Poul Sander 2022-01-15 13:55 854
      handler.on_tz_name();
f8deb5b9 Poul Sander 2022-01-15 13:55 855
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 856
    // Alternative representation:
f8deb5b9 Poul Sander 2022-01-15 13:55 857
    case 'E': {
f8deb5b9 Poul Sander 2022-01-15 13:55 858
      if (ptr == end) FMT_THROW(format_error("invalid format"));
f8deb5b9 Poul Sander 2022-01-15 13:55 859
      c = *ptr++;
f8deb5b9 Poul Sander 2022-01-15 13:55 860
      switch (c) {
f8deb5b9 Poul Sander 2022-01-15 13:55 861
      case 'Y':
f8deb5b9 Poul Sander 2022-01-15 13:55 862
        handler.on_year(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 863
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 864
      case 'y':
f8deb5b9 Poul Sander 2022-01-15 13:55 865
        handler.on_offset_year();
f8deb5b9 Poul Sander 2022-01-15 13:55 866
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 867
      case 'C':
f8deb5b9 Poul Sander 2022-01-15 13:55 868
        handler.on_century(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 869
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 870
      case 'c':
f8deb5b9 Poul Sander 2022-01-15 13:55 871
        handler.on_datetime(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 872
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 873
      case 'x':
f8deb5b9 Poul Sander 2022-01-15 13:55 874
        handler.on_loc_date(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 875
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 876
      case 'X':
f8deb5b9 Poul Sander 2022-01-15 13:55 877
        handler.on_loc_time(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 878
        break;
47fd5c32 Poul Sander 2024-10-05 08:44 879
      case 'z':
47fd5c32 Poul Sander 2024-10-05 08:44 880
        handler.on_utc_offset(numeric_system::alternative);
47fd5c32 Poul Sander 2024-10-05 08:44 881
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 882
      default:
f8deb5b9 Poul Sander 2022-01-15 13:55 883
        FMT_THROW(format_error("invalid format"));
f8deb5b9 Poul Sander 2022-01-15 13:55 884
      }
f8deb5b9 Poul Sander 2022-01-15 13:55 885
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 886
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 887
    case 'O':
f8deb5b9 Poul Sander 2022-01-15 13:55 888
      if (ptr == end) FMT_THROW(format_error("invalid format"));
f8deb5b9 Poul Sander 2022-01-15 13:55 889
      c = *ptr++;
f8deb5b9 Poul Sander 2022-01-15 13:55 890
      switch (c) {
f8deb5b9 Poul Sander 2022-01-15 13:55 891
      case 'y':
f8deb5b9 Poul Sander 2022-01-15 13:55 892
        handler.on_short_year(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 893
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 894
      case 'm':
f8deb5b9 Poul Sander 2022-01-15 13:55 895
        handler.on_dec_month(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 896
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 897
      case 'U':
47fd5c32 Poul Sander 2024-10-05 08:44 898
        handler.on_dec0_week_of_year(numeric_system::alternative, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 899
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 900
      case 'W':
47fd5c32 Poul Sander 2024-10-05 08:44 901
        handler.on_dec1_week_of_year(numeric_system::alternative, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 902
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 903
      case 'V':
47fd5c32 Poul Sander 2024-10-05 08:44 904
        handler.on_iso_week_of_year(numeric_system::alternative, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 905
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 906
      case 'd':
47fd5c32 Poul Sander 2024-10-05 08:44 907
        handler.on_day_of_month(numeric_system::alternative, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 908
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 909
      case 'e':
47fd5c32 Poul Sander 2024-10-05 08:44 910
        handler.on_day_of_month(numeric_system::alternative, pad_type::space);
f8deb5b9 Poul Sander 2022-01-15 13:55 911
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 912
      case 'w':
f8deb5b9 Poul Sander 2022-01-15 13:55 913
        handler.on_dec0_weekday(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 914
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 915
      case 'u':
f8deb5b9 Poul Sander 2022-01-15 13:55 916
        handler.on_dec1_weekday(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 917
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 918
      case 'H':
47fd5c32 Poul Sander 2024-10-05 08:44 919
        handler.on_24_hour(numeric_system::alternative, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 920
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 921
      case 'I':
47fd5c32 Poul Sander 2024-10-05 08:44 922
        handler.on_12_hour(numeric_system::alternative, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 923
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 924
      case 'M':
47fd5c32 Poul Sander 2024-10-05 08:44 925
        handler.on_minute(numeric_system::alternative, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 926
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 927
      case 'S':
47fd5c32 Poul Sander 2024-10-05 08:44 928
        handler.on_second(numeric_system::alternative, pad);
47fd5c32 Poul Sander 2024-10-05 08:44 929
        break;
47fd5c32 Poul Sander 2024-10-05 08:44 930
      case 'z':
47fd5c32 Poul Sander 2024-10-05 08:44 931
        handler.on_utc_offset(numeric_system::alternative);
f8deb5b9 Poul Sander 2022-01-15 13:55 932
        break;
f8deb5b9 Poul Sander 2022-01-15 13:55 933
      default:
f8deb5b9 Poul Sander 2022-01-15 13:55 934
        FMT_THROW(format_error("invalid format"));
f8deb5b9 Poul Sander 2022-01-15 13:55 935
      }
f8deb5b9 Poul Sander 2022-01-15 13:55 936
      break;
f8deb5b9 Poul Sander 2022-01-15 13:55 937
    default:
f8deb5b9 Poul Sander 2022-01-15 13:55 938
      FMT_THROW(format_error("invalid format"));
f8deb5b9 Poul Sander 2022-01-15 13:55 939
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 940
    begin = ptr;
f8deb5b9 Poul Sander 2022-01-15 13:55 941
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 942
  if (begin != ptr) handler.on_text(begin, ptr);
f8deb5b9 Poul Sander 2022-01-15 13:55 943
  return ptr;
f8deb5b9 Poul Sander 2022-01-15 13:55 944
}
f8deb5b9 Poul Sander 2022-01-15 13:55 945
f8deb5b9 Poul Sander 2022-01-15 13:55 946
template <typename Derived> struct null_chrono_spec_handler {
f8deb5b9 Poul Sander 2022-01-15 13:55 947
  FMT_CONSTEXPR void unsupported() {
f8deb5b9 Poul Sander 2022-01-15 13:55 948
    static_cast<Derived*>(this)->unsupported();
f8deb5b9 Poul Sander 2022-01-15 13:55 949
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 950
  FMT_CONSTEXPR void on_year(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 951
  FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 952
  FMT_CONSTEXPR void on_offset_year() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 953
  FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 954
  FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 955
  FMT_CONSTEXPR void on_iso_week_based_short_year() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 956
  FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 957
  FMT_CONSTEXPR void on_full_weekday() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 958
  FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 959
  FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 960
  FMT_CONSTEXPR void on_abbr_month() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 961
  FMT_CONSTEXPR void on_full_month() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 962
  FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); }
47fd5c32 Poul Sander 2024-10-05 08:44 963
  FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) {
47fd5c32 Poul Sander 2024-10-05 08:44 964
    unsupported();
47fd5c32 Poul Sander 2024-10-05 08:44 965
  }
47fd5c32 Poul Sander 2024-10-05 08:44 966
  FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) {
47fd5c32 Poul Sander 2024-10-05 08:44 967
    unsupported();
47fd5c32 Poul Sander 2024-10-05 08:44 968
  }
47fd5c32 Poul Sander 2024-10-05 08:44 969
  FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) {
47fd5c32 Poul Sander 2024-10-05 08:44 970
    unsupported();
47fd5c32 Poul Sander 2024-10-05 08:44 971
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 972
  FMT_CONSTEXPR void on_day_of_year() { unsupported(); }
47fd5c32 Poul Sander 2024-10-05 08:44 973
  FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) {
47fd5c32 Poul Sander 2024-10-05 08:44 974
    unsupported();
47fd5c32 Poul Sander 2024-10-05 08:44 975
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 976
  FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 977
  FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 978
  FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 979
  FMT_CONSTEXPR void on_second(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 980
  FMT_CONSTEXPR void on_datetime(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 981
  FMT_CONSTEXPR void on_loc_date(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 982
  FMT_CONSTEXPR void on_loc_time(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 983
  FMT_CONSTEXPR void on_us_date() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 984
  FMT_CONSTEXPR void on_iso_date() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 985
  FMT_CONSTEXPR void on_12_hour_time() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 986
  FMT_CONSTEXPR void on_24_hour_time() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 987
  FMT_CONSTEXPR void on_iso_time() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 988
  FMT_CONSTEXPR void on_am_pm() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 989
  FMT_CONSTEXPR void on_duration_value() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 990
  FMT_CONSTEXPR void on_duration_unit() { unsupported(); }
47fd5c32 Poul Sander 2024-10-05 08:44 991
  FMT_CONSTEXPR void on_utc_offset(numeric_system) { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 992
  FMT_CONSTEXPR void on_tz_name() { unsupported(); }
f8deb5b9 Poul Sander 2022-01-15 13:55 993
};
f8deb5b9 Poul Sander 2022-01-15 13:55 994
f8deb5b9 Poul Sander 2022-01-15 13:55 995
struct tm_format_checker : null_chrono_spec_handler<tm_format_checker> {
f8deb5b9 Poul Sander 2022-01-15 13:55 996
  FMT_NORETURN void unsupported() { FMT_THROW(format_error("no format")); }
f8deb5b9 Poul Sander 2022-01-15 13:55 997
f8deb5b9 Poul Sander 2022-01-15 13:55 998
  template <typename Char>
f8deb5b9 Poul Sander 2022-01-15 13:55 999
  FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1000
  FMT_CONSTEXPR void on_year(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1001
  FMT_CONSTEXPR void on_short_year(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1002
  FMT_CONSTEXPR void on_offset_year() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1003
  FMT_CONSTEXPR void on_century(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1004
  FMT_CONSTEXPR void on_iso_week_based_year() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1005
  FMT_CONSTEXPR void on_iso_week_based_short_year() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1006
  FMT_CONSTEXPR void on_abbr_weekday() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1007
  FMT_CONSTEXPR void on_full_weekday() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1008
  FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1009
  FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1010
  FMT_CONSTEXPR void on_abbr_month() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1011
  FMT_CONSTEXPR void on_full_month() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1012
  FMT_CONSTEXPR void on_dec_month(numeric_system) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1013
  FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1014
  FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1015
  FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1016
  FMT_CONSTEXPR void on_day_of_year() {}
47fd5c32 Poul Sander 2024-10-05 08:44 1017
  FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1018
  FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1019
  FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1020
  FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1021
  FMT_CONSTEXPR void on_second(numeric_system, pad_type) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1022
  FMT_CONSTEXPR void on_datetime(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1023
  FMT_CONSTEXPR void on_loc_date(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1024
  FMT_CONSTEXPR void on_loc_time(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1025
  FMT_CONSTEXPR void on_us_date() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1026
  FMT_CONSTEXPR void on_iso_date() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1027
  FMT_CONSTEXPR void on_12_hour_time() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1028
  FMT_CONSTEXPR void on_24_hour_time() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1029
  FMT_CONSTEXPR void on_iso_time() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1030
  FMT_CONSTEXPR void on_am_pm() {}
47fd5c32 Poul Sander 2024-10-05 08:44 1031
  FMT_CONSTEXPR void on_utc_offset(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1032
  FMT_CONSTEXPR void on_tz_name() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1033
};
f8deb5b9 Poul Sander 2022-01-15 13:55 1034
47fd5c32 Poul Sander 2024-10-05 08:44 1035
inline auto tm_wday_full_name(int wday) -> const char* {
f8deb5b9 Poul Sander 2022-01-15 13:55 1036
  static constexpr const char* full_name_list[] = {
f8deb5b9 Poul Sander 2022-01-15 13:55 1037
      "Sunday",   "Monday", "Tuesday", "Wednesday",
f8deb5b9 Poul Sander 2022-01-15 13:55 1038
      "Thursday", "Friday", "Saturday"};
f8deb5b9 Poul Sander 2022-01-15 13:55 1039
  return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?";
f8deb5b9 Poul Sander 2022-01-15 13:55 1040
}
47fd5c32 Poul Sander 2024-10-05 08:44 1041
inline auto tm_wday_short_name(int wday) -> const char* {
f8deb5b9 Poul Sander 2022-01-15 13:55 1042
  static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed",
f8deb5b9 Poul Sander 2022-01-15 13:55 1043
                                                    "Thu", "Fri", "Sat"};
f8deb5b9 Poul Sander 2022-01-15 13:55 1044
  return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???";
f8deb5b9 Poul Sander 2022-01-15 13:55 1045
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1046
47fd5c32 Poul Sander 2024-10-05 08:44 1047
inline auto tm_mon_full_name(int mon) -> const char* {
f8deb5b9 Poul Sander 2022-01-15 13:55 1048
  static constexpr const char* full_name_list[] = {
f8deb5b9 Poul Sander 2022-01-15 13:55 1049
      "January", "February", "March",     "April",   "May",      "June",
f8deb5b9 Poul Sander 2022-01-15 13:55 1050
      "July",    "August",   "September", "October", "November", "December"};
f8deb5b9 Poul Sander 2022-01-15 13:55 1051
  return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?";
f8deb5b9 Poul Sander 2022-01-15 13:55 1052
}
47fd5c32 Poul Sander 2024-10-05 08:44 1053
inline auto tm_mon_short_name(int mon) -> const char* {
f8deb5b9 Poul Sander 2022-01-15 13:55 1054
  static constexpr const char* short_name_list[] = {
f8deb5b9 Poul Sander 2022-01-15 13:55 1055
      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
f8deb5b9 Poul Sander 2022-01-15 13:55 1056
      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
f8deb5b9 Poul Sander 2022-01-15 13:55 1057
  };
f8deb5b9 Poul Sander 2022-01-15 13:55 1058
  return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???";
f8deb5b9 Poul Sander 2022-01-15 13:55 1059
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1060
f8deb5b9 Poul Sander 2022-01-15 13:55 1061
template <typename T, typename = void>
f8deb5b9 Poul Sander 2022-01-15 13:55 1062
struct has_member_data_tm_gmtoff : std::false_type {};
f8deb5b9 Poul Sander 2022-01-15 13:55 1063
template <typename T>
f8deb5b9 Poul Sander 2022-01-15 13:55 1064
struct has_member_data_tm_gmtoff<T, void_t<decltype(T::tm_gmtoff)>>
f8deb5b9 Poul Sander 2022-01-15 13:55 1065
    : std::true_type {};
f8deb5b9 Poul Sander 2022-01-15 13:55 1066
f8deb5b9 Poul Sander 2022-01-15 13:55 1067
template <typename T, typename = void>
f8deb5b9 Poul Sander 2022-01-15 13:55 1068
struct has_member_data_tm_zone : std::false_type {};
f8deb5b9 Poul Sander 2022-01-15 13:55 1069
template <typename T>
f8deb5b9 Poul Sander 2022-01-15 13:55 1070
struct has_member_data_tm_zone<T, void_t<decltype(T::tm_zone)>>
f8deb5b9 Poul Sander 2022-01-15 13:55 1071
    : std::true_type {};
f8deb5b9 Poul Sander 2022-01-15 13:55 1072
f8deb5b9 Poul Sander 2022-01-15 13:55 1073
#if FMT_USE_TZSET
f8deb5b9 Poul Sander 2022-01-15 13:55 1074
inline void tzset_once() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1075
  static bool init = []() -> bool {
f8deb5b9 Poul Sander 2022-01-15 13:55 1076
    _tzset();
f8deb5b9 Poul Sander 2022-01-15 13:55 1077
    return true;
f8deb5b9 Poul Sander 2022-01-15 13:55 1078
  }();
f8deb5b9 Poul Sander 2022-01-15 13:55 1079
  ignore_unused(init);
f8deb5b9 Poul Sander 2022-01-15 13:55 1080
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1081
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 1082
47fd5c32 Poul Sander 2024-10-05 08:44 1083
// Converts value to Int and checks that it's in the range [0, upper).
47fd5c32 Poul Sander 2024-10-05 08:44 1084
template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1085
inline auto to_nonnegative_int(T value, Int upper) -> Int {
47fd5c32 Poul Sander 2024-10-05 08:44 1086
  if (!std::is_unsigned<Int>::value &&
47fd5c32 Poul Sander 2024-10-05 08:44 1087
      (value < 0 || to_unsigned(value) > to_unsigned(upper))) {
47fd5c32 Poul Sander 2024-10-05 08:44 1088
    FMT_THROW(fmt::format_error("chrono value is out of range"));
47fd5c32 Poul Sander 2024-10-05 08:44 1089
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1090
  return static_cast<Int>(value);
47fd5c32 Poul Sander 2024-10-05 08:44 1091
}
47fd5c32 Poul Sander 2024-10-05 08:44 1092
template <typename T, typename Int, FMT_ENABLE_IF(!std::is_integral<T>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1093
inline auto to_nonnegative_int(T value, Int upper) -> Int {
47fd5c32 Poul Sander 2024-10-05 08:44 1094
  auto int_value = static_cast<Int>(value);
47fd5c32 Poul Sander 2024-10-05 08:44 1095
  if (int_value < 0 || value > static_cast<T>(upper))
47fd5c32 Poul Sander 2024-10-05 08:44 1096
    FMT_THROW(format_error("invalid value"));
47fd5c32 Poul Sander 2024-10-05 08:44 1097
  return int_value;
47fd5c32 Poul Sander 2024-10-05 08:44 1098
}
47fd5c32 Poul Sander 2024-10-05 08:44 1099
47fd5c32 Poul Sander 2024-10-05 08:44 1100
constexpr auto pow10(std::uint32_t n) -> long long {
47fd5c32 Poul Sander 2024-10-05 08:44 1101
  return n == 0 ? 1 : 10 * pow10(n - 1);
47fd5c32 Poul Sander 2024-10-05 08:44 1102
}
47fd5c32 Poul Sander 2024-10-05 08:44 1103
47fd5c32 Poul Sander 2024-10-05 08:44 1104
// Counts the number of fractional digits in the range [0, 18] according to the
47fd5c32 Poul Sander 2024-10-05 08:44 1105
// C++20 spec. If more than 18 fractional digits are required then returns 6 for
47fd5c32 Poul Sander 2024-10-05 08:44 1106
// microseconds precision.
47fd5c32 Poul Sander 2024-10-05 08:44 1107
template <long long Num, long long Den, int N = 0,
47fd5c32 Poul Sander 2024-10-05 08:44 1108
          bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
47fd5c32 Poul Sander 2024-10-05 08:44 1109
struct count_fractional_digits {
47fd5c32 Poul Sander 2024-10-05 08:44 1110
  static constexpr int value =
47fd5c32 Poul Sander 2024-10-05 08:44 1111
      Num % Den == 0 ? N : count_fractional_digits<Num * 10, Den, N + 1>::value;
47fd5c32 Poul Sander 2024-10-05 08:44 1112
};
47fd5c32 Poul Sander 2024-10-05 08:44 1113
47fd5c32 Poul Sander 2024-10-05 08:44 1114
// Base case that doesn't instantiate any more templates
47fd5c32 Poul Sander 2024-10-05 08:44 1115
// in order to avoid overflow.
47fd5c32 Poul Sander 2024-10-05 08:44 1116
template <long long Num, long long Den, int N>
47fd5c32 Poul Sander 2024-10-05 08:44 1117
struct count_fractional_digits<Num, Den, N, false> {
47fd5c32 Poul Sander 2024-10-05 08:44 1118
  static constexpr int value = (Num % Den == 0) ? N : 6;
47fd5c32 Poul Sander 2024-10-05 08:44 1119
};
47fd5c32 Poul Sander 2024-10-05 08:44 1120
47fd5c32 Poul Sander 2024-10-05 08:44 1121
// Format subseconds which are given as an integer type with an appropriate
47fd5c32 Poul Sander 2024-10-05 08:44 1122
// number of digits.
47fd5c32 Poul Sander 2024-10-05 08:44 1123
template <typename Char, typename OutputIt, typename Duration>
47fd5c32 Poul Sander 2024-10-05 08:44 1124
void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) {
47fd5c32 Poul Sander 2024-10-05 08:44 1125
  constexpr auto num_fractional_digits =
47fd5c32 Poul Sander 2024-10-05 08:44 1126
      count_fractional_digits<Duration::period::num,
47fd5c32 Poul Sander 2024-10-05 08:44 1127
                              Duration::period::den>::value;
47fd5c32 Poul Sander 2024-10-05 08:44 1128
47fd5c32 Poul Sander 2024-10-05 08:44 1129
  using subsecond_precision = std::chrono::duration<
47fd5c32 Poul Sander 2024-10-05 08:44 1130
      typename std::common_type<typename Duration::rep,
47fd5c32 Poul Sander 2024-10-05 08:44 1131
                                std::chrono::seconds::rep>::type,
47fd5c32 Poul Sander 2024-10-05 08:44 1132
      std::ratio<1, detail::pow10(num_fractional_digits)>>;
47fd5c32 Poul Sander 2024-10-05 08:44 1133
47fd5c32 Poul Sander 2024-10-05 08:44 1134
  const auto fractional = d - fmt_duration_cast<std::chrono::seconds>(d);
47fd5c32 Poul Sander 2024-10-05 08:44 1135
  const auto subseconds =
47fd5c32 Poul Sander 2024-10-05 08:44 1136
      std::chrono::treat_as_floating_point<
47fd5c32 Poul Sander 2024-10-05 08:44 1137
          typename subsecond_precision::rep>::value
47fd5c32 Poul Sander 2024-10-05 08:44 1138
          ? fractional.count()
47fd5c32 Poul Sander 2024-10-05 08:44 1139
          : fmt_duration_cast<subsecond_precision>(fractional).count();
47fd5c32 Poul Sander 2024-10-05 08:44 1140
  auto n = static_cast<uint32_or_64_or_128_t<long long>>(subseconds);
47fd5c32 Poul Sander 2024-10-05 08:44 1141
  const int num_digits = detail::count_digits(n);
47fd5c32 Poul Sander 2024-10-05 08:44 1142
47fd5c32 Poul Sander 2024-10-05 08:44 1143
  int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits);
47fd5c32 Poul Sander 2024-10-05 08:44 1144
  if (precision < 0) {
47fd5c32 Poul Sander 2024-10-05 08:44 1145
    FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value, "");
47fd5c32 Poul Sander 2024-10-05 08:44 1146
    if (std::ratio_less<typename subsecond_precision::period,
47fd5c32 Poul Sander 2024-10-05 08:44 1147
                        std::chrono::seconds::period>::value) {
47fd5c32 Poul Sander 2024-10-05 08:44 1148
      *out++ = '.';
47fd5c32 Poul Sander 2024-10-05 08:44 1149
      out = detail::fill_n(out, leading_zeroes, '0');
47fd5c32 Poul Sander 2024-10-05 08:44 1150
      out = format_decimal<Char>(out, n, num_digits).end;
47fd5c32 Poul Sander 2024-10-05 08:44 1151
    }
47fd5c32 Poul Sander 2024-10-05 08:44 1152
  } else if (precision > 0) {
47fd5c32 Poul Sander 2024-10-05 08:44 1153
    *out++ = '.';
47fd5c32 Poul Sander 2024-10-05 08:44 1154
    leading_zeroes = (std::min)(leading_zeroes, precision);
47fd5c32 Poul Sander 2024-10-05 08:44 1155
    int remaining = precision - leading_zeroes;
47fd5c32 Poul Sander 2024-10-05 08:44 1156
    out = detail::fill_n(out, leading_zeroes, '0');
47fd5c32 Poul Sander 2024-10-05 08:44 1157
    if (remaining < num_digits) {
47fd5c32 Poul Sander 2024-10-05 08:44 1158
      int num_truncated_digits = num_digits - remaining;
47fd5c32 Poul Sander 2024-10-05 08:44 1159
      n /= to_unsigned(detail::pow10(to_unsigned(num_truncated_digits)));
47fd5c32 Poul Sander 2024-10-05 08:44 1160
      if (n) {
47fd5c32 Poul Sander 2024-10-05 08:44 1161
        out = format_decimal<Char>(out, n, remaining).end;
47fd5c32 Poul Sander 2024-10-05 08:44 1162
      }
47fd5c32 Poul Sander 2024-10-05 08:44 1163
      return;
47fd5c32 Poul Sander 2024-10-05 08:44 1164
    }
47fd5c32 Poul Sander 2024-10-05 08:44 1165
    if (n) {
47fd5c32 Poul Sander 2024-10-05 08:44 1166
      out = format_decimal<Char>(out, n, num_digits).end;
47fd5c32 Poul Sander 2024-10-05 08:44 1167
      remaining -= num_digits;
47fd5c32 Poul Sander 2024-10-05 08:44 1168
    }
47fd5c32 Poul Sander 2024-10-05 08:44 1169
    out = detail::fill_n(out, remaining, '0');
47fd5c32 Poul Sander 2024-10-05 08:44 1170
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1171
}
47fd5c32 Poul Sander 2024-10-05 08:44 1172
47fd5c32 Poul Sander 2024-10-05 08:44 1173
// Format subseconds which are given as a floating point type with an
47fd5c32 Poul Sander 2024-10-05 08:44 1174
// appropriate number of digits. We cannot pass the Duration here, as we
47fd5c32 Poul Sander 2024-10-05 08:44 1175
// explicitly need to pass the Rep value in the chrono_formatter.
47fd5c32 Poul Sander 2024-10-05 08:44 1176
template <typename Duration>
47fd5c32 Poul Sander 2024-10-05 08:44 1177
void write_floating_seconds(memory_buffer& buf, Duration duration,
47fd5c32 Poul Sander 2024-10-05 08:44 1178
                            int num_fractional_digits = -1) {
47fd5c32 Poul Sander 2024-10-05 08:44 1179
  using rep = typename Duration::rep;
47fd5c32 Poul Sander 2024-10-05 08:44 1180
  FMT_ASSERT(std::is_floating_point<rep>::value, "");
47fd5c32 Poul Sander 2024-10-05 08:44 1181
47fd5c32 Poul Sander 2024-10-05 08:44 1182
  auto val = duration.count();
47fd5c32 Poul Sander 2024-10-05 08:44 1183
47fd5c32 Poul Sander 2024-10-05 08:44 1184
  if (num_fractional_digits < 0) {
47fd5c32 Poul Sander 2024-10-05 08:44 1185
    // For `std::round` with fallback to `round`:
47fd5c32 Poul Sander 2024-10-05 08:44 1186
    // On some toolchains `std::round` is not available (e.g. GCC 6).
47fd5c32 Poul Sander 2024-10-05 08:44 1187
    using namespace std;
47fd5c32 Poul Sander 2024-10-05 08:44 1188
    num_fractional_digits =
47fd5c32 Poul Sander 2024-10-05 08:44 1189
        count_fractional_digits<Duration::period::num,
47fd5c32 Poul Sander 2024-10-05 08:44 1190
                                Duration::period::den>::value;
47fd5c32 Poul Sander 2024-10-05 08:44 1191
    if (num_fractional_digits < 6 && static_cast<rep>(round(val)) != val)
47fd5c32 Poul Sander 2024-10-05 08:44 1192
      num_fractional_digits = 6;
47fd5c32 Poul Sander 2024-10-05 08:44 1193
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1194
47fd5c32 Poul Sander 2024-10-05 08:44 1195
  fmt::format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"),
47fd5c32 Poul Sander 2024-10-05 08:44 1196
                 std::fmod(val * static_cast<rep>(Duration::period::num) /
47fd5c32 Poul Sander 2024-10-05 08:44 1197
                               static_cast<rep>(Duration::period::den),
47fd5c32 Poul Sander 2024-10-05 08:44 1198
                           static_cast<rep>(60)),
47fd5c32 Poul Sander 2024-10-05 08:44 1199
                 num_fractional_digits);
47fd5c32 Poul Sander 2024-10-05 08:44 1200
}
47fd5c32 Poul Sander 2024-10-05 08:44 1201
47fd5c32 Poul Sander 2024-10-05 08:44 1202
template <typename OutputIt, typename Char,
47fd5c32 Poul Sander 2024-10-05 08:44 1203
          typename Duration = std::chrono::seconds>
47fd5c32 Poul Sander 2024-10-05 08:44 1204
class tm_writer {
f8deb5b9 Poul Sander 2022-01-15 13:55 1205
 private:
f8deb5b9 Poul Sander 2022-01-15 13:55 1206
  static constexpr int days_per_week = 7;
f8deb5b9 Poul Sander 2022-01-15 13:55 1207
f8deb5b9 Poul Sander 2022-01-15 13:55 1208
  const std::locale& loc_;
f8deb5b9 Poul Sander 2022-01-15 13:55 1209
  const bool is_classic_;
f8deb5b9 Poul Sander 2022-01-15 13:55 1210
  OutputIt out_;
47fd5c32 Poul Sander 2024-10-05 08:44 1211
  const Duration* subsecs_;
f8deb5b9 Poul Sander 2022-01-15 13:55 1212
  const std::tm& tm_;
f8deb5b9 Poul Sander 2022-01-15 13:55 1213
f8deb5b9 Poul Sander 2022-01-15 13:55 1214
  auto tm_sec() const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1215
    FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, "");
f8deb5b9 Poul Sander 2022-01-15 13:55 1216
    return tm_.tm_sec;
f8deb5b9 Poul Sander 2022-01-15 13:55 1217
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1218
  auto tm_min() const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1219
    FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, "");
f8deb5b9 Poul Sander 2022-01-15 13:55 1220
    return tm_.tm_min;
f8deb5b9 Poul Sander 2022-01-15 13:55 1221
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1222
  auto tm_hour() const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1223
    FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, "");
f8deb5b9 Poul Sander 2022-01-15 13:55 1224
    return tm_.tm_hour;
f8deb5b9 Poul Sander 2022-01-15 13:55 1225
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1226
  auto tm_mday() const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1227
    FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, "");
f8deb5b9 Poul Sander 2022-01-15 13:55 1228
    return tm_.tm_mday;
f8deb5b9 Poul Sander 2022-01-15 13:55 1229
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1230
  auto tm_mon() const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1231
    FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, "");
f8deb5b9 Poul Sander 2022-01-15 13:55 1232
    return tm_.tm_mon;
f8deb5b9 Poul Sander 2022-01-15 13:55 1233
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1234
  auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; }
f8deb5b9 Poul Sander 2022-01-15 13:55 1235
  auto tm_wday() const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1236
    FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, "");
f8deb5b9 Poul Sander 2022-01-15 13:55 1237
    return tm_.tm_wday;
f8deb5b9 Poul Sander 2022-01-15 13:55 1238
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1239
  auto tm_yday() const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1240
    FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, "");
f8deb5b9 Poul Sander 2022-01-15 13:55 1241
    return tm_.tm_yday;
f8deb5b9 Poul Sander 2022-01-15 13:55 1242
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1243
f8deb5b9 Poul Sander 2022-01-15 13:55 1244
  auto tm_hour12() const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1245
    const auto h = tm_hour();
f8deb5b9 Poul Sander 2022-01-15 13:55 1246
    const auto z = h < 12 ? h : h - 12;
f8deb5b9 Poul Sander 2022-01-15 13:55 1247
    return z == 0 ? 12 : z;
f8deb5b9 Poul Sander 2022-01-15 13:55 1248
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1249
f8deb5b9 Poul Sander 2022-01-15 13:55 1250
  // POSIX and the C Standard are unclear or inconsistent about what %C and %y
f8deb5b9 Poul Sander 2022-01-15 13:55 1251
  // do if the year is negative or exceeds 9999. Use the convention that %C
f8deb5b9 Poul Sander 2022-01-15 13:55 1252
  // concatenated with %y yields the same output as %Y, and that %Y contains at
f8deb5b9 Poul Sander 2022-01-15 13:55 1253
  // least 4 characters, with more only if necessary.
f8deb5b9 Poul Sander 2022-01-15 13:55 1254
  auto split_year_lower(long long year) const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1255
    auto l = year % 100;
f8deb5b9 Poul Sander 2022-01-15 13:55 1256
    if (l < 0) l = -l;  // l in [0, 99]
f8deb5b9 Poul Sander 2022-01-15 13:55 1257
    return static_cast<int>(l);
f8deb5b9 Poul Sander 2022-01-15 13:55 1258
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1259
47fd5c32 Poul Sander 2024-10-05 08:44 1260
  // Algorithm: https://en.wikipedia.org/wiki/ISO_week_date.
f8deb5b9 Poul Sander 2022-01-15 13:55 1261
  auto iso_year_weeks(long long curr_year) const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1262
    const auto prev_year = curr_year - 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 1263
    const auto curr_p =
f8deb5b9 Poul Sander 2022-01-15 13:55 1264
        (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) %
f8deb5b9 Poul Sander 2022-01-15 13:55 1265
        days_per_week;
f8deb5b9 Poul Sander 2022-01-15 13:55 1266
    const auto prev_p =
f8deb5b9 Poul Sander 2022-01-15 13:55 1267
        (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) %
f8deb5b9 Poul Sander 2022-01-15 13:55 1268
        days_per_week;
f8deb5b9 Poul Sander 2022-01-15 13:55 1269
    return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0);
f8deb5b9 Poul Sander 2022-01-15 13:55 1270
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1271
  auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1272
    return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) /
f8deb5b9 Poul Sander 2022-01-15 13:55 1273
           days_per_week;
f8deb5b9 Poul Sander 2022-01-15 13:55 1274
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1275
  auto tm_iso_week_year() const noexcept -> long long {
f8deb5b9 Poul Sander 2022-01-15 13:55 1276
    const auto year = tm_year();
f8deb5b9 Poul Sander 2022-01-15 13:55 1277
    const auto w = iso_week_num(tm_yday(), tm_wday());
f8deb5b9 Poul Sander 2022-01-15 13:55 1278
    if (w < 1) return year - 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 1279
    if (w > iso_year_weeks(year)) return year + 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 1280
    return year;
f8deb5b9 Poul Sander 2022-01-15 13:55 1281
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1282
  auto tm_iso_week_of_year() const noexcept -> int {
f8deb5b9 Poul Sander 2022-01-15 13:55 1283
    const auto year = tm_year();
f8deb5b9 Poul Sander 2022-01-15 13:55 1284
    const auto w = iso_week_num(tm_yday(), tm_wday());
f8deb5b9 Poul Sander 2022-01-15 13:55 1285
    if (w < 1) return iso_year_weeks(year - 1);
f8deb5b9 Poul Sander 2022-01-15 13:55 1286
    if (w > iso_year_weeks(year)) return 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 1287
    return w;
f8deb5b9 Poul Sander 2022-01-15 13:55 1288
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1289
f8deb5b9 Poul Sander 2022-01-15 13:55 1290
  void write1(int value) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1291
    *out_++ = static_cast<char>('0' + to_unsigned(value) % 10);
f8deb5b9 Poul Sander 2022-01-15 13:55 1292
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1293
  void write2(int value) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1294
    const char* d = digits2(to_unsigned(value) % 100);
f8deb5b9 Poul Sander 2022-01-15 13:55 1295
    *out_++ = *d++;
f8deb5b9 Poul Sander 2022-01-15 13:55 1296
    *out_++ = *d;
f8deb5b9 Poul Sander 2022-01-15 13:55 1297
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1298
  void write2(int value, pad_type pad) {
47fd5c32 Poul Sander 2024-10-05 08:44 1299
    unsigned int v = to_unsigned(value) % 100;
47fd5c32 Poul Sander 2024-10-05 08:44 1300
    if (v >= 10) {
47fd5c32 Poul Sander 2024-10-05 08:44 1301
      const char* d = digits2(v);
47fd5c32 Poul Sander 2024-10-05 08:44 1302
      *out_++ = *d++;
47fd5c32 Poul Sander 2024-10-05 08:44 1303
      *out_++ = *d;
47fd5c32 Poul Sander 2024-10-05 08:44 1304
    } else {
47fd5c32 Poul Sander 2024-10-05 08:44 1305
      out_ = detail::write_padding(out_, pad);
47fd5c32 Poul Sander 2024-10-05 08:44 1306
      *out_++ = static_cast<char>('0' + v);
47fd5c32 Poul Sander 2024-10-05 08:44 1307
    }
47fd5c32 Poul Sander 2024-10-05 08:44 1308
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1309
f8deb5b9 Poul Sander 2022-01-15 13:55 1310
  void write_year_extended(long long year) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1311
    // At least 4 characters.
f8deb5b9 Poul Sander 2022-01-15 13:55 1312
    int width = 4;
f8deb5b9 Poul Sander 2022-01-15 13:55 1313
    if (year < 0) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1314
      *out_++ = '-';
f8deb5b9 Poul Sander 2022-01-15 13:55 1315
      year = 0 - year;
f8deb5b9 Poul Sander 2022-01-15 13:55 1316
      --width;
f8deb5b9 Poul Sander 2022-01-15 13:55 1317
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1318
    uint32_or_64_or_128_t<long long> n = to_unsigned(year);
f8deb5b9 Poul Sander 2022-01-15 13:55 1319
    const int num_digits = count_digits(n);
47fd5c32 Poul Sander 2024-10-05 08:44 1320
    if (width > num_digits)
47fd5c32 Poul Sander 2024-10-05 08:44 1321
      out_ = detail::fill_n(out_, width - num_digits, '0');
f8deb5b9 Poul Sander 2022-01-15 13:55 1322
    out_ = format_decimal<Char>(out_, n, num_digits).end;
f8deb5b9 Poul Sander 2022-01-15 13:55 1323
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1324
  void write_year(long long year) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1325
    if (year >= 0 && year < 10000) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1326
      write2(static_cast<int>(year / 100));
f8deb5b9 Poul Sander 2022-01-15 13:55 1327
      write2(static_cast<int>(year % 100));
f8deb5b9 Poul Sander 2022-01-15 13:55 1328
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1329
      write_year_extended(year);
f8deb5b9 Poul Sander 2022-01-15 13:55 1330
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1331
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1332
47fd5c32 Poul Sander 2024-10-05 08:44 1333
  void write_utc_offset(long offset, numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1334
    if (offset < 0) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1335
      *out_++ = '-';
f8deb5b9 Poul Sander 2022-01-15 13:55 1336
      offset = -offset;
f8deb5b9 Poul Sander 2022-01-15 13:55 1337
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1338
      *out_++ = '+';
f8deb5b9 Poul Sander 2022-01-15 13:55 1339
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1340
    offset /= 60;
f8deb5b9 Poul Sander 2022-01-15 13:55 1341
    write2(static_cast<int>(offset / 60));
47fd5c32 Poul Sander 2024-10-05 08:44 1342
    if (ns != numeric_system::standard) *out_++ = ':';
f8deb5b9 Poul Sander 2022-01-15 13:55 1343
    write2(static_cast<int>(offset % 60));
f8deb5b9 Poul Sander 2022-01-15 13:55 1344
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1345
  template <typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1346
  void format_utc_offset_impl(const T& tm, numeric_system ns) {
47fd5c32 Poul Sander 2024-10-05 08:44 1347
    write_utc_offset(tm.tm_gmtoff, ns);
f8deb5b9 Poul Sander 2022-01-15 13:55 1348
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1349
  template <typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1350
  void format_utc_offset_impl(const T& tm, numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1351
#if defined(_WIN32) && defined(_UCRT)
f8deb5b9 Poul Sander 2022-01-15 13:55 1352
#  if FMT_USE_TZSET
f8deb5b9 Poul Sander 2022-01-15 13:55 1353
    tzset_once();
f8deb5b9 Poul Sander 2022-01-15 13:55 1354
#  endif
f8deb5b9 Poul Sander 2022-01-15 13:55 1355
    long offset = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 1356
    _get_timezone(&offset);
f8deb5b9 Poul Sander 2022-01-15 13:55 1357
    if (tm.tm_isdst) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1358
      long dstbias = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 1359
      _get_dstbias(&dstbias);
f8deb5b9 Poul Sander 2022-01-15 13:55 1360
      offset += dstbias;
f8deb5b9 Poul Sander 2022-01-15 13:55 1361
    }
47fd5c32 Poul Sander 2024-10-05 08:44 1362
    write_utc_offset(-offset, ns);
f8deb5b9 Poul Sander 2022-01-15 13:55 1363
#else
47fd5c32 Poul Sander 2024-10-05 08:44 1364
    if (ns == numeric_system::standard) return format_localized('z');
47fd5c32 Poul Sander 2024-10-05 08:44 1365
47fd5c32 Poul Sander 2024-10-05 08:44 1366
    // Extract timezone offset from timezone conversion functions.
47fd5c32 Poul Sander 2024-10-05 08:44 1367
    std::tm gtm = tm;
47fd5c32 Poul Sander 2024-10-05 08:44 1368
    std::time_t gt = std::mktime(&gtm);
47fd5c32 Poul Sander 2024-10-05 08:44 1369
    std::tm ltm = gmtime(gt);
47fd5c32 Poul Sander 2024-10-05 08:44 1370
    std::time_t lt = std::mktime(&ltm);
47fd5c32 Poul Sander 2024-10-05 08:44 1371
    long offset = gt - lt;
47fd5c32 Poul Sander 2024-10-05 08:44 1372
    write_utc_offset(offset, ns);
f8deb5b9 Poul Sander 2022-01-15 13:55 1373
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 1374
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1375
f8deb5b9 Poul Sander 2022-01-15 13:55 1376
  template <typename T, FMT_ENABLE_IF(has_member_data_tm_zone<T>::value)>
f8deb5b9 Poul Sander 2022-01-15 13:55 1377
  void format_tz_name_impl(const T& tm) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1378
    if (is_classic_)
f8deb5b9 Poul Sander 2022-01-15 13:55 1379
      out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_);
f8deb5b9 Poul Sander 2022-01-15 13:55 1380
    else
f8deb5b9 Poul Sander 2022-01-15 13:55 1381
      format_localized('Z');
f8deb5b9 Poul Sander 2022-01-15 13:55 1382
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1383
  template <typename T, FMT_ENABLE_IF(!has_member_data_tm_zone<T>::value)>
f8deb5b9 Poul Sander 2022-01-15 13:55 1384
  void format_tz_name_impl(const T&) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1385
    format_localized('Z');
f8deb5b9 Poul Sander 2022-01-15 13:55 1386
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1387
f8deb5b9 Poul Sander 2022-01-15 13:55 1388
  void format_localized(char format, char modifier = 0) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1389
    out_ = write<Char>(out_, tm_, loc_, format, modifier);
f8deb5b9 Poul Sander 2022-01-15 13:55 1390
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1391
f8deb5b9 Poul Sander 2022-01-15 13:55 1392
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 1393
  tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm,
47fd5c32 Poul Sander 2024-10-05 08:44 1394
            const Duration* subsecs = nullptr)
f8deb5b9 Poul Sander 2022-01-15 13:55 1395
      : loc_(loc),
f8deb5b9 Poul Sander 2022-01-15 13:55 1396
        is_classic_(loc_ == get_classic_locale()),
f8deb5b9 Poul Sander 2022-01-15 13:55 1397
        out_(out),
47fd5c32 Poul Sander 2024-10-05 08:44 1398
        subsecs_(subsecs),
f8deb5b9 Poul Sander 2022-01-15 13:55 1399
        tm_(tm) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1400
47fd5c32 Poul Sander 2024-10-05 08:44 1401
  auto out() const -> OutputIt { return out_; }
f8deb5b9 Poul Sander 2022-01-15 13:55 1402
f8deb5b9 Poul Sander 2022-01-15 13:55 1403
  FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
47fd5c32 Poul Sander 2024-10-05 08:44 1404
    out_ = copy<Char>(begin, end, out_);
f8deb5b9 Poul Sander 2022-01-15 13:55 1405
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1406
f8deb5b9 Poul Sander 2022-01-15 13:55 1407
  void on_abbr_weekday() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1408
    if (is_classic_)
f8deb5b9 Poul Sander 2022-01-15 13:55 1409
      out_ = write(out_, tm_wday_short_name(tm_wday()));
f8deb5b9 Poul Sander 2022-01-15 13:55 1410
    else
f8deb5b9 Poul Sander 2022-01-15 13:55 1411
      format_localized('a');
f8deb5b9 Poul Sander 2022-01-15 13:55 1412
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1413
  void on_full_weekday() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1414
    if (is_classic_)
f8deb5b9 Poul Sander 2022-01-15 13:55 1415
      out_ = write(out_, tm_wday_full_name(tm_wday()));
f8deb5b9 Poul Sander 2022-01-15 13:55 1416
    else
f8deb5b9 Poul Sander 2022-01-15 13:55 1417
      format_localized('A');
f8deb5b9 Poul Sander 2022-01-15 13:55 1418
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1419
  void on_dec0_weekday(numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1420
    if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday());
f8deb5b9 Poul Sander 2022-01-15 13:55 1421
    format_localized('w', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1422
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1423
  void on_dec1_weekday(numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1424
    if (is_classic_ || ns == numeric_system::standard) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1425
      auto wday = tm_wday();
f8deb5b9 Poul Sander 2022-01-15 13:55 1426
      write1(wday == 0 ? days_per_week : wday);
f8deb5b9 Poul Sander 2022-01-15 13:55 1427
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1428
      format_localized('u', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1429
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1430
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1431
f8deb5b9 Poul Sander 2022-01-15 13:55 1432
  void on_abbr_month() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1433
    if (is_classic_)
f8deb5b9 Poul Sander 2022-01-15 13:55 1434
      out_ = write(out_, tm_mon_short_name(tm_mon()));
f8deb5b9 Poul Sander 2022-01-15 13:55 1435
    else
f8deb5b9 Poul Sander 2022-01-15 13:55 1436
      format_localized('b');
f8deb5b9 Poul Sander 2022-01-15 13:55 1437
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1438
  void on_full_month() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1439
    if (is_classic_)
f8deb5b9 Poul Sander 2022-01-15 13:55 1440
      out_ = write(out_, tm_mon_full_name(tm_mon()));
f8deb5b9 Poul Sander 2022-01-15 13:55 1441
    else
f8deb5b9 Poul Sander 2022-01-15 13:55 1442
      format_localized('B');
f8deb5b9 Poul Sander 2022-01-15 13:55 1443
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1444
f8deb5b9 Poul Sander 2022-01-15 13:55 1445
  void on_datetime(numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1446
    if (is_classic_) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1447
      on_abbr_weekday();
f8deb5b9 Poul Sander 2022-01-15 13:55 1448
      *out_++ = ' ';
f8deb5b9 Poul Sander 2022-01-15 13:55 1449
      on_abbr_month();
f8deb5b9 Poul Sander 2022-01-15 13:55 1450
      *out_++ = ' ';
47fd5c32 Poul Sander 2024-10-05 08:44 1451
      on_day_of_month(numeric_system::standard, pad_type::space);
f8deb5b9 Poul Sander 2022-01-15 13:55 1452
      *out_++ = ' ';
f8deb5b9 Poul Sander 2022-01-15 13:55 1453
      on_iso_time();
f8deb5b9 Poul Sander 2022-01-15 13:55 1454
      *out_++ = ' ';
f8deb5b9 Poul Sander 2022-01-15 13:55 1455
      on_year(numeric_system::standard);
f8deb5b9 Poul Sander 2022-01-15 13:55 1456
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1457
      format_localized('c', ns == numeric_system::standard ? '\0' : 'E');
f8deb5b9 Poul Sander 2022-01-15 13:55 1458
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1459
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1460
  void on_loc_date(numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1461
    if (is_classic_)
f8deb5b9 Poul Sander 2022-01-15 13:55 1462
      on_us_date();
f8deb5b9 Poul Sander 2022-01-15 13:55 1463
    else
f8deb5b9 Poul Sander 2022-01-15 13:55 1464
      format_localized('x', ns == numeric_system::standard ? '\0' : 'E');
f8deb5b9 Poul Sander 2022-01-15 13:55 1465
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1466
  void on_loc_time(numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1467
    if (is_classic_)
f8deb5b9 Poul Sander 2022-01-15 13:55 1468
      on_iso_time();
f8deb5b9 Poul Sander 2022-01-15 13:55 1469
    else
f8deb5b9 Poul Sander 2022-01-15 13:55 1470
      format_localized('X', ns == numeric_system::standard ? '\0' : 'E');
f8deb5b9 Poul Sander 2022-01-15 13:55 1471
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1472
  void on_us_date() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1473
    char buf[8];
f8deb5b9 Poul Sander 2022-01-15 13:55 1474
    write_digit2_separated(buf, to_unsigned(tm_mon() + 1),
f8deb5b9 Poul Sander 2022-01-15 13:55 1475
                           to_unsigned(tm_mday()),
f8deb5b9 Poul Sander 2022-01-15 13:55 1476
                           to_unsigned(split_year_lower(tm_year())), '/');
47fd5c32 Poul Sander 2024-10-05 08:44 1477
    out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
f8deb5b9 Poul Sander 2022-01-15 13:55 1478
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1479
  void on_iso_date() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1480
    auto year = tm_year();
f8deb5b9 Poul Sander 2022-01-15 13:55 1481
    char buf[10];
f8deb5b9 Poul Sander 2022-01-15 13:55 1482
    size_t offset = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 1483
    if (year >= 0 && year < 10000) {
47fd5c32 Poul Sander 2024-10-05 08:44 1484
      copy2(buf, digits2(static_cast<size_t>(year / 100)));
f8deb5b9 Poul Sander 2022-01-15 13:55 1485
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1486
      offset = 4;
f8deb5b9 Poul Sander 2022-01-15 13:55 1487
      write_year_extended(year);
f8deb5b9 Poul Sander 2022-01-15 13:55 1488
      year = 0;
f8deb5b9 Poul Sander 2022-01-15 13:55 1489
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1490
    write_digit2_separated(buf + 2, static_cast<unsigned>(year % 100),
f8deb5b9 Poul Sander 2022-01-15 13:55 1491
                           to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()),
f8deb5b9 Poul Sander 2022-01-15 13:55 1492
                           '-');
47fd5c32 Poul Sander 2024-10-05 08:44 1493
    out_ = copy<Char>(std::begin(buf) + offset, std::end(buf), out_);
f8deb5b9 Poul Sander 2022-01-15 13:55 1494
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1495
47fd5c32 Poul Sander 2024-10-05 08:44 1496
  void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); }
f8deb5b9 Poul Sander 2022-01-15 13:55 1497
  void on_tz_name() { format_tz_name_impl(tm_); }
f8deb5b9 Poul Sander 2022-01-15 13:55 1498
f8deb5b9 Poul Sander 2022-01-15 13:55 1499
  void on_year(numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1500
    if (is_classic_ || ns == numeric_system::standard)
f8deb5b9 Poul Sander 2022-01-15 13:55 1501
      return write_year(tm_year());
f8deb5b9 Poul Sander 2022-01-15 13:55 1502
    format_localized('Y', 'E');
f8deb5b9 Poul Sander 2022-01-15 13:55 1503
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1504
  void on_short_year(numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1505
    if (is_classic_ || ns == numeric_system::standard)
f8deb5b9 Poul Sander 2022-01-15 13:55 1506
      return write2(split_year_lower(tm_year()));
f8deb5b9 Poul Sander 2022-01-15 13:55 1507
    format_localized('y', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1508
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1509
  void on_offset_year() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1510
    if (is_classic_) return write2(split_year_lower(tm_year()));
f8deb5b9 Poul Sander 2022-01-15 13:55 1511
    format_localized('y', 'E');
f8deb5b9 Poul Sander 2022-01-15 13:55 1512
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1513
f8deb5b9 Poul Sander 2022-01-15 13:55 1514
  void on_century(numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1515
    if (is_classic_ || ns == numeric_system::standard) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1516
      auto year = tm_year();
f8deb5b9 Poul Sander 2022-01-15 13:55 1517
      auto upper = year / 100;
f8deb5b9 Poul Sander 2022-01-15 13:55 1518
      if (year >= -99 && year < 0) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1519
        // Zero upper on negative year.
f8deb5b9 Poul Sander 2022-01-15 13:55 1520
        *out_++ = '-';
f8deb5b9 Poul Sander 2022-01-15 13:55 1521
        *out_++ = '0';
f8deb5b9 Poul Sander 2022-01-15 13:55 1522
      } else if (upper >= 0 && upper < 100) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1523
        write2(static_cast<int>(upper));
f8deb5b9 Poul Sander 2022-01-15 13:55 1524
      } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1525
        out_ = write<Char>(out_, upper);
f8deb5b9 Poul Sander 2022-01-15 13:55 1526
      }
f8deb5b9 Poul Sander 2022-01-15 13:55 1527
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1528
      format_localized('C', 'E');
f8deb5b9 Poul Sander 2022-01-15 13:55 1529
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1530
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1531
f8deb5b9 Poul Sander 2022-01-15 13:55 1532
  void on_dec_month(numeric_system ns) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1533
    if (is_classic_ || ns == numeric_system::standard)
f8deb5b9 Poul Sander 2022-01-15 13:55 1534
      return write2(tm_mon() + 1);
f8deb5b9 Poul Sander 2022-01-15 13:55 1535
    format_localized('m', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1536
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1537
47fd5c32 Poul Sander 2024-10-05 08:44 1538
  void on_dec0_week_of_year(numeric_system ns, pad_type pad) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1539
    if (is_classic_ || ns == numeric_system::standard)
47fd5c32 Poul Sander 2024-10-05 08:44 1540
      return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week,
47fd5c32 Poul Sander 2024-10-05 08:44 1541
                    pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1542
    format_localized('U', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1543
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1544
  void on_dec1_week_of_year(numeric_system ns, pad_type pad) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1545
    if (is_classic_ || ns == numeric_system::standard) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1546
      auto wday = tm_wday();
f8deb5b9 Poul Sander 2022-01-15 13:55 1547
      write2((tm_yday() + days_per_week -
f8deb5b9 Poul Sander 2022-01-15 13:55 1548
              (wday == 0 ? (days_per_week - 1) : (wday - 1))) /
47fd5c32 Poul Sander 2024-10-05 08:44 1549
                 days_per_week,
47fd5c32 Poul Sander 2024-10-05 08:44 1550
             pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1551
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1552
      format_localized('W', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1553
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1554
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1555
  void on_iso_week_of_year(numeric_system ns, pad_type pad) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1556
    if (is_classic_ || ns == numeric_system::standard)
47fd5c32 Poul Sander 2024-10-05 08:44 1557
      return write2(tm_iso_week_of_year(), pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1558
    format_localized('V', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1559
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1560
f8deb5b9 Poul Sander 2022-01-15 13:55 1561
  void on_iso_week_based_year() { write_year(tm_iso_week_year()); }
f8deb5b9 Poul Sander 2022-01-15 13:55 1562
  void on_iso_week_based_short_year() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1563
    write2(split_year_lower(tm_iso_week_year()));
f8deb5b9 Poul Sander 2022-01-15 13:55 1564
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1565
f8deb5b9 Poul Sander 2022-01-15 13:55 1566
  void on_day_of_year() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1567
    auto yday = tm_yday() + 1;
f8deb5b9 Poul Sander 2022-01-15 13:55 1568
    write1(yday / 100);
f8deb5b9 Poul Sander 2022-01-15 13:55 1569
    write2(yday % 100);
f8deb5b9 Poul Sander 2022-01-15 13:55 1570
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1571
  void on_day_of_month(numeric_system ns, pad_type pad) {
47fd5c32 Poul Sander 2024-10-05 08:44 1572
    if (is_classic_ || ns == numeric_system::standard)
47fd5c32 Poul Sander 2024-10-05 08:44 1573
      return write2(tm_mday(), pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1574
    format_localized('d', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1575
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1576
47fd5c32 Poul Sander 2024-10-05 08:44 1577
  void on_24_hour(numeric_system ns, pad_type pad) {
47fd5c32 Poul Sander 2024-10-05 08:44 1578
    if (is_classic_ || ns == numeric_system::standard)
47fd5c32 Poul Sander 2024-10-05 08:44 1579
      return write2(tm_hour(), pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1580
    format_localized('H', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1581
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1582
  void on_12_hour(numeric_system ns, pad_type pad) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1583
    if (is_classic_ || ns == numeric_system::standard)
47fd5c32 Poul Sander 2024-10-05 08:44 1584
      return write2(tm_hour12(), pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1585
    format_localized('I', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1586
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1587
  void on_minute(numeric_system ns, pad_type pad) {
47fd5c32 Poul Sander 2024-10-05 08:44 1588
    if (is_classic_ || ns == numeric_system::standard)
47fd5c32 Poul Sander 2024-10-05 08:44 1589
      return write2(tm_min(), pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1590
    format_localized('M', 'O');
f8deb5b9 Poul Sander 2022-01-15 13:55 1591
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1592
47fd5c32 Poul Sander 2024-10-05 08:44 1593
  void on_second(numeric_system ns, pad_type pad) {
47fd5c32 Poul Sander 2024-10-05 08:44 1594
    if (is_classic_ || ns == numeric_system::standard) {
47fd5c32 Poul Sander 2024-10-05 08:44 1595
      write2(tm_sec(), pad);
47fd5c32 Poul Sander 2024-10-05 08:44 1596
      if (subsecs_) {
47fd5c32 Poul Sander 2024-10-05 08:44 1597
        if (std::is_floating_point<typename Duration::rep>::value) {
47fd5c32 Poul Sander 2024-10-05 08:44 1598
          auto buf = memory_buffer();
47fd5c32 Poul Sander 2024-10-05 08:44 1599
          write_floating_seconds(buf, *subsecs_);
47fd5c32 Poul Sander 2024-10-05 08:44 1600
          if (buf.size() > 1) {
47fd5c32 Poul Sander 2024-10-05 08:44 1601
            // Remove the leading "0", write something like ".123".
47fd5c32 Poul Sander 2024-10-05 08:44 1602
            out_ = std::copy(buf.begin() + 1, buf.end(), out_);
47fd5c32 Poul Sander 2024-10-05 08:44 1603
          }
47fd5c32 Poul Sander 2024-10-05 08:44 1604
        } else {
47fd5c32 Poul Sander 2024-10-05 08:44 1605
          write_fractional_seconds<Char>(out_, *subsecs_);
47fd5c32 Poul Sander 2024-10-05 08:44 1606
        }
47fd5c32 Poul Sander 2024-10-05 08:44 1607
      }
47fd5c32 Poul Sander 2024-10-05 08:44 1608
    } else {
47fd5c32 Poul Sander 2024-10-05 08:44 1609
      // Currently no formatting of subseconds when a locale is set.
47fd5c32 Poul Sander 2024-10-05 08:44 1610
      format_localized('S', 'O');
47fd5c32 Poul Sander 2024-10-05 08:44 1611
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1612
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1613
f8deb5b9 Poul Sander 2022-01-15 13:55 1614
  void on_12_hour_time() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1615
    if (is_classic_) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1616
      char buf[8];
f8deb5b9 Poul Sander 2022-01-15 13:55 1617
      write_digit2_separated(buf, to_unsigned(tm_hour12()),
f8deb5b9 Poul Sander 2022-01-15 13:55 1618
                             to_unsigned(tm_min()), to_unsigned(tm_sec()), ':');
47fd5c32 Poul Sander 2024-10-05 08:44 1619
      out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
f8deb5b9 Poul Sander 2022-01-15 13:55 1620
      *out_++ = ' ';
f8deb5b9 Poul Sander 2022-01-15 13:55 1621
      on_am_pm();
f8deb5b9 Poul Sander 2022-01-15 13:55 1622
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1623
      format_localized('r');
f8deb5b9 Poul Sander 2022-01-15 13:55 1624
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1625
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1626
  void on_24_hour_time() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1627
    write2(tm_hour());
f8deb5b9 Poul Sander 2022-01-15 13:55 1628
    *out_++ = ':';
f8deb5b9 Poul Sander 2022-01-15 13:55 1629
    write2(tm_min());
f8deb5b9 Poul Sander 2022-01-15 13:55 1630
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1631
  void on_iso_time() {
47fd5c32 Poul Sander 2024-10-05 08:44 1632
    on_24_hour_time();
47fd5c32 Poul Sander 2024-10-05 08:44 1633
    *out_++ = ':';
47fd5c32 Poul Sander 2024-10-05 08:44 1634
    on_second(numeric_system::standard, pad_type::zero);
f8deb5b9 Poul Sander 2022-01-15 13:55 1635
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1636
f8deb5b9 Poul Sander 2022-01-15 13:55 1637
  void on_am_pm() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1638
    if (is_classic_) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1639
      *out_++ = tm_hour() < 12 ? 'A' : 'P';
f8deb5b9 Poul Sander 2022-01-15 13:55 1640
      *out_++ = 'M';
f8deb5b9 Poul Sander 2022-01-15 13:55 1641
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1642
      format_localized('p');
f8deb5b9 Poul Sander 2022-01-15 13:55 1643
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1644
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1645
f8deb5b9 Poul Sander 2022-01-15 13:55 1646
  // These apply to chrono durations but not tm.
f8deb5b9 Poul Sander 2022-01-15 13:55 1647
  void on_duration_value() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1648
  void on_duration_unit() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1649
};
f8deb5b9 Poul Sander 2022-01-15 13:55 1650
f8deb5b9 Poul Sander 2022-01-15 13:55 1651
struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> {
47fd5c32 Poul Sander 2024-10-05 08:44 1652
  bool has_precision_integral = false;
47fd5c32 Poul Sander 2024-10-05 08:44 1653
f8deb5b9 Poul Sander 2022-01-15 13:55 1654
  FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); }
f8deb5b9 Poul Sander 2022-01-15 13:55 1655
f8deb5b9 Poul Sander 2022-01-15 13:55 1656
  template <typename Char>
f8deb5b9 Poul Sander 2022-01-15 13:55 1657
  FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1658
  FMT_CONSTEXPR void on_day_of_year() {}
47fd5c32 Poul Sander 2024-10-05 08:44 1659
  FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1660
  FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1661
  FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1662
  FMT_CONSTEXPR void on_second(numeric_system, pad_type) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1663
  FMT_CONSTEXPR void on_12_hour_time() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1664
  FMT_CONSTEXPR void on_24_hour_time() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1665
  FMT_CONSTEXPR void on_iso_time() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1666
  FMT_CONSTEXPR void on_am_pm() {}
47fd5c32 Poul Sander 2024-10-05 08:44 1667
  FMT_CONSTEXPR void on_duration_value() const {
47fd5c32 Poul Sander 2024-10-05 08:44 1668
    if (has_precision_integral) {
47fd5c32 Poul Sander 2024-10-05 08:44 1669
      FMT_THROW(format_error("precision not allowed for this argument type"));
47fd5c32 Poul Sander 2024-10-05 08:44 1670
    }
47fd5c32 Poul Sander 2024-10-05 08:44 1671
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1672
  FMT_CONSTEXPR void on_duration_unit() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1673
};
f8deb5b9 Poul Sander 2022-01-15 13:55 1674
47fd5c32 Poul Sander 2024-10-05 08:44 1675
template <typename T,
47fd5c32 Poul Sander 2024-10-05 08:44 1676
          FMT_ENABLE_IF(std::is_integral<T>::value&& has_isfinite<T>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1677
inline auto isfinite(T) -> bool {
f8deb5b9 Poul Sander 2022-01-15 13:55 1678
  return true;
f8deb5b9 Poul Sander 2022-01-15 13:55 1679
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1680
f8deb5b9 Poul Sander 2022-01-15 13:55 1681
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1682
inline auto mod(T x, int y) -> T {
f8deb5b9 Poul Sander 2022-01-15 13:55 1683
  return x % static_cast<T>(y);
f8deb5b9 Poul Sander 2022-01-15 13:55 1684
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1685
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1686
inline auto mod(T x, int y) -> T {
f8deb5b9 Poul Sander 2022-01-15 13:55 1687
  return std::fmod(x, static_cast<T>(y));
f8deb5b9 Poul Sander 2022-01-15 13:55 1688
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1689
f8deb5b9 Poul Sander 2022-01-15 13:55 1690
// If T is an integral type, maps T to its unsigned counterpart, otherwise
f8deb5b9 Poul Sander 2022-01-15 13:55 1691
// leaves it unchanged (unlike std::make_unsigned).
f8deb5b9 Poul Sander 2022-01-15 13:55 1692
template <typename T, bool INTEGRAL = std::is_integral<T>::value>
f8deb5b9 Poul Sander 2022-01-15 13:55 1693
struct make_unsigned_or_unchanged {
f8deb5b9 Poul Sander 2022-01-15 13:55 1694
  using type = T;
f8deb5b9 Poul Sander 2022-01-15 13:55 1695
};
f8deb5b9 Poul Sander 2022-01-15 13:55 1696
f8deb5b9 Poul Sander 2022-01-15 13:55 1697
template <typename T> struct make_unsigned_or_unchanged<T, true> {
f8deb5b9 Poul Sander 2022-01-15 13:55 1698
  using type = typename std::make_unsigned<T>::type;
f8deb5b9 Poul Sander 2022-01-15 13:55 1699
};
f8deb5b9 Poul Sander 2022-01-15 13:55 1700
f8deb5b9 Poul Sander 2022-01-15 13:55 1701
template <typename Rep, typename Period,
f8deb5b9 Poul Sander 2022-01-15 13:55 1702
          FMT_ENABLE_IF(std::is_integral<Rep>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1703
inline auto get_milliseconds(std::chrono::duration<Rep, Period> d)
47fd5c32 Poul Sander 2024-10-05 08:44 1704
    -> std::chrono::duration<Rep, std::milli> {
f8deb5b9 Poul Sander 2022-01-15 13:55 1705
  // this may overflow and/or the result may not fit in the
f8deb5b9 Poul Sander 2022-01-15 13:55 1706
  // target type.
f8deb5b9 Poul Sander 2022-01-15 13:55 1707
#if FMT_SAFE_DURATION_CAST
f8deb5b9 Poul Sander 2022-01-15 13:55 1708
  using CommonSecondsType =
f8deb5b9 Poul Sander 2022-01-15 13:55 1709
      typename std::common_type<decltype(d), std::chrono::seconds>::type;
47fd5c32 Poul Sander 2024-10-05 08:44 1710
  const auto d_as_common = fmt_duration_cast<CommonSecondsType>(d);
f8deb5b9 Poul Sander 2022-01-15 13:55 1711
  const auto d_as_whole_seconds =
47fd5c32 Poul Sander 2024-10-05 08:44 1712
      fmt_duration_cast<std::chrono::seconds>(d_as_common);
f8deb5b9 Poul Sander 2022-01-15 13:55 1713
  // this conversion should be nonproblematic
f8deb5b9 Poul Sander 2022-01-15 13:55 1714
  const auto diff = d_as_common - d_as_whole_seconds;
f8deb5b9 Poul Sander 2022-01-15 13:55 1715
  const auto ms =
47fd5c32 Poul Sander 2024-10-05 08:44 1716
      fmt_duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
f8deb5b9 Poul Sander 2022-01-15 13:55 1717
  return ms;
f8deb5b9 Poul Sander 2022-01-15 13:55 1718
#else
47fd5c32 Poul Sander 2024-10-05 08:44 1719
  auto s = fmt_duration_cast<std::chrono::seconds>(d);
47fd5c32 Poul Sander 2024-10-05 08:44 1720
  return fmt_duration_cast<std::chrono::milliseconds>(d - s);
f8deb5b9 Poul Sander 2022-01-15 13:55 1721
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 1722
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1723
f8deb5b9 Poul Sander 2022-01-15 13:55 1724
template <typename Char, typename Rep, typename OutputIt,
f8deb5b9 Poul Sander 2022-01-15 13:55 1725
          FMT_ENABLE_IF(std::is_integral<Rep>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1726
auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt {
f8deb5b9 Poul Sander 2022-01-15 13:55 1727
  return write<Char>(out, val);
f8deb5b9 Poul Sander 2022-01-15 13:55 1728
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1729
f8deb5b9 Poul Sander 2022-01-15 13:55 1730
template <typename Char, typename Rep, typename OutputIt,
f8deb5b9 Poul Sander 2022-01-15 13:55 1731
          FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
47fd5c32 Poul Sander 2024-10-05 08:44 1732
auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt {
47fd5c32 Poul Sander 2024-10-05 08:44 1733
  auto specs = format_specs();
f8deb5b9 Poul Sander 2022-01-15 13:55 1734
  specs.precision = precision;
47fd5c32 Poul Sander 2024-10-05 08:44 1735
  specs.type =
47fd5c32 Poul Sander 2024-10-05 08:44 1736
      precision >= 0 ? presentation_type::fixed : presentation_type::general;
f8deb5b9 Poul Sander 2022-01-15 13:55 1737
  return write<Char>(out, val, specs);
f8deb5b9 Poul Sander 2022-01-15 13:55 1738
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1739
f8deb5b9 Poul Sander 2022-01-15 13:55 1740
template <typename Char, typename OutputIt>
47fd5c32 Poul Sander 2024-10-05 08:44 1741
auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt {
f8deb5b9 Poul Sander 2022-01-15 13:55 1742
  return std::copy(unit.begin(), unit.end(), out);
f8deb5b9 Poul Sander 2022-01-15 13:55 1743
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1744
f8deb5b9 Poul Sander 2022-01-15 13:55 1745
template <typename OutputIt>
47fd5c32 Poul Sander 2024-10-05 08:44 1746
auto copy_unit(string_view unit, OutputIt out, wchar_t) -> OutputIt {
f8deb5b9 Poul Sander 2022-01-15 13:55 1747
  // This works when wchar_t is UTF-32 because units only contain characters
f8deb5b9 Poul Sander 2022-01-15 13:55 1748
  // that have the same representation in UTF-16 and UTF-32.
f8deb5b9 Poul Sander 2022-01-15 13:55 1749
  utf8_to_utf16 u(unit);
f8deb5b9 Poul Sander 2022-01-15 13:55 1750
  return std::copy(u.c_str(), u.c_str() + u.size(), out);
f8deb5b9 Poul Sander 2022-01-15 13:55 1751
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1752
f8deb5b9 Poul Sander 2022-01-15 13:55 1753
template <typename Char, typename Period, typename OutputIt>
47fd5c32 Poul Sander 2024-10-05 08:44 1754
auto format_duration_unit(OutputIt out) -> OutputIt {
f8deb5b9 Poul Sander 2022-01-15 13:55 1755
  if (const char* unit = get_units<Period>())
f8deb5b9 Poul Sander 2022-01-15 13:55 1756
    return copy_unit(string_view(unit), out, Char());
f8deb5b9 Poul Sander 2022-01-15 13:55 1757
  *out++ = '[';
f8deb5b9 Poul Sander 2022-01-15 13:55 1758
  out = write<Char>(out, Period::num);
f8deb5b9 Poul Sander 2022-01-15 13:55 1759
  if (const_check(Period::den != 1)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1760
    *out++ = '/';
f8deb5b9 Poul Sander 2022-01-15 13:55 1761
    out = write<Char>(out, Period::den);
f8deb5b9 Poul Sander 2022-01-15 13:55 1762
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1763
  *out++ = ']';
f8deb5b9 Poul Sander 2022-01-15 13:55 1764
  *out++ = 's';
f8deb5b9 Poul Sander 2022-01-15 13:55 1765
  return out;
f8deb5b9 Poul Sander 2022-01-15 13:55 1766
}
f8deb5b9 Poul Sander 2022-01-15 13:55 1767
f8deb5b9 Poul Sander 2022-01-15 13:55 1768
class get_locale {
f8deb5b9 Poul Sander 2022-01-15 13:55 1769
 private:
f8deb5b9 Poul Sander 2022-01-15 13:55 1770
  union {
f8deb5b9 Poul Sander 2022-01-15 13:55 1771
    std::locale locale_;
f8deb5b9 Poul Sander 2022-01-15 13:55 1772
  };
f8deb5b9 Poul Sander 2022-01-15 13:55 1773
  bool has_locale_ = false;
f8deb5b9 Poul Sander 2022-01-15 13:55 1774
f8deb5b9 Poul Sander 2022-01-15 13:55 1775
 public:
f8deb5b9 Poul Sander 2022-01-15 13:55 1776
  get_locale(bool localized, locale_ref loc) : has_locale_(localized) {
47fd5c32 Poul Sander 2024-10-05 08:44 1777
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
f8deb5b9 Poul Sander 2022-01-15 13:55 1778
    if (localized)
f8deb5b9 Poul Sander 2022-01-15 13:55 1779
      ::new (&locale_) std::locale(loc.template get<std::locale>());
47fd5c32 Poul Sander 2024-10-05 08:44 1780
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 1781
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1782
  ~get_locale() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1783
    if (has_locale_) locale_.~locale();
f8deb5b9 Poul Sander 2022-01-15 13:55 1784
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1785
  operator const std::locale&() const {
f8deb5b9 Poul Sander 2022-01-15 13:55 1786
    return has_locale_ ? locale_ : get_classic_locale();
f8deb5b9 Poul Sander 2022-01-15 13:55 1787
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1788
};
f8deb5b9 Poul Sander 2022-01-15 13:55 1789
f8deb5b9 Poul Sander 2022-01-15 13:55 1790
template <typename FormatContext, typename OutputIt, typename Rep,
f8deb5b9 Poul Sander 2022-01-15 13:55 1791
          typename Period>
f8deb5b9 Poul Sander 2022-01-15 13:55 1792
struct chrono_formatter {
f8deb5b9 Poul Sander 2022-01-15 13:55 1793
  FormatContext& context;
f8deb5b9 Poul Sander 2022-01-15 13:55 1794
  OutputIt out;
f8deb5b9 Poul Sander 2022-01-15 13:55 1795
  int precision;
f8deb5b9 Poul Sander 2022-01-15 13:55 1796
  bool localized = false;
f8deb5b9 Poul Sander 2022-01-15 13:55 1797
  // rep is unsigned to avoid overflow.
f8deb5b9 Poul Sander 2022-01-15 13:55 1798
  using rep =
f8deb5b9 Poul Sander 2022-01-15 13:55 1799
      conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
f8deb5b9 Poul Sander 2022-01-15 13:55 1800
                    unsigned, typename make_unsigned_or_unchanged<Rep>::type>;
f8deb5b9 Poul Sander 2022-01-15 13:55 1801
  rep val;
f8deb5b9 Poul Sander 2022-01-15 13:55 1802
  using seconds = std::chrono::duration<rep>;
f8deb5b9 Poul Sander 2022-01-15 13:55 1803
  seconds s;
f8deb5b9 Poul Sander 2022-01-15 13:55 1804
  using milliseconds = std::chrono::duration<rep, std::milli>;
f8deb5b9 Poul Sander 2022-01-15 13:55 1805
  bool negative;
f8deb5b9 Poul Sander 2022-01-15 13:55 1806
f8deb5b9 Poul Sander 2022-01-15 13:55 1807
  using char_type = typename FormatContext::char_type;
f8deb5b9 Poul Sander 2022-01-15 13:55 1808
  using tm_writer_type = tm_writer<OutputIt, char_type>;
f8deb5b9 Poul Sander 2022-01-15 13:55 1809
f8deb5b9 Poul Sander 2022-01-15 13:55 1810
  chrono_formatter(FormatContext& ctx, OutputIt o,
f8deb5b9 Poul Sander 2022-01-15 13:55 1811
                   std::chrono::duration<Rep, Period> d)
f8deb5b9 Poul Sander 2022-01-15 13:55 1812
      : context(ctx),
f8deb5b9 Poul Sander 2022-01-15 13:55 1813
        out(o),
f8deb5b9 Poul Sander 2022-01-15 13:55 1814
        val(static_cast<rep>(d.count())),
f8deb5b9 Poul Sander 2022-01-15 13:55 1815
        negative(false) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1816
    if (d.count() < 0) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1817
      val = 0 - val;
f8deb5b9 Poul Sander 2022-01-15 13:55 1818
      negative = true;
f8deb5b9 Poul Sander 2022-01-15 13:55 1819
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1820
f8deb5b9 Poul Sander 2022-01-15 13:55 1821
    // this may overflow and/or the result may not fit in the
f8deb5b9 Poul Sander 2022-01-15 13:55 1822
    // target type.
f8deb5b9 Poul Sander 2022-01-15 13:55 1823
    // might need checked conversion (rep!=Rep)
47fd5c32 Poul Sander 2024-10-05 08:44 1824
    s = fmt_duration_cast<seconds>(std::chrono::duration<rep, Period>(val));
f8deb5b9 Poul Sander 2022-01-15 13:55 1825
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1826
f8deb5b9 Poul Sander 2022-01-15 13:55 1827
  // returns true if nan or inf, writes to out.
47fd5c32 Poul Sander 2024-10-05 08:44 1828
  auto handle_nan_inf() -> bool {
f8deb5b9 Poul Sander 2022-01-15 13:55 1829
    if (isfinite(val)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1830
      return false;
f8deb5b9 Poul Sander 2022-01-15 13:55 1831
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1832
    if (isnan(val)) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1833
      write_nan();
f8deb5b9 Poul Sander 2022-01-15 13:55 1834
      return true;
f8deb5b9 Poul Sander 2022-01-15 13:55 1835
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1836
    // must be +-inf
f8deb5b9 Poul Sander 2022-01-15 13:55 1837
    if (val > 0) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1838
      write_pinf();
f8deb5b9 Poul Sander 2022-01-15 13:55 1839
    } else {
f8deb5b9 Poul Sander 2022-01-15 13:55 1840
      write_ninf();
f8deb5b9 Poul Sander 2022-01-15 13:55 1841
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1842
    return true;
f8deb5b9 Poul Sander 2022-01-15 13:55 1843
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1844
47fd5c32 Poul Sander 2024-10-05 08:44 1845
  auto days() const -> Rep { return static_cast<Rep>(s.count() / 86400); }
47fd5c32 Poul Sander 2024-10-05 08:44 1846
  auto hour() const -> Rep {
47fd5c32 Poul Sander 2024-10-05 08:44 1847
    return static_cast<Rep>(mod((s.count() / 3600), 24));
47fd5c32 Poul Sander 2024-10-05 08:44 1848
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1849
47fd5c32 Poul Sander 2024-10-05 08:44 1850
  auto hour12() const -> Rep {
f8deb5b9 Poul Sander 2022-01-15 13:55 1851
    Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
f8deb5b9 Poul Sander 2022-01-15 13:55 1852
    return hour <= 0 ? 12 : hour;
f8deb5b9 Poul Sander 2022-01-15 13:55 1853
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1854
47fd5c32 Poul Sander 2024-10-05 08:44 1855
  auto minute() const -> Rep {
47fd5c32 Poul Sander 2024-10-05 08:44 1856
    return static_cast<Rep>(mod((s.count() / 60), 60));
47fd5c32 Poul Sander 2024-10-05 08:44 1857
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1858
  auto second() const -> Rep { return static_cast<Rep>(mod(s.count(), 60)); }
f8deb5b9 Poul Sander 2022-01-15 13:55 1859
47fd5c32 Poul Sander 2024-10-05 08:44 1860
  auto time() const -> std::tm {
f8deb5b9 Poul Sander 2022-01-15 13:55 1861
    auto time = std::tm();
f8deb5b9 Poul Sander 2022-01-15 13:55 1862
    time.tm_hour = to_nonnegative_int(hour(), 24);
f8deb5b9 Poul Sander 2022-01-15 13:55 1863
    time.tm_min = to_nonnegative_int(minute(), 60);
f8deb5b9 Poul Sander 2022-01-15 13:55 1864
    time.tm_sec = to_nonnegative_int(second(), 60);
f8deb5b9 Poul Sander 2022-01-15 13:55 1865
    return time;
f8deb5b9 Poul Sander 2022-01-15 13:55 1866
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1867
f8deb5b9 Poul Sander 2022-01-15 13:55 1868
  void write_sign() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1869
    if (negative) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1870
      *out++ = '-';
f8deb5b9 Poul Sander 2022-01-15 13:55 1871
      negative = false;
f8deb5b9 Poul Sander 2022-01-15 13:55 1872
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1873
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1874
47fd5c32 Poul Sander 2024-10-05 08:44 1875
  void write(Rep value, int width, pad_type pad = pad_type::zero) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1876
    write_sign();
f8deb5b9 Poul Sander 2022-01-15 13:55 1877
    if (isnan(value)) return write_nan();
f8deb5b9 Poul Sander 2022-01-15 13:55 1878
    uint32_or_64_or_128_t<int> n =
f8deb5b9 Poul Sander 2022-01-15 13:55 1879
        to_unsigned(to_nonnegative_int(value, max_value<int>()));
f8deb5b9 Poul Sander 2022-01-15 13:55 1880
    int num_digits = detail::count_digits(n);
47fd5c32 Poul Sander 2024-10-05 08:44 1881
    if (width > num_digits) {
47fd5c32 Poul Sander 2024-10-05 08:44 1882
      out = detail::write_padding(out, pad, width - num_digits);
f8deb5b9 Poul Sander 2022-01-15 13:55 1883
    }
47fd5c32 Poul Sander 2024-10-05 08:44 1884
    out = format_decimal<char_type>(out, n, num_digits).end;
f8deb5b9 Poul Sander 2022-01-15 13:55 1885
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1886
f8deb5b9 Poul Sander 2022-01-15 13:55 1887
  void write_nan() { std::copy_n("nan", 3, out); }
f8deb5b9 Poul Sander 2022-01-15 13:55 1888
  void write_pinf() { std::copy_n("inf", 3, out); }
f8deb5b9 Poul Sander 2022-01-15 13:55 1889
  void write_ninf() { std::copy_n("-inf", 4, out); }
f8deb5b9 Poul Sander 2022-01-15 13:55 1890
f8deb5b9 Poul Sander 2022-01-15 13:55 1891
  template <typename Callback, typename... Args>
f8deb5b9 Poul Sander 2022-01-15 13:55 1892
  void format_tm(const tm& time, Callback cb, Args... args) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1893
    if (isnan(val)) return write_nan();
f8deb5b9 Poul Sander 2022-01-15 13:55 1894
    get_locale loc(localized, context.locale());
f8deb5b9 Poul Sander 2022-01-15 13:55 1895
    auto w = tm_writer_type(loc, out, time);
f8deb5b9 Poul Sander 2022-01-15 13:55 1896
    (w.*cb)(args...);
f8deb5b9 Poul Sander 2022-01-15 13:55 1897
    out = w.out();
f8deb5b9 Poul Sander 2022-01-15 13:55 1898
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1899
f8deb5b9 Poul Sander 2022-01-15 13:55 1900
  void on_text(const char_type* begin, const char_type* end) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1901
    std::copy(begin, end, out);
f8deb5b9 Poul Sander 2022-01-15 13:55 1902
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1903
f8deb5b9 Poul Sander 2022-01-15 13:55 1904
  // These are not implemented because durations don't have date information.
f8deb5b9 Poul Sander 2022-01-15 13:55 1905
  void on_abbr_weekday() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1906
  void on_full_weekday() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1907
  void on_dec0_weekday(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1908
  void on_dec1_weekday(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1909
  void on_abbr_month() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1910
  void on_full_month() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1911
  void on_datetime(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1912
  void on_loc_date(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1913
  void on_loc_time(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1914
  void on_us_date() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1915
  void on_iso_date() {}
47fd5c32 Poul Sander 2024-10-05 08:44 1916
  void on_utc_offset(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1917
  void on_tz_name() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1918
  void on_year(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1919
  void on_short_year(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1920
  void on_offset_year() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1921
  void on_century(numeric_system) {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1922
  void on_iso_week_based_year() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1923
  void on_iso_week_based_short_year() {}
f8deb5b9 Poul Sander 2022-01-15 13:55 1924
  void on_dec_month(numeric_system) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1925
  void on_dec0_week_of_year(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1926
  void on_dec1_week_of_year(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1927
  void on_iso_week_of_year(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1928
  void on_day_of_month(numeric_system, pad_type) {}
47fd5c32 Poul Sander 2024-10-05 08:44 1929
47fd5c32 Poul Sander 2024-10-05 08:44 1930
  void on_day_of_year() {
47fd5c32 Poul Sander 2024-10-05 08:44 1931
    if (handle_nan_inf()) return;
47fd5c32 Poul Sander 2024-10-05 08:44 1932
    write(days(), 0);
47fd5c32 Poul Sander 2024-10-05 08:44 1933
  }
47fd5c32 Poul Sander 2024-10-05 08:44 1934
47fd5c32 Poul Sander 2024-10-05 08:44 1935
  void on_24_hour(numeric_system ns, pad_type pad) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1936
    if (handle_nan_inf()) return;
f8deb5b9 Poul Sander 2022-01-15 13:55 1937
47fd5c32 Poul Sander 2024-10-05 08:44 1938
    if (ns == numeric_system::standard) return write(hour(), 2, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1939
    auto time = tm();
f8deb5b9 Poul Sander 2022-01-15 13:55 1940
    time.tm_hour = to_nonnegative_int(hour(), 24);
47fd5c32 Poul Sander 2024-10-05 08:44 1941
    format_tm(time, &tm_writer_type::on_24_hour, ns, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1942
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1943
47fd5c32 Poul Sander 2024-10-05 08:44 1944
  void on_12_hour(numeric_system ns, pad_type pad) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1945
    if (handle_nan_inf()) return;
f8deb5b9 Poul Sander 2022-01-15 13:55 1946
47fd5c32 Poul Sander 2024-10-05 08:44 1947
    if (ns == numeric_system::standard) return write(hour12(), 2, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1948
    auto time = tm();
f8deb5b9 Poul Sander 2022-01-15 13:55 1949
    time.tm_hour = to_nonnegative_int(hour12(), 12);
47fd5c32 Poul Sander 2024-10-05 08:44 1950
    format_tm(time, &tm_writer_type::on_12_hour, ns, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1951
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1952
47fd5c32 Poul Sander 2024-10-05 08:44 1953
  void on_minute(numeric_system ns, pad_type pad) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1954
    if (handle_nan_inf()) return;
f8deb5b9 Poul Sander 2022-01-15 13:55 1955
47fd5c32 Poul Sander 2024-10-05 08:44 1956
    if (ns == numeric_system::standard) return write(minute(), 2, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1957
    auto time = tm();
f8deb5b9 Poul Sander 2022-01-15 13:55 1958
    time.tm_min = to_nonnegative_int(minute(), 60);
47fd5c32 Poul Sander 2024-10-05 08:44 1959
    format_tm(time, &tm_writer_type::on_minute, ns, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1960
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1961
47fd5c32 Poul Sander 2024-10-05 08:44 1962
  void on_second(numeric_system ns, pad_type pad) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1963
    if (handle_nan_inf()) return;
f8deb5b9 Poul Sander 2022-01-15 13:55 1964
f8deb5b9 Poul Sander 2022-01-15 13:55 1965
    if (ns == numeric_system::standard) {
47fd5c32 Poul Sander 2024-10-05 08:44 1966
      if (std::is_floating_point<rep>::value) {
47fd5c32 Poul Sander 2024-10-05 08:44 1967
        auto buf = memory_buffer();
47fd5c32 Poul Sander 2024-10-05 08:44 1968
        write_floating_seconds(buf, std::chrono::duration<rep, Period>(val),
47fd5c32 Poul Sander 2024-10-05 08:44 1969
                               precision);
47fd5c32 Poul Sander 2024-10-05 08:44 1970
        if (negative) *out++ = '-';
47fd5c32 Poul Sander 2024-10-05 08:44 1971
        if (buf.size() < 2 || buf[1] == '.') {
47fd5c32 Poul Sander 2024-10-05 08:44 1972
          out = detail::write_padding(out, pad);
47fd5c32 Poul Sander 2024-10-05 08:44 1973
        }
47fd5c32 Poul Sander 2024-10-05 08:44 1974
        out = std::copy(buf.begin(), buf.end(), out);
47fd5c32 Poul Sander 2024-10-05 08:44 1975
      } else {
47fd5c32 Poul Sander 2024-10-05 08:44 1976
        write(second(), 2, pad);
47fd5c32 Poul Sander 2024-10-05 08:44 1977
        write_fractional_seconds<char_type>(
47fd5c32 Poul Sander 2024-10-05 08:44 1978
            out, std::chrono::duration<rep, Period>(val), precision);
47fd5c32 Poul Sander 2024-10-05 08:44 1979
      }
f8deb5b9 Poul Sander 2022-01-15 13:55 1980
      return;
f8deb5b9 Poul Sander 2022-01-15 13:55 1981
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1982
    auto time = tm();
f8deb5b9 Poul Sander 2022-01-15 13:55 1983
    time.tm_sec = to_nonnegative_int(second(), 60);
47fd5c32 Poul Sander 2024-10-05 08:44 1984
    format_tm(time, &tm_writer_type::on_second, ns, pad);
f8deb5b9 Poul Sander 2022-01-15 13:55 1985
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1986
f8deb5b9 Poul Sander 2022-01-15 13:55 1987
  void on_12_hour_time() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1988
    if (handle_nan_inf()) return;
f8deb5b9 Poul Sander 2022-01-15 13:55 1989
    format_tm(time(), &tm_writer_type::on_12_hour_time);
f8deb5b9 Poul Sander 2022-01-15 13:55 1990
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 1991
f8deb5b9 Poul Sander 2022-01-15 13:55 1992
  void on_24_hour_time() {
f8deb5b9 Poul Sander 2022-01-15 13:55 1993
    if (handle_nan_inf()) {
f8deb5b9 Poul Sander 2022-01-15 13:55 1994
      *out++ = ':';
f8deb5b9 Poul Sander 2022-01-15 13:55 1995
      handle_nan_inf();
f8deb5b9 Poul Sander 2022-01-15 13:55 1996
      return;
f8deb5b9 Poul Sander 2022-01-15 13:55 1997
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 1998
f8deb5b9 Poul Sander 2022-01-15 13:55 1999
    write(hour(), 2);
f8deb5b9 Poul Sander 2022-01-15 13:55 2000
    *out++ = ':';
f8deb5b9 Poul Sander 2022-01-15 13:55 2001
    write(minute(), 2);
f8deb5b9 Poul Sander 2022-01-15 13:55 2002
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2003
f8deb5b9 Poul Sander 2022-01-15 13:55 2004
  void on_iso_time() {
f8deb5b9 Poul Sander 2022-01-15 13:55 2005
    on_24_hour_time();
f8deb5b9 Poul Sander 2022-01-15 13:55 2006
    *out++ = ':';
f8deb5b9 Poul Sander 2022-01-15 13:55 2007
    if (handle_nan_inf()) return;
47fd5c32 Poul Sander 2024-10-05 08:44 2008
    on_second(numeric_system::standard, pad_type::zero);
f8deb5b9 Poul Sander 2022-01-15 13:55 2009
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2010
f8deb5b9 Poul Sander 2022-01-15 13:55 2011
  void on_am_pm() {
f8deb5b9 Poul Sander 2022-01-15 13:55 2012
    if (handle_nan_inf()) return;
f8deb5b9 Poul Sander 2022-01-15 13:55 2013
    format_tm(time(), &tm_writer_type::on_am_pm);
f8deb5b9 Poul Sander 2022-01-15 13:55 2014
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2015
f8deb5b9 Poul Sander 2022-01-15 13:55 2016
  void on_duration_value() {
f8deb5b9 Poul Sander 2022-01-15 13:55 2017
    if (handle_nan_inf()) return;
f8deb5b9 Poul Sander 2022-01-15 13:55 2018
    write_sign();
f8deb5b9 Poul Sander 2022-01-15 13:55 2019
    out = format_duration_value<char_type>(out, val, precision);
f8deb5b9 Poul Sander 2022-01-15 13:55 2020
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2021
f8deb5b9 Poul Sander 2022-01-15 13:55 2022
  void on_duration_unit() {
f8deb5b9 Poul Sander 2022-01-15 13:55 2023
    out = format_duration_unit<char_type, Period>(out);
f8deb5b9 Poul Sander 2022-01-15 13:55 2024
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2025
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2026
47fd5c32 Poul Sander 2024-10-05 08:44 2027
}  // namespace detail
f8deb5b9 Poul Sander 2022-01-15 13:55 2028
f8deb5b9 Poul Sander 2022-01-15 13:55 2029
#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
f8deb5b9 Poul Sander 2022-01-15 13:55 2030
using weekday = std::chrono::weekday;
47fd5c32 Poul Sander 2024-10-05 08:44 2031
using day = std::chrono::day;
47fd5c32 Poul Sander 2024-10-05 08:44 2032
using month = std::chrono::month;
47fd5c32 Poul Sander 2024-10-05 08:44 2033
using year = std::chrono::year;
47fd5c32 Poul Sander 2024-10-05 08:44 2034
using year_month_day = std::chrono::year_month_day;
f8deb5b9 Poul Sander 2022-01-15 13:55 2035
#else
f8deb5b9 Poul Sander 2022-01-15 13:55 2036
// A fallback version of weekday.
f8deb5b9 Poul Sander 2022-01-15 13:55 2037
class weekday {
f8deb5b9 Poul Sander 2022-01-15 13:55 2038
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2039
  unsigned char value_;
f8deb5b9 Poul Sander 2022-01-15 13:55 2040
f8deb5b9 Poul Sander 2022-01-15 13:55 2041
 public:
f8deb5b9 Poul Sander 2022-01-15 13:55 2042
  weekday() = default;
47fd5c32 Poul Sander 2024-10-05 08:44 2043
  constexpr explicit weekday(unsigned wd) noexcept
47fd5c32 Poul Sander 2024-10-05 08:44 2044
      : value_(static_cast<unsigned char>(wd != 7 ? wd : 0)) {}
47fd5c32 Poul Sander 2024-10-05 08:44 2045
  constexpr auto c_encoding() const noexcept -> unsigned { return value_; }
47fd5c32 Poul Sander 2024-10-05 08:44 2046
};
47fd5c32 Poul Sander 2024-10-05 08:44 2047
47fd5c32 Poul Sander 2024-10-05 08:44 2048
class day {
47fd5c32 Poul Sander 2024-10-05 08:44 2049
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2050
  unsigned char value_;
47fd5c32 Poul Sander 2024-10-05 08:44 2051
47fd5c32 Poul Sander 2024-10-05 08:44 2052
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 2053
  day() = default;
47fd5c32 Poul Sander 2024-10-05 08:44 2054
  constexpr explicit day(unsigned d) noexcept
47fd5c32 Poul Sander 2024-10-05 08:44 2055
      : value_(static_cast<unsigned char>(d)) {}
47fd5c32 Poul Sander 2024-10-05 08:44 2056
  constexpr explicit operator unsigned() const noexcept { return value_; }
47fd5c32 Poul Sander 2024-10-05 08:44 2057
};
47fd5c32 Poul Sander 2024-10-05 08:44 2058
47fd5c32 Poul Sander 2024-10-05 08:44 2059
class month {
47fd5c32 Poul Sander 2024-10-05 08:44 2060
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2061
  unsigned char value_;
47fd5c32 Poul Sander 2024-10-05 08:44 2062
47fd5c32 Poul Sander 2024-10-05 08:44 2063
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 2064
  month() = default;
47fd5c32 Poul Sander 2024-10-05 08:44 2065
  constexpr explicit month(unsigned m) noexcept
47fd5c32 Poul Sander 2024-10-05 08:44 2066
      : value_(static_cast<unsigned char>(m)) {}
47fd5c32 Poul Sander 2024-10-05 08:44 2067
  constexpr explicit operator unsigned() const noexcept { return value_; }
47fd5c32 Poul Sander 2024-10-05 08:44 2068
};
47fd5c32 Poul Sander 2024-10-05 08:44 2069
47fd5c32 Poul Sander 2024-10-05 08:44 2070
class year {
47fd5c32 Poul Sander 2024-10-05 08:44 2071
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2072
  int value_;
47fd5c32 Poul Sander 2024-10-05 08:44 2073
47fd5c32 Poul Sander 2024-10-05 08:44 2074
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 2075
  year() = default;
47fd5c32 Poul Sander 2024-10-05 08:44 2076
  constexpr explicit year(int y) noexcept : value_(y) {}
47fd5c32 Poul Sander 2024-10-05 08:44 2077
  constexpr explicit operator int() const noexcept { return value_; }
f8deb5b9 Poul Sander 2022-01-15 13:55 2078
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2079
47fd5c32 Poul Sander 2024-10-05 08:44 2080
class year_month_day {
47fd5c32 Poul Sander 2024-10-05 08:44 2081
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2082
  fmt::year year_;
47fd5c32 Poul Sander 2024-10-05 08:44 2083
  fmt::month month_;
47fd5c32 Poul Sander 2024-10-05 08:44 2084
  fmt::day day_;
47fd5c32 Poul Sander 2024-10-05 08:44 2085
47fd5c32 Poul Sander 2024-10-05 08:44 2086
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 2087
  year_month_day() = default;
47fd5c32 Poul Sander 2024-10-05 08:44 2088
  constexpr year_month_day(const year& y, const month& m, const day& d) noexcept
47fd5c32 Poul Sander 2024-10-05 08:44 2089
      : year_(y), month_(m), day_(d) {}
47fd5c32 Poul Sander 2024-10-05 08:44 2090
  constexpr auto year() const noexcept -> fmt::year { return year_; }
47fd5c32 Poul Sander 2024-10-05 08:44 2091
  constexpr auto month() const noexcept -> fmt::month { return month_; }
47fd5c32 Poul Sander 2024-10-05 08:44 2092
  constexpr auto day() const noexcept -> fmt::day { return day_; }
47fd5c32 Poul Sander 2024-10-05 08:44 2093
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2094
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 2095
47fd5c32 Poul Sander 2024-10-05 08:44 2096
template <typename Char>
47fd5c32 Poul Sander 2024-10-05 08:44 2097
struct formatter<weekday, Char> : private formatter<std::tm, Char> {
f8deb5b9 Poul Sander 2022-01-15 13:55 2098
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2099
  bool localized_ = false;
47fd5c32 Poul Sander 2024-10-05 08:44 2100
  bool use_tm_formatter_ = false;
f8deb5b9 Poul Sander 2022-01-15 13:55 2101
f8deb5b9 Poul Sander 2022-01-15 13:55 2102
 public:
f8deb5b9 Poul Sander 2022-01-15 13:55 2103
  FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
f8deb5b9 Poul Sander 2022-01-15 13:55 2104
      -> decltype(ctx.begin()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2105
    auto it = ctx.begin(), end = ctx.end();
47fd5c32 Poul Sander 2024-10-05 08:44 2106
    if (it != end && *it == 'L') {
47fd5c32 Poul Sander 2024-10-05 08:44 2107
      ++it;
47fd5c32 Poul Sander 2024-10-05 08:44 2108
      localized_ = true;
47fd5c32 Poul Sander 2024-10-05 08:44 2109
      return it;
f8deb5b9 Poul Sander 2022-01-15 13:55 2110
    }
47fd5c32 Poul Sander 2024-10-05 08:44 2111
    use_tm_formatter_ = it != end && *it != '}';
47fd5c32 Poul Sander 2024-10-05 08:44 2112
    return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
f8deb5b9 Poul Sander 2022-01-15 13:55 2113
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2114
f8deb5b9 Poul Sander 2022-01-15 13:55 2115
  template <typename FormatContext>
f8deb5b9 Poul Sander 2022-01-15 13:55 2116
  auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) {
f8deb5b9 Poul Sander 2022-01-15 13:55 2117
    auto time = std::tm();
f8deb5b9 Poul Sander 2022-01-15 13:55 2118
    time.tm_wday = static_cast<int>(wd.c_encoding());
47fd5c32 Poul Sander 2024-10-05 08:44 2119
    if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2120
    detail::get_locale loc(localized_, ctx.locale());
f8deb5b9 Poul Sander 2022-01-15 13:55 2121
    auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
f8deb5b9 Poul Sander 2022-01-15 13:55 2122
    w.on_abbr_weekday();
f8deb5b9 Poul Sander 2022-01-15 13:55 2123
    return w.out();
f8deb5b9 Poul Sander 2022-01-15 13:55 2124
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2125
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2126
47fd5c32 Poul Sander 2024-10-05 08:44 2127
template <typename Char>
47fd5c32 Poul Sander 2024-10-05 08:44 2128
struct formatter<day, Char> : private formatter<std::tm, Char> {
f8deb5b9 Poul Sander 2022-01-15 13:55 2129
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2130
  bool use_tm_formatter_ = false;
f8deb5b9 Poul Sander 2022-01-15 13:55 2131
47fd5c32 Poul Sander 2024-10-05 08:44 2132
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 2133
  FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
47fd5c32 Poul Sander 2024-10-05 08:44 2134
      -> decltype(ctx.begin()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2135
    auto it = ctx.begin(), end = ctx.end();
47fd5c32 Poul Sander 2024-10-05 08:44 2136
    use_tm_formatter_ = it != end && *it != '}';
47fd5c32 Poul Sander 2024-10-05 08:44 2137
    return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
47fd5c32 Poul Sander 2024-10-05 08:44 2138
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2139
47fd5c32 Poul Sander 2024-10-05 08:44 2140
  template <typename FormatContext>
47fd5c32 Poul Sander 2024-10-05 08:44 2141
  auto format(day d, FormatContext& ctx) const -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2142
    auto time = std::tm();
47fd5c32 Poul Sander 2024-10-05 08:44 2143
    time.tm_mday = static_cast<int>(static_cast<unsigned>(d));
47fd5c32 Poul Sander 2024-10-05 08:44 2144
    if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2145
    detail::get_locale loc(false, ctx.locale());
47fd5c32 Poul Sander 2024-10-05 08:44 2146
    auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
47fd5c32 Poul Sander 2024-10-05 08:44 2147
    w.on_day_of_month(detail::numeric_system::standard, detail::pad_type::zero);
47fd5c32 Poul Sander 2024-10-05 08:44 2148
    return w.out();
47fd5c32 Poul Sander 2024-10-05 08:44 2149
  }
47fd5c32 Poul Sander 2024-10-05 08:44 2150
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2151
47fd5c32 Poul Sander 2024-10-05 08:44 2152
template <typename Char>
47fd5c32 Poul Sander 2024-10-05 08:44 2153
struct formatter<month, Char> : private formatter<std::tm, Char> {
47fd5c32 Poul Sander 2024-10-05 08:44 2154
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2155
  bool localized_ = false;
47fd5c32 Poul Sander 2024-10-05 08:44 2156
  bool use_tm_formatter_ = false;
f8deb5b9 Poul Sander 2022-01-15 13:55 2157
47fd5c32 Poul Sander 2024-10-05 08:44 2158
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 2159
  FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
47fd5c32 Poul Sander 2024-10-05 08:44 2160
      -> decltype(ctx.begin()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2161
    auto it = ctx.begin(), end = ctx.end();
47fd5c32 Poul Sander 2024-10-05 08:44 2162
    if (it != end && *it == 'L') {
47fd5c32 Poul Sander 2024-10-05 08:44 2163
      ++it;
47fd5c32 Poul Sander 2024-10-05 08:44 2164
      localized_ = true;
47fd5c32 Poul Sander 2024-10-05 08:44 2165
      return it;
f8deb5b9 Poul Sander 2022-01-15 13:55 2166
    }
47fd5c32 Poul Sander 2024-10-05 08:44 2167
    use_tm_formatter_ = it != end && *it != '}';
47fd5c32 Poul Sander 2024-10-05 08:44 2168
    return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
47fd5c32 Poul Sander 2024-10-05 08:44 2169
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2170
47fd5c32 Poul Sander 2024-10-05 08:44 2171
  template <typename FormatContext>
47fd5c32 Poul Sander 2024-10-05 08:44 2172
  auto format(month m, FormatContext& ctx) const -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2173
    auto time = std::tm();
47fd5c32 Poul Sander 2024-10-05 08:44 2174
    time.tm_mon = static_cast<int>(static_cast<unsigned>(m)) - 1;
47fd5c32 Poul Sander 2024-10-05 08:44 2175
    if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2176
    detail::get_locale loc(localized_, ctx.locale());
47fd5c32 Poul Sander 2024-10-05 08:44 2177
    auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
47fd5c32 Poul Sander 2024-10-05 08:44 2178
    w.on_abbr_month();
47fd5c32 Poul Sander 2024-10-05 08:44 2179
    return w.out();
47fd5c32 Poul Sander 2024-10-05 08:44 2180
  }
47fd5c32 Poul Sander 2024-10-05 08:44 2181
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2182
47fd5c32 Poul Sander 2024-10-05 08:44 2183
template <typename Char>
47fd5c32 Poul Sander 2024-10-05 08:44 2184
struct formatter<year, Char> : private formatter<std::tm, Char> {
47fd5c32 Poul Sander 2024-10-05 08:44 2185
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2186
  bool use_tm_formatter_ = false;
f8deb5b9 Poul Sander 2022-01-15 13:55 2187
47fd5c32 Poul Sander 2024-10-05 08:44 2188
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 2189
  FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
47fd5c32 Poul Sander 2024-10-05 08:44 2190
      -> decltype(ctx.begin()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2191
    auto it = ctx.begin(), end = ctx.end();
47fd5c32 Poul Sander 2024-10-05 08:44 2192
    use_tm_formatter_ = it != end && *it != '}';
47fd5c32 Poul Sander 2024-10-05 08:44 2193
    return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
47fd5c32 Poul Sander 2024-10-05 08:44 2194
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2195
47fd5c32 Poul Sander 2024-10-05 08:44 2196
  template <typename FormatContext>
47fd5c32 Poul Sander 2024-10-05 08:44 2197
  auto format(year y, FormatContext& ctx) const -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2198
    auto time = std::tm();
47fd5c32 Poul Sander 2024-10-05 08:44 2199
    time.tm_year = static_cast<int>(y) - 1900;
47fd5c32 Poul Sander 2024-10-05 08:44 2200
    if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2201
    detail::get_locale loc(false, ctx.locale());
47fd5c32 Poul Sander 2024-10-05 08:44 2202
    auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
47fd5c32 Poul Sander 2024-10-05 08:44 2203
    w.on_year(detail::numeric_system::standard);
47fd5c32 Poul Sander 2024-10-05 08:44 2204
    return w.out();
47fd5c32 Poul Sander 2024-10-05 08:44 2205
  }
47fd5c32 Poul Sander 2024-10-05 08:44 2206
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2207
47fd5c32 Poul Sander 2024-10-05 08:44 2208
template <typename Char>
47fd5c32 Poul Sander 2024-10-05 08:44 2209
struct formatter<year_month_day, Char> : private formatter<std::tm, Char> {
47fd5c32 Poul Sander 2024-10-05 08:44 2210
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2211
  bool use_tm_formatter_ = false;
47fd5c32 Poul Sander 2024-10-05 08:44 2212
47fd5c32 Poul Sander 2024-10-05 08:44 2213
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 2214
  FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
47fd5c32 Poul Sander 2024-10-05 08:44 2215
      -> decltype(ctx.begin()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2216
    auto it = ctx.begin(), end = ctx.end();
47fd5c32 Poul Sander 2024-10-05 08:44 2217
    use_tm_formatter_ = it != end && *it != '}';
47fd5c32 Poul Sander 2024-10-05 08:44 2218
    return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
47fd5c32 Poul Sander 2024-10-05 08:44 2219
  }
47fd5c32 Poul Sander 2024-10-05 08:44 2220
47fd5c32 Poul Sander 2024-10-05 08:44 2221
  template <typename FormatContext>
47fd5c32 Poul Sander 2024-10-05 08:44 2222
  auto format(year_month_day val, FormatContext& ctx) const
47fd5c32 Poul Sander 2024-10-05 08:44 2223
      -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2224
    auto time = std::tm();
47fd5c32 Poul Sander 2024-10-05 08:44 2225
    time.tm_year = static_cast<int>(val.year()) - 1900;
47fd5c32 Poul Sander 2024-10-05 08:44 2226
    time.tm_mon = static_cast<int>(static_cast<unsigned>(val.month())) - 1;
47fd5c32 Poul Sander 2024-10-05 08:44 2227
    time.tm_mday = static_cast<int>(static_cast<unsigned>(val.day()));
47fd5c32 Poul Sander 2024-10-05 08:44 2228
    if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2229
    detail::get_locale loc(true, ctx.locale());
47fd5c32 Poul Sander 2024-10-05 08:44 2230
    auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
47fd5c32 Poul Sander 2024-10-05 08:44 2231
    w.on_iso_date();
47fd5c32 Poul Sander 2024-10-05 08:44 2232
    return w.out();
f8deb5b9 Poul Sander 2022-01-15 13:55 2233
  }
47fd5c32 Poul Sander 2024-10-05 08:44 2234
};
47fd5c32 Poul Sander 2024-10-05 08:44 2235
47fd5c32 Poul Sander 2024-10-05 08:44 2236
template <typename Rep, typename Period, typename Char>
47fd5c32 Poul Sander 2024-10-05 08:44 2237
struct formatter<std::chrono::duration<Rep, Period>, Char> {
47fd5c32 Poul Sander 2024-10-05 08:44 2238
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2239
  format_specs specs_;
47fd5c32 Poul Sander 2024-10-05 08:44 2240
  detail::arg_ref<Char> width_ref_;
47fd5c32 Poul Sander 2024-10-05 08:44 2241
  detail::arg_ref<Char> precision_ref_;
47fd5c32 Poul Sander 2024-10-05 08:44 2242
  bool localized_ = false;
47fd5c32 Poul Sander 2024-10-05 08:44 2243
  basic_string_view<Char> format_str_;
f8deb5b9 Poul Sander 2022-01-15 13:55 2244
f8deb5b9 Poul Sander 2022-01-15 13:55 2245
 public:
f8deb5b9 Poul Sander 2022-01-15 13:55 2246
  FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
f8deb5b9 Poul Sander 2022-01-15 13:55 2247
      -> decltype(ctx.begin()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2248
    auto it = ctx.begin(), end = ctx.end();
47fd5c32 Poul Sander 2024-10-05 08:44 2249
    if (it == end || *it == '}') return it;
47fd5c32 Poul Sander 2024-10-05 08:44 2250
47fd5c32 Poul Sander 2024-10-05 08:44 2251
    it = detail::parse_align(it, end, specs_);
47fd5c32 Poul Sander 2024-10-05 08:44 2252
    if (it == end) return it;
47fd5c32 Poul Sander 2024-10-05 08:44 2253
47fd5c32 Poul Sander 2024-10-05 08:44 2254
    it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2255
    if (it == end) return it;
47fd5c32 Poul Sander 2024-10-05 08:44 2256
47fd5c32 Poul Sander 2024-10-05 08:44 2257
    auto checker = detail::chrono_format_checker();
47fd5c32 Poul Sander 2024-10-05 08:44 2258
    if (*it == '.') {
47fd5c32 Poul Sander 2024-10-05 08:44 2259
      checker.has_precision_integral = !std::is_floating_point<Rep>::value;
47fd5c32 Poul Sander 2024-10-05 08:44 2260
      it = detail::parse_precision(it, end, specs_.precision, precision_ref_,
47fd5c32 Poul Sander 2024-10-05 08:44 2261
                                   ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2262
    }
47fd5c32 Poul Sander 2024-10-05 08:44 2263
    if (it != end && *it == 'L') {
47fd5c32 Poul Sander 2024-10-05 08:44 2264
      localized_ = true;
47fd5c32 Poul Sander 2024-10-05 08:44 2265
      ++it;
47fd5c32 Poul Sander 2024-10-05 08:44 2266
    }
47fd5c32 Poul Sander 2024-10-05 08:44 2267
    end = detail::parse_chrono_format(it, end, checker);
47fd5c32 Poul Sander 2024-10-05 08:44 2268
    format_str_ = {it, detail::to_unsigned(end - it)};
47fd5c32 Poul Sander 2024-10-05 08:44 2269
    return end;
f8deb5b9 Poul Sander 2022-01-15 13:55 2270
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2271
f8deb5b9 Poul Sander 2022-01-15 13:55 2272
  template <typename FormatContext>
47fd5c32 Poul Sander 2024-10-05 08:44 2273
  auto format(std::chrono::duration<Rep, Period> d, FormatContext& ctx) const
f8deb5b9 Poul Sander 2022-01-15 13:55 2274
      -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2275
    auto specs = specs_;
47fd5c32 Poul Sander 2024-10-05 08:44 2276
    auto precision = specs.precision;
47fd5c32 Poul Sander 2024-10-05 08:44 2277
    specs.precision = -1;
47fd5c32 Poul Sander 2024-10-05 08:44 2278
    auto begin = format_str_.begin(), end = format_str_.end();
f8deb5b9 Poul Sander 2022-01-15 13:55 2279
    // As a possible future optimization, we could avoid extra copying if width
f8deb5b9 Poul Sander 2022-01-15 13:55 2280
    // is not specified.
47fd5c32 Poul Sander 2024-10-05 08:44 2281
    auto buf = basic_memory_buffer<Char>();
f8deb5b9 Poul Sander 2022-01-15 13:55 2282
    auto out = std::back_inserter(buf);
47fd5c32 Poul Sander 2024-10-05 08:44 2283
    detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
47fd5c32 Poul Sander 2024-10-05 08:44 2284
                                                       ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2285
    detail::handle_dynamic_spec<detail::precision_checker>(precision,
47fd5c32 Poul Sander 2024-10-05 08:44 2286
                                                           precision_ref_, ctx);
f8deb5b9 Poul Sander 2022-01-15 13:55 2287
    if (begin == end || *begin == '}') {
47fd5c32 Poul Sander 2024-10-05 08:44 2288
      out = detail::format_duration_value<Char>(out, d.count(), precision);
f8deb5b9 Poul Sander 2022-01-15 13:55 2289
      detail::format_duration_unit<Char, Period>(out);
f8deb5b9 Poul Sander 2022-01-15 13:55 2290
    } else {
47fd5c32 Poul Sander 2024-10-05 08:44 2291
      using chrono_formatter =
47fd5c32 Poul Sander 2024-10-05 08:44 2292
          detail::chrono_formatter<FormatContext, decltype(out), Rep, Period>;
47fd5c32 Poul Sander 2024-10-05 08:44 2293
      auto f = chrono_formatter(ctx, out, d);
47fd5c32 Poul Sander 2024-10-05 08:44 2294
      f.precision = precision;
47fd5c32 Poul Sander 2024-10-05 08:44 2295
      f.localized = localized_;
f8deb5b9 Poul Sander 2022-01-15 13:55 2296
      detail::parse_chrono_format(begin, end, f);
f8deb5b9 Poul Sander 2022-01-15 13:55 2297
    }
f8deb5b9 Poul Sander 2022-01-15 13:55 2298
    return detail::write(
47fd5c32 Poul Sander 2024-10-05 08:44 2299
        ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
f8deb5b9 Poul Sander 2022-01-15 13:55 2300
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2301
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2302
f8deb5b9 Poul Sander 2022-01-15 13:55 2303
template <typename Char, typename Duration>
f8deb5b9 Poul Sander 2022-01-15 13:55 2304
struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
f8deb5b9 Poul Sander 2022-01-15 13:55 2305
                 Char> : formatter<std::tm, Char> {
f8deb5b9 Poul Sander 2022-01-15 13:55 2306
  FMT_CONSTEXPR formatter() {
47fd5c32 Poul Sander 2024-10-05 08:44 2307
    this->format_str_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
47fd5c32 Poul Sander 2024-10-05 08:44 2308
  }
47fd5c32 Poul Sander 2024-10-05 08:44 2309
47fd5c32 Poul Sander 2024-10-05 08:44 2310
  template <typename FormatContext>
47fd5c32 Poul Sander 2024-10-05 08:44 2311
  auto format(std::chrono::time_point<std::chrono::system_clock, Duration> val,
47fd5c32 Poul Sander 2024-10-05 08:44 2312
              FormatContext& ctx) const -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2313
    std::tm tm = gmtime(val);
47fd5c32 Poul Sander 2024-10-05 08:44 2314
    using period = typename Duration::period;
47fd5c32 Poul Sander 2024-10-05 08:44 2315
    if (detail::const_check(
47fd5c32 Poul Sander 2024-10-05 08:44 2316
            period::num == 1 && period::den == 1 &&
47fd5c32 Poul Sander 2024-10-05 08:44 2317
            !std::is_floating_point<typename Duration::rep>::value)) {
47fd5c32 Poul Sander 2024-10-05 08:44 2318
      return formatter<std::tm, Char>::format(tm, ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2319
    }
47fd5c32 Poul Sander 2024-10-05 08:44 2320
    Duration epoch = val.time_since_epoch();
47fd5c32 Poul Sander 2024-10-05 08:44 2321
    Duration subsecs = detail::fmt_duration_cast<Duration>(
47fd5c32 Poul Sander 2024-10-05 08:44 2322
        epoch - detail::fmt_duration_cast<std::chrono::seconds>(epoch));
47fd5c32 Poul Sander 2024-10-05 08:44 2323
    if (subsecs.count() < 0) {
47fd5c32 Poul Sander 2024-10-05 08:44 2324
      auto second =
47fd5c32 Poul Sander 2024-10-05 08:44 2325
          detail::fmt_duration_cast<Duration>(std::chrono::seconds(1));
47fd5c32 Poul Sander 2024-10-05 08:44 2326
      if (tm.tm_sec != 0)
47fd5c32 Poul Sander 2024-10-05 08:44 2327
        --tm.tm_sec;
47fd5c32 Poul Sander 2024-10-05 08:44 2328
      else
47fd5c32 Poul Sander 2024-10-05 08:44 2329
        tm = gmtime(val - second);
47fd5c32 Poul Sander 2024-10-05 08:44 2330
      subsecs += detail::fmt_duration_cast<Duration>(std::chrono::seconds(1));
47fd5c32 Poul Sander 2024-10-05 08:44 2331
    }
47fd5c32 Poul Sander 2024-10-05 08:44 2332
    return formatter<std::tm, Char>::do_format(tm, ctx, &subsecs);
f8deb5b9 Poul Sander 2022-01-15 13:55 2333
  }
47fd5c32 Poul Sander 2024-10-05 08:44 2334
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2335
47fd5c32 Poul Sander 2024-10-05 08:44 2336
#if FMT_USE_LOCAL_TIME
47fd5c32 Poul Sander 2024-10-05 08:44 2337
template <typename Char, typename Duration>
47fd5c32 Poul Sander 2024-10-05 08:44 2338
struct formatter<std::chrono::local_time<Duration>, Char>
47fd5c32 Poul Sander 2024-10-05 08:44 2339
    : formatter<std::tm, Char> {
47fd5c32 Poul Sander 2024-10-05 08:44 2340
  FMT_CONSTEXPR formatter() {
47fd5c32 Poul Sander 2024-10-05 08:44 2341
    this->format_str_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
f8deb5b9 Poul Sander 2022-01-15 13:55 2342
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2343
f8deb5b9 Poul Sander 2022-01-15 13:55 2344
  template <typename FormatContext>
47fd5c32 Poul Sander 2024-10-05 08:44 2345
  auto format(std::chrono::local_time<Duration> val, FormatContext& ctx) const
47fd5c32 Poul Sander 2024-10-05 08:44 2346
      -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2347
    using period = typename Duration::period;
47fd5c32 Poul Sander 2024-10-05 08:44 2348
    if (period::num != 1 || period::den != 1 ||
47fd5c32 Poul Sander 2024-10-05 08:44 2349
        std::is_floating_point<typename Duration::rep>::value) {
47fd5c32 Poul Sander 2024-10-05 08:44 2350
      const auto epoch = val.time_since_epoch();
47fd5c32 Poul Sander 2024-10-05 08:44 2351
      const auto subsecs = detail::fmt_duration_cast<Duration>(
47fd5c32 Poul Sander 2024-10-05 08:44 2352
          epoch - detail::fmt_duration_cast<std::chrono::seconds>(epoch));
47fd5c32 Poul Sander 2024-10-05 08:44 2353
47fd5c32 Poul Sander 2024-10-05 08:44 2354
      return formatter<std::tm, Char>::do_format(localtime(val), ctx, &subsecs);
47fd5c32 Poul Sander 2024-10-05 08:44 2355
    }
47fd5c32 Poul Sander 2024-10-05 08:44 2356
f8deb5b9 Poul Sander 2022-01-15 13:55 2357
    return formatter<std::tm, Char>::format(localtime(val), ctx);
f8deb5b9 Poul Sander 2022-01-15 13:55 2358
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2359
};
47fd5c32 Poul Sander 2024-10-05 08:44 2360
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 2361
47fd5c32 Poul Sander 2024-10-05 08:44 2362
#if FMT_USE_UTC_TIME
f8deb5b9 Poul Sander 2022-01-15 13:55 2363
template <typename Char, typename Duration>
47fd5c32 Poul Sander 2024-10-05 08:44 2364
struct formatter<std::chrono::time_point<std::chrono::utc_clock, Duration>,
47fd5c32 Poul Sander 2024-10-05 08:44 2365
                 Char>
47fd5c32 Poul Sander 2024-10-05 08:44 2366
    : formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
47fd5c32 Poul Sander 2024-10-05 08:44 2367
                Char> {
47fd5c32 Poul Sander 2024-10-05 08:44 2368
  template <typename FormatContext>
47fd5c32 Poul Sander 2024-10-05 08:44 2369
  auto format(std::chrono::time_point<std::chrono::utc_clock, Duration> val,
47fd5c32 Poul Sander 2024-10-05 08:44 2370
              FormatContext& ctx) const -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2371
    return formatter<
47fd5c32 Poul Sander 2024-10-05 08:44 2372
        std::chrono::time_point<std::chrono::system_clock, Duration>,
47fd5c32 Poul Sander 2024-10-05 08:44 2373
        Char>::format(std::chrono::utc_clock::to_sys(val), ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2374
  }
47fd5c32 Poul Sander 2024-10-05 08:44 2375
};
47fd5c32 Poul Sander 2024-10-05 08:44 2376
#endif
f8deb5b9 Poul Sander 2022-01-15 13:55 2377
f8deb5b9 Poul Sander 2022-01-15 13:55 2378
template <typename Char> struct formatter<std::tm, Char> {
f8deb5b9 Poul Sander 2022-01-15 13:55 2379
 private:
47fd5c32 Poul Sander 2024-10-05 08:44 2380
  format_specs specs_;
47fd5c32 Poul Sander 2024-10-05 08:44 2381
  detail::arg_ref<Char> width_ref_;
f8deb5b9 Poul Sander 2022-01-15 13:55 2382
f8deb5b9 Poul Sander 2022-01-15 13:55 2383
 protected:
47fd5c32 Poul Sander 2024-10-05 08:44 2384
  basic_string_view<Char> format_str_;
47fd5c32 Poul Sander 2024-10-05 08:44 2385
47fd5c32 Poul Sander 2024-10-05 08:44 2386
  template <typename FormatContext, typename Duration>
47fd5c32 Poul Sander 2024-10-05 08:44 2387
  auto do_format(const std::tm& tm, FormatContext& ctx,
47fd5c32 Poul Sander 2024-10-05 08:44 2388
                 const Duration* subsecs) const -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2389
    auto specs = specs_;
47fd5c32 Poul Sander 2024-10-05 08:44 2390
    auto buf = basic_memory_buffer<Char>();
47fd5c32 Poul Sander 2024-10-05 08:44 2391
    auto out = std::back_inserter(buf);
47fd5c32 Poul Sander 2024-10-05 08:44 2392
    detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
47fd5c32 Poul Sander 2024-10-05 08:44 2393
                                                       ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2394
47fd5c32 Poul Sander 2024-10-05 08:44 2395
    auto loc_ref = ctx.locale();
47fd5c32 Poul Sander 2024-10-05 08:44 2396
    detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
47fd5c32 Poul Sander 2024-10-05 08:44 2397
    auto w =
47fd5c32 Poul Sander 2024-10-05 08:44 2398
        detail::tm_writer<decltype(out), Char, Duration>(loc, out, tm, subsecs);
47fd5c32 Poul Sander 2024-10-05 08:44 2399
    detail::parse_chrono_format(format_str_.begin(), format_str_.end(), w);
47fd5c32 Poul Sander 2024-10-05 08:44 2400
    return detail::write(
47fd5c32 Poul Sander 2024-10-05 08:44 2401
        ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
f8deb5b9 Poul Sander 2022-01-15 13:55 2402
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2403
f8deb5b9 Poul Sander 2022-01-15 13:55 2404
 public:
47fd5c32 Poul Sander 2024-10-05 08:44 2405
  FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
47fd5c32 Poul Sander 2024-10-05 08:44 2406
      -> decltype(ctx.begin()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2407
    auto it = ctx.begin(), end = ctx.end();
47fd5c32 Poul Sander 2024-10-05 08:44 2408
    if (it == end || *it == '}') return it;
47fd5c32 Poul Sander 2024-10-05 08:44 2409
47fd5c32 Poul Sander 2024-10-05 08:44 2410
    it = detail::parse_align(it, end, specs_);
47fd5c32 Poul Sander 2024-10-05 08:44 2411
    if (it == end) return it;
47fd5c32 Poul Sander 2024-10-05 08:44 2412
47fd5c32 Poul Sander 2024-10-05 08:44 2413
    it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
47fd5c32 Poul Sander 2024-10-05 08:44 2414
    if (it == end) return it;
47fd5c32 Poul Sander 2024-10-05 08:44 2415
47fd5c32 Poul Sander 2024-10-05 08:44 2416
    end = detail::parse_chrono_format(it, end, detail::tm_format_checker());
47fd5c32 Poul Sander 2024-10-05 08:44 2417
    // Replace the default format_str only if the new spec is not empty.
47fd5c32 Poul Sander 2024-10-05 08:44 2418
    if (end != it) format_str_ = {it, detail::to_unsigned(end - it)};
47fd5c32 Poul Sander 2024-10-05 08:44 2419
    return end;
f8deb5b9 Poul Sander 2022-01-15 13:55 2420
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2421
f8deb5b9 Poul Sander 2022-01-15 13:55 2422
  template <typename FormatContext>
f8deb5b9 Poul Sander 2022-01-15 13:55 2423
  auto format(const std::tm& tm, FormatContext& ctx) const
f8deb5b9 Poul Sander 2022-01-15 13:55 2424
      -> decltype(ctx.out()) {
47fd5c32 Poul Sander 2024-10-05 08:44 2425
    return do_format<FormatContext, std::chrono::seconds>(tm, ctx, nullptr);
f8deb5b9 Poul Sander 2022-01-15 13:55 2426
  }
f8deb5b9 Poul Sander 2022-01-15 13:55 2427
};
f8deb5b9 Poul Sander 2022-01-15 13:55 2428
47fd5c32 Poul Sander 2024-10-05 08:44 2429
FMT_END_EXPORT
f8deb5b9 Poul Sander 2022-01-15 13:55 2430
FMT_END_NAMESPACE
f8deb5b9 Poul Sander 2022-01-15 13:55 2431
f8deb5b9 Poul Sander 2022-01-15 13:55 2432
#endif  // FMT_CHRONO_H_
1970-01-01 00:00 2433