fmtlegacy/include/fmt/time.h

156 lines
4.2 KiB
C
Raw Normal View History

2018-01-06 17:09:50 +00:00
// Formatting library for C++ - time formatting
//
// Copyright (c) 2012 - present, Victor Zverovich
2018-01-06 17:09:50 +00:00
// All rights reserved.
//
// For the license information refer to format.h.
2016-04-25 15:07:27 +00:00
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
#include <ctime>
2018-11-30 16:52:01 +00:00
#include <locale>
2019-01-13 02:27:38 +00:00
#include "format.h"
2016-04-25 15:07:27 +00:00
2018-05-12 15:33:51 +00:00
FMT_BEGIN_NAMESPACE
2016-10-25 12:55:40 +00:00
// Prevents expansion of a preceding token as a function-style macro.
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO
2019-01-13 02:27:38 +00:00
namespace internal {
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
2016-10-09 21:57:52 +00:00
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }
} // namespace internal
2016-10-09 21:57:52 +00:00
// Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) {
2018-05-19 15:57:31 +00:00
struct dispatcher {
2016-10-09 21:57:52 +00:00
std::time_t time_;
std::tm tm_;
2019-01-13 02:27:38 +00:00
dispatcher(std::time_t t) : time_(t) {}
2016-10-09 21:57:52 +00:00
bool run() {
using namespace fmt::internal;
return handle(localtime_r(&time_, &tm_));
}
2019-01-13 02:27:38 +00:00
bool handle(std::tm* tm) { return tm != FMT_NULL; }
2016-10-09 21:57:52 +00:00
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(localtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
2016-10-09 21:57:52 +00:00
bool fallback(internal::null<>) {
using namespace fmt::internal;
2019-01-13 02:27:38 +00:00
std::tm* tm = std::localtime(&time_);
2018-01-21 02:37:57 +00:00
if (tm) tm_ = *tm;
return tm != FMT_NULL;
2016-10-09 21:57:52 +00:00
}
#endif
2016-10-09 21:57:52 +00:00
};
2018-05-19 15:57:31 +00:00
dispatcher lt(time);
2016-10-09 21:57:52 +00:00
// Too big time values may be unsupported.
2019-01-13 02:27:38 +00:00
if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
2018-11-25 23:33:28 +00:00
return lt.tm_;
2016-10-09 21:57:52 +00:00
}
// Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) {
2018-05-19 15:57:31 +00:00
struct dispatcher {
2016-10-09 21:57:52 +00:00
std::time_t time_;
std::tm tm_;
2019-01-13 02:27:38 +00:00
dispatcher(std::time_t t) : time_(t) {}
2016-10-09 21:57:52 +00:00
bool run() {
using namespace fmt::internal;
return handle(gmtime_r(&time_, &tm_));
}
2019-01-13 02:27:38 +00:00
bool handle(std::tm* tm) { return tm != FMT_NULL; }
2016-10-09 21:57:52 +00:00
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(gmtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
2016-10-09 21:57:52 +00:00
bool fallback(internal::null<>) {
2019-01-13 02:27:38 +00:00
std::tm* tm = std::gmtime(&time_);
2018-01-21 02:37:57 +00:00
if (tm) tm_ = *tm;
return tm != FMT_NULL;
2016-10-09 21:57:52 +00:00
}
#endif
2016-10-09 21:57:52 +00:00
};
2018-05-19 15:57:31 +00:00
dispatcher gt(time);
2016-10-09 21:57:52 +00:00
// Too big time values may be unsupported.
2019-01-13 02:27:38 +00:00
if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
2018-11-25 23:33:28 +00:00
return gt.tm_;
2016-10-09 21:57:52 +00:00
}
namespace internal {
2019-01-13 02:27:38 +00:00
inline std::size_t strftime(char* str, std::size_t count, const char* format,
const std::tm* time) {
return std::strftime(str, count, format, time);
}
2019-01-13 02:27:38 +00:00
inline std::size_t strftime(wchar_t* str, std::size_t count,
const wchar_t* format, const std::tm* time) {
return std::wcsftime(str, count, format, time);
}
2019-01-13 02:27:38 +00:00
} // namespace internal
2019-01-13 02:27:38 +00:00
template <typename Char> struct formatter<std::tm, Char> {
template <typename ParseContext>
2019-01-13 02:27:38 +00:00
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin();
2019-01-13 02:27:38 +00:00
if (it != ctx.end() && *it == ':') ++it;
2017-08-13 20:09:02 +00:00
auto end = it;
2019-01-13 02:27:38 +00:00
while (end != ctx.end() && *end != '}') ++end;
tm_format.reserve(internal::to_unsigned(end - it + 1));
tm_format.append(it, end);
2017-08-13 20:09:02 +00:00
tm_format.push_back('\0');
return end;
2017-08-13 20:09:02 +00:00
}
template <typename FormatContext>
2019-01-13 02:27:38 +00:00
auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buf;
2017-08-13 20:09:02 +00:00
std::size_t start = buf.size();
for (;;) {
std::size_t size = buf.capacity() - start;
2018-05-19 15:57:31 +00:00
std::size_t count =
2019-01-13 02:27:38 +00:00
internal::strftime(&buf[start], size, &tm_format[0], &tm);
2017-08-13 20:09:02 +00:00
if (count != 0) {
buf.resize(start + count);
break;
}
if (size >= tm_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;
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
return std::copy(buf.begin(), buf.end(), ctx.out());
2016-04-25 15:24:14 +00:00
}
2017-08-13 20:09:02 +00:00
basic_memory_buffer<Char> tm_format;
2017-08-13 20:09:02 +00:00
};
2018-05-12 15:33:51 +00:00
FMT_END_NAMESPACE
2016-04-25 15:07:27 +00:00
#endif // FMT_TIME_H_