date: case flags ^ and # don't match GNU on %c %p %P %r %Z
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 24.1k
- Forks
- 2k
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 365
Description
^ 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 b7519db78, 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, b7519db78 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"));
}
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading src/uu/date/src/format_modifiers.rs around line 392, then run or add the test_date_strftime_case_flags_match_gnu test from the issue. Compare the listed outputs for the case flags against GNU date; done means all cases, including flag combinations and %c, %r, %P, and %Z, produce the expected output.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli, testing-qa
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100