From 5e6bddb6f56d9749876599a7ae0a2e44772ca18b Mon Sep 17 00:00:00 2001 From: ysthakur <45539777+ysthakur@users.noreply.github.com> Date: Tue, 27 Aug 2024 22:13:47 -0400 Subject: [PATCH] Get rid of parse_relative_time --- src/lib.rs | 10 +- src/parse_relative_time.rs | 239 ++++++++++++++++++------------------- 2 files changed, 116 insertions(+), 133 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4d634f4..db1c8ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ use chrono::{ Timelike, }; -use parse_relative_time::parse_relative_time; +use parse_relative_time::parse_relative_time_at_date; use parse_timestamp::parse_timestamp; #[derive(Debug, PartialEq)] @@ -228,12 +228,8 @@ pub fn parse_datetime_at_date + Clone>( } // Parse relative time. - if let Ok(relative_time) = parse_relative_time(s.as_ref()) { - let current_time = DateTime::::from(date); - - if let Some(date_time) = current_time.checked_add_signed(relative_time) { - return Ok(date_time); - } + if let Ok(datetime) = parse_relative_time_at_date(date, s.as_ref()) { + return Ok(DateTime::::from(datetime)); } // parse time only dates diff --git a/src/parse_relative_time.rs b/src/parse_relative_time.rs index 091adcf..70a6489 100644 --- a/src/parse_relative_time.rs +++ b/src/parse_relative_time.rs @@ -1,16 +1,17 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. use crate::ParseDateTimeError; -use chrono::{DateTime, Days, Duration, Months, TimeZone, Utc}; +use chrono::{DateTime, Days, Duration, Months, TimeZone}; use regex::Regex; -/// Parses a relative time string and returns a `Duration` representing the -/// relative time. -///Regex + +/// Parses a relative time string and adds the duration that it represents to the +/// given date. +/// /// # Arguments /// +/// * `date` - A `Date` instance representing the base date for the calculation /// * `s` - A string slice representing the relative time. /// -/// /// # Supported formats /// /// The function supports the following formats for relative time: @@ -38,27 +39,7 @@ use regex::Regex; /// This function will return `Err(ParseDateTimeError::InvalidInput)` if the input string /// cannot be parsed as a relative time. /// -/// ``` -pub fn parse_relative_time(s: &str) -> Result { - let now = Utc::now(); - let parsed = parse_relative_time_at_date(now, s)?; - Ok(parsed - now) -} - -/// Parses a duration string and returns a `Duration` instance, with the duration -/// calculated from the specified date. -/// -/// # Arguments -/// -/// * `date` - A `Date` instance representing the base date for the calculation -/// * `s` - A string slice representing the relative time. -/// -/// # Errors -/// -/// This function will return `Err(ParseDateTimeError::InvalidInput)` if the input string -/// cannot be parsed as a relative time. -/// ``` -fn parse_relative_time_at_date( +pub fn parse_relative_time_at_date( mut datetime: DateTime, s: &str, ) -> Result, ParseDateTimeError> { @@ -193,27 +174,33 @@ fn add_duration( #[cfg(test)] mod tests { + use super::parse_relative_time_at_date; use super::ParseDateTimeError; - use super::{parse_relative_time, parse_relative_time_at_date}; use chrono::{Days, Duration, Months, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc}; + fn parse_duration(s: &str) -> Result { + let now = Utc::now(); + let parsed = parse_relative_time_at_date(now, s)?; + Ok(parsed - now) + } + #[test] fn test_years() { let now = Utc::now(); assert_eq!( - now + parse_relative_time("1 year").unwrap(), + parse_relative_time_at_date(now, "1 year").unwrap(), now.checked_add_months(Months::new(12)).unwrap() ); assert_eq!( - now + parse_relative_time("-2 years").unwrap(), + parse_relative_time_at_date(now, "-2 years").unwrap(), now.checked_sub_months(Months::new(24)).unwrap() ); assert_eq!( - now + parse_relative_time("2 years ago").unwrap(), + parse_relative_time_at_date(now, "2 years ago").unwrap(), now.checked_sub_months(Months::new(24)).unwrap() ); assert_eq!( - now + parse_relative_time("year").unwrap(), + parse_relative_time_at_date(now, "year").unwrap(), now.checked_add_months(Months::new(12)).unwrap() ); } @@ -222,29 +209,29 @@ mod tests { fn test_months() { let now = Utc::now(); assert_eq!( - now + parse_relative_time("1 month").unwrap(), + parse_relative_time_at_date(now, "1 month").unwrap(), now.checked_add_months(Months::new(1)).unwrap() ); assert_eq!( - now + parse_relative_time("1 month and 2 weeks").unwrap(), + parse_relative_time_at_date(now, "1 month and 2 weeks").unwrap(), now.checked_add_months(Months::new(1)) .unwrap() .checked_add_days(Days::new(14)) .unwrap() ); assert_eq!( - now + parse_relative_time("1 month and 2 weeks ago").unwrap(), + parse_relative_time_at_date(now, "1 month and 2 weeks ago").unwrap(), now.checked_sub_months(Months::new(1)) .unwrap() .checked_sub_days(Days::new(14)) .unwrap() ); assert_eq!( - now + parse_relative_time("2 months").unwrap(), + parse_relative_time_at_date(now, "2 months").unwrap(), now.checked_add_months(Months::new(2)).unwrap() ); assert_eq!( - now + parse_relative_time("month").unwrap(), + parse_relative_time_at_date(now, "month").unwrap(), now.checked_add_months(Months::new(1)).unwrap() ); } @@ -252,15 +239,15 @@ mod tests { #[test] fn test_fortnights() { assert_eq!( - parse_relative_time("1 fortnight").unwrap(), + parse_duration("1 fortnight").unwrap(), Duration::seconds(1_209_600) ); assert_eq!( - parse_relative_time("3 fortnights").unwrap(), + parse_duration("3 fortnights").unwrap(), Duration::seconds(3_628_800) ); assert_eq!( - parse_relative_time("fortnight").unwrap(), + parse_duration("fortnight").unwrap(), Duration::seconds(1_209_600) ); } @@ -268,27 +255,27 @@ mod tests { #[test] fn test_weeks() { assert_eq!( - parse_relative_time("1 week").unwrap(), + parse_duration("1 week").unwrap(), Duration::seconds(604_800) ); assert_eq!( - parse_relative_time("1 week 3 days").unwrap(), + parse_duration("1 week 3 days").unwrap(), Duration::seconds(864_000) ); assert_eq!( - parse_relative_time("1 week 3 days ago").unwrap(), + parse_duration("1 week 3 days ago").unwrap(), Duration::seconds(-864_000) ); assert_eq!( - parse_relative_time("-2 weeks").unwrap(), + parse_duration("-2 weeks").unwrap(), Duration::seconds(-1_209_600) ); assert_eq!( - parse_relative_time("2 weeks ago").unwrap(), + parse_duration("2 weeks ago").unwrap(), Duration::seconds(-1_209_600) ); assert_eq!( - parse_relative_time("week").unwrap(), + parse_duration("week").unwrap(), Duration::seconds(604_800) ); } @@ -296,19 +283,19 @@ mod tests { #[test] fn test_days() { assert_eq!( - parse_relative_time("1 day").unwrap(), + parse_duration("1 day").unwrap(), Duration::seconds(86400) ); assert_eq!( - parse_relative_time("2 days ago").unwrap(), + parse_duration("2 days ago").unwrap(), Duration::seconds(-172_800) ); assert_eq!( - parse_relative_time("-2 days").unwrap(), + parse_duration("-2 days").unwrap(), Duration::seconds(-172_800) ); assert_eq!( - parse_relative_time("day").unwrap(), + parse_duration("day").unwrap(), Duration::seconds(86400) ); } @@ -316,19 +303,19 @@ mod tests { #[test] fn test_hours() { assert_eq!( - parse_relative_time("1 hour").unwrap(), + parse_duration("1 hour").unwrap(), Duration::seconds(3600) ); assert_eq!( - parse_relative_time("1 hour ago").unwrap(), + parse_duration("1 hour ago").unwrap(), Duration::seconds(-3600) ); assert_eq!( - parse_relative_time("-2 hours").unwrap(), + parse_duration("-2 hours").unwrap(), Duration::seconds(-7200) ); assert_eq!( - parse_relative_time("hour").unwrap(), + parse_duration("hour").unwrap(), Duration::seconds(3600) ); } @@ -336,39 +323,39 @@ mod tests { #[test] fn test_minutes() { assert_eq!( - parse_relative_time("1 minute").unwrap(), + parse_duration("1 minute").unwrap(), Duration::seconds(60) ); assert_eq!( - parse_relative_time("2 minutes").unwrap(), + parse_duration("2 minutes").unwrap(), Duration::seconds(120) ); - assert_eq!(parse_relative_time("min").unwrap(), Duration::seconds(60)); + assert_eq!(parse_duration("min").unwrap(), Duration::seconds(60)); } #[test] fn test_seconds() { assert_eq!( - parse_relative_time("1 second").unwrap(), + parse_duration("1 second").unwrap(), Duration::seconds(1) ); assert_eq!( - parse_relative_time("2 seconds").unwrap(), + parse_duration("2 seconds").unwrap(), Duration::seconds(2) ); - assert_eq!(parse_relative_time("sec").unwrap(), Duration::seconds(1)); + assert_eq!(parse_duration("sec").unwrap(), Duration::seconds(1)); } #[test] fn test_relative_days() { - assert_eq!(parse_relative_time("now").unwrap(), Duration::seconds(0)); - assert_eq!(parse_relative_time("today").unwrap(), Duration::seconds(0)); + assert_eq!(parse_duration("now").unwrap(), Duration::seconds(0)); + assert_eq!(parse_duration("today").unwrap(), Duration::seconds(0)); assert_eq!( - parse_relative_time("yesterday").unwrap(), + parse_duration("yesterday").unwrap(), Duration::seconds(-86400) ); assert_eq!( - parse_relative_time("tomorrow").unwrap(), + parse_duration("tomorrow").unwrap(), Duration::seconds(86400) ); } @@ -376,46 +363,46 @@ mod tests { #[test] fn test_no_spaces() { let now = Utc::now(); - assert_eq!(parse_relative_time("-1hour").unwrap(), Duration::hours(-1)); - assert_eq!(parse_relative_time("+3days").unwrap(), Duration::days(3)); - assert_eq!(parse_relative_time("2weeks").unwrap(), Duration::weeks(2)); + assert_eq!(parse_duration("-1hour").unwrap(), Duration::hours(-1)); + assert_eq!(parse_duration("+3days").unwrap(), Duration::days(3)); + assert_eq!(parse_duration("2weeks").unwrap(), Duration::weeks(2)); assert_eq!( - parse_relative_time("2weeks 1hour").unwrap(), + parse_duration("2weeks 1hour").unwrap(), Duration::seconds(1_213_200) ); assert_eq!( - parse_relative_time("2weeks 1hour ago").unwrap(), + parse_duration("2weeks 1hour ago").unwrap(), Duration::seconds(-1_213_200) ); assert_eq!( - now + parse_relative_time("+4months").unwrap(), + parse_relative_time_at_date(now, "+4months").unwrap(), now.checked_add_months(Months::new(4)).unwrap() ); assert_eq!( - now + parse_relative_time("-2years").unwrap(), + parse_relative_time_at_date(now, "-2years").unwrap(), now.checked_sub_months(Months::new(24)).unwrap() ); assert_eq!( - parse_relative_time("15minutes").unwrap(), + parse_duration("15minutes").unwrap(), Duration::minutes(15) ); assert_eq!( - parse_relative_time("-30seconds").unwrap(), + parse_duration("-30seconds").unwrap(), Duration::seconds(-30) ); assert_eq!( - parse_relative_time("30seconds ago").unwrap(), + parse_duration("30seconds ago").unwrap(), Duration::seconds(-30) ); } #[test] fn test_invalid_input() { - let result = parse_relative_time("foobar"); + let result = parse_duration("foobar"); println!("{result:?}"); assert_eq!(result, Err(ParseDateTimeError::InvalidInput)); - let result = parse_relative_time("invalid 1"); + let result = parse_duration("invalid 1"); assert_eq!(result, Err(ParseDateTimeError::InvalidInput)); // Fails for now with a panic /* let result = parse_relative_time("777777777777777771m"); @@ -449,16 +436,16 @@ mod tests { fn test_direction() { let now = Utc::now(); assert_eq!( - parse_relative_time("last hour").unwrap(), + parse_duration("last hour").unwrap(), Duration::seconds(-3600) ); assert_eq!( - now + parse_relative_time("next year").unwrap(), + parse_relative_time_at_date(now, "next year").unwrap(), now.checked_add_months(Months::new(12)).unwrap() ); - assert_eq!(parse_relative_time("next week").unwrap(), Duration::days(7)); + assert_eq!(parse_duration("next week").unwrap(), Duration::days(7)); assert_eq!( - now + parse_relative_time("last month").unwrap(), + parse_relative_time_at_date(now, "last month").unwrap(), now.checked_sub_months(Months::new(1)).unwrap() ); } @@ -467,173 +454,173 @@ mod tests { fn test_duration_parsing() { let now = Utc::now(); assert_eq!( - now + parse_relative_time("1 year").unwrap(), + parse_relative_time_at_date(now, "1 year").unwrap(), now.checked_add_months(Months::new(12)).unwrap() ); assert_eq!( - now + parse_relative_time("-2 years").unwrap(), + parse_relative_time_at_date(now, "-2 years").unwrap(), now.checked_sub_months(Months::new(24)).unwrap() ); assert_eq!( - now + parse_relative_time("2 years ago").unwrap(), + parse_relative_time_at_date(now, "2 years ago").unwrap(), now.checked_sub_months(Months::new(24)).unwrap() ); assert_eq!( - now + parse_relative_time("year").unwrap(), + parse_relative_time_at_date(now, "year").unwrap(), now.checked_add_months(Months::new(12)).unwrap() ); assert_eq!( - now + parse_relative_time("1 month").unwrap(), + parse_relative_time_at_date(now, "1 month").unwrap(), now.checked_add_months(Months::new(1)).unwrap() ); assert_eq!( - now + parse_relative_time("1 month and 2 weeks").unwrap(), + parse_relative_time_at_date(now, "1 month and 2 weeks").unwrap(), now.checked_add_months(Months::new(1)) .unwrap() .checked_add_days(Days::new(14)) .unwrap() ); assert_eq!( - now + parse_relative_time("1 month, 2 weeks").unwrap(), + parse_relative_time_at_date(now, "1 month, 2 weeks").unwrap(), now.checked_add_months(Months::new(1)) .unwrap() .checked_add_days(Days::new(14)) .unwrap() ); assert_eq!( - now + parse_relative_time("1 months 2 weeks").unwrap(), + parse_relative_time_at_date(now, "1 months 2 weeks").unwrap(), now.checked_add_months(Months::new(1)) .unwrap() .checked_add_days(Days::new(14)) .unwrap() ); assert_eq!( - now + parse_relative_time("1 month and 2 weeks ago").unwrap(), + parse_relative_time_at_date(now, "1 month and 2 weeks ago").unwrap(), now.checked_sub_months(Months::new(1)) .unwrap() .checked_sub_days(Days::new(14)) .unwrap() ); assert_eq!( - now + parse_relative_time("2 months").unwrap(), + parse_relative_time_at_date(now, "2 months").unwrap(), now.checked_add_months(Months::new(2)).unwrap() ); assert_eq!( - now + parse_relative_time("month").unwrap(), + parse_relative_time_at_date(now, "month").unwrap(), now.checked_add_months(Months::new(1)).unwrap() ); assert_eq!( - now + parse_relative_time("1 fortnight").unwrap(), + parse_relative_time_at_date(now, "1 fortnight").unwrap(), now.checked_add_days(Days::new(14)).unwrap() ); assert_eq!( - now + parse_relative_time("3 fortnights").unwrap(), + parse_relative_time_at_date(now, "3 fortnights").unwrap(), now.checked_add_days(Days::new(3 * 14)).unwrap() ); assert_eq!( - now + parse_relative_time("fortnight").unwrap(), + parse_relative_time_at_date(now, "fortnight").unwrap(), now.checked_add_days(Days::new(14)).unwrap() ); assert_eq!( - now + parse_relative_time("1 week").unwrap(), + parse_relative_time_at_date(now, "1 week").unwrap(), now.checked_add_days(Days::new(7)).unwrap() ); assert_eq!( - now + parse_relative_time("1 week 3 days").unwrap(), + parse_relative_time_at_date(now, "1 week 3 days").unwrap(), now.checked_add_days(Days::new(7 + 3)).unwrap() ); assert_eq!( - now + parse_relative_time("1 week 3 days ago").unwrap(), + parse_relative_time_at_date(now, "1 week 3 days ago").unwrap(), now.checked_sub_days(Days::new(7 + 3)).unwrap() ); assert_eq!( - now + parse_relative_time("-2 weeks").unwrap(), + parse_relative_time_at_date(now, "-2 weeks").unwrap(), now.checked_sub_days(Days::new(14)).unwrap() ); assert_eq!( - now + parse_relative_time("2 weeks ago").unwrap(), + parse_relative_time_at_date(now, "2 weeks ago").unwrap(), now.checked_sub_days(Days::new(14)).unwrap() ); assert_eq!( - now + parse_relative_time("week").unwrap(), + parse_relative_time_at_date(now, "week").unwrap(), now.checked_add_days(Days::new(7)).unwrap() ); assert_eq!( - parse_relative_time("1 day").unwrap(), + parse_duration("1 day").unwrap(), Duration::seconds(86_400) ); assert_eq!( - parse_relative_time("2 days ago").unwrap(), + parse_duration("2 days ago").unwrap(), Duration::seconds(-172_800) ); assert_eq!( - parse_relative_time("-2 days").unwrap(), + parse_duration("-2 days").unwrap(), Duration::seconds(-172_800) ); assert_eq!( - parse_relative_time("day").unwrap(), + parse_duration("day").unwrap(), Duration::seconds(86_400) ); assert_eq!( - parse_relative_time("1 hour").unwrap(), + parse_duration("1 hour").unwrap(), Duration::seconds(3_600) ); assert_eq!( - parse_relative_time("1 h").unwrap(), + parse_duration("1 h").unwrap(), Duration::seconds(3_600) ); assert_eq!( - parse_relative_time("1 hour ago").unwrap(), + parse_duration("1 hour ago").unwrap(), Duration::seconds(-3_600) ); assert_eq!( - parse_relative_time("-2 hours").unwrap(), + parse_duration("-2 hours").unwrap(), Duration::seconds(-7_200) ); assert_eq!( - parse_relative_time("hour").unwrap(), + parse_duration("hour").unwrap(), Duration::seconds(3_600) ); assert_eq!( - parse_relative_time("1 minute").unwrap(), + parse_duration("1 minute").unwrap(), Duration::seconds(60) ); - assert_eq!(parse_relative_time("1 min").unwrap(), Duration::seconds(60)); + assert_eq!(parse_duration("1 min").unwrap(), Duration::seconds(60)); assert_eq!( - parse_relative_time("2 minutes").unwrap(), + parse_duration("2 minutes").unwrap(), Duration::seconds(120) ); assert_eq!( - parse_relative_time("2 mins").unwrap(), + parse_duration("2 mins").unwrap(), Duration::seconds(120) ); - assert_eq!(parse_relative_time("2m").unwrap(), Duration::seconds(120)); - assert_eq!(parse_relative_time("min").unwrap(), Duration::seconds(60)); + assert_eq!(parse_duration("2m").unwrap(), Duration::seconds(120)); + assert_eq!(parse_duration("min").unwrap(), Duration::seconds(60)); assert_eq!( - parse_relative_time("1 second").unwrap(), + parse_duration("1 second").unwrap(), Duration::seconds(1) ); - assert_eq!(parse_relative_time("1 s").unwrap(), Duration::seconds(1)); + assert_eq!(parse_duration("1 s").unwrap(), Duration::seconds(1)); assert_eq!( - parse_relative_time("2 seconds").unwrap(), + parse_duration("2 seconds").unwrap(), Duration::seconds(2) ); - assert_eq!(parse_relative_time("2 secs").unwrap(), Duration::seconds(2)); - assert_eq!(parse_relative_time("2 sec").unwrap(), Duration::seconds(2)); - assert_eq!(parse_relative_time("sec").unwrap(), Duration::seconds(1)); + assert_eq!(parse_duration("2 secs").unwrap(), Duration::seconds(2)); + assert_eq!(parse_duration("2 sec").unwrap(), Duration::seconds(2)); + assert_eq!(parse_duration("sec").unwrap(), Duration::seconds(1)); - assert_eq!(parse_relative_time("now").unwrap(), Duration::seconds(0)); - assert_eq!(parse_relative_time("today").unwrap(), Duration::seconds(0)); + assert_eq!(parse_duration("now").unwrap(), Duration::seconds(0)); + assert_eq!(parse_duration("today").unwrap(), Duration::seconds(0)); assert_eq!( - now + parse_relative_time("1 year 2 months 4 weeks 3 days and 2 seconds").unwrap(), + parse_relative_time_at_date(now, "1 year 2 months 4 weeks 3 days and 2 seconds").unwrap(), now.checked_add_months(Months::new(12 + 2)) .unwrap() .checked_add_days(Days::new(4 * 7 + 3)) @@ -642,7 +629,7 @@ mod tests { .unwrap() ); assert_eq!( - now + parse_relative_time("1 year 2 months 4 weeks 3 days and 2 seconds ago").unwrap(), + parse_relative_time_at_date(now, "1 year 2 months 4 weeks 3 days and 2 seconds ago").unwrap(), now.checked_sub_months(Months::new(12 + 2)) .unwrap() .checked_sub_days(Days::new(4 * 7 + 3)) @@ -656,13 +643,13 @@ mod tests { #[should_panic] fn test_display_parse_duration_error_through_parse_relative_time() { let invalid_input = "9223372036854775807 seconds and 1 second"; - let _ = parse_relative_time(invalid_input).unwrap(); + let _ = parse_duration(invalid_input).unwrap(); } #[test] fn test_display_should_fail() { let invalid_input = "Thu Jan 01 12:34:00 2015"; - let error = parse_relative_time(invalid_input).unwrap_err(); + let error = parse_duration(invalid_input).unwrap_err(); assert_eq!( format!("{error}"),