diff --git a/Cargo.lock b/Cargo.lock index 4dc36c88f..98f95032f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1499,9 +1499,9 @@ dependencies = [ [[package]] name = "parse_datetime" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecceaede7767a9a98058687a321bc91742eff7670167a34104afb30fc8757df" +checksum = "3bbf4e25b13841080e018a1e666358adfe5e39b6d353f986ca5091c210b586a1" dependencies = [ "chrono", "regex", diff --git a/Cargo.toml b/Cargo.toml index 831d4ae48..d6feeb0ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -301,7 +301,7 @@ num-traits = "0.2.16" number_prefix = "0.4" once_cell = "1.18.0" onig = { version = "~6.4", default-features = false } -parse_datetime = "0.4.0" +parse_datetime = "0.5.0" phf = "0.11.2" phf_codegen = "0.11.2" platform-info = "2.0.2" diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 745fd5423..b5ab8993a 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -166,7 +166,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; let date_source = if let Some(date) = matches.get_one::(OPT_DATE) { - if let Ok(duration) = parse_datetime::from_str(date.as_str()) { + let ref_time = Local::now(); + if let Ok(new_time) = parse_datetime::parse_datetime_at_date(ref_time, date.as_str()) { + let duration = new_time.signed_duration_since(ref_time); DateSource::Human(duration) } else { DateSource::Custom(date.into()) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 85eb97bc4..6555773ee 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -68,6 +68,10 @@ fn datetime_to_filetime(dt: &DateTime) -> FileTime { FileTime::from_unix_time(dt.timestamp(), dt.timestamp_subsec_nanos()) } +fn filetime_to_datetime(ft: &FileTime) -> Option> { + Some(DateTime::from_timestamp(ft.unix_seconds(), ft.nanoseconds())?.into()) +} + #[uucore::main] #[allow(clippy::cognitive_complexity)] pub fn uumain(args: impl uucore::Args) -> UResult<()> { @@ -88,35 +92,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { ) { (Some(reference), Some(date)) => { let (atime, mtime) = stat(Path::new(reference), !matches.get_flag(options::NO_DEREF))?; - if let Ok(offset) = parse_datetime::from_str(date) { - let seconds = offset.num_seconds(); - let nanos = offset.num_nanoseconds().unwrap_or(0) % 1_000_000_000; - - let ref_atime_secs = atime.unix_seconds(); - let ref_atime_nanos = atime.nanoseconds(); - let atime = FileTime::from_unix_time( - ref_atime_secs + seconds, - ref_atime_nanos + nanos as u32, - ); - - let ref_mtime_secs = mtime.unix_seconds(); - let ref_mtime_nanos = mtime.nanoseconds(); - let mtime = FileTime::from_unix_time( - ref_mtime_secs + seconds, - ref_mtime_nanos + nanos as u32, - ); - - (atime, mtime) - } else { - let timestamp = parse_date(date)?; - (timestamp, timestamp) - } + let atime = filetime_to_datetime(&atime).ok_or_else(|| { + USimpleError::new(1, "Could not process the reference access time") + })?; + let mtime = filetime_to_datetime(&mtime).ok_or_else(|| { + USimpleError::new(1, "Could not process the reference modification time") + })?; + (parse_date(atime, date)?, parse_date(mtime, date)?) } (Some(reference), None) => { stat(Path::new(reference), !matches.get_flag(options::NO_DEREF))? } (None, Some(date)) => { - let timestamp = parse_date(date)?; + let timestamp = parse_date(Local::now(), date)?; (timestamp, timestamp) } (None, None) => { @@ -336,7 +324,7 @@ fn stat(path: &Path, follow: bool) -> UResult<(FileTime, FileTime)> { )) } -fn parse_date(s: &str) -> UResult { +fn parse_date(ref_time: DateTime, s: &str) -> UResult { // This isn't actually compatible with GNU touch, but there doesn't seem to // be any simple specification for what format this parameter allows and I'm // not about to implement GNU parse_datetime. @@ -385,8 +373,7 @@ fn parse_date(s: &str) -> UResult { } } - if let Ok(duration) = parse_datetime::from_str(s) { - let dt = Local::now() + duration; + if let Ok(dt) = parse_datetime::parse_datetime_at_date(ref_time, s) { return Ok(datetime_to_filetime(&dt)); } diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index c9c0d700e..7b659fc51 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -844,3 +844,15 @@ fn test_touch_dash() { ucmd.args(&["-h", "-"]).succeeds().no_stderr().no_stdout(); } + +#[test] +// Chrono panics for now +#[ignore] +fn test_touch_invalid_date_format() { + let (_at, mut ucmd) = at_and_ucmd!(); + let file = "test_touch_invalid_date_format"; + + ucmd.args(&["-m", "-t", "+1000000000000 years", file]) + .fails() + .stderr_contains("touch: invalid date format ‘+1000000000000 years’"); +}