Thread-safe time formatting
This adds thread-safe (at least on platforms that provide necessary extensions) replacement functions for std::localtime and std::gmtime. Alternatively they could be placed in a new source file time.cc, but time.h seems so empty right now...
This commit is contained in:
parent
4809e2956a
commit
3acdbc03d9
99
fmt/time.h
99
fmt/time.h
@ -13,6 +13,12 @@
|
|||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4702) // unreachable code
|
||||||
|
#pragma warning(disable: 4996) // "deprecated" functions
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fmt {
|
namespace fmt {
|
||||||
template <typename ArgFormatter>
|
template <typename ArgFormatter>
|
||||||
void format_arg(BasicFormatter<char, ArgFormatter> &f,
|
void format_arg(BasicFormatter<char, ArgFormatter> &f,
|
||||||
@ -48,6 +54,99 @@ void format_arg(BasicFormatter<char, ArgFormatter> &f,
|
|||||||
}
|
}
|
||||||
format_str = end + 1;
|
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_
|
#endif // FMT_TIME_H_
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user