diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 128 |
1 files changed, 72 insertions, 56 deletions
@@ -18,7 +18,7 @@ or "until". extern crate two_timer; use two_timer::{parse, Config}; extern crate chrono; -use chrono::{Date, TimeZone, Utc}; +use chrono::naive::NaiveDate; pub fn main() { let phrases = [ @@ -44,7 +44,7 @@ pub fn main() { Err(e) => println!("{:?}", e), } } - let now = Utc.ymd_opt(1066, 10, 14).unwrap().and_hms(12, 30, 15); + let now = NaiveDate::from_ymd_opt(1066, 10, 14).unwrap().and_hms(12, 30, 15); println!("\nlet \"now\" be some moment during the Battle of Hastings, specifically {}\n", now); let conf = Config::new().now(now); for phrase in phrases.iter() { @@ -181,8 +181,8 @@ extern crate pidgin; #[macro_use] extern crate lazy_static; extern crate chrono; -use chrono::offset::LocalResult; -use chrono::{Date, DateTime, Datelike, Duration, TimeZone, Timelike, Utc, Weekday}; +use chrono::naive::{NaiveDate, NaiveDateTime}; +use chrono::{Date, DateTime, Datelike, Duration, Local, TimeZone, Timelike, Weekday}; use pidgin::{Match, Matcher}; use regex::Regex; @@ -207,7 +207,7 @@ lazy_static! { named_period => <a_day> | <a_month> modified_period -> <modifier> <modifiable_period> modifier => [["this", "last", "next"]] - modifiable_period => [["week", "month", "year", "pay period", "pp"]] | <a_month> | <a_day> + modifiable_period => [["week", "month", "year", "pay period", "pp", "weekend"]] | <a_month> | <a_day> moment -> <at_time_on>? <some_day> <at_time>? | <specific_time> | <time> specific_time => <first_time> | <last_time> some_day => <specific_day> | <relative_day> @@ -320,18 +320,18 @@ lazy_static! { /// of time expressions. #[derive(Debug, Clone)] pub struct Config { - now: DateTime<Utc>, + now: NaiveDateTime, monday_starts_week: bool, period: Period, pay_period_length: u32, - pay_period_start: Option<Date<Utc>>, + pay_period_start: Option<NaiveDate>, } impl Config { /// Constructs an expression with the default parameters. pub fn new() -> Config { Config { - now: Utc::now(), + now: Local::now().naive_local(), monday_starts_week: true, period: Period::Minute, pay_period_length: 7, @@ -340,7 +340,7 @@ impl Config { } /// Returns a copy of the configuration parameters with the "now" moment /// set to the parameter supplied. - pub fn now(&self, n: DateTime<Utc>) -> Config { + pub fn now(&self, n: NaiveDateTime) -> Config { let mut c = self.clone(); c.now = n; c @@ -371,7 +371,7 @@ impl Config { /// date for a pay period set to the parameter supplied. By default this date /// is undefined. Unless it is defined, expressions containing the phrase "pay period" /// or "pp" cannot be interpreted. - pub fn pay_period_start(&self, pay_period_start: Option<Date<Utc>>) -> Config { + pub fn pay_period_start(&self, pay_period_start: Option<NaiveDate>) -> Config { let mut c = self.clone(); c.pay_period_start = pay_period_start; c @@ -400,7 +400,7 @@ pub enum TimeError { /// Converts a time expression into a pair or timestamps and a boolean indicating whether /// the expression was literally a range, such as "9 to 11", as opposed to "9 AM", say. -/// +/// /// The second parameter is an optional `Config` object. In general you will not need to /// use this except in testing or in the interpretation of pay periods. /// @@ -416,7 +416,7 @@ pub enum TimeError { pub fn parse( phrase: &str, config: Option<Config>, -) -> Result<(DateTime<Utc>, DateTime<Utc>, bool), TimeError> { +) -> Result<(NaiveDateTime, NaiveDateTime, bool), TimeError> { let parse = MATCHER.parse(phrase); if parse.is_none() { return Err(TimeError::Parse(format!( @@ -490,7 +490,7 @@ pub fn parse( // for the end time, if the span is less than a day, use the first, otherwise use the second // e.g., Monday through Friday at 3 PM should end at 3 PM, but Monday through Friday should end at the end of Friday -fn pick_terminus(d1: DateTime<Utc>, d2: DateTime<Utc>, through: bool) -> DateTime<Utc> { +fn pick_terminus(d1: NaiveDateTime, d2: NaiveDateTime, through: bool) -> NaiveDateTime { if d1.day() == d2.day() && d1.month() == d2.month() && d1.year() == d2.year() { d1 } else if through { @@ -509,8 +509,8 @@ fn pick_terminus(d1: DateTime<Utc>, d2: DateTime<Utc>, through: bool) -> DateTim /// # 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) +pub fn first_moment() -> NaiveDateTime { + chrono::naive::MIN_DATE.and_hms_milli(0, 0, 0, 0) } /// The moment regarded as the end of time. @@ -522,8 +522,8 @@ pub fn first_moment() -> DateTime<Utc> { /// # 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) +pub fn last_moment() -> NaiveDateTime { + chrono::naive::MAX_DATE.and_hms_milli(23, 59, 59, 999) } fn specific(m: &Match) -> bool { @@ -533,7 +533,7 @@ fn specific(m: &Match) -> bool { fn handle_specific_day( m: &Match, config: &Config, -) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { +) -> Result<(NaiveDateTime, NaiveDateTime), TimeError> { let now = config.now.clone(); let mut times = m.all_names("time"); if times.len() > 1 { @@ -574,33 +574,32 @@ fn handle_specific_day( let year = year(date, &now); let month = n_month(date); let day = n_day(date); - let d_opt = Utc.ymd_opt(year, month, day); + let d_opt = NaiveDate::from_ymd_opt(year, month, day); return match d_opt { - LocalResult::None => Err(TimeError::ImpossibleDate(format!( + None => Err(TimeError::ImpossibleDate(format!( "cannot construct UTC date with year {}, month {}, and day {}", year, month, day ))), - LocalResult::Single(d1) => { + Some(d1) => { let d1 = d1.and_hms(0, 0, 0); Ok(moment_and_time( &Config::new().now(d1).period(Period::Day), time, )) } - LocalResult::Ambiguous(_, _) => unreachable!(), }; } if let Some(date) = date.name("a_date") { let year = year(date, &now); let month = a_month(date); let day = n_day(date); - let d_opt = Utc.ymd_opt(year, month, day); + let d_opt = NaiveDate::from_ymd_opt(year, month, day); return match d_opt { - LocalResult::None => Err(TimeError::ImpossibleDate(format!( + None => Err(TimeError::ImpossibleDate(format!( "cannot construct UTC date with year {}, month {}, and day {}", year, month, day ))), - LocalResult::Single(d1) => { + Some(d1) => { if let Some(wd) = date.name("a_day") { let wd = weekday(wd.as_str()); if wd == d1.weekday() { @@ -626,7 +625,6 @@ fn handle_specific_day( )) } } - LocalResult::Ambiguous(_, _) => unreachable!(), }; } unreachable!(); @@ -637,20 +635,19 @@ fn handle_specific_day( fn handle_specific_period( moment: &Match, config: &Config, -) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { +) -> Result<(NaiveDateTime, NaiveDateTime), TimeError> { if let Some(moment) = moment.name("month_and_year") { let y = year(moment, &config.now); let m = a_month(moment); - return match Utc.ymd_opt(y, m, 1) { - LocalResult::None => unreachable!(), - LocalResult::Single(d1) => { + return match NaiveDate::from_ymd_opt(y, m, 1) { + None => unreachable!(), + Some(d1) => { let d1 = d1.and_hms(0, 0, 0); Ok(moment_and_time( &Config::new().now(d1).period(Period::Month), None, )) } - LocalResult::Ambiguous(_, _) => unreachable!(), }; } if let Some(moment) = moment.name("modified_period") { @@ -687,6 +684,17 @@ fn handle_specific_period( }; Ok(moment_to_period(d, &Period::Week, config)) } + ModifiablePeriod::Weekend => { + let (_, d2) = + moment_to_period(config.now, &Period::Week, &config.monday_starts_week(true)); + let d2 = match modifier { + PeriodModifier::Next => d2 + Duration::days(7), + PeriodModifier::Last => d2 - Duration::days(7), + PeriodModifier::This => d2, + }; + let d1 = d2 - Duration::days(2); + Ok((d1, d2)) + } ModifiablePeriod::Month => { let (d, _) = moment_to_period(config.now, &Period::Month, config); let d = match modifier { @@ -742,12 +750,19 @@ enum ModifiablePeriod { Month, Year, PayPeriod, + Weekend, } impl ModifiablePeriod { fn from_match(m: &Match) -> ModifiablePeriod { match m.as_str().chars().nth(0).expect("unreachable") { - 'w' | 'W' => ModifiablePeriod::Week, + 'w' | 'W' => { + if m.as_str().len() == 4 { + ModifiablePeriod::Week + } else { + ModifiablePeriod::Weekend + } + } 'm' | 'M' => ModifiablePeriod::Month, 'y' | 'Y' => ModifiablePeriod::Year, 'p' | 'P' => ModifiablePeriod::PayPeriod, @@ -776,7 +791,7 @@ impl PeriodModifier { fn handle_specific_time( moment: &Match, config: &Config, -) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { +) -> Result<(NaiveDateTime, NaiveDateTime), TimeError> { return if moment.has("first_time") { Ok(moment_to_period(first_moment(), &config.period, config)) } else { @@ -787,7 +802,7 @@ fn handle_specific_time( fn handle_one_time( moment: &Match, config: &Config, -) -> Result<(DateTime<Utc>, DateTime<Utc>, bool), TimeError> { +) -> Result<(NaiveDateTime, NaiveDateTime, bool), TimeError> { let r = if moment.has("specific_day") { handle_specific_day(moment, config) } else if let Some(moment) = moment.name("specific_period") { @@ -804,7 +819,7 @@ fn handle_one_time( } // add time to a date -fn moment_and_time(config: &Config, daytime: Option<&Match>) -> (DateTime<Utc>, DateTime<Utc>) { +fn moment_and_time(config: &Config, daytime: Option<&Match>) -> (NaiveDateTime, NaiveDateTime) { if let Some(daytime) = daytime { let (hour, minute, second) = time(daytime); let period = if second.is_some() { @@ -831,9 +846,9 @@ fn moment_and_time(config: &Config, daytime: Option<&Match>) -> (DateTime<Utc>, fn relative_moment( m: &Match, config: &Config, - other_time: &DateTime<Utc>, + other_time: &NaiveDateTime, before: bool, -) -> (DateTime<Utc>, DateTime<Utc>) { +) -> (NaiveDateTime, NaiveDateTime) { if let Some(day) = m.name("a_day") { let wd = weekday(day.as_str()); let mut delta = @@ -888,7 +903,7 @@ fn relative_moment( other_time.year() } }; - let d = Utc.ymd(year, month, 1).and_hms(0, 0, 0); + let d = NaiveDate::from_ymd(year, month, 1).and_hms(0, 0, 0); let (d1, d2) = moment_to_period(d, &Period::Month, config); if before && d1 >= *other_time { return moment_to_period(d1.with_year(d1.year() - 1).unwrap(), &Period::Month, config); @@ -903,7 +918,7 @@ fn relative_moment( fn specific_moment( m: &Match, config: &Config, -) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> { +) -> Result<(NaiveDateTime, NaiveDateTime), TimeError> { if let Some(m) = m.name("specific_day") { return handle_specific_day(m, config); } @@ -975,7 +990,7 @@ fn n_month(m: &Match) -> u32 { cap[1].parse::<u32>().unwrap() } -fn year(m: &Match, now: &DateTime<Utc>) -> i32 { +fn year(m: &Match, now: &NaiveDateTime) -> i32 { let year = m.name("year").unwrap(); if let Some(sy) = year.name("short_year") { let y = s_to_n(sy.as_str()) as i32; @@ -1015,22 +1030,22 @@ fn n_day(m: &Match) -> u32 { /// expand a moment to the period containing it fn moment_to_period( - now: DateTime<Utc>, + now: NaiveDateTime, period: &Period, config: &Config, -) -> (DateTime<Utc>, DateTime<Utc>) { +) -> (NaiveDateTime, NaiveDateTime) { match period { Period::Year => { - let d1 = Utc.ymd(now.year(), 1, 1).and_hms(0, 0, 0); - let d2 = Utc.ymd(now.year() + 1, 1, 1).and_hms(0, 0, 0); + let d1 = NaiveDate::from_ymd(now.year(), 1, 1).and_hms(0, 0, 0); + let d2 = NaiveDate::from_ymd(now.year() + 1, 1, 1).and_hms(0, 0, 0); (d1, d2) } Period::Month => { - let d1 = Utc.ymd(now.year(), now.month(), 1).and_hms(0, 0, 0); + let d1 = NaiveDate::from_ymd(now.year(), now.month(), 1).and_hms(0, 0, 0); let d2 = if now.month() == 12 { - Utc.ymd(now.year() + 1, 1, 1) + NaiveDate::from_ymd(now.year() + 1, 1, 1) } else { - Utc.ymd(now.year(), now.month() + 1, 1) + NaiveDate::from_ymd(now.year(), now.month() + 1, 1) } .and_hms(0, 0, 0); (d1, d2) @@ -1041,28 +1056,29 @@ fn moment_to_period( } else { now.weekday().num_days_from_sunday() }; - let d1 = Utc.ymd(now.year(), now.month(), now.day()).and_hms(0, 0, 0) + let d1 = NaiveDate::from_ymd(now.year(), now.month(), now.day()).and_hms(0, 0, 0) - Duration::days(offset as i64); (d1, d1 + Duration::days(7)) } Period::Day => { - let d1 = Utc.ymd(now.year(), now.month(), now.day()).and_hms(0, 0, 0); + let d1 = NaiveDate::from_ymd(now.year(), now.month(), now.day()).and_hms(0, 0, 0); (d1, d1 + Duration::days(1)) } Period::Hour => { - let d1 = Utc - .ymd(now.year(), now.month(), now.day()) - .and_hms(now.hour(), 0, 0); + let d1 = + NaiveDate::from_ymd(now.year(), now.month(), now.day()).and_hms(now.hour(), 0, 0); (d1, d1 + Duration::hours(1)) } Period::Minute => { - let d1 = - Utc.ymd(now.year(), now.month(), now.day()) - .and_hms(now.hour(), now.minute(), 0); + let d1 = NaiveDate::from_ymd(now.year(), now.month(), now.day()).and_hms( + now.hour(), + now.minute(), + 0, + ); (d1, d1 + Duration::minutes(1)) } Period::Second => { - let d1 = Utc.ymd(now.year(), now.month(), now.day()).and_hms( + let d1 = NaiveDate::from_ymd(now.year(), now.month(), now.day()).and_hms( now.hour(), now.minute(), now.second(), |