date: use --reference=file to display the file modification time

This commit is contained in:
yuankunzhang 2025-09-12 23:35:44 +08:00
parent bca02e45f2
commit 88a7fa7adf
2 changed files with 33 additions and 0 deletions

View file

@ -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::<String>(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)

View file

@ -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.