^ and # aren't in POSIX, and the manual describes them without saying which
specifiers they apply to, so I've been treating the GNU binary as the reference.
gnudate is GNU 9.7, uu is a build of b7519db, TZ=UTC LC_ALL=C
throughout. Same output on the 9.11 reference build.
$ gnudate -d '2024-06-15 13:05:03' +'[%#c]' [Sat Jun 15 13:05:03 2024]
uu: [SAT JUN 15 13:05:03 2024]
$ gnudate -d '2024-06-15 13:05:03' +'[%#r]' [01:05:03 PM] uu: [01:05:03 pm]
$ gnudate -d '2024-06-15 13:05:03' +'[%^P]' [pm] uu: [PM]
$ gnudate -d '2024-06-15 13:05:03' +'[%^#p]' [pm] uu: [PM]
$ gnudate -d '2024-06-15 13:05:03' +'[%#^p]' [pm] uu: [PM]
$ gnudate -d '2024-06-15 13:05:03' +'[%^#Z]' [utc] uu: [UTC]
$ TZ=America/New_York gnudate -d 2024-06-15 +'[%^#Z]' [edt] uu: [EDT]
uutils applies ^/# to the whole rendered string and lets ^ cancel #.
GNU's are per specifier — strftime(3) says as much for # ("This flag works
only with certain conversion specifier characters, and of these, it is only
really useful with %Z") without saying which ones.
%^P doesn't need # at all — it's the same shape as #11659, with ^ in
place of # (that one was fixed in #11671).
Singles all agree: %p %^p %#p %P %#P %Z %^Z %#Z %c %^c %r %^r. So do %^#B
and %^#A on that date — JUNE and SATURDAY both ways. That's why the
combination is easy to miss. Found by sweeping flag, specifier and width
combinations against GNU.
The precedence is explicit, b7519db src/uu/date/src/format_modifiers.rs:392:
'^' => {
uppercase = true;
swap_case = false; // ^ overrides #
}
'#' if !uppercase => {
// Only apply # if ^ hasn't been set
swap_case = true;
}
A test that fails on main:
#[test]
fn test_date_strftime_case_flags_match_gnu() {
for (fmt, expected) in [
("%#c", "Sat Jun 15 13:05:03 2024"),
("%#r", "01:05:03 PM"),
("%^P", "pm"),
("%^#p", "pm"),
("%#^p", "pm"),
("%^#Z", "utc"),
] {
new_ucmd!()
.env("LC_ALL", "C")
.env("TZ", "UTC")
.arg("-d")
.arg("2024-06-15 13:05:03")
.arg(format!("+{fmt}"))
.succeeds()
.stdout_is(format!("{expected}\n"));
}
}
^and#aren't in POSIX, and the manual describes them without saying whichspecifiers they apply to, so I've been treating the GNU binary as the reference.
gnudateis GNU 9.7,uuis a build of b7519db,TZ=UTC LC_ALL=Cthroughout. Same output on the 9.11 reference build.
uutils applies
^/#to the whole rendered string and lets^cancel#.GNU's are per specifier — strftime(3) says as much for
#("This flag worksonly with certain conversion specifier characters, and of these, it is only
really useful with %Z") without saying which ones.
%^Pdoesn't need#at all — it's the same shape as #11659, with^inplace of
#(that one was fixed in #11671).Singles all agree:
%p %^p %#p %P %#P %Z %^Z %#Z %c %^c %r %^r. So do%^#Band
%^#Aon that date —JUNEandSATURDAYboth ways. That's why thecombination is easy to miss. Found by sweeping flag, specifier and width
combinations against GNU.
The precedence is explicit, b7519db src/uu/date/src/format_modifiers.rs:392:
A test that fails on main: