Created
November 2, 2023 00:41
-
-
Save dcechano/5eeeb47a2591d75b42f04afa8d2915b3 to your computer and use it in GitHub Desktop.
parse_relative_time refactored to allow getting dates back rather that simply a net Duration.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::ops::{Add, Sub}; | |
// For the full copyright and license information, please view the LICENSE | |
// file that was distributed with this source code. | |
use crate::ParseDateTimeError; | |
use chrono::{Duration, Local, Months, NaiveDate, Utc}; | |
use regex::Regex; | |
/// Parses a relative time string and returns a `Duration` representing the | |
/// relative time. | |
///Regex | |
/// # Arguments | |
/// | |
/// * `s` - A string slice representing the relative time. | |
/// | |
/// | |
/// # Supported formats | |
/// | |
/// The function supports the following formats for relative time: | |
/// | |
/// * `num` `unit` (e.g., "-1 hour", "+3 days") | |
/// * `unit` (e.g., "hour", "day") | |
/// * "now" or "today" | |
/// * "yesterday" | |
/// * "tomorrow" | |
/// * use "ago" for the past | |
/// | |
/// `[num]` can be a positive or negative integer. | |
/// [unit] can be one of the following: "fortnight", "week", "day", "hour", | |
/// "minute", "min", "second", "sec" and their plural forms. | |
/// | |
/// It is also possible to pass "1 hour 2 minutes" or "2 days and 2 hours" | |
/// | |
/// # Returns | |
/// | |
/// * `Ok(Duration)` - If the input string can be parsed as a relative time | |
/// * `Err(ParseDateTimeError)` - If the input string cannot be parsed as a relative time | |
/// | |
/// # Errors | |
/// | |
/// 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<Duration, ParseDateTimeError> { | |
parse_relative_time_at_date(Utc::now().date_naive(), s) | |
} | |
/// 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. | |
/// ``` | |
pub fn parse_relative_time_at_date( | |
date: NaiveDate, | |
s: &str, | |
) -> Result<Duration, ParseDateTimeError> { | |
duration_from_relative(s).map(|duration| { | |
let time_now = Local::now().date_naive(); | |
let date_duration = date - time_now; | |
duration + date_duration | |
}) | |
} | |
pub fn duration_from_relative(s: &str) -> Result<Duration, ParseDateTimeError> { | |
let time_pattern: Regex = Regex::new( | |
r"(?x) | |
(?:(?P<value>[-+]?\d*)\s*)? | |
(\s*(?P<direction>next|last)?\s*)? | |
(?P<unit>years?|months?|fortnights?|weeks?|days?|hours?|h|minutes?|mins?|m|seconds?|secs?|s|yesterday|tomorrow|now|today) | |
(\s*(?P<separator>and|,)?\s*)? | |
(\s*(?P<ago>ago)?)?", | |
)?; | |
let mut total_duration = Duration::seconds(0); | |
let mut is_ago = s.contains(" ago"); | |
let mut captures_processed = 0; | |
let mut total_length = 0; | |
for capture in time_pattern.captures_iter(s) { | |
captures_processed += 1; | |
let value_str = capture | |
.name("value") | |
.ok_or(ParseDateTimeError::InvalidInput)? | |
.as_str(); | |
let value = if value_str.is_empty() { | |
1 | |
} else { | |
value_str | |
.parse::<i64>() | |
.map_err(|_| ParseDateTimeError::InvalidInput)? | |
}; | |
if let Some(direction) = capture.name("direction") { | |
if direction.as_str() == "last" { | |
is_ago = true; | |
} | |
} | |
let unit = capture | |
.name("unit") | |
.ok_or(ParseDateTimeError::InvalidInput)? | |
.as_str(); | |
if capture.name("ago").is_some() { | |
is_ago = true; | |
} | |
let duration = match unit { | |
"years" | "year" => Duration::days(value * 365), | |
"months" | "month" => Duration::days(value * 30), | |
"fortnights" | "fortnight" => Duration::weeks(value * 2), | |
"weeks" | "week" => Duration::weeks(value), | |
"days" | "day" => Duration::days(value), | |
"hours" | "hour" | "h" => Duration::hours(value), | |
"minutes" | "minute" | "mins" | "min" | "m" => Duration::minutes(value), | |
"seconds" | "second" | "secs" | "sec" | "s" => Duration::seconds(value), | |
"yesterday" => Duration::days(-1), | |
"tomorrow" => Duration::days(1), | |
"now" | "today" => Duration::zero(), | |
_ => return Err(ParseDateTimeError::InvalidInput), | |
}; | |
let neg_duration = -duration; | |
total_duration = | |
match total_duration.checked_add(if is_ago { &neg_duration } else { &duration }) { | |
Some(duration) => duration, | |
None => return Err(ParseDateTimeError::InvalidInput), | |
}; | |
// Calculate the total length of the matched substring | |
if let Some(m) = capture.get(0) { | |
total_length += m.end() - m.start(); | |
} | |
} | |
// Check if the entire input string has been captured | |
if total_length != s.len() { | |
return Err(ParseDateTimeError::InvalidInput); | |
} | |
if captures_processed == 0 { | |
Err(ParseDateTimeError::InvalidInput) | |
} else { | |
Ok(total_duration) | |
} | |
} | |
pub fn date_from_relative<D>(s: &str, date: D) -> Result<D, ParseDateTimeError> | |
where | |
D: Add<Duration, Output = D> | |
+ Sub<Duration, Output = D> | |
{ | |
duration_from_relative(s).map(|duration| | |
date.add(duration) | |
) | |
} | |
#[cfg(test)] | |
mod tests { | |
use std::ops::Add; | |
use super::{date_from_relative, ParseDateTimeError}; | |
use super::{parse_relative_time, parse_relative_time_at_date}; | |
use chrono::{Duration, Local, Months, NaiveDate, NaiveDateTime, Utc}; | |
#[test] | |
fn test_years() { | |
assert_eq!( | |
parse_relative_time("1 year").unwrap(), | |
Duration::seconds(31_536_000) | |
); | |
assert_eq!( | |
parse_relative_time("-2 years").unwrap(), | |
Duration::seconds(-63_072_000) | |
); | |
assert_eq!( | |
parse_relative_time("2 years ago").unwrap(), | |
Duration::seconds(-63_072_000) | |
); | |
assert_eq!( | |
parse_relative_time("year").unwrap(), | |
Duration::seconds(31_536_000) | |
); | |
} | |
#[test] | |
fn test_months() { | |
assert_eq!( | |
parse_relative_time("1 month").unwrap(), | |
Duration::seconds(2_592_000) | |
); | |
assert_eq!( | |
parse_relative_time("1 month and 2 weeks").unwrap(), | |
Duration::seconds(3_801_600) | |
); | |
assert_eq!( | |
parse_relative_time("1 month and 2 weeks ago").unwrap(), | |
Duration::seconds(-3_801_600) | |
); | |
assert_eq!( | |
parse_relative_time("2 months").unwrap(), | |
Duration::seconds(5_184_000) | |
); | |
assert_eq!( | |
parse_relative_time("month").unwrap(), | |
Duration::seconds(2_592_000) | |
); | |
} | |
#[test] | |
fn test_fortnights() { | |
assert_eq!( | |
parse_relative_time("1 fortnight").unwrap(), | |
Duration::seconds(1_209_600) | |
); | |
assert_eq!( | |
parse_relative_time("3 fortnights").unwrap(), | |
Duration::seconds(3_628_800) | |
); | |
assert_eq!( | |
parse_relative_time("fortnight").unwrap(), | |
Duration::seconds(1_209_600) | |
); | |
} | |
#[test] | |
fn test_weeks() { | |
assert_eq!( | |
parse_relative_time("1 week").unwrap(), | |
Duration::seconds(604_800) | |
); | |
assert_eq!( | |
parse_relative_time("1 week 3 days").unwrap(), | |
Duration::seconds(864_000) | |
); | |
assert_eq!( | |
parse_relative_time("1 week 3 days ago").unwrap(), | |
Duration::seconds(-864_000) | |
); | |
assert_eq!( | |
parse_relative_time("-2 weeks").unwrap(), | |
Duration::seconds(-1_209_600) | |
); | |
assert_eq!( | |
parse_relative_time("2 weeks ago").unwrap(), | |
Duration::seconds(-1_209_600) | |
); | |
assert_eq!( | |
parse_relative_time("week").unwrap(), | |
Duration::seconds(604_800) | |
); | |
} | |
#[test] | |
fn test_days() { | |
assert_eq!( | |
parse_relative_time("1 day").unwrap(), | |
Duration::seconds(86400) | |
); | |
assert_eq!( | |
parse_relative_time("2 days ago").unwrap(), | |
Duration::seconds(-172_800) | |
); | |
assert_eq!( | |
parse_relative_time("-2 days").unwrap(), | |
Duration::seconds(-172_800) | |
); | |
assert_eq!( | |
parse_relative_time("day").unwrap(), | |
Duration::seconds(86400) | |
); | |
} | |
#[test] | |
fn test_hours() { | |
assert_eq!( | |
parse_relative_time("1 hour").unwrap(), | |
Duration::seconds(3600) | |
); | |
assert_eq!( | |
parse_relative_time("1 hour ago").unwrap(), | |
Duration::seconds(-3600) | |
); | |
assert_eq!( | |
parse_relative_time("-2 hours").unwrap(), | |
Duration::seconds(-7200) | |
); | |
assert_eq!( | |
parse_relative_time("hour").unwrap(), | |
Duration::seconds(3600) | |
); | |
} | |
#[test] | |
fn test_minutes() { | |
assert_eq!( | |
parse_relative_time("1 minute").unwrap(), | |
Duration::seconds(60) | |
); | |
assert_eq!( | |
parse_relative_time("2 minutes").unwrap(), | |
Duration::seconds(120) | |
); | |
assert_eq!(parse_relative_time("min").unwrap(), Duration::seconds(60)); | |
} | |
#[test] | |
fn test_seconds() { | |
assert_eq!( | |
parse_relative_time("1 second").unwrap(), | |
Duration::seconds(1) | |
); | |
assert_eq!( | |
parse_relative_time("2 seconds").unwrap(), | |
Duration::seconds(2) | |
); | |
assert_eq!(parse_relative_time("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_relative_time("yesterday").unwrap(), | |
Duration::seconds(-86400) | |
); | |
assert_eq!( | |
parse_relative_time("tomorrow").unwrap(), | |
Duration::seconds(86400) | |
); | |
} | |
#[test] | |
fn test_no_spaces() { | |
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_relative_time("2weeks 1hour").unwrap(), | |
Duration::seconds(1_213_200) | |
); | |
assert_eq!( | |
parse_relative_time("2weeks 1hour ago").unwrap(), | |
Duration::seconds(-1_213_200) | |
); | |
assert_eq!( | |
parse_relative_time("+4months").unwrap(), | |
Duration::days(4 * 30) | |
); | |
assert_eq!( | |
parse_relative_time("-2years").unwrap(), | |
Duration::days(-2 * 365) | |
); | |
assert_eq!( | |
parse_relative_time("15minutes").unwrap(), | |
Duration::minutes(15) | |
); | |
assert_eq!( | |
parse_relative_time("-30seconds").unwrap(), | |
Duration::seconds(-30) | |
); | |
assert_eq!( | |
parse_relative_time("30seconds ago").unwrap(), | |
Duration::seconds(-30) | |
); | |
} | |
#[test] | |
fn test_invalid_input() { | |
let result = parse_relative_time("foobar"); | |
println!("{result:?}"); | |
assert_eq!(result, Err(ParseDateTimeError::InvalidInput)); | |
let result = parse_relative_time("invalid 1"); | |
assert_eq!(result, Err(ParseDateTimeError::InvalidInput)); | |
// Fails for now with a panic | |
/* let result = parse_relative_time("777777777777777771m"); | |
match result { | |
Err(ParseDateTimeError::InvalidInput) => assert!(true), | |
_ => assert!(false), | |
}*/ | |
} | |
#[test] | |
fn test_parse_relative_time_at_date() { | |
let date = NaiveDate::from_ymd_opt(2014, 9, 5).unwrap(); | |
let now = Local::now().date_naive(); | |
let days_diff = (date - now).num_days(); | |
assert_eq!( | |
parse_relative_time_at_date(date, "1 day").unwrap(), | |
Duration::days(days_diff + 1) | |
); | |
assert_eq!( | |
parse_relative_time_at_date(date, "2 hours").unwrap(), | |
Duration::days(days_diff) + Duration::hours(2) | |
); | |
} | |
#[test] | |
fn test_invalid_input_at_date() { | |
let date = NaiveDate::from_ymd_opt(2014, 9, 5).unwrap(); | |
assert!(matches!( | |
parse_relative_time_at_date(date, "invalid"), | |
Err(ParseDateTimeError::InvalidInput) | |
)); | |
} | |
#[test] | |
fn test_direction() { | |
assert_eq!( | |
parse_relative_time("last hour").unwrap(), | |
Duration::seconds(-3600) | |
); | |
assert_eq!( | |
parse_relative_time("next year").unwrap(), | |
Duration::days(365) | |
); | |
assert_eq!(parse_relative_time("next week").unwrap(), Duration::days(7)); | |
assert_eq!( | |
parse_relative_time("last month").unwrap(), | |
Duration::days(-30) | |
); | |
} | |
#[test] | |
fn test_duration_parsing() { | |
assert_eq!( | |
parse_relative_time("1 year").unwrap(), | |
Duration::seconds(31_536_000) | |
); | |
assert_eq!( | |
parse_relative_time("-2 years").unwrap(), | |
Duration::seconds(-63_072_000) | |
); | |
assert_eq!( | |
parse_relative_time("2 years ago").unwrap(), | |
Duration::seconds(-63_072_000) | |
); | |
assert_eq!( | |
parse_relative_time("year").unwrap(), | |
Duration::seconds(31_536_000) | |
); | |
assert_eq!( | |
parse_relative_time("1 month").unwrap(), | |
Duration::seconds(2_592_000) | |
); | |
assert_eq!( | |
parse_relative_time("1 month and 2 weeks").unwrap(), | |
Duration::seconds(3_801_600) | |
); | |
assert_eq!( | |
parse_relative_time("1 month, 2 weeks").unwrap(), | |
Duration::seconds(3_801_600) | |
); | |
assert_eq!( | |
parse_relative_time("1 months 2 weeks").unwrap(), | |
Duration::seconds(3_801_600) | |
); | |
assert_eq!( | |
parse_relative_time("1 month and 2 weeks ago").unwrap(), | |
Duration::seconds(-3_801_600) | |
); | |
assert_eq!( | |
parse_relative_time("2 months").unwrap(), | |
Duration::seconds(5_184_000) | |
); | |
assert_eq!( | |
parse_relative_time("month").unwrap(), | |
Duration::seconds(2_592_000) | |
); | |
assert_eq!( | |
parse_relative_time("1 fortnight").unwrap(), | |
Duration::seconds(1_209_600) | |
); | |
assert_eq!( | |
parse_relative_time("3 fortnights").unwrap(), | |
Duration::seconds(3_628_800) | |
); | |
assert_eq!( | |
parse_relative_time("fortnight").unwrap(), | |
Duration::seconds(1_209_600) | |
); | |
assert_eq!( | |
parse_relative_time("1 week").unwrap(), | |
Duration::seconds(604_800) | |
); | |
assert_eq!( | |
parse_relative_time("1 week 3 days").unwrap(), | |
Duration::seconds(864_000) | |
); | |
assert_eq!( | |
parse_relative_time("1 week 3 days ago").unwrap(), | |
Duration::seconds(-864_000) | |
); | |
assert_eq!( | |
parse_relative_time("-2 weeks").unwrap(), | |
Duration::seconds(-1_209_600) | |
); | |
assert_eq!( | |
parse_relative_time("2 weeks ago").unwrap(), | |
Duration::seconds(-1_209_600) | |
); | |
assert_eq!( | |
parse_relative_time("week").unwrap(), | |
Duration::seconds(604_800) | |
); | |
assert_eq!( | |
parse_relative_time("1 day").unwrap(), | |
Duration::seconds(86_400) | |
); | |
assert_eq!( | |
parse_relative_time("2 days ago").unwrap(), | |
Duration::seconds(-172_800) | |
); | |
assert_eq!( | |
parse_relative_time("-2 days").unwrap(), | |
Duration::seconds(-172_800) | |
); | |
assert_eq!( | |
parse_relative_time("day").unwrap(), | |
Duration::seconds(86_400) | |
); | |
assert_eq!( | |
parse_relative_time("1 hour").unwrap(), | |
Duration::seconds(3_600) | |
); | |
assert_eq!( | |
parse_relative_time("1 h").unwrap(), | |
Duration::seconds(3_600) | |
); | |
assert_eq!( | |
parse_relative_time("1 hour ago").unwrap(), | |
Duration::seconds(-3_600) | |
); | |
assert_eq!( | |
parse_relative_time("-2 hours").unwrap(), | |
Duration::seconds(-7_200) | |
); | |
assert_eq!( | |
parse_relative_time("hour").unwrap(), | |
Duration::seconds(3_600) | |
); | |
assert_eq!( | |
parse_relative_time("1 minute").unwrap(), | |
Duration::seconds(60) | |
); | |
assert_eq!(parse_relative_time("1 min").unwrap(), Duration::seconds(60)); | |
assert_eq!( | |
parse_relative_time("2 minutes").unwrap(), | |
Duration::seconds(120) | |
); | |
assert_eq!( | |
parse_relative_time("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_relative_time("1 second").unwrap(), | |
Duration::seconds(1) | |
); | |
assert_eq!(parse_relative_time("1 s").unwrap(), Duration::seconds(1)); | |
assert_eq!( | |
parse_relative_time("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_relative_time("now").unwrap(), Duration::seconds(0)); | |
assert_eq!(parse_relative_time("today").unwrap(), Duration::seconds(0)); | |
assert_eq!( | |
parse_relative_time("1 year 2 months 4 weeks 3 days and 2 seconds").unwrap(), | |
Duration::seconds(39_398_402) | |
); | |
assert_eq!( | |
parse_relative_time("1 year 2 months 4 weeks 3 days and 2 seconds ago").unwrap(), | |
Duration::seconds(-39_398_402) | |
); | |
} | |
#[test] | |
#[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(); | |
} | |
#[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(); | |
assert_eq!( | |
format!("{error}"), | |
"Invalid input string: cannot be parsed as a relative time" | |
); | |
} | |
#[test] | |
fn test_parse_relative_time_at_date_day() { | |
let today = Utc::now().date_naive(); | |
let yesterday = today - Duration::days(1); | |
assert_eq!( | |
parse_relative_time_at_date(yesterday, "2 days").unwrap(), | |
Duration::days(1) | |
); | |
} | |
#[test] | |
fn test_invalid_input_at_date_relative() { | |
let today = Utc::now().date_naive(); | |
let result = parse_relative_time_at_date(today, "foobar"); | |
println!("{result:?}"); | |
assert_eq!(result, Err(ParseDateTimeError::InvalidInput)); | |
let result = parse_relative_time_at_date(today, "invalid 1r"); | |
assert_eq!(result, Err(ParseDateTimeError::InvalidInput)); | |
} | |
#[test] | |
fn test_parse_date_from_modifier_ok() { | |
const MODIFIER_OK_0: &str = "+01month"; | |
const MODIFIER_OK_1: &str = "00001year-000000001year+\t12months"; | |
const MODIFIER_OK_2: &str = ""; | |
const MODIFIER_OK_3: &str = "30SecONDS1houR"; | |
const MODIFIER_OK_4: &str = "30 \t\n\t SECONDS000050000houR-10000yearS"; | |
const MODIFIER_OK_5: &str = "+0000111MONTHs - 20 yearS 100000day"; | |
const MODIFIER_OK_6: &str = "100 week + 0024HOUrs - 50 minutes"; | |
const MODIFIER_OK_7: &str = "-100 MONTHS 300 days + 20 \t YEARS"; | |
let date0 = NaiveDate::parse_from_str("2022-05-15", "%Y-%m-%d").unwrap(); | |
if let Ok(modified_date) = date_from_relative(MODIFIER_OK_0, date0) { | |
let expected = NaiveDate::parse_from_str("2022-06-15", "%Y-%m-%d").unwrap(); | |
assert_eq!(modified_date, expected); | |
} else { | |
assert!(false); | |
} | |
if let Ok(modified_date) = date_from_relative(MODIFIER_OK_1, date0) { | |
let expected = NaiveDate::parse_from_str("2023-05-15", "%Y-%m-%d").unwrap(); | |
assert_eq!(modified_date, expected); | |
} else { | |
assert!(false); | |
} | |
if let Ok(modified_date) = date_from_relative(MODIFIER_OK_2, date0) { | |
let expected = NaiveDate::parse_from_str("2022-05-15", "%Y-%m-%d").unwrap(); | |
assert_eq!(modified_date, expected); | |
} else { | |
assert!(false); | |
} | |
let date1 = | |
NaiveDateTime::parse_from_str("2022-05-15 18:30:00.0", "%Y-%m-%d %H:%M:%S.%f").unwrap(); | |
if let Ok(modified_date) = date_from_relative(MODIFIER_OK_3, date1) { | |
let expected = | |
NaiveDateTime::parse_from_str("2022-05-15 19:30:30.0", "%Y-%m-%d %H:%M:%S.%f") | |
.unwrap(); | |
assert_eq!(modified_date, expected); | |
} else { | |
assert!(false); | |
} | |
if let Ok(modified_date) = date_from_relative(MODIFIER_OK_4, date1) { | |
let expected = | |
NaiveDateTime::parse_from_str("-7972-01-28 2:30:30.0", "%Y-%m-%d %H:%M:%S.%f") | |
.unwrap(); | |
assert_eq!(modified_date, expected); | |
} else { | |
assert!(false); | |
} | |
if let Ok(modified_date) = date_from_relative(MODIFIER_OK_5, date0) { | |
let expected = NaiveDate::parse_from_str("2285-05-30", "%Y-%m-%d").unwrap(); | |
assert_eq!(modified_date, expected); | |
} else { | |
assert!(false); | |
} | |
let date1 = | |
NaiveDateTime::parse_from_str("2022-05-15 0:0:00.0", "%Y-%m-%d %H:%M:%S.%f").unwrap(); | |
if let Ok(modified_date) = date_from_relative(MODIFIER_OK_6, date1) { | |
let expected = | |
NaiveDateTime::parse_from_str("2024-04-14 23:10:0.0", "%Y-%m-%d %H:%M:%S.%f") | |
.unwrap(); | |
assert_eq!(modified_date, expected); | |
} else { | |
assert!(false); | |
} | |
if let Ok(modified_date) = date_from_relative(MODIFIER_OK_7, date0) { | |
let expected = NaiveDate::parse_from_str("2034-11-11", "%Y-%m-%d").unwrap(); | |
assert_eq!(modified_date, expected); | |
} else { | |
assert!(false); | |
} | |
} | |
#[test] | |
fn test_parse_date_from_modifier_err() { | |
const MODIFIER_F_0: &str = "100000000000000000000000000000000000000 Years"; | |
const MODIFIER_F_1: &str = "1000"; | |
const MODIFIER_F_2: &str = " 1000 [YEARS]"; | |
const MODIFIER_F_3: &str = "-100 Years + 20.0 days "; | |
const MODIFIER_F_4: &str = "days + 10 weeks"; | |
// i64::MAX / 12 + 1 | |
const MODIFIER_F_5: &str = "768614336404564651 years"; | |
// i64::MAX / 604_800 (seconds/week) | |
const MODIFIER_F_6: &str = "15250284452472 weeks"; | |
// i32::MAX | |
const MODIFIER_F_7: &str = "9223372036854775808 days "; | |
let date0 = NaiveDate::parse_from_str("2022-05-15", "%Y-%m-%d").unwrap(); | |
let modified_date = date_from_relative(MODIFIER_F_0, date0); | |
assert!(modified_date.is_err()); | |
let modified_date = date_from_relative(MODIFIER_F_1, date0); | |
assert!(modified_date.is_err()); | |
let modified_date = date_from_relative(MODIFIER_F_2, date0); | |
assert!(modified_date.is_err()); | |
let modified_date = date_from_relative(MODIFIER_F_3, date0); | |
assert!(modified_date.is_err()); | |
let modified_date = date_from_relative(MODIFIER_F_4, date0); | |
assert!(modified_date.is_err()); | |
// let modified_date = date_from_relative(MODIFIER_F_5, date0); | |
// assert!(modified_date.is_err()); | |
// | |
// let modified_date = date_from_relative(MODIFIER_F_6, date0); | |
// assert!(modified_date.is_err()); | |
// | |
// let modified_date = date_from_relative(MODIFIER_F_7, date0); | |
// assert!(modified_date.is_err()); | |
} | |
#[test] | |
fn test_test(){ | |
let date0 = NaiveDate::from_ymd(2023, 1, 31).add(Months::new(1)).add(Months::new(1)); | |
let date1 = NaiveDate::from_ymd(2023, 1, 31).add(Months::new(2)); | |
assert_eq!(date1, date0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment