diff --git a/src/uucore/src/lib/features/i18n/datetime.rs b/src/uucore/src/lib/features/i18n/datetime.rs index df29bccf0c3..88816d9daed 100644 --- a/src/uucore/src/lib/features/i18n/datetime.rs +++ b/src/uucore/src/lib/features/i18n/datetime.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore fieldsets prefs +// spell-checker:ignore fieldsets prefs febr //! Locale-aware datetime formatting utilities using ICU and jiff-icu @@ -111,7 +111,13 @@ pub fn localize_format_string(format: &str, date: JiffDate) -> String { } if fmt.contains("%b") || fmt.contains("%h") { if let Ok(f) = DateTimeFormatter::try_new(locale_prefs, fieldsets::M::medium()) { + // ICU's medium format may include trailing periods (e.g., "febr." for Hungarian), + // which when combined with locale format strings that also add periods after + // %b (e.g., "%Y. %b. %d") results in double periods ("febr.."). + // The standard C/POSIX locale via nl_langinfo returns abbreviations + // WITHOUT trailing periods, so we strip them here for consistency. let month_abbrev = f.format(&iso_date).to_string(); + let month_abbrev = month_abbrev.trim_end_matches('.').to_string(); fmt = fmt .replace("%b", &month_abbrev) .replace("%h", &month_abbrev); diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index ffbb4a2bea9..b9a3c9f8712 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // -// spell-checker: ignore: AEDT AEST EEST NZDT NZST Kolkata Iseconds févr février janv janvier mercredi samedi sommes juin décembre Januar Juni Dezember enero junio diciembre gennaio giugno dicembre junho dezembro lundi dimanche Montag Sonntag Samstag sábado +// spell-checker: ignore: AEDT AEST EEST NZDT NZST Kolkata Iseconds févr février janv janvier mercredi samedi sommes juin décembre Januar Juni Dezember enero junio diciembre gennaio giugno dicembre junho dezembro lundi dimanche Montag Sonntag Samstag sábado febr use std::cmp::Ordering; @@ -2056,6 +2056,29 @@ fn test_locale_month_names() { } } +#[test] +#[cfg(unix)] +fn test_locale_abbreviated_month_names() { + // %b abbreviated month names: Feb, Jun, Dec for each locale + // This test ensures we don't get double periods in locales like Hungarian + // where ICU returns "febr." but the format string also adds a period after %b + for (loc, feb, jun, dec) in [ + ("fr_FR.UTF-8", "févr", "juin", "déc"), + ("de_DE.UTF-8", "Feb", "Jun", "Dez"), + ("es_ES.UTF-8", "feb", "jun", "dic"), + ("it_IT.UTF-8", "feb", "giu", "dic"), + ("pt_BR.UTF-8", "fev", "jun", "dez"), + ("ja_JP.UTF-8", "2月", "6月", "12月"), + ("zh_CN.UTF-8", "2月", "6月", "12月"), + // Hungarian locale - the fix ensures no double periods + ("hu_HU.UTF-8", "febr", "jún", "dec"), + ] { + check_date(loc, "2026-02-12", "+%b", feb); + check_date(loc, "2026-06-14", "+%b", jun); + check_date(loc, "2026-12-09", "+%b", dec); + } +} + #[test] #[cfg(unix)] fn test_locale_day_names() {