| /* |
| Formatting library for C++ - time formatting |
| |
| Copyright (c) 2012 - 2016, Victor Zverovich |
| All rights reserved. |
| |
| For the license information refer to format.h. |
| */ |
| |
| #ifndef FMT_TIME_H_ |
| #define FMT_TIME_H_ |
| |
| #include "format.h" |
| #include <ctime> |
| |
| #ifdef _MSC_VER |
| # pragma warning(push) |
| # pragma warning(disable: 4702) // unreachable code |
| # pragma warning(disable: 4996) // "deprecated" functions |
| #endif |
| |
| namespace fmt { |
| template <typename ArgFormatter> |
| void format_arg(BasicFormatter<char, ArgFormatter> &f, |
| const char *&format_str, const std::tm &tm) { |
| if (*format_str == ':') |
| ++format_str; |
| const char *end = format_str; |
| while (*end && *end != '}') |
| ++end; |
| if (*end != '}') |
| FMT_THROW(FormatError("missing '}' in format string")); |
| internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format; |
| format.append(format_str, end + 1); |
| format[format.size() - 1] = '\0'; |
| Buffer<char> &buffer = f.writer().buffer(); |
| std::size_t start = buffer.size(); |
| for (;;) { |
| std::size_t size = buffer.capacity() - start; |
| std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); |
| if (count != 0) { |
| buffer.resize(start + count); |
| break; |
| } |
| if (size >= format.size() * 256) { |
| // If the buffer is 256 times larger than the format string, assume |
| // that `strftime` gives an empty result. There doesn't seem to be a |
| // better way to distinguish the two cases: |
| // https://github.com/fmtlib/fmt/issues/367 |
| break; |
| } |
| const std::size_t MIN_GROWTH = 10; |
| buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); |
| } |
| format_str = end + 1; |
| } |
| |
| namespace internal{ |
| inline Null<> localtime_r(...) { return Null<>(); } |
| inline Null<> localtime_s(...) { return Null<>(); } |
| inline Null<> gmtime_r(...) { return Null<>(); } |
| inline Null<> gmtime_s(...) { return Null<>(); } |
| } |
| |
| // Thread-safe replacement for std::localtime |
| inline std::tm localtime(std::time_t time) { |
| struct LocalTime { |
| std::time_t time_; |
| std::tm tm_; |
| |
| LocalTime(std::time_t t): time_(t) {} |
| |
| bool run() { |
| using namespace fmt::internal; |
| return handle(localtime_r(&time_, &tm_)); |
| } |
| |
| bool handle(std::tm *tm) { return tm != FMT_NULL; } |
| |
| bool handle(internal::Null<>) { |
| using namespace fmt::internal; |
| return fallback(localtime_s(&tm_, &time_)); |
| } |
| |
| bool fallback(int res) { return res == 0; } |
| |
| bool fallback(internal::Null<>) { |
| using namespace fmt::internal; |
| std::tm *tm = std::localtime(&time_); |
| if (tm) tm_ = *tm; |
| return tm != FMT_NULL; |
| } |
| }; |
| LocalTime lt(time); |
| if (lt.run()) |
| return lt.tm_; |
| // Too big time values may be unsupported. |
| FMT_THROW(fmt::FormatError("time_t value out of range")); |
| return std::tm(); |
| } |
| |
| // Thread-safe replacement for std::gmtime |
| inline std::tm gmtime(std::time_t time) { |
| struct GMTime { |
| std::time_t time_; |
| std::tm tm_; |
| |
| GMTime(std::time_t t): time_(t) {} |
| |
| bool run() { |
| using namespace fmt::internal; |
| return handle(gmtime_r(&time_, &tm_)); |
| } |
| |
| bool handle(std::tm *tm) { return tm != FMT_NULL; } |
| |
| bool handle(internal::Null<>) { |
| using namespace fmt::internal; |
| return fallback(gmtime_s(&tm_, &time_)); |
| } |
| |
| bool fallback(int res) { return res == 0; } |
| |
| bool fallback(internal::Null<>) { |
| std::tm *tm = std::gmtime(&time_); |
| if (tm != FMT_NULL) tm_ = *tm; |
| return tm != FMT_NULL; |
| } |
| }; |
| GMTime gt(time); |
| if (gt.run()) |
| return gt.tm_; |
| // Too big time values may be unsupported. |
| FMT_THROW(fmt::FormatError("time_t value out of range")); |
| return std::tm(); |
| } |
| } //namespace fmt |
| |
| #ifdef _MSC_VER |
| # pragma warning(pop) |
| #endif |
| |
| #endif // FMT_TIME_H_ |