diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 19e0a8712..6daf89f33 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -65,6 +65,7 @@ enum Format { enum DateSource { Now, File(PathBuf), + FileMtime(PathBuf), Stdin, Human(String), } @@ -146,6 +147,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { "-" => DateSource::Stdin, _ => DateSource::File(file.into()), } + } else if let Some(file) = matches.get_one::(OPT_REFERENCE) { + DateSource::FileMtime(file.into()) } else { DateSource::Now }; @@ -213,6 +216,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let iter = lines.map_while(Result::ok).map(parse_date); Box::new(iter) } + DateSource::FileMtime(ref path) => { + let metadata = std::fs::metadata(path) + .map_err_context(|| path.as_os_str().to_string_lossy().to_string())?; + let mtime = metadata.modified()?; + let ts = Timestamp::try_from(mtime).map_err(|e| { + USimpleError::new( + 1, + translate!("date-error-cannot-set-date", "path" => path.to_string_lossy(), "error" => e), + ) + })?; + let date = ts.to_zoned(TimeZone::try_system().unwrap_or(TimeZone::UTC)); + let iter = std::iter::once(Ok(date)); + Box::new(iter) + } DateSource::Now => { let iter = std::iter::once(Ok(now)); Box::new(iter) diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 28b98c84b..f9b4caeba 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -352,6 +352,22 @@ fn test_date_for_file() { ucmd.arg("--file").arg(file).succeeds(); } +#[test] +fn test_date_for_file_mtime() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "reference_file"; + at.touch(file); + std::thread::sleep(std::time::Duration::from_millis(100)); + let result = ucmd.arg("--reference").arg(file).arg("+%s%N").succeeds(); + let mtime = at.metadata(file).modified().unwrap(); + let mtime_nanos = mtime + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos() + .to_string(); + assert_eq!(result.stdout_str().trim(), &mtime_nanos[..]); +} + #[test] #[cfg(all(unix, not(target_os = "macos")))] /// TODO: expected to fail currently; change to `succeeds()` when required.