summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs128
1 files changed, 72 insertions, 56 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 552bb21..6b87938 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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(),