• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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