Skip to content

Commit

Permalink
Replace strftime to std::time_put
Browse files Browse the repository at this point in the history
  • Loading branch information
phprus committed Oct 18, 2021
1 parent d933742 commit 8ba27a3
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 55 deletions.
51 changes: 6 additions & 45 deletions include/fmt/chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,25 +474,6 @@ inline std::tm gmtime(

FMT_BEGIN_DETAIL_NAMESPACE

inline size_t strftime(char* str, size_t count, const char* format,
const std::tm* time) {
// Assign to a pointer to suppress GCCs -Wformat-nonliteral
// First assign the nullptr to suppress -Wsuggest-attribute=format
std::size_t (*strftime)(char*, std::size_t, const char*, const std::tm*) =
nullptr;
strftime = std::strftime;
return strftime(str, count, format, time);
}

inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format,
const std::tm* time) {
// See above
std::size_t (*wcsftime)(wchar_t*, std::size_t, const wchar_t*,
const std::tm*) = nullptr;
wcsftime = std::wcsftime;
return wcsftime(str, count, format, time);
}

// Writes two-digit numbers a, b and c separated by sep to buf.
// The method by Pavel Novikov based on
// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/.
Expand Down Expand Up @@ -1415,6 +1396,7 @@ template <typename OutputIt, typename Char> class tm_writer {
private:
static constexpr int days_per_week = 7;

const std::locale& loc_;
OutputIt out_;
const std::tm& tm_;

Expand Down Expand Up @@ -1494,34 +1476,12 @@ template <typename OutputIt, typename Char> class tm_writer {
}

void format_localized(char format, char modifier = 0) {
// By prepending an extra space we can distinguish an empty result that
// indicates insufficient buffer size from a guaranteed non-empty result
// https://github.com/fmtlib/fmt/issues/2238
Char tm_format[5] = {' ', '%', 'x', '\0', '\0'};
if (modifier) {
tm_format[2] = modifier;
tm_format[3] = format;
} else {
tm_format[2] = format;
}

basic_memory_buffer<Char> buf;
for (;;) {
size_t size = buf.capacity();
size_t count = detail::strftime(buf.data(), size, tm_format, &tm_);
if (count != 0) {
buf.resize(count);
break;
}
const size_t min_growth = 10;
buf.reserve(buf.capacity() + (size > min_growth ? size : min_growth));
}
// Remove the extra space.
out_ = copy_str<Char>(buf.begin() + 1, buf.end(), out_);
out_ = write(Char(), out_, tm_, loc_, format, modifier);
}

public:
explicit tm_writer(OutputIt out, const std::tm& tm) : out_(out), tm_(tm) {}
explicit tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm)
: loc_(loc), out_(out), tm_(tm) {}

OutputIt out() const { return out_; }

Expand Down Expand Up @@ -1748,7 +1708,8 @@ template <typename Char> struct formatter<std::tm, Char> {
template <typename FormatContext>
auto format(const std::tm& tm, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto w = detail::tm_writer<decltype(ctx.out()), Char>(ctx.out(), tm);
const auto& loc = std::locale::classic();
auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), tm);
if (spec_ == spec::year_month_day)
w.on_iso_date();
else if (spec_ == spec::hh_mm_ss)
Expand Down
13 changes: 8 additions & 5 deletions test/chrono-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ auto make_second(int s) -> std::tm {
}

std::string system_strftime(const std::string& format, const std::tm* timeptr,
size_t maxsize = 1024) {
std::vector<char> output(maxsize);
auto size =
std::strftime(output.data(), output.size(), format.c_str(), timeptr);
return std::string(output.data(), size);
std::locale* locptr = nullptr) {
auto loc = locptr ? *locptr : std::locale::classic();
auto& facet = std::use_facet<std::time_put<char>>(loc);
std::ostringstream os;
os.imbue(loc);
facet.put(os, os, ' ', timeptr, format.c_str(),
format.c_str() + format.size());
return os.str();
}

FMT_CONSTEXPR std::tm make_tm(int year, int mon, int mday, int hour, int min,
Expand Down
13 changes: 8 additions & 5 deletions test/xchar-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,14 @@ TEST(xchar_test, chrono) {
}

std::wstring system_wcsftime(const std::wstring& format, const std::tm* timeptr,
size_t maxsize = 1024) {
std::vector<wchar_t> output(maxsize);
auto size =
std::wcsftime(output.data(), output.size(), format.c_str(), timeptr);
return std::wstring(output.data(), size);
std::locale* locptr = nullptr) {
auto loc = locptr ? *locptr : std::locale::classic();
auto& facet = std::use_facet<std::time_put<wchar_t>>(loc);
std::wostringstream os;
os.imbue(loc);
facet.put(os, os, L' ', timeptr, format.c_str(),
format.c_str() + format.size());
return os.str();
}

TEST(chrono_test, time_point) {
Expand Down

0 comments on commit 8ba27a3

Please sign in to comment.