Repository: fmtlib/fmt
File: include/fmt/chrono.h (C/C++)

Code before:

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);
}

FMT_END_DETAIL_NAMESPACE

template <typename Char, typename Duration>
struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
                 Char> : formatter<std::tm, Char> {
  FMT_CONSTEXPR FMT_INLINE void generate_default_spec(char) {
    this->specs = {"%Y-%m-%d %H:%M:%S", 17};
  }
  FMT_CONSTEXPR FMT_INLINE void generate_default_spec(wchar_t) {
    this->specs = {L"%Y-%m-%d %H:%M:%S", 17};
  }

  template <typename ParseContext>
  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
    auto it = ctx.begin();
    if (it != ctx.end() && *it == ':') ++it;
    auto end = it;
    while (end != ctx.end() && *end != '}') ++end;
    if (end == it) {
      generate_default_spec(typename ParseContext::char_type{});
    } else {
      this->specs = {it, detail::to_unsigned(end - it)};
    }
    return end;
  }

  template <typename FormatContext>
  auto format(std::chrono::time_point<std::chrono::system_clock> val,
              FormatContext& ctx) -> decltype(ctx.out()) {
    std::tm time = localtime(val);
    return formatter<std::tm, Char>::format(time, ctx);

Review comment (refactor):
`FMT_INLINE` is not needed here, please remove.

Also it's better to move this function to the detail namespace since it doesn't depend on template parameters and is not part of the public API.

Code after:

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);
}

FMT_END_DETAIL_NAMESPACE

template <typename Char, typename Duration>
struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
                 Char> : formatter<std::tm, Char> {
  FMT_CONSTEXPR formatter() {
    this->specs = {default_specs, sizeof(default_specs) / sizeof(Char)};
  }

  template <typename ParseContext>
  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
    auto it = ctx.begin();
    if (it != ctx.end() && *it == ':') ++it;
    auto end = it;
    while (end != ctx.end() && *end != '}') ++end;
    if (end != it) this->specs = {it, detail::to_unsigned(end - it)};
    return end;
  }

  template <typename FormatContext>
  auto format(std::chrono::time_point<std::chrono::system_clock> val,
              FormatContext& ctx) -> decltype(ctx.out()) {
    std::tm time = localtime(val);
    return formatter<std::tm, Char>::format(time, ctx);
  }

  static constexpr Char default_specs[] = {'%', 'Y', '-', '%', 'm', '-',
                                           '%', 'd', ' ', '%', 'H', ':',
                                           '%', 'M', ':', '%', 'S'};
};