diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 0e470fcf..17b957c0 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -961,6 +961,16 @@ OutputIt format_duration_unit(OutputIt out) { return out; } +template +auto with_locale(bool localized, locale_ref loc_ref, F&& f) + -> decltype(f(std::locale{})) { + if (localized) return f(loc_ref.template get()); + // in contrast to the case above, classic locale is returned by reference + // without introducing a temporary object + // (locale copy ctor & dtor are relatively expensive) + return f(get_classic_locale()); +} + template struct chrono_formatter { @@ -1062,14 +1072,11 @@ struct chrono_formatter { void format_localized(const tm& time, char format, char modifier = 0) { if (isnan(val)) return write_nan(); - if (localized) { - out = detail::write( - out, time, context.locale().template get(), format, - modifier); - } else { - out = detail::write(out, time, get_classic_locale(), format, - modifier); - } + with_locale(localized, context.locale(), + [this, &time, format, modifier](const std::locale& loc) { + out = detail::write(out, time, loc, format, + modifier); + }); } void on_text(const char_type* begin, const char_type* end) { @@ -1234,13 +1241,13 @@ template struct formatter { template auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { - auto time = std::tm(); - time.tm_wday = static_cast(wd.c_encoding()); - if (localized) - return detail::write(ctx.out(), time, - ctx.locale().template get(), 'a'); - return detail::write(ctx.out(), time, detail::get_classic_locale(), - 'a'); + auto out = ctx.out(); + return detail::with_locale( + localized, ctx.locale(), [&out, wd](const std::locale& loc) { + auto time = std::tm(); + time.tm_wday = static_cast(wd.c_encoding()); + return detail::write(out, time, loc, 'a'); + }); } }; @@ -1855,10 +1862,11 @@ template struct formatter { template auto format(const std::tm& tm, FormatContext& ctx) const -> decltype(ctx.out()) { - if (const auto& loc_ref = ctx.locale()) - return this->do_format(ctx.out(), tm, - loc_ref.template get()); - return this->do_format(ctx.out(), tm, detail::get_classic_locale()); + auto out = ctx.out(); + return detail::with_locale(static_cast(ctx.locale()), ctx.locale(), + [this, &out, &tm](const std::locale& loc) { + return do_format(out, tm, loc); + }); } };