diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 4a46249a3a..4daef8e6c8 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -771,6 +771,46 @@ fn substitute_epoch_seconds(fmt: &str, date: &Zoned) -> String { out } +/// Remove the `O` strftime modifier from `fmt`. +/// +/// In the C locale `%O` requests alternative numeric symbols that do not +/// exist, so GNU `date` treats it as a no-op: `%Om` renders exactly like +/// `%m`. jiff does not know the modifier and would emit it literally. +/// Remove the `O` strftime modifier from `fmt`. +/// +/// In the C locale `%O` requests alternative numeric symbols that do not +/// exist, so GNU `date` treats it as a no-op: `%Om` renders exactly like +/// `%m` (issue #11656). jiff does not know the modifier and would emit it +/// literally, so strip it before jiff sees the format string. +fn strip_o_modifier(fmt: &str) -> String { + if !fmt.contains("%O") { + return fmt.to_string(); + } + + let mut out = String::with_capacity(fmt.len()); + let mut chars = fmt.chars().peekable(); + while let Some(c) = chars.next() { + if c != '%' { + out.push(c); + continue; + } + match chars.peek() { + // Drop the modifier but keep the specifier: `%Om` -> `%m`. + Some('O') => { + chars.next(); + out.push('%'); + } + // Keep `%%` intact: an `O` after a literal percent is plain text. + Some('%') => { + chars.next(); + out.push_str("%%"); + } + _ => out.push('%'), + } + } + out +} + fn format_extended_default( date: &ExtendedDateTime, format_string: &str, @@ -865,7 +905,7 @@ fn format_date_with_locale_aware_months( // negative infinity (e.g. `@-1.5` → `-2`, not `-1`). Every other field jiff // produces already agrees with GNU, so only `%s` needs correcting; rewrite it // to the floored epoch second before jiff sees the format string. - let fmt_owned = substitute_epoch_seconds(fmt, date); + let fmt_owned = strip_o_modifier(&substitute_epoch_seconds(fmt, date)); let fmt = fmt_owned.as_str(); // Check if format string has GNU modifiers (width/flags) and format if present diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 1b7f18dd7d..20ede68d77 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -2066,7 +2066,6 @@ fn test_date_strftime_flag_on_composite() { } #[test] -#[ignore = "https://github.com/uutils/coreutils/issues/11656 — GNU date strips the `O` strftime modifier in C locale (e.g. `%Om` -> `%m`); uutils leaks it as literal `%om`."] fn test_date_strftime_o_modifier() { // In C locale the `O` modifier is a no-op (alternative numeric symbols). // GNU renders `%Om` as `06` for June; uutils renders it as the literal `%Om`.