diff --git a/fmt/time.h b/fmt/time.h index ccdad77fbf86..ba1dd4269926 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -13,6 +13,12 @@ #include "fmt/format.h" #include +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4702) // unreachable code + #pragma warning(disable: 4996) // "deprecated" functions +#endif + namespace fmt { template void format_arg(BasicFormatter &f, @@ -48,6 +54,99 @@ void format_arg(BasicFormatter &f, } 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 != 0; + } + 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 != 0) tm_ = *tm; + return tm != 0; + } + }; + 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 != 0; + } + 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 != 0) tm_ = *tm; + return tm != 0; + } + }; + 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_