Support fill, align & width for time point
Resolve #3237
{"label": "fmtlib:master", "ref": "master", "sha": "2622cd23e69b67316cf678a97c268a874774c0e1"}
The grammar in the documentation 

```
   replacement_field: "{" [`arg_id`] [":" (`format_spec` | `chrono_format_spec`)] "}"

   chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`]
   chrono_specs: [`chrono_specs`] `conversion_spec` | `chrono_specs` `literal_char`
   conversion_spec: "%" [`modifier`] `chrono_type`
```

suggests to me that `{:>30%H}` is valid, but this is not what fmt-9.1.0 and/or master @ b90895412f46e18e5b17efdea2c8f79e7d7504b3 outputs.

Input:

```c
#include <chrono>
#include <fmt/core.h>
#include <fmt/chrono.h>
int main()
{
        fmt::print("{:>30d}\n", 30);
        fmt::print("{:>30%H:%M}\n", std::chrono::system_clock::now());
}
```

Output:

```
                            30
>3023:48
```

Expected:

```
                            30
                         23:48
```
formatting chrono with padding
diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h
index 64ebdabe5a59..b957ab6f300a 100644
--- a/include/fmt/chrono.h
+++ b/include/fmt/chrono.h
@@ -2115,9 +2115,7 @@ template <typename Char, typename Duration>
 struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
                  Char> : formatter<std::tm, Char> {
   FMT_CONSTEXPR formatter() {
-    basic_string_view<Char> default_specs =
-        detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
-    this->do_parse(default_specs.begin(), default_specs.end());
+    this->format_str = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
   }
 
   template <typename FormatContext>
@@ -2145,9 +2143,7 @@ template <typename Char, typename Duration>
 struct formatter<std::chrono::local_time<Duration>, Char>
     : formatter<std::tm, Char> {
   FMT_CONSTEXPR formatter() {
-    basic_string_view<Char> default_specs =
-        detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
-    this->do_parse(default_specs.begin(), default_specs.end());
+    this->format_str = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
   }
 
   template <typename FormatContext>
@@ -2190,51 +2186,51 @@ struct formatter<std::chrono::time_point<std::chrono::utc_clock, Duration>,
 
 template <typename Char> struct formatter<std::tm, Char> {
  private:
-  enum class spec {
-    unknown,
-    year_month_day,
-    hh_mm_ss,
-  };
-  spec spec_ = spec::unknown;
-  basic_string_view<Char> specs;
+  format_specs<Char> specs;
+  detail::arg_ref<Char> width_ref;
 
  protected:
-  template <typename It> FMT_CONSTEXPR auto do_parse(It begin, It end) -> It {
-    if (begin != end && *begin == ':') ++begin;
+  basic_string_view<Char> format_str;
+
+  FMT_CONSTEXPR auto do_parse(basic_format_parse_context<Char>& ctx)
+      -> decltype(ctx.begin()) {
+    auto begin = ctx.begin(), end = ctx.end();
+    if (begin == end || *begin == '}') return end;
+
+    begin = detail::parse_align(begin, end, specs);
+    if (begin == end) return end;
+
+    begin = detail::parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
+    if (begin == end) return end;
+
     end = detail::parse_chrono_format(begin, end, detail::tm_format_checker());
-    // Replace default spec only if the new spec is not empty.
-    if (end != begin) specs = {begin, detail::to_unsigned(end - begin)};
+    // Replace default format_str only if the new spec is not empty.
+    if (end != begin) format_str = {begin, detail::to_unsigned(end - begin)};
     return end;
   }
 
   template <typename FormatContext, typename Duration>
   auto do_format(const std::tm& tm, FormatContext& ctx,
                  const Duration* subsecs) const -> decltype(ctx.out()) {
+    auto specs_copy = specs;
+    basic_memory_buffer<Char> buf;
+    auto out = std::back_inserter(buf);
+    detail::handle_dynamic_spec<detail::width_checker>(specs_copy.width,
+                                                       width_ref, ctx);
+
     const auto loc_ref = ctx.locale();
     detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
-    auto w = detail::tm_writer<decltype(ctx.out()), Char, Duration>(
-        loc, ctx.out(), tm, subsecs);
-    if (spec_ == spec::year_month_day)
-      w.on_iso_date();
-    else if (spec_ == spec::hh_mm_ss)
-      w.on_iso_time();
-    else
-      detail::parse_chrono_format(specs.begin(), specs.end(), w);
-    return w.out();
+    auto w =
+        detail::tm_writer<decltype(out), Char, Duration>(loc, out, tm, subsecs);
+    detail::parse_chrono_format(format_str.begin(), format_str.end(), w);
+    return detail::write(
+        ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs_copy);
   }
 
  public:
   FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
       -> decltype(ctx.begin()) {
-    auto end = this->do_parse(ctx.begin(), ctx.end());
-    // basic_string_view<>::compare isn't constexpr before C++17.
-    if (specs.size() == 2 && specs[0] == Char('%')) {
-      if (specs[1] == Char('F'))
-        spec_ = spec::year_month_day;
-      else if (specs[1] == Char('T'))
-        spec_ = spec::hh_mm_ss;
-    }
-    return end;
+    return this->do_parse(ctx);
   }
 
   template <typename FormatContext>

diff --git a/test/chrono-test.cc b/test/chrono-test.cc
index 9ac9142c5e4c..65e99a9c0a78 100644
--- a/test/chrono-test.cc
+++ b/test/chrono-test.cc
@@ -462,7 +462,7 @@ TEST(chrono_test, format_default) {
       fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
 }
 
-TEST(chrono_test, align) {
+TEST(chrono_test, duration_align) {
   auto s = std::chrono::seconds(42);
   EXPECT_EQ("42s  ", fmt::format("{:5}", s));
   EXPECT_EQ("42s  ", fmt::format("{:{}}", s, 5));
@@ -478,6 +478,35 @@ TEST(chrono_test, align) {
             fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12));
 }
 
+TEST(chrono_test, tm_align) {
+  auto t = make_tm(1975, 12, 29, 12, 14, 16);
+  EXPECT_EQ("1975-12-29 12:14:16", fmt::format("{:%F %T}", t));
+  EXPECT_EQ("1975-12-29 12:14:16           ", fmt::format("{:30%F %T}", t));
+  EXPECT_EQ("1975-12-29 12:14:16           ", fmt::format("{:{}%F %T}", t, 30));
+  EXPECT_EQ("1975-12-29 12:14:16           ", fmt::format("{:<30%F %T}", t));
+  EXPECT_EQ("     1975-12-29 12:14:16      ", fmt::format("{:^30%F %T}", t));
+  EXPECT_EQ("           1975-12-29 12:14:16", fmt::format("{:>30%F %T}", t));
+
+  EXPECT_EQ("1975-12-29 12:14:16***********", fmt::format("{:*<30%F %T}", t));
+  EXPECT_EQ("*****1975-12-29 12:14:16******", fmt::format("{:*^30%F %T}", t));
+  EXPECT_EQ("***********1975-12-29 12:14:16", fmt::format("{:*>30%F %T}", t));
+}
+
+TEST(chrono_test, tp_align) {
+  auto tp = std::chrono::time_point_cast<std::chrono::microseconds>(
+      std::chrono::system_clock::from_time_t(0));
+  EXPECT_EQ("00:00.000000", fmt::format("{:%M:%S}", tp));
+  EXPECT_EQ("00:00.000000   ", fmt::format("{:15%M:%S}", tp));
+  EXPECT_EQ("00:00.000000   ", fmt::format("{:{}%M:%S}", tp, 15));
+  EXPECT_EQ("00:00.000000   ", fmt::format("{:<15%M:%S}", tp));
+  EXPECT_EQ(" 00:00.000000  ", fmt::format("{:^15%M:%S}", tp));
+  EXPECT_EQ("   00:00.000000", fmt::format("{:>15%M:%S}", tp));
+
+  EXPECT_EQ("00:00.000000***", fmt::format("{:*<15%M:%S}", tp));
+  EXPECT_EQ("*00:00.000000**", fmt::format("{:*^15%M:%S}", tp));
+  EXPECT_EQ("***00:00.000000", fmt::format("{:*>15%M:%S}", tp));
+}
+
 TEST(chrono_test, format_specs) {
   EXPECT_EQ("%", fmt::format("{:%%}", std::chrono::seconds(0)));
   EXPECT_EQ("\n", fmt::format("{:%n}", std::chrono::seconds(0)));

{"chrono-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}}
{"compile-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "ostream-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "ranges-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "std-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "core-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "scan-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "color-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "format-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "gtest-extra-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "args-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "compile-fp-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "unicode-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "assert-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "posix-mock-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "printf-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "enforce-checks-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "format-impl-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "os-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "xchar-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}}
{"chrono-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}}
{"passed_count": 20, "failed_count": 0, "skipped_count": 0, "passed_tests": ["compile-test", "core-test", "chrono-test", "gtest-extra-test", "compile-fp-test", "unicode-test", "assert-test", "enforce-checks-test", "format-impl-test", "os-test", "xchar-test", "ostream-test", "ranges-test", "std-test", "scan-test", "color-test", "format-test", "args-test", "posix-mock-test", "printf-test"], "failed_tests": [], "skipped_tests": []}
{"passed_count": 19, "failed_count": 0, "skipped_count": 0, "passed_tests": ["compile-test", "core-test", "gtest-extra-test", "compile-fp-test", "unicode-test", "assert-test", "enforce-checks-test", "format-impl-test", "os-test", "xchar-test", "ostream-test", "ranges-test", "std-test", "scan-test", "color-test", "format-test", "args-test", "posix-mock-test", "printf-test"], "failed_tests": [], "skipped_tests": []}
{"passed_count": 20, "failed_count": 0, "skipped_count": 0, "passed_tests": ["compile-test", "core-test", "chrono-test", "gtest-extra-test", "compile-fp-test", "unicode-test", "assert-test", "enforce-checks-test", "format-impl-test", "os-test", "xchar-test", "ostream-test", "ranges-test", "std-test", "scan-test", "color-test", "format-test", "args-test", "posix-mock-test", "printf-test"], "failed_tests": [], "skipped_tests": []}