diff options
-rw-r--r-- | src/lib.rs | 179 | ||||
-rw-r--r-- | tests/tests.rs | 112 |
2 files changed, 171 insertions, 120 deletions
@@ -6,11 +6,11 @@ extern crate lazy_static; extern crate chrono; use chrono::offset::LocalResult; use chrono::{Date, DateTime, Datelike, Duration, TimeZone, Timelike, Utc, Weekday}; -use pidgin::{Grammar, Match, Matcher}; +use pidgin::{Match, Matcher}; use regex::Regex; lazy_static! { - static ref GRAMMAR: Grammar = grammar!{ + static ref MATCHER: Matcher = grammar!{ (?ibBw) TOP -> r(r"\A") <something> r(r"\z") @@ -19,7 +19,7 @@ lazy_static! { universal => [["always", "ever", "all time", "forever", "from beginning to end", "from the beginning to the end"]] particular => <one_time> | <two_times> one_time => <moment_or_period> - two_times -> <moment_or_period> <to> <moment_or_period> + two_times -> ("from")? <moment_or_period> <to> <moment_or_period> to => [["to", "through", "until", "up to", "thru", "till"]] | r("-+") moment_or_period => <moment> | <period> period => <named_period> | <specific_period> @@ -50,32 +50,26 @@ lazy_static! { am_pm => (?-i) [["am", "AM", "pm", "PM", "a.m.", "A.M.", "p.m.", "P.M."]] h12 => [(1..=12).into_iter().collect::<Vec<_>>()] h24 => [(1..=24).into_iter().collect::<Vec<_>>()] - n_date -> <year> ("/") <n_month> ("/") <n_day> - n_date -> <year> ("-") <n_month> ("-") <n_day> - n_date -> <year> (".") <n_month> (".") <n_day> - n_date -> <year> ("/") <n_day> ("/") <n_month> - n_date -> <year> ("-") <n_day> ("-") <n_month> - n_date -> <year> (".") <n_day> (".") <n_month> - n_date -> <n_month> ("/") <n_day> ("/") <year> - n_date -> <n_month> ("-") <n_day> ("-") <year> - n_date -> <n_month> (".") <n_day> (".") <year> - n_date -> <n_day> ("/") <n_month> ("/") <year> - n_date -> <n_day> ("-") <n_month> ("-") <year> - n_date -> <n_day> (".") <n_month> (".") <year> + n_date -> <year> r("[./-]") <n_month> r("[./-]") <n_day> + n_date -> <year> r("[./-]") <n_day> r("[./-]") <n_month> + n_date -> <n_month> r("[./-]") <n_day> r("[./-]") <year> + n_date -> <n_day> r("[./-]") <n_month> r("[./-]") <year> a_date -> <a_month> <n_day> (",") <year> a_date -> <n_day> <a_month> <year> a_date -> <a_day> (",") <a_month> <n_day> (",") <year> - year => [ - (100..=3000) - .into_iter() - .collect::<Vec<_>>() - ] - year => [ + year => <short_year> | ("-")? <n_year> + year -> <suffix_year> <year_suffix> + short_year => [ (0..=99) .into_iter() .flat_map(|i| vec![format!("'{:02}", i), format!("{:02}", i)]) .collect::<Vec<_>>() ] + n_year => r(r"\b(?:[1-9][0-9]{0,4}|0)\b") + suffix_year => r(r"\b[1-9][0-9]{0,4}\b") + year_suffix => <ce> | <bce> + ce => (?-i) [["ce", "c.e.", "ad", "a.d.", "CE", "C.E.", "AD", "A.D."]] + bce => (?-i) [["bce", "b.c.e.", "bc", "b.c.", "BCE", "B.C.E.", "BC", "B.C."]] n_day => [ (1..=31) .into_iter() @@ -140,10 +134,7 @@ lazy_static! { "ever after", "the last syllable of recorded time", ]] - }; -} -lazy_static! { - static ref MATCHER: Matcher = GRAMMAR.matcher().unwrap(); + }.matcher().unwrap(); } #[derive(Debug, Clone)] @@ -156,7 +147,7 @@ pub struct Config { } impl Config { - pub fn default() -> Config { + pub fn new() -> Config { Config { now: Utc::now(), monday_starts_week: true, @@ -170,7 +161,7 @@ impl Config { c.now = n; c } - pub fn period(&self, period: Period) -> Config { + fn period(&self, period: Period) -> Config { let mut c = self.clone(); c.period = period; c @@ -192,23 +183,36 @@ impl Config { } } +/// A simple categorization of things that could go wrong. +/// +/// Every error provides a descriptive string that can be displayed. +#[derive(Debug, Clone)] +pub enum TimeError { + Parse(String), + Misordered(String), + ImpossibleDate(String), + Weekday(String), + NoPayPeriod(String), +} + +/// pub fn parse( phrase: &str, config: Option<Config>, -) -> Result<(DateTime<Utc>, DateTime<Utc>), String> { +) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { let parse = MATCHER.parse(phrase); if parse.is_none() { - return Err(format!( + return Err(TimeError::Parse(format!( "could not parse \"{}\" as a time expression", phrase - )); + ))); } let parse = parse.unwrap(); if parse.has("universal") { return Ok((first_moment(), last_moment())); } let parse = parse.name("particular").unwrap(); - let config = config.unwrap_or(Config::default()); + let config = config.unwrap_or(Config::new()); if let Some(moment) = parse.name("one_time") { return handle_one_time(moment, &config); } @@ -224,7 +228,11 @@ pub fn parse( if d1 <= d2 { Ok((d1, d2)) } else { - Err(format!("{} is after {}", first.as_str(), last.as_str())) + Err(TimeError::Misordered(format!( + "{} is after {}", + first.as_str(), + last.as_str() + ))) } } Err(s) => Err(s), @@ -272,11 +280,29 @@ fn pick_terminus(d1: DateTime<Utc>, d2: DateTime<Utc>) -> DateTime<Utc> { } } -fn first_moment() -> DateTime<Utc> { +/// The moment regarded as the beginning of time. +/// +/// # Examples +/// +/// ```rust +/// # extern crate two_timer; +/// # use two_timer::first_moment; +/// println!("{}", first_moment()); // -262144-01-01 00:00:00 UTC +/// ``` +pub fn first_moment() -> DateTime<Utc> { chrono::MIN_DATE.and_hms_milli(0, 0, 0, 0) } -fn last_moment() -> DateTime<Utc> { +/// The moment regarded as the end of time. +/// +/// # Examples +/// +/// ```rust +/// # extern crate two_timer; +/// # use two_timer::last_moment; +/// println!("{}", last_moment()); // +262143-12-31 23:59:59.999 UTC +/// ``` +pub fn last_moment() -> DateTime<Utc> { chrono::MAX_DATE.and_hms_milli(23, 59, 59, 999) } @@ -287,11 +313,14 @@ fn specific(m: &Match) -> bool { fn handle_specific_day( m: &Match, config: &Config, -) -> Result<(DateTime<Utc>, DateTime<Utc>), String> { +) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { let now = config.now.clone(); let mut times = m.all_names("time"); if times.len() > 1 { - return Err(format!("more than one daytime specified in {}", m.as_str())); + return Err(TimeError::Parse(format!( + "more than one daytime specified in {}", + m.as_str() + ))); } let time = times.pop(); if let Some(adverb) = m.name("adverb") { @@ -303,7 +332,7 @@ fn handle_specific_day( 'd' | 'D' => Ok(moment_and_time(&config.period(Period::Day), time)), // tomorrow 'm' | 'M' => Ok(moment_and_time( - &Config::default() + &Config::new() .now(now + Duration::days(1)) .period(Period::Day), time, @@ -312,7 +341,7 @@ fn handle_specific_day( }, // yesterday 'y' | 'Y' => Ok(moment_and_time( - &Config::default() + &Config::new() .now(now - Duration::days(1)) .period(Period::Day), time, @@ -327,21 +356,18 @@ fn handle_specific_day( let day = n_day(date); let d_opt = Utc.ymd_opt(year, month, day); return match d_opt { - LocalResult::None => Err(format!( + LocalResult::None => Err(TimeError::ImpossibleDate(format!( "cannot construct UTC date with year {}, month {}, and day {}", year, month, day - )), + ))), LocalResult::Single(d1) => { let d1 = d1.and_hms(0, 0, 0); Ok(moment_and_time( - &Config::default().now(d1).period(Period::Day), + &Config::new().now(d1).period(Period::Day), time, )) } - LocalResult::Ambiguous(_, _) => Err(format!( - "cannot construct unambiguous UTC date with year {}, month {}, and day {}", - year, month, day - )), + LocalResult::Ambiguous(_, _) => unreachable!(), }; } if let Some(date) = date.name("a_date") { @@ -350,40 +376,37 @@ fn handle_specific_day( let day = n_day(date); let d_opt = Utc.ymd_opt(year, month, day); return match d_opt { - LocalResult::None => Err(format!( + LocalResult::None => Err(TimeError::ImpossibleDate(format!( "cannot construct UTC date with year {}, month {}, and day {}", year, month, day - )), + ))), LocalResult::Single(d1) => { if let Some(wd) = date.name("a_day") { let wd = weekday(wd.as_str()); if wd == d1.weekday() { let d1 = d1.and_hms(0, 0, 0); Ok(moment_and_time( - &Config::default().now(d1).period(Period::Day), + &Config::new().now(d1).period(Period::Day), time, )) } else { - Err(format!( + Err(TimeError::Weekday(format!( "the weekday of year {}, month {}, day {} is not {}", year, month, day, date.name("a_day").unwrap().as_str() - )) + ))) } } else { let d1 = d1.and_hms(0, 0, 0); Ok(moment_and_time( - &Config::default().now(d1).period(Period::Day), + &Config::new().now(d1).period(Period::Day), time, )) } } - LocalResult::Ambiguous(_, _) => Err(format!( - "cannot construct unambiguous UTC date with year {}, month {}, and day {}", - year, month, day - )), + LocalResult::Ambiguous(_, _) => unreachable!(), }; } unreachable!(); @@ -394,7 +417,7 @@ fn handle_specific_day( fn handle_specific_period( moment: &Match, config: &Config, -) -> Result<(DateTime<Utc>, DateTime<Utc>), String> { +) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { if let Some(moment) = moment.name("month_and_year") { let y = year(moment, &config.now); let m = a_month(moment); @@ -403,7 +426,7 @@ fn handle_specific_period( LocalResult::Single(d1) => { let d1 = d1.and_hms(0, 0, 0); Ok(moment_and_time( - &Config::default().now(d1).period(Period::Month), + &Config::new().now(d1).period(Period::Month), None, )) } @@ -484,7 +507,9 @@ fn handle_specific_period( }; Ok(moment_to_period(d, &Period::PayPeriod, config)) } else { - Err(String::from("no pay period start date provided")) + Err(TimeError::NoPayPeriod(String::from( + "no pay period start date provided", + ))) } } }; @@ -531,7 +556,7 @@ impl PeriodModifier { fn handle_specific_time( moment: &Match, config: &Config, -) -> Result<(DateTime<Utc>, DateTime<Utc>), String> { +) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { return if moment.has("first_time") { Ok(moment_to_period(first_moment(), &config.period, config)) } else { @@ -542,7 +567,7 @@ fn handle_specific_time( fn handle_one_time( moment: &Match, config: &Config, -) -> Result<(DateTime<Utc>, DateTime<Utc>), String> { +) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { if moment.has("specific_day") { return handle_specific_day(moment, config); } @@ -652,7 +677,10 @@ fn relative_moment( unreachable!() } -fn specific_moment(m: &Match, config: &Config) -> Result<(DateTime<Utc>, DateTime<Utc>), String> { +fn specific_moment( + m: &Match, + config: &Config, +) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { if let Some(m) = m.name("specific_day") { return handle_specific_day(m, config); } @@ -725,22 +753,29 @@ fn n_month(m: &Match) -> u32 { } fn year(m: &Match, now: &DateTime<Utc>) -> i32 { - lazy_static! { - static ref YEAR: Regex = Regex::new(r"\A(?:'0?|0)?(\d{1,2})\z").unwrap(); - } - let year = m.name("year").unwrap().as_str(); - let cap = YEAR.captures(year); - if let Some(cap) = cap { - // year is assumed to be in the current century - let y = cap[1].parse::<i32>().unwrap(); + let year = m.name("year").unwrap(); + if let Some(sy) = year.name("short_year") { + let y = s_to_n(sy.as_str()) as i32; let this_year = now.year() % 100; if this_year < y { now.year() - this_year - 100 + y } else { now.year() - this_year + y } + } else if let Some(suffix) = year.name("year_suffix") { + let y = s_to_n(year.name("suffix_year").unwrap().as_str()) as i32; + if suffix.has("bce") { + 1 - y // there is no year 0 + } else { + y + } } else { - year.parse::<i32>().unwrap() + let y = s_to_n(year.name("n_year").unwrap().as_str()) as i32; + if year.as_str().chars().nth(0).expect("unreachable") == '-' { + -y + } else { + y + } } } @@ -811,7 +846,6 @@ fn moment_to_period( ); (d1, d1 + Duration::seconds(1)) } - Period::Nanosecond => (now, now + Duration::nanoseconds(1)), Period::PayPeriod => { if let Some(pps) = config.pay_period_start { // find the current pay period start @@ -831,7 +865,7 @@ fn moment_to_period( } #[derive(Debug, Clone)] -pub enum Period { +enum Period { Year, Month, Week, @@ -839,7 +873,6 @@ pub enum Period { Hour, Minute, Second, - Nanosecond, PayPeriod, } diff --git a/tests/tests.rs b/tests/tests.rs index 9280c82..4a0aa82 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -27,7 +27,7 @@ fn always() { #[test] fn yesterday() { let now = Utc::now(); - let (start, end) = parse("yesterday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("yesterday", Some(Config::new().now(now))).unwrap(); assert!(start < now); assert!(end < now); let then = now - Duration::days(1); @@ -40,7 +40,7 @@ fn yesterday() { #[test] fn tomorrow() { let now = Utc::now(); - let (start, end) = parse("tomorrow", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("tomorrow", Some(Config::new().now(now))).unwrap(); assert!(start > now); assert!(end > now); let then = now + Duration::days(1); @@ -53,7 +53,7 @@ fn tomorrow() { #[test] fn today() { let now = Utc::now(); - let (start, end) = parse("today", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("today", Some(Config::new().now(now))).unwrap(); assert!(start < now); assert!(end > now); let then = now + Duration::days(1); @@ -154,7 +154,7 @@ fn at_3_pm() { let now = Utc.ymd(1969, 5, 6).and_hms(16, 0, 0); let then = Utc.ymd(1969, 5, 6).and_hms(15, 0, 0); for phrase in ["3 PM", "3 pm", "15"].iter() { - let (start, end) = parse(phrase, Some(Config::default().now(now))).unwrap(); + let (start, end) = parse(phrase, Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::hours(1), end); } @@ -165,7 +165,7 @@ fn at_3_00_pm() { let now = Utc.ymd(1969, 5, 6).and_hms(16, 0, 0); let then = Utc.ymd(1969, 5, 6).and_hms(15, 0, 0); for phrase in ["3:00 PM", "3:00 pm", "15:00"].iter() { - let (start, end) = parse(phrase, Some(Config::default().now(now))).unwrap(); + let (start, end) = parse(phrase, Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::minutes(1), end); } @@ -176,7 +176,7 @@ fn at_3_00_00_pm() { let now = Utc.ymd(1969, 5, 6).and_hms(16, 0, 0); let then = Utc.ymd(1969, 5, 6).and_hms(15, 0, 0); for phrase in ["3:00:00 PM", "3:00:00 pm", "15:00:00"].iter() { - let (start, end) = parse(phrase, Some(Config::default().now(now))).unwrap(); + let (start, end) = parse(phrase, Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::seconds(1), end); } @@ -187,7 +187,7 @@ fn at_3_pm_yesterday() { let now = Utc.ymd(1969, 5, 6).and_hms(14, 0, 0); let then = Utc.ymd(1969, 5, 5).and_hms(15, 0, 0); for phrase in ["3 PM yesterday", "3 pm yesterday", "15 yesterday"].iter() { - let (start, end) = parse(phrase, Some(Config::default().now(now))).unwrap(); + let (start, end) = parse(phrase, Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::hours(1), end); } @@ -345,7 +345,7 @@ fn this_month() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 6, 1).and_hms(0, 0, 0); - let (start, end) = parse("this month", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("this month", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -355,7 +355,7 @@ fn next_month() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 6, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 7, 1).and_hms(0, 0, 0); - let (start, end) = parse("next month", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("next month", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -365,7 +365,7 @@ fn last_month() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 4, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 1).and_hms(0, 0, 0); - let (start, end) = parse("last month", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("last month", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -375,7 +375,7 @@ fn this_year() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 1, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0); - let (start, end) = parse("this year", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("this year", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -385,7 +385,7 @@ fn next_year() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1971, 1, 1).and_hms(0, 0, 0); - let (start, end) = parse("next year", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("next year", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -395,7 +395,7 @@ fn last_year() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1968, 1, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 1, 1).and_hms(0, 0, 0); - let (start, end) = parse("last year", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("last year", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -405,7 +405,7 @@ fn this_week() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 5).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 12).and_hms(0, 0, 0); - let (start, end) = parse("this week", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("this week", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -415,7 +415,7 @@ fn next_week() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 12).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 19).and_hms(0, 0, 0); - let (start, end) = parse("next week", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("next week", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -425,7 +425,7 @@ fn last_week() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 4, 28).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 5).and_hms(0, 0, 0); - let (start, end) = parse("last week", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("last week", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -437,7 +437,7 @@ fn this_week_sunday_starts() { let d2 = Utc.ymd(1969, 5, 11).and_hms(0, 0, 0); let (start, end) = parse( "this week", - Some(Config::default().now(now).monday_starts_week(false)), + Some(Config::new().now(now).monday_starts_week(false)), ) .unwrap(); assert_eq!(d1, start); @@ -451,7 +451,7 @@ fn next_week_sunday_starts() { let d2 = Utc.ymd(1969, 5, 18).and_hms(0, 0, 0); let (start, end) = parse( "next week", - Some(Config::default().now(now).monday_starts_week(false)), + Some(Config::new().now(now).monday_starts_week(false)), ) .unwrap(); assert_eq!(d1, start); @@ -465,7 +465,7 @@ fn last_week_sunday_starts() { let d2 = Utc.ymd(1969, 5, 4).and_hms(0, 0, 0); let (start, end) = parse( "last week", - Some(Config::default().now(now).monday_starts_week(false)), + Some(Config::new().now(now).monday_starts_week(false)), ) .unwrap(); assert_eq!(d1, start); @@ -476,7 +476,7 @@ fn last_week_sunday_starts() { fn this_pay_period() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); // two-week pay period beginning about a year before "now" on a Sunday - let config = Config::default() + let config = Config::new() .pay_period_start(Some(Utc.ymd(1968, 5, 5))) .pay_period_length(14) .now(now); @@ -491,7 +491,7 @@ fn this_pay_period() { fn next_pay_period() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); // two-week pay period beginning about a year before "now" on a Sunday - let config = Config::default() + let config = Config::new() .pay_period_start(Some(Utc.ymd(1968, 5, 5))) .pay_period_length(14) .now(now); @@ -506,7 +506,7 @@ fn next_pay_period() { fn last_pay_period() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); // two-week pay period beginning about a year before "now" on a Sunday - let config = Config::default() + let config = Config::new() .pay_period_start(Some(Utc.ymd(1968, 5, 5))) .pay_period_length(14) .now(now); @@ -521,7 +521,7 @@ fn last_pay_period() { fn this_pay_period_weird() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); // two-week pay period beginning about a year *after* "now" on a Sunday - let config = Config::default() + let config = Config::new() .pay_period_start(Some(Utc.ymd(1970, 4, 5))) .pay_period_length(14) .now(now); @@ -536,7 +536,7 @@ fn this_pay_period_weird() { fn next_pay_period_weird() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); // two-week pay period beginning about a year *after* "now" on a Sunday - let config = Config::default() + let config = Config::new() .pay_period_start(Some(Utc.ymd(1970, 4, 5))) .pay_period_length(14) .now(now); @@ -551,7 +551,7 @@ fn next_pay_period_weird() { fn last_pay_period_weird() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); // two-week pay period beginning about a year *after* "now" on a Sunday - let config = Config::default() + let config = Config::new() .pay_period_start(Some(Utc.ymd(1970, 4, 5))) .pay_period_length(14) .now(now); @@ -567,7 +567,7 @@ fn this_april() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 4, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 1).and_hms(0, 0, 0); - let (start, end) = parse("this april", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("this april", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -577,7 +577,7 @@ fn next_april() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1970, 4, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1970, 5, 1).and_hms(0, 0, 0); - let (start, end) = parse("next april", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("next april", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -587,7 +587,7 @@ fn last_april() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1968, 4, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1968, 5, 1).and_hms(0, 0, 0); - let (start, end) = parse("last april", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("last april", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -597,7 +597,7 @@ fn this_friday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 9).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 10).and_hms(0, 0, 0); - let (start, end) = parse("this friday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("this friday", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -607,7 +607,7 @@ fn next_friday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 16).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 17).and_hms(0, 0, 0); - let (start, end) = parse("next friday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("next friday", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -617,7 +617,7 @@ fn last_friday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 2).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 3).and_hms(0, 0, 0); - let (start, end) = parse("last friday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("last friday", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -627,7 +627,7 @@ fn this_monday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 5).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); - let (start, end) = parse("this monday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("this monday", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -637,7 +637,7 @@ fn next_monday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 12).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 13).and_hms(0, 0, 0); - let (start, end) = parse("next monday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("next monday", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -647,7 +647,7 @@ fn last_monday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 4, 28).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 4, 29).and_hms(0, 0, 0); - let (start, end) = parse("last monday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("last monday", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -708,7 +708,7 @@ fn the_crack_of_doom() { fn friday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let then = Utc.ymd(1969, 5, 2).and_hms(0, 0, 0); - let (start, end) = parse("Friday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("Friday", Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::days(1), end); } @@ -717,7 +717,7 @@ fn friday() { fn tuesday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let then = Utc.ymd(1969, 4, 29).and_hms(0, 0, 0); - let (start, end) = parse("Tuesday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("Tuesday", Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::days(1), end); } @@ -726,7 +726,7 @@ fn tuesday() { fn monday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let then = Utc.ymd(1969, 5, 5).and_hms(0, 0, 0); - let (start, end) = parse("Monday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("Monday", Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::days(1), end); } @@ -735,7 +735,7 @@ fn monday() { fn friday_at_3_pm() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let then = Utc.ymd(1969, 5, 2).and_hms(15, 0, 0); - let (start, end) = parse("Friday at 3 pm", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("Friday at 3 pm", Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::hours(1), end); } @@ -744,7 +744,7 @@ fn friday_at_3_pm() { fn tuesday_at_3_pm() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let then = Utc.ymd(1969, 4, 29).and_hms(15, 0, 0); - let (start, end) = parse("Tuesday at 3 pm", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("Tuesday at 3 pm", Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::hours(1), end); } @@ -753,7 +753,7 @@ fn tuesday_at_3_pm() { fn monday_at_3_pm() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let then = Utc.ymd(1969, 5, 5).and_hms(15, 0, 0); - let (start, end) = parse("Monday at 3 pm", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("Monday at 3 pm", Some(Config::new().now(now))).unwrap(); assert_eq!(then, start); assert_eq!(then + Duration::hours(1), end); } @@ -763,7 +763,7 @@ fn just_may() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 6, 1).and_hms(0, 0, 0); - let (start, end) = parse("May", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("May", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -773,7 +773,7 @@ fn just_april() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 4, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 1).and_hms(0, 0, 0); - let (start, end) = parse("April", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("April", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -783,7 +783,7 @@ fn just_june() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1968, 6, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1968, 7, 1).and_hms(0, 0, 0); - let (start, end) = parse("June", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("June", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -793,7 +793,7 @@ fn monday_through_friday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 5, 5).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 10).and_hms(0, 0, 0); - let (start, end) = parse("Monday through Friday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("Monday through Friday", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -803,7 +803,7 @@ fn tuesday_through_friday() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 4, 29).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 3).and_hms(0, 0, 0); - let (start, end) = parse("Tuesday through Friday", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("Tuesday through Friday", Some(Config::new().now(now))).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } @@ -815,7 +815,7 @@ fn tuesday_through_3_pm_on_friday() { let d2 = Utc.ymd(1969, 5, 2).and_hms(15, 0, 0); let (start, end) = parse( "Tuesday through 3 PM on Friday", - Some(Config::default().now(now)), + Some(Config::new().now(now)), ) .unwrap(); assert_eq!(d1, start); @@ -827,7 +827,25 @@ fn this_year_through_today() { let now = Utc.ymd(1969, 5, 6).and_hms(0, 0, 0); let d1 = Utc.ymd(1969, 1, 1).and_hms(0, 0, 0); let d2 = Utc.ymd(1969, 5, 7).and_hms(0, 0, 0); - let (start, end) = parse("this year through today", Some(Config::default().now(now))).unwrap(); + let (start, end) = parse("this year through today", Some(Config::new().now(now))).unwrap(); + assert_eq!(d1, start); + assert_eq!(d2, end); +} + +#[test] +fn april_3_25_bc() { + let d1 = Utc.ymd(-24, 4, 3).and_hms(0, 0, 0); + let d2 = d1 + Duration::days(1); + let (start, end) = parse("April 3, 25 BC", None).unwrap(); + assert_eq!(d1, start); + assert_eq!(d2, end); +} + +#[test] +fn april_3_25_ad() { + let d1 = Utc.ymd(25, 4, 3).and_hms(0, 0, 0); + let d2 = d1 + Duration::days(1); + let (start, end) = parse("April 3, 25 AD", None).unwrap(); assert_eq!(d1, start); assert_eq!(d2, end); } |