1 /*
2 Formatting library for C++ - time formatting
3
4 Copyright (c) 2012 - 2016, Victor Zverovich
5 All rights reserved.
6
7 For the license information refer to format.h.
8 */
9
10 #ifndef FMT_TIME_H_
11 #define FMT_TIME_H_
12
13 #include "format.h"
14 #include <ctime>
15
16 #ifdef _MSC_VER
17 # pragma warning(push)
18 # pragma warning(disable: 4702) // unreachable code
19 # pragma warning(disable: 4996) // "deprecated" functions
20 #endif
21
22 namespace fmt {
23 template <typename ArgFormatter>
format_arg(BasicFormatter<char,ArgFormatter> & f,const char * & format_str,const std::tm & tm)24 void format_arg(BasicFormatter<char, ArgFormatter> &f,
25 const char *&format_str, const std::tm &tm) {
26 if (*format_str == ':')
27 ++format_str;
28 const char *end = format_str;
29 while (*end && *end != '}')
30 ++end;
31 if (*end != '}')
32 FMT_THROW(FormatError("missing '}' in format string"));
33 internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format;
34 format.append(format_str, end + 1);
35 format[format.size() - 1] = '\0';
36 Buffer<char> &buffer = f.writer().buffer();
37 std::size_t start = buffer.size();
38 for (;;) {
39 std::size_t size = buffer.capacity() - start;
40 std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
41 if (count != 0) {
42 buffer.resize(start + count);
43 break;
44 }
45 if (size >= format.size() * 256) {
46 // If the buffer is 256 times larger than the format string, assume
47 // that `strftime` gives an empty result. There doesn't seem to be a
48 // better way to distinguish the two cases:
49 // https://github.com/fmtlib/fmt/issues/367
50 break;
51 }
52 const std::size_t MIN_GROWTH = 10;
53 buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
54 }
55 format_str = end + 1;
56 }
57
58 namespace internal{
localtime_r(...)59 inline Null<> localtime_r(...) { return Null<>(); }
localtime_s(...)60 inline Null<> localtime_s(...) { return Null<>(); }
gmtime_r(...)61 inline Null<> gmtime_r(...) { return Null<>(); }
gmtime_s(...)62 inline Null<> gmtime_s(...) { return Null<>(); }
63 }
64
65 // Thread-safe replacement for std::localtime
localtime(std::time_t time)66 inline std::tm localtime(std::time_t time) {
67 struct LocalTime {
68 std::time_t time_;
69 std::tm tm_;
70
71 LocalTime(std::time_t t): time_(t) {}
72
73 bool run() {
74 using namespace fmt::internal;
75 return handle(localtime_r(&time_, &tm_));
76 }
77
78 bool handle(std::tm *tm) { return tm != FMT_NULL; }
79
80 bool handle(internal::Null<>) {
81 using namespace fmt::internal;
82 return fallback(localtime_s(&tm_, &time_));
83 }
84
85 bool fallback(int res) { return res == 0; }
86
87 bool fallback(internal::Null<>) {
88 using namespace fmt::internal;
89 std::tm *tm = std::localtime(&time_);
90 if (tm) tm_ = *tm;
91 return tm != FMT_NULL;
92 }
93 };
94 LocalTime lt(time);
95 if (lt.run())
96 return lt.tm_;
97 // Too big time values may be unsupported.
98 FMT_THROW(fmt::FormatError("time_t value out of range"));
99 return std::tm();
100 }
101
102 // Thread-safe replacement for std::gmtime
gmtime(std::time_t time)103 inline std::tm gmtime(std::time_t time) {
104 struct GMTime {
105 std::time_t time_;
106 std::tm tm_;
107
108 GMTime(std::time_t t): time_(t) {}
109
110 bool run() {
111 using namespace fmt::internal;
112 return handle(gmtime_r(&time_, &tm_));
113 }
114
115 bool handle(std::tm *tm) { return tm != FMT_NULL; }
116
117 bool handle(internal::Null<>) {
118 using namespace fmt::internal;
119 return fallback(gmtime_s(&tm_, &time_));
120 }
121
122 bool fallback(int res) { return res == 0; }
123
124 bool fallback(internal::Null<>) {
125 std::tm *tm = std::gmtime(&time_);
126 if (tm != FMT_NULL) tm_ = *tm;
127 return tm != FMT_NULL;
128 }
129 };
130 GMTime gt(time);
131 if (gt.run())
132 return gt.tm_;
133 // Too big time values may be unsupported.
134 FMT_THROW(fmt::FormatError("time_t value out of range"));
135 return std::tm();
136 }
137 } //namespace fmt
138
139 #ifdef _MSC_VER
140 # pragma warning(pop)
141 #endif
142
143 #endif // FMT_TIME_H_
144