diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 317fd72d4..577cba460 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -207,11 +207,16 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .alias(OPT_UNIVERSAL_2) .help("print or set Coordinated Universal Time (UTC)"), ) - .arg(Arg::with_name(OPT_FORMAT).multiple(true)) + .arg(Arg::with_name(OPT_FORMAT).multiple(false)) .get_matches_from(args); let format = if let Some(form) = matches.value_of(OPT_FORMAT) { - let form = form[1..].into(); + if !form.starts_with('+') { + eprintln!("date: invalid date ‘{}’", form); + return 1; + } + // GNU `date` uses `%N` for nano seconds, however crate::chrono uses `%f` + let form = form[1..].replace("%N", "%f"); Format::Custom(form) } else if let Some(fmt) = matches .values_of(OPT_ISO_8601) @@ -237,7 +242,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let set_to = match matches.value_of(OPT_SET).map(parse_date) { None => None, Some(Err((input, _err))) => { - eprintln!("date: invalid date '{}'", input); + eprintln!("date: invalid date ‘{}’", input); return 1; } Some(Ok(date)) => Some(date), @@ -301,7 +306,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { println!("{}", formatted); } Err((input, _err)) => { - println!("date: invalid date '{}'", input); + println!("date: invalid date ‘{}’", input); } } } diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 0ca0a74ea..464655315 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -104,6 +104,23 @@ fn test_date_format_full_day() { .stdout_matches(&re); } +#[test] +fn test_date_nano_seconds() { + // %N nanoseconds (000000000..999999999) + let re = Regex::new(r"^\d{1,9}$").unwrap(); + new_ucmd!().arg("+%N").succeeds().stdout_matches(&re); +} + +#[test] +fn test_date_format_without_plus() { + // [+FORMAT] + new_ucmd!() + .arg("%s") + .fails() + .stderr_contains("date: invalid date ‘%s’") + .code_is(1); +} + #[test] #[cfg(all(unix, not(target_os = "macos")))] fn test_date_set_valid() {