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> 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{ 59 inline Null<> localtime_r(...) { return Null<>(); } 60 inline Null<> localtime_s(...) { return Null<>(); } 61 inline Null<> gmtime_r(...) { return Null<>(); } 62 inline Null<> gmtime_s(...) { return Null<>(); } 63 } 64 65 // Thread-safe replacement for std::localtime 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 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