Skip to content

date: apply the ^ and # case flags per specifier - #14375

Open
harshasiddartha wants to merge 1 commit into
uutils:mainfrom
harshasiddartha:date-case-flags-per-specifier
Open

date: apply the ^ and # case flags per specifier#14375
harshasiddartha wants to merge 1 commit into
uutils:mainfrom
harshasiddartha:date-case-flags-per-specifier

Conversation

@harshasiddartha

Copy link
Copy Markdown

GNU applies the ^ and # case flags inside each conversion rather than to the whole rendered string. # reaches only the specifiers that emit a name, it is not carried into the recursive expansion of %c and %r, and where it does apply it takes precedence over ^.

uutils instead let ^ cancel # and applied both flags to every specifier, so with TZ=UTC LC_ALL=C -d '2024-06-15 13:05:03' it printed SAT JUN 15 13:05:03 2024 for %#c, lower-cased the PM in %#r, and printed PM/UTC for %^P, %^#p and %^#Z where GNU prints pm/utc.

The fix stops ^ from clearing # and gates both flags on the specifier: # is honored for %a %A %b %B %h %p %P %Z and wins over ^, and %P stays lower case whatever the flags ask for. The existing swap-case heuristic already matched GNU for those specifiers in the C locale, so only the gating changed. Single flags and %^#B/%^#A behave as before.

Tested with a table of the %c %p %P %r %Z flag combinations plus a named-zone case (TZ=America/New_York) in tests/by-util/test_date.rs; both new tests fail on main and pass with the change, and the rest of the date suite is unaffected. Every expected value was checked against GNU coreutils 9.11 under TZ=UTC LC_ALL=C. No GNU coreutils source was consulted.

One thing this PR does not address: in glibc, # sets upper-case for %a %A %b %B %h and lower-case for %p %P %Z, rather than swapping case. That is invisible in the C locale, where the names are already mixed or upper case, but it does show elsewhere: LC_ALL=es_ES.UTF-8 date +%#B gives JUNIO where a swap would leave junio alone. The swap heuristic predates this change and the gating here is correct either way, so I left the locale question for a separate PR.

Fixes #14351

GNU applies the case flags inside each conversion, not to the whole
rendered string, so `#` reaches only the specifiers that emit a name and
there it wins over `^`. uutils instead let `^` cancel `#` and applied
both to every specifier, so `%#c` printed `SAT JUN 15 13:05:03 2024`
instead of `Sat Jun 15 13:05:03 2024`, `%#r` lower-cased the `PM`,
`%^P` printed `PM`, and `%^#p` and `%^#Z` printed `PM` and `UTC` rather
than `pm` and `utc`.

Honor `#` only for `%a %A %b %B %h %p %P %Z`, let it take precedence
over `^`, and keep `%P` lower case whatever the flags ask for. Single
flags and `%^#B`/`%^#A` already matched GNU and are unchanged.
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/pr/bounded-memory (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/date/resolution (passes in this run but fails in the 'main' branch)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

date: case flags ^ and # don't match GNU on %c %p %P %r %Z

1 participant