From 4a0a3d6d53e6242549d59d620384c912d2d368d1 Mon Sep 17 00:00:00 2001 From: dragutreis <235304016+dragutreis@users.noreply.github.com> Date: Tue, 28 Apr 2026 11:06:06 -0500 Subject: [PATCH 1/4] date: fix %N modifier handling --- src/uu/date/src/format_modifiers.rs | 50 ++++++++++++++++++++++++++--- tests/by-util/test_date.rs | 18 +++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/uu/date/src/format_modifiers.rs b/src/uu/date/src/format_modifiers.rs index b77ed78dd65..2788de9cdbc 100644 --- a/src/uu/date/src/format_modifiers.rs +++ b/src/uu/date/src/format_modifiers.rs @@ -341,6 +341,40 @@ fn apply_modifiers(value: &str, parsed: &ParsedSpec<'_>) -> Result 9 => { + return Err(FormatError::FieldWidthTooLarge { + width: w, + specifier: specifier.to_string(), + }); + } + Some(w) => w, + None => 9, + }; + + let truncated = &value[..target_width.min(value.len())]; + + if underscore { + let trimmed = truncated.trim_end_matches('0'); + let core = if trimmed.is_empty() { "0" } else { trimmed }; + let padding = target_width.saturating_sub(core.len()); + return Ok(format!("{core}{}", " ".repeat(padding))); + } + + return Ok(truncated.to_string()); + } + let mut result = value.to_string(); // Determine default pad character based on specifier type @@ -474,10 +508,6 @@ fn apply_modifiers(value: &str, parsed: &ParsedSpec<'_>) -> Result Date: Wed, 29 Apr 2026 07:49:48 +0100 Subject: [PATCH 2/4] date: fix tests for %N modifier handling --- tests/by-util/test_date.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index f06af09c519..a2976bf9b24 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -407,24 +407,6 @@ fn test_date_nano_seconds() { new_ucmd!().arg("+%N").succeeds().stdout_matches(&re); } -#[test] -fn test_date_strftime_n_width_and_flags() { - new_ucmd!() - .env("LC_ALL", "C") - .env("TZ", "UTC") - .arg("-d").arg("@0") - .arg("+%_3N") - .succeeds() - .stdout_is("0 \n"); - new_ucmd!() - .env("LC_ALL", "C") - .env("TZ", "UTC") - .arg("-d").arg("@0") - .arg("+%-N") - .succeeds() - .stdout_is("000000000\n"); -} - #[test] fn test_date_format_without_plus() { // [+FORMAT] From 4b4a62827adb4640e524a1e2c75d488841715d4d Mon Sep 17 00:00:00 2001 From: dragutreis <235304016+dragutreis@users.noreply.github.com> Date: Wed, 29 Apr 2026 07:56:25 +0100 Subject: [PATCH 3/4] date: formatting(fmt) --- src/uu/date/src/format_modifiers.rs | 34 +++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/uu/date/src/format_modifiers.rs b/src/uu/date/src/format_modifiers.rs index 2788de9cdbc..a200a408ade 100644 --- a/src/uu/date/src/format_modifiers.rs +++ b/src/uu/date/src/format_modifiers.rs @@ -1060,13 +1060,33 @@ mod tests { #[test] fn test_apply_modifiers_nanoseconds() { - assert_eq!(apply_modifiers("123456789", &spec("", None, "N")).unwrap(), "123456789"); - assert_eq!(apply_modifiers("000000000", &spec("", None, "N")).unwrap(), "000000000"); - assert_eq!(apply_modifiers("123456789", &spec("", Some(3), "N")).unwrap(), "123"); - assert_eq!(apply_modifiers("000000000", &spec("_", Some(3), "N")).unwrap(), "0 "); - assert_eq!(apply_modifiers("000000000", &spec("-", None, "N")).unwrap(), "000000000"); - assert_eq!(apply_modifiers("000000000", &spec("-", Some(3), "N")).unwrap(), "000"); + assert_eq!( + apply_modifiers("123456789", &spec("", None, "N")).unwrap(), + "123456789" + ); + assert_eq!( + apply_modifiers("000000000", &spec("", None, "N")).unwrap(), + "000000000" + ); + assert_eq!( + apply_modifiers("123456789", &spec("", Some(3), "N")).unwrap(), + "123" + ); + assert_eq!( + apply_modifiers("000000000", &spec("_", Some(3), "N")).unwrap(), + "0 " + ); + assert_eq!( + apply_modifiers("000000000", &spec("-", None, "N")).unwrap(), + "000000000" + ); + assert_eq!( + apply_modifiers("000000000", &spec("-", Some(3), "N")).unwrap(), + "000" + ); let err = apply_modifiers("123456789", &spec("", Some(10), "N")).unwrap_err(); - assert!(matches!(err, FormatError::FieldWidthTooLarge { width, specifier } if width == 10 && specifier == "N")); + assert!( + matches!(err, FormatError::FieldWidthTooLarge { width, specifier } if width == 10 && specifier == "N") + ); } } From 3d9aa5ce3810b31a442493fe1433cd631e38701f Mon Sep 17 00:00:00 2001 From: dragutreis <235304016+dragutreis@users.noreply.github.com> Date: Sat, 16 May 2026 14:00:26 -0500 Subject: [PATCH 4/4] date: add tests for nanosecond modifiers --- tests/by-util/test_date.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index a2976bf9b24..571de8ca4ae 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -407,6 +407,39 @@ fn test_date_nano_seconds() { new_ucmd!().arg("+%N").succeeds().stdout_matches(&re); } +#[test] +fn test_date_nano_seconds_modifiers() { + let scene = TestScenario::new(util_name!()); + + // (epoch_input, format, expected_output) + let cases = [ + ("@0.123456789", "%N", "123456789"), + ("@0.123456789", "%3N", "123"), + ("@0.123456789", "%6N", "123456"), + ("@0.120000000", "%_3N", "12 "), + ("@0.100000000", "%_3N", "1 "), + ("@0.000000000", "%_3N", "0 "), + ("@0.123000000", "%_6N", "123 "), + ("@0.123456789", "%-N", "123456789"), + ("@0.123456789", "%-3N", "123"), + ]; + + for (input, fmt, expected) in cases { + scene + .ucmd() + .args(&["-d", input, &format!("+{fmt}")]) + .succeeds() + .stdout_is(format!("{expected}\n")); + } + + // width > 9 is invalid + scene + .ucmd() + .arg("+%10N") + .fails() + .stderr_contains("is too large for specifier"); +} + #[test] fn test_date_format_without_plus() { // [+FORMAT]