From f95e42a488b422191f6b5e507b86f1a3d8478371 Mon Sep 17 00:00:00 2001 From: Patrick Klitzke Date: Mon, 21 Aug 2023 11:30:38 +0900 Subject: [PATCH] date: Adds support datetime for parameter -d This resolved issue #5177. The PR adds a new enum HumanDuration(Duration), HumanDateTime(DateTime) and uses parse_datetime::parse_datetime::from_str to support datetime if relative time cannot be parsed. Furthermore tests are added for tests/by-util/test_date.rs. --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/uu/date/src/date.rs | 26 ++++++------------------- tests/by-util/test_date.rs | 39 +++++++++++++++++++++++++++++++++++++- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3723c52da62..06049f73b64 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 65b23faa2bb..b7d6d97720a 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 745fd54239c..3b357f93c93 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -92,7 +92,7 @@ enum DateSource { Now, Custom(String), File(PathBuf), - Human(Duration), + Human(DateTime), } enum Iso8601Format { @@ -166,8 +166,8 @@ 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()) { - DateSource::Human(duration) + if let Ok(datetime) = parse_datetime::parse_datetime(date.as_str()) { + DateSource::Human(datetime) } else { DateSource::Custom(date.into()) } @@ -221,23 +221,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let iter = std::iter::once(date); Box::new(iter) } - DateSource::Human(relative_time) => { - // Get the current DateTime for things like "1 year ago" - let current_time = DateTime::::from(Local::now()); - // double check the result is overflow or not of the current_time + relative_time - // it may cause a panic of chrono::datetime::DateTime add - match current_time.checked_add_signed(relative_time) { - Some(date) => { - let iter = std::iter::once(Ok(date)); - Box::new(iter) - } - None => { - return Err(USimpleError::new( - 1, - format!("invalid date {}", relative_time), - )); - } - } + DateSource::Human(date) => { + let iter = std::iter::once(Ok(date)); + Box::new(iter) } DateSource::File(ref path) => { if path.is_dir() { diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index a65f02fa4c7..4ce335cda1b 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -368,7 +368,7 @@ fn test_unsupported_format() { } #[test] -fn test_date_string_human() { +fn test_date_string_human_relative_time() { let date_formats = vec![ "1 year ago", "1 year", @@ -390,6 +390,43 @@ fn test_date_string_human() { } } +#[test] +fn test_date_string_human_date_time() { + let date_formats = vec![ + // unix timestamp format + "@0", + "@2", + "@10", + "@100", + "@2000", + "@1234400000", + "@1334400000", + "@1692582913", + "@2092582910", + // format YYYY-MM-DD + "2012-01-01", + "1999-01-12", + "2012-01-12", + // format YYYY-MM-DD HH:mm + "1970-01-01 00:00", + "2000-02-29 12:34", + "2100-02-28 23:59", + "2012-12-31 05:30", + "1800-01-01 18:45", + "9999-12-31 11:11", + "2023-08-21 14:55", // + ]; + let re = Regex::new(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}\n$").unwrap(); + for date_format in date_formats { + new_ucmd!() + .arg("-d") + .arg(date_format) + .arg("+%Y-%m-%d %S:%M") + .succeeds() + .stdout_matches(&re); + } +} + #[test] fn test_invalid_date_string() { new_ucmd!()