time.h
Go to the documentation of this file.
1 // Formatting library for C++ - time formatting
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 
8 #ifndef FMT_TIME_H_
9 #define FMT_TIME_H_
10 
11 #include "format.h"
12 #include <ctime>
13 #include <locale>
14 
16 
17 // Prevents expansion of a preceding token as a function-style macro.
18 // Usage: f FMT_NOMACRO()
19 #define FMT_NOMACRO
20 
21 namespace internal{
22 inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
23 inline null<> localtime_s(...) { return null<>(); }
24 inline null<> gmtime_r(...) { return null<>(); }
25 inline null<> gmtime_s(...) { return null<>(); }
26 } // namespace internal
27 
28 // Thread-safe replacement for std::localtime
29 inline std::tm localtime(std::time_t time) {
30  struct dispatcher {
31  std::time_t time_;
32  std::tm tm_;
33 
34  dispatcher(std::time_t t): time_(t) {}
35 
36  bool run() {
37  using namespace fmt::internal;
38  return handle(localtime_r(&time_, &tm_));
39  }
40 
41  bool handle(std::tm *tm) { return tm != FMT_NULL; }
42 
43  bool handle(internal::null<>) {
44  using namespace fmt::internal;
45  return fallback(localtime_s(&tm_, &time_));
46  }
47 
48  bool fallback(int res) { return res == 0; }
49 
50 #if !FMT_MSC_VER
51  bool fallback(internal::null<>) {
52  using namespace fmt::internal;
53  std::tm *tm = std::localtime(&time_);
54  if (tm) tm_ = *tm;
55  return tm != FMT_NULL;
56  }
57 #endif
58  };
59  dispatcher lt(time);
60  // Too big time values may be unsupported.
61  if (!lt.run())
62  FMT_THROW(format_error("time_t value out of range"));
63  return lt.tm_;
64 }
65 
66 // Thread-safe replacement for std::gmtime
67 inline std::tm gmtime(std::time_t time) {
68  struct dispatcher {
69  std::time_t time_;
70  std::tm tm_;
71 
72  dispatcher(std::time_t t): time_(t) {}
73 
74  bool run() {
75  using namespace fmt::internal;
76  return handle(gmtime_r(&time_, &tm_));
77  }
78 
79  bool handle(std::tm *tm) { return tm != FMT_NULL; }
80 
81  bool handle(internal::null<>) {
82  using namespace fmt::internal;
83  return fallback(gmtime_s(&tm_, &time_));
84  }
85 
86  bool fallback(int res) { return res == 0; }
87 
88 #if !FMT_MSC_VER
89  bool fallback(internal::null<>) {
90  std::tm *tm = std::gmtime(&time_);
91  if (tm) tm_ = *tm;
92  return tm != FMT_NULL;
93  }
94 #endif
95  };
96  dispatcher gt(time);
97  // Too big time values may be unsupported.
98  if (!gt.run())
99  FMT_THROW(format_error("time_t value out of range"));
100  return gt.tm_;
101 }
102 
103 namespace internal {
104 inline std::size_t strftime(char *str, std::size_t count, const char *format,
105  const std::tm *time) {
106  return std::strftime(str, count, format, time);
107 }
108 
109 inline std::size_t strftime(wchar_t *str, std::size_t count,
110  const wchar_t *format, const std::tm *time) {
111  return std::wcsftime(str, count, format, time);
112 }
113 }
114 
115 template <typename Char>
116 struct formatter<std::tm, Char> {
117  template <typename ParseContext>
118  auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
119  auto it = ctx.begin();
120  if (it != ctx.end() && *it == ':')
121  ++it;
122  auto end = it;
123  while (end != ctx.end() && *end != '}')
124  ++end;
125  tm_format.reserve(internal::to_unsigned(end - it + 1));
126  tm_format.append(it, end);
127  tm_format.push_back('\0');
128  return end;
129  }
130 
131  template <typename FormatContext>
132  auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
134  std::size_t start = buf.size();
135  for (;;) {
136  std::size_t size = buf.capacity() - start;
137  std::size_t count =
138  internal::strftime(&buf[start], size, &tm_format[0], &tm);
139  if (count != 0) {
140  buf.resize(start + count);
141  break;
142  }
143  if (size >= tm_format.size() * 256) {
144  // If the buffer is 256 times larger than the format string, assume
145  // that `strftime` gives an empty result. There doesn't seem to be a
146  // better way to distinguish the two cases:
147  // https://github.com/fmtlib/fmt/issues/367
148  break;
149  }
150  const std::size_t MIN_GROWTH = 10;
151  buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
152  }
153  return std::copy(buf.begin(), buf.end(), ctx.out());
154  }
155 
157 };
159 
160 #endif // FMT_TIME_H_
std::size_t strftime(wchar_t *str, std::size_t count, const wchar_t *format, const std::tm *time)
Definition: time.h:109
T * begin() FMT_NOEXCEPT
Definition: core.h:246
STL namespace.
void resize(std::size_t new_size)
Definition: core.h:264
null gmtime_s(...)
Definition: time.h:25
null gmtime_r(...)
Definition: time.h:24
#define FMT_END_NAMESPACE
Definition: core.h:153
#define FMT_THROW(x)
Definition: format.h:115
null localtime_s(...)
Definition: time.h:23
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:87
FMT_CONSTEXPR auto end(const C &c) -> decltype(c.end())
Definition: format.h:257
null localtime_r FMT_NOMACRO(...)
Definition: time.h:22
std::tm localtime(std::time_t time)
Definition: time.h:29
auto parse(ParseContext &ctx) -> decltype(ctx.begin())
Definition: time.h:118
std::size_t strftime(char *str, std::size_t count, const char *format, const std::tm *time)
Definition: time.h:104
std::size_t size() const FMT_NOEXCEPT
Definition: core.h:250
std::size_t capacity() const FMT_NOEXCEPT
Definition: core.h:253
void reserve(std::size_t new_capacity)
Definition: core.h:273
std::string str(const std::pair< Type, Type > &tt)
Definition: test_pimpos.cxx:12
std::tm gmtime(std::time_t time)
Definition: time.h:67
#define FMT_NULL
Definition: core.h:107
FMT_CONSTEXPR std::make_unsigned< Int >::type to_unsigned(Int value)
Definition: core.h:208
basic_memory_buffer< Char > tm_format
Definition: time.h:156
T copy(T const &v)
T * end() FMT_NOEXCEPT
Definition: core.h:247
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out())
Definition: time.h:132
unsigned int run