diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 783b95ad9ac3d..68bd4ed8c048f 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -1396,7 +1396,30 @@ template class tm_writer { private: static constexpr int days_per_week = 7; + static constexpr const Char day_of_week[][10] = { + {'S', 'u', 'n', 'd', 'a', 'y', '\0', '\0', '\0', '\0'}, + {'M', 'o', 'n', 'd', 'a', 'y', '\0', '\0', '\0', '\0'}, + {'T', 'u', 'e', 's', 'd', 'a', 'y', '\0', '\0', '\0'}, + {'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', '\0'}, + {'T', 'h', 'u', 'r', 's', 'd', 'a', 'y', '\0', '\0'}, + {'F', 'r', 'i', 'd', 'a', 'y', '\0', '\0', '\0', '\0'}, + {'S', 'a', 't', 'u', 'r', 'd', 'a', 'y', '\0', '\0'}}; + static constexpr const Char month[][10] = { + {'J', 'a', 'n', 'u', 'a', 'r', 'y', '\0', '\0', '\0'}, + {'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y', '\0', '\0'}, + {'M', 'a', 'r', 'c', 'h', '\0', '\0', '\0', '\0', '\0'}, + {'A', 'p', 'r', 'i', 'l', '\0', '\0', '\0', '\0', '\0'}, + {'M', 'a', 'y', '\0', '\0', '\0', '\0', '\0', '\0', '\0'}, + {'J', 'u', 'n', 'e', '\0', '\0', '\0', '\0', '\0', '\0'}, + {'J', 'u', 'l', 'y', '\0', '\0', '\0', '\0', '\0', '\0'}, + {'A', 'u', 'g', 'u', 's', 't', '\0', '\0', '\0', '\0'}, + {'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', '\0'}, + {'O', 'c', 't', 'o', 'b', 'e', 'r', '\0', '\0', '\0'}, + {'N', 'o', 'v', 'e', 'm', 'b', 'e', 'r', '\0', '\0'}, + {'D', 'e', 'c', 'e', 'm', 'b', 'e', 'r', '\0', '\0'}}; + const std::locale& loc_; + const bool is_classic_; OutputIt out_; const std::tm& tm_; @@ -1482,7 +1505,10 @@ template class tm_writer { public: explicit tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm) - : loc_(loc), out_(out), tm_(tm) {} + : loc_(loc), + is_classic_(loc_ == std::locale::classic()), + out_(out), + tm_(tm) {} OutputIt out() const { return out_; } @@ -1490,8 +1516,22 @@ template class tm_writer { out_ = copy_str(begin, end, out_); } - void on_abbr_weekday() { format_localized('a'); } - void on_full_weekday() { format_localized('A'); } + void on_abbr_weekday() { + FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday < 7, + "tm_wday not in range [0, 6]"); + if (is_classic_) + out_ = write(out_, basic_string_view(day_of_week[tm_.tm_wday], 3)); + else + format_localized('a'); + } + void on_full_weekday() { + FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday < 7, + "tm_wday not in range [0, 6]"); + if (is_classic_) + out_ = write(out_, day_of_week[tm_.tm_wday]); + else + format_localized('A'); + } void on_dec0_weekday(numeric_system ns) { if (ns != numeric_system::standard) return format_localized('w', 'O'); write1(tm_.tm_wday); @@ -1501,17 +1541,54 @@ template class tm_writer { write1(tm_.tm_wday == 0 ? days_per_week : tm_.tm_wday); } - void on_abbr_month() { format_localized('b'); } - void on_full_month() { format_localized('B'); } + void on_abbr_month() { + FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon < 12, + "tm_mon not in range [0, 11]"); + if (is_classic_) + out_ = write(out_, basic_string_view(month[tm_.tm_mon], 3)); + else + format_localized('b'); + } + void on_full_month() { + FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon < 12, + "tm_mon not in range [0, 11]"); + if (is_classic_) + out_ = write(out_, month[tm_.tm_mon]); + else + format_localized('B'); + } void on_datetime(numeric_system ns) { - format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); + if (is_classic_) { +#ifdef _WIN32 + on_us_date(); + *out_++ = ' '; + on_iso_time(); +#else + on_abbr_weekday(); + *out_++ = ' '; + on_abbr_month(); + *out_++ = ' '; + on_day_of_month_space(numeric_system::standard); + *out_++ = ' '; + on_iso_time(); + *out_++ = ' '; + on_year(numeric_system::standard); +#endif + } else + format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); } void on_loc_date(numeric_system ns) { - format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); + if (is_classic_) + on_us_date(); + else + format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); } void on_loc_time(numeric_system ns) { - format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); + if (is_classic_) + on_iso_time(); + else + format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); } void on_us_date() { char buf[8]; @@ -1622,7 +1699,22 @@ template class tm_writer { write2(tm_.tm_sec); } - void on_12_hour_time() { format_localized('r'); } + void on_12_hour_time() { + if (is_classic_) { +#ifdef _WIN32 + on_iso_time(); +#else + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour12()), + to_unsigned(tm_.tm_min), to_unsigned(tm_.tm_sec), + ':'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + *out_++ = ' '; + on_am_pm(); +#endif + } else + format_localized('r'); + } void on_24_hour_time() { write2(tm_.tm_hour); *out_++ = ':'; @@ -1636,13 +1728,25 @@ template class tm_writer { out_ = copy_str(std::begin(buf), std::end(buf), out_); } - void on_am_pm() { format_localized('p'); } + void on_am_pm() { + if (is_classic_) { + *out_++ = tm_.tm_hour < 12 ? 'A' : 'P'; + *out_++ = 'M'; + } else + format_localized('p'); + } // These apply to chrono durations but not tm. void on_duration_value() {} void on_duration_unit() {} }; +template +constexpr const Char tm_writer::day_of_week[][10]; + +template +constexpr const Char tm_writer::month[][10]; + FMT_END_DETAIL_NAMESPACE template