summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2017-09-16 12:24:12 +0200
committerMatthias Beyer <mail@beyermatthias.de>2017-09-16 12:24:12 +0200
commit2106cb48ba94f687eb6aff36e42f9a42f731fdaf (patch)
treea88fcb5d52152744835fff41fc5d1a29f6d58b86
parent96852e5f79fc22fefd69af89535a8934a51707b9 (diff)
parent134654ba25761984fc2c4b9e55975e2fbfca5d8e (diff)
Merge branch 'end-of-day-hour-minute'
-rw-r--r--src/timetype.rs870
1 files changed, 857 insertions, 13 deletions
diff --git a/src/timetype.rs b/src/timetype.rs
index a6c51d2..b0a5967 100644
--- a/src/timetype.rs
+++ b/src/timetype.rs
@@ -34,6 +34,9 @@ pub enum TimeType {
EndOfYear(Box<TimeType>),
EndOfMonth(Box<TimeType>),
+ EndOfDay(Box<TimeType>),
+ EndOfHour(Box<TimeType>),
+ EndOfMinute(Box<TimeType>),
}
impl Add for TimeType {
@@ -177,6 +180,36 @@ impl TimeType {
TimeType::EndOfMonth(Box::new(self))
}
+ /// Calculate the end of the day based on the current TimeType
+ ///
+ /// # Warning
+ ///
+ /// If the current TimeType does _not_ evaluate to a `TimeType::Moment`, calculating the end of
+ /// the day will fail
+ pub fn end_of_day(self) -> TimeType {
+ TimeType::EndOfDay(Box::new(self))
+ }
+
+ /// Calculate the end of the hour based on the current TimeType
+ ///
+ /// # Warning
+ ///
+ /// If the current TimeType does _not_ evaluate to a `TimeType::Moment`, calculating the end of
+ /// the hour will fail
+ pub fn end_of_hour(self) -> TimeType {
+ TimeType::EndOfHour(Box::new(self))
+ }
+
+ /// Calculate the end of the minute based on the current TimeType
+ ///
+ /// # Warning
+ ///
+ /// If the current TimeType does _not_ evaluate to a `TimeType::Moment`, calculating the end of
+ /// the minute will fail
+ pub fn end_of_minute(self) -> TimeType {
+ TimeType::EndOfMinute(Box::new(self))
+ }
+
/// Get the number of seconds, if the TimeType is not a duration type, zero is returned
///
/// # Warning
@@ -349,11 +382,14 @@ fn do_calculate(tt: TimeType) -> Result<TimeType> {
use timetype::TimeType as TT;
match tt {
- TT::Addition(a, b) => add(a, b),
- TT::Subtraction(a, b) => sub(a, b),
- TT::EndOfYear(inner) => end_of_year(*inner),
- TT::EndOfMonth(inner) => end_of_month(*inner),
- x => Ok(x)
+ TT::Addition(a, b) => add(a, b),
+ TT::Subtraction(a, b) => sub(a, b),
+ TT::EndOfYear(inner) => end_of_year(*inner),
+ TT::EndOfMonth(inner) => end_of_month(*inner),
+ TT::EndOfDay(inner) => end_of_day(*inner),
+ TT::EndOfHour(inner) => end_of_hour(*inner),
+ TT::EndOfMinute(inner) => end_of_minute(*inner),
+ x => Ok(x)
}
}
@@ -374,8 +410,12 @@ fn end_of_year(tt: TimeType) -> Result<TimeType> {
els @ TT::Addition(_, _) |
els @ TT::Subtraction(_, _) => Err(KE::from_kind(KEK::CannotCalculateEndOfYearOn(els))),
TT::Moment(m) => Ok(TT::moment(NaiveDate::from_ymd(m.year(), 12, 31).and_hms(0, 0, 0))),
- TT::EndOfYear(e) => do_calculate(*e),
- TT::EndOfMonth(e) => do_calculate(*e),
+
+ TT::EndOfYear(e) => do_calculate(*e),
+ TT::EndOfMonth(e) => do_calculate(*e),
+ TT::EndOfDay(e) => do_calculate(*e),
+ TT::EndOfHour(e) => do_calculate(*e),
+ TT::EndOfMinute(e) => do_calculate(*e),
}
}
@@ -399,8 +439,94 @@ fn end_of_month(tt: TimeType) -> Result<TimeType> {
let last_day = get_num_of_days_in_month(m.year() as i64, m.month() as i64) as u32;
Ok(TT::moment(NaiveDate::from_ymd(m.year(), m.month(), last_day).and_hms(0, 0, 0)))
},
- TT::EndOfYear(e) => do_calculate(*e),
- TT::EndOfMonth(e) => do_calculate(*e),
+ TT::EndOfYear(e) => do_calculate(*e),
+ TT::EndOfMonth(e) => do_calculate(*e),
+ TT::EndOfDay(e) => do_calculate(*e),
+ TT::EndOfHour(e) => do_calculate(*e),
+ TT::EndOfMinute(e) => do_calculate(*e),
+ }
+}
+
+/// Evaluates the passed argument and if it is a `TT::Moment` it adjust its to the end of the day
+/// else returns an error
+///
+/// Calling a end-of-day on a end-of-day yields end-of-month applied only once.
+fn end_of_day(tt: TimeType) -> Result<TimeType> {
+ use timetype::TimeType as TT;
+
+ match try!(do_calculate(tt)) {
+ els @ TT::Seconds(_) |
+ els @ TT::Minutes(_) |
+ els @ TT::Hours(_) |
+ els @ TT::Days(_) |
+ els @ TT::Months(_) |
+ els @ TT::Years(_) |
+ els @ TT::Addition(_, _) |
+ els @ TT::Subtraction(_, _) => Err(KE::from_kind(KEK::CannotCalculateEndOfMonthOn(els))),
+ TT::Moment(m) => {
+ Ok(TT::moment(NaiveDate::from_ymd(m.year(), m.month(), m.day()).and_hms(23, 59, 59)))
+ },
+ TT::EndOfYear(e) => do_calculate(*e),
+ TT::EndOfMonth(e) => do_calculate(*e),
+ TT::EndOfDay(e) => do_calculate(*e),
+ TT::EndOfHour(e) => do_calculate(*e),
+ TT::EndOfMinute(e) => do_calculate(*e),
+ }
+}
+
+/// Evaluates the passed argument and if it is a `TT::Moment` it adjust its to the end of the hour
+/// else returns an error
+///
+/// Calling a end-of-hour on a end-of-hour yields end-of-month applied only once.
+fn end_of_hour(tt: TimeType) -> Result<TimeType> {
+ use timetype::TimeType as TT;
+
+ match try!(do_calculate(tt)) {
+ els @ TT::Seconds(_) |
+ els @ TT::Minutes(_) |
+ els @ TT::Hours(_) |
+ els @ TT::Days(_) |
+ els @ TT::Months(_) |
+ els @ TT::Years(_) |
+ els @ TT::Addition(_, _) |
+ els @ TT::Subtraction(_, _) => Err(KE::from_kind(KEK::CannotCalculateEndOfMonthOn(els))),
+ TT::Moment(m) => {
+ Ok(TT::moment(NaiveDate::from_ymd(m.year(), m.month(), m.day())
+ .and_hms(m.hour(), 59, 59)))
+ },
+ TT::EndOfYear(e) => do_calculate(*e),
+ TT::EndOfMonth(e) => do_calculate(*e),
+ TT::EndOfDay(e) => do_calculate(*e),
+ TT::EndOfHour(e) => do_calculate(*e),
+ TT::EndOfMinute(e) => do_calculate(*e),
+ }
+}
+
+/// Evaluates the passed argument and if it is a `TT::Moment` it adjust its to the end of the
+/// minute else returns an error
+///
+/// Calling a end-of-minute on a end-of-minute yields end-of-month applied only once.
+fn end_of_minute(tt: TimeType) -> Result<TimeType> {
+ use timetype::TimeType as TT;
+
+ match try!(do_calculate(tt)) {
+ els @ TT::Seconds(_) |
+ els @ TT::Minutes(_) |
+ els @ TT::Hours(_) |
+ els @ TT::Days(_) |
+ els @ TT::Months(_) |
+ els @ TT::Years(_) |
+ els @ TT::Addition(_, _) |
+ els @ TT::Subtraction(_, _) => Err(KE::from_kind(KEK::CannotCalculateEndOfMonthOn(els))),
+ TT::Moment(m) => {
+ Ok(TT::moment(NaiveDate::from_ymd(m.year(), m.month(), m.day())
+ .and_hms(m.hour(), m.minute(), 59)))
+ },
+ TT::EndOfYear(e) => do_calculate(*e),
+ TT::EndOfMonth(e) => do_calculate(*e),
+ TT::EndOfDay(e) => do_calculate(*e),
+ TT::EndOfHour(e) => do_calculate(*e),
+ TT::EndOfMinute(e) => do_calculate(*e),
}
}
@@ -449,6 +575,12 @@ fn add(a: Box<TimeType>, b: Box<TimeType>) -> Result<TimeType> {
(TT::EndOfMonth(e), other) => Err(KE::from_kind(KEK::CannotAdd(other, TT::EndOfMonth(e)))),
(other, TT::EndOfMonth(e)) => Err(KE::from_kind(KEK::CannotAdd(other, TT::EndOfMonth(e)))),
+ (TT::EndOfDay(e), other) => Err(KE::from_kind(KEK::CannotAdd(other, TT::EndOfDay(e)))),
+ (other, TT::EndOfDay(e)) => Err(KE::from_kind(KEK::CannotAdd(other, TT::EndOfDay(e)))),
+
+ (TT::EndOfHour(e), other) => Err(KE::from_kind(KEK::CannotAdd(other, TT::EndOfHour(e)))),
+ (other, TT::EndOfHour(e)) => Err(KE::from_kind(KEK::CannotAdd(other, TT::EndOfHour(e)))),
+
others => unimplemented!(),
}
}
@@ -466,6 +598,9 @@ fn add_to_seconds(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotAdd(TT::Seconds(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Seconds(amount), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Seconds(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Seconds(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Seconds(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Seconds(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => add_to_seconds(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_seconds(amount, try!(sub(b, c))),
}
@@ -484,6 +619,9 @@ fn add_to_minutes(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotAdd(TT::Minutes(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Minutes(amount), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Minutes(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Minutes(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Minutes(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Minutes(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => add_to_minutes(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_minutes(amount, try!(sub(b, c))),
}
@@ -502,6 +640,9 @@ fn add_to_hours(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotAdd(TT::Hours(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Hours(amount), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Hours(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Hours(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Hours(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Hours(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => add_to_hours(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_hours(amount, try!(sub(b, c))),
}
@@ -520,6 +661,9 @@ fn add_to_days(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotAdd(TT::Days(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Days(amount), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Days(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Days(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Days(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Days(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => add_to_days(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_days(amount, try!(sub(b, c))),
}
@@ -538,6 +682,9 @@ fn add_to_months(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotAdd(TT::Months(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Months(amount), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Months(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Months(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Months(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Months(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => add_to_months(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_months(amount, try!(sub(b, c))),
}
@@ -556,6 +703,9 @@ fn add_to_years(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotAdd(TT::Years(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Years(amount), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Years(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Years(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Years(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Years(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => add_to_years(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_years(amount, try!(sub(b, c))),
}
@@ -652,6 +802,9 @@ fn add_to_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotAdd(TT::Moment(mom), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Moment(mom), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Moment(mom), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Moment(mom), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Moment(mom), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Moment(mom), TT::EndOfMinute(e)))),
TT::Addition(a, b) => add_to_moment(mom, try!(add(a, b))),
TT::Subtraction(a, b) => add_to_moment(mom, try!(sub(a, b))),
}
@@ -714,6 +867,14 @@ fn sub(a: Box<TimeType>, b: Box<TimeType>) -> Result<TimeType> {
(TT::EndOfMonth(e), other) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfMonth(e)))),
(other, TT::EndOfMonth(e)) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfMonth(e)))),
+ (TT::EndOfDay(e), other) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfDay(e)))),
+ (other, TT::EndOfDay(e)) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfDay(e)))),
+
+ (TT::EndOfHour(e), other) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfHour(e)))),
+ (other, TT::EndOfHour(e)) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfHour(e)))),
+
+ (TT::EndOfMinute(e), other) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfMinute(e)))),
+ (other, TT::EndOfMinute(e)) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfMinute(e)))),
others => unimplemented!(),
}
@@ -732,6 +893,9 @@ fn sub_from_seconds(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotSub(TT::Seconds(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotSub(TT::Seconds(amount), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Seconds(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotSub(TT::Seconds(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotSub(TT::Seconds(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotSub(TT::Seconds(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => sub_from_seconds(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_seconds(amount, try!(sub(b, c))),
}
@@ -750,6 +914,9 @@ fn sub_from_minutes(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotSub(TT::Minutes(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotSub(TT::Minutes(amount), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Minutes(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotSub(TT::Minutes(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotSub(TT::Minutes(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotSub(TT::Minutes(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => sub_from_minutes(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_minutes(amount, try!(sub(b, c))),
}
@@ -766,8 +933,11 @@ fn sub_from_hours(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Months(a) => Ok(TT::Hours(amount - a * 24 * 30)),
TT::Years(a) => Ok(TT::Hours(amount - a * 24 * 30 * 12)),
TT::Moment(m) => Err(KE::from_kind(KEK::CannotSub(TT::Hours(amount), TT::Moment(m)))),
- TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotSub(TT::Hours(amount), TT::EndOfYear(e)))),
+ TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotSub(TT::Hours(amount), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Hours(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotSub(TT::Hours(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotSub(TT::Hours(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotSub(TT::Hours(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => sub_from_hours(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_hours(amount, try!(sub(b, c))),
}
@@ -785,7 +955,10 @@ fn sub_from_days(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Years(a) => Ok(TT::Days(amount - a * 30 * 12)),
TT::Moment(m) => Err(KE::from_kind(KEK::CannotSub(TT::Days(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotSub(TT::Days(amount), TT::EndOfYear(e)))),
- TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Days(amount), TT::EndOfMonth(e)))),
+ TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Days(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotSub(TT::Days(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotSub(TT::Days(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotSub(TT::Days(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => sub_from_days(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_days(amount, try!(sub(b, c))),
}
@@ -803,7 +976,10 @@ fn sub_from_months(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Years(a) => Ok(TT::Months(amount - a * 12)),
TT::Moment(m) => Err(KE::from_kind(KEK::CannotSub(TT::Months(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotSub(TT::Months(amount), TT::EndOfYear(e)))),
- TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Months(amount), TT::EndOfMonth(e)))),
+ TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Months(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotSub(TT::Months(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotSub(TT::Months(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotSub(TT::Months(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => sub_from_months(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_months(amount, try!(sub(b, c))),
}
@@ -821,7 +997,10 @@ fn sub_from_years(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Years(a) => Ok(TT::Years(amount - a)),
TT::Moment(m) => Err(KE::from_kind(KEK::CannotSub(TT::Years(amount), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotSub(TT::Years(amount), TT::EndOfYear(e)))),
- TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Months(amount), TT::EndOfMonth(e)))),
+ TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Years(amount), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotSub(TT::Years(amount), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotSub(TT::Years(amount), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotSub(TT::Years(amount), TT::EndOfMinute(e)))),
TT::Addition(b, c) => sub_from_years(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_years(amount, try!(sub(b, c))),
}
@@ -918,6 +1097,9 @@ fn sub_from_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> {
TT::Moment(m) => Err(KE::from_kind(KEK::CannotSub(TT::Moment(mom), TT::Moment(m)))),
TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotSub(TT::Moment(mom), TT::EndOfYear(e)))),
TT::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Moment(mom), TT::EndOfMonth(e)))),
+ TT::EndOfDay(e) => Err(KE::from_kind(KEK::CannotSub(TT::Moment(mom), TT::EndOfDay(e)))),
+ TT::EndOfHour(e) => Err(KE::from_kind(KEK::CannotSub(TT::Moment(mom), TT::EndOfHour(e)))),
+ TT::EndOfMinute(e) => Err(KE::from_kind(KEK::CannotSub(TT::Moment(mom), TT::EndOfMinute(e)))),
TT::Addition(a, b) => sub_from_moment(mom, try!(add(a, b))),
TT::Subtraction(a, b) => sub_from_moment(mom, try!(sub(a, b))),
}
@@ -2605,3 +2787,665 @@ mod test_end_of_month {
}
}
+
+
+#[cfg(test)]
+mod test_end_of_day {
+ use super::TimeType as TT;
+ use chrono::NaiveDate;
+ use chrono::Timelike;
+ use chrono::Datelike;
+
+ macro_rules! generate_test_moment_operator_amount_and_end_of_day {
+ {
+ name = $name:ident;
+ base = $base:expr;
+ amount = $amount:expr;
+ expected = $exp:expr;
+ operator = $op:expr;
+ } => {
+ #[test]
+ fn $name() {
+ let base = TT::moment($base);
+ let result = $op(base, $amount).end_of_day().calculate();
+ assert!(result.is_ok(), "Operation failed: {:?}", result);
+ let result = result.unwrap();
+ let expected = $exp;
+
+ assert_eq!(expected, *result.get_moment().unwrap());
+ }
+ }
+ }
+
+ macro_rules! generate_test_moment_plus_amount_and_end_of_day {
+ {
+ name = $name:ident;
+ base = $base:expr;
+ amount = $amount:expr;
+ expected = $exp:expr;
+ } => {
+ generate_test_moment_operator_amount_and_end_of_day! {
+ name = $name;
+ base = $base;
+ amount = $amount;
+ expected = $exp;
+ operator = |base, amount| base + amount;
+ }
+ }
+ }
+
+ macro_rules! generate_test_moment_minus_amount_and_end_of_day {
+ {
+ name = $name:ident;
+ base = $base:expr;
+ amount = $amount:expr;
+ expected = $exp:expr;
+ } => {
+ generate_test_moment_operator_amount_and_end_of_day! {
+ name = $name;
+ base = $base;
+ amount = $amount;
+ expected = $exp;
+ operator = |base, amount| base - amount;
+ }
+ }
+ }
+
+ //
+ // tests
+ //
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_zero_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(0);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(1);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_too_much_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(62);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_minutes;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::minutes(2);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_too_much_minutes;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::minutes(65);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_minutes_in_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(62);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_months;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::months(14);
+ expected = NaiveDate::from_ymd(2001, 3, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_years;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::years(62);
+ expected = NaiveDate::from_ymd(2062, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_more_than_one_year;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::years(1) + TT::months(1);
+ expected = NaiveDate::from_ymd(2001, 2, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_more_than_one_month;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+
+ // As we calculate 1 month + 1 day first, we end up adding 31 days to the base
+ amount = TT::months(1) + TT::days(1);
+
+ // and therefor this results in the date 2000-02-01
+ // This is not that inuitive, of course.
+ expected = NaiveDate::from_ymd(2000, 2, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_more_than_one_day;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::days(1) + TT::hours(1);
+ expected = NaiveDate::from_ymd(2000, 1, 2).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_more_than_one_hour;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::hours(1) + TT::minutes(1);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_more_than_one_minute;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::minutes(1) + TT::seconds(1);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_invalid_months;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::months(13);
+ expected = NaiveDate::from_ymd(2001, 2, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_invalid_days;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::days(31);
+ expected = NaiveDate::from_ymd(2000, 2, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_invalid_hours;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::hours(25);
+ expected = NaiveDate::from_ymd(2000, 1, 2).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_invalid_minutes;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::minutes(61);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_day! {
+ name = test_moment_plus_invalid_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(61);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_minus_amount_and_end_of_day! {
+ name = test_moment_minus_nothing;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(0);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_minus_amount_and_end_of_day! {
+ name = test_moment_minus_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(1);
+ expected = NaiveDate::from_ymd(1999, 12, 31).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_minus_amount_and_end_of_day! {
+ name = test_moment_minus_months;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::months(12);
+ expected = NaiveDate::from_ymd(1999, 1, 1).and_hms(23, 59, 59);
+ }
+
+}
+
+#[cfg(test)]
+mod test_end_of_hour {
+ use super::TimeType as TT;
+ use chrono::NaiveDate;
+ use chrono::Timelike;
+ use chrono::Datelike;
+
+ macro_rules! generate_test_moment_operator_amount_and_end_of_hour {
+ {
+ name = $name:ident;
+ base = $base:expr;
+ amount = $amount:expr;
+ expected = $exp:expr;
+ operator = $op:expr;
+ } => {
+ #[test]
+ fn $name() {
+ let base = TT::moment($base);
+ let result = $op(base, $amount).end_of_hour().calculate();
+ assert!(result.is_ok(), "Operation failed: {:?}", result);
+ let result = result.unwrap();
+ let expected = $exp;
+
+ assert_eq!(expected, *result.get_moment().unwrap());
+ }
+ }
+ }
+
+ macro_rules! generate_test_moment_plus_amount_and_end_of_hour {
+ {
+ name = $name:ident;
+ base = $base:expr;
+ amount = $amount:expr;
+ expected = $exp:expr;
+ } => {
+ generate_test_moment_operator_amount_and_end_of_hour! {
+ name = $name;
+ base = $base;
+ amount = $amount;
+ expected = $exp;
+ operator = |base, amount| base + amount;
+ }
+ }
+ }
+
+ macro_rules! generate_test_moment_minus_amount_and_end_of_hour {
+ {
+ name = $name:ident;
+ base = $base:expr;
+ amount = $amount:expr;
+ expected = $exp:expr;
+ } => {
+ generate_test_moment_operator_amount_and_end_of_hour! {
+ name = $name;
+ base = $base;
+ amount = $amount;
+ expected = $exp;
+ operator = |base, amount| base - amount;
+ }
+ }
+ }
+
+ //
+ // tests
+ //
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_zero_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(0);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(1);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_too_much_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(62);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_minutes;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::minutes(2);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_too_much_minutes;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::minutes(65);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(1, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_minutes_in_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(62);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_months;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::months(14);
+ expected = NaiveDate::from_ymd(2001, 3, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_years;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::years(62);
+ expected = NaiveDate::from_ymd(2062, 1, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_more_than_one_year;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::years(1) + TT::months(1);
+ expected = NaiveDate::from_ymd(2001, 2, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_more_than_one_month;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+
+ // As we calculate 1 month + 1 day first, we end up adding 31 days to the base
+ amount = TT::months(1) + TT::days(1);
+
+ // and therefor this results in the date 2000-02-01
+ // This is not that inuitive, of course.
+ expected = NaiveDate::from_ymd(2000, 2, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_more_than_one_day;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::days(1) + TT::hours(1);
+ expected = NaiveDate::from_ymd(2000, 1, 2).and_hms(1, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_more_than_one_hour;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::hours(1) + TT::minutes(1);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(1, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_more_than_one_minute;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::minutes(1) + TT::seconds(1);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_invalid_months;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::months(13);
+ expected = NaiveDate::from_ymd(2001, 2, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_invalid_days;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::days(31);
+ expected = NaiveDate::from_ymd(2000, 2, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_invalid_hours;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::hours(25);
+ expected = NaiveDate::from_ymd(2000, 1, 2).and_hms(1, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_invalid_minutes;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::minutes(61);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(1, 59, 59);
+ }
+
+ generate_test_moment_plus_amount_and_end_of_hour! {
+ name = test_moment_plus_invalid_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(61);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_minus_amount_and_end_of_hour! {
+ name = test_moment_minus_nothing;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(0);
+ expected = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 59, 59);
+ }
+
+ generate_test_moment_minus_amount_and_end_of_hour! {
+ name = test_moment_minus_seconds;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::seconds(1);
+ expected = NaiveDate::from_ymd(1999, 12, 31).and_hms(23, 59, 59);
+ }
+
+ generate_test_moment_minus_amount_and_end_of_hour! {
+ name = test_moment_minus_months;
+ base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
+ amount = TT::months(12);
+ expected = NaiveDate::from_ymd(1999, 1, 1).and_hms(0, 59, 59);
+ }
+
+}
+
+#[cfg(test)]
+mod test_end_of_minute {
+ use super::TimeType as TT;
+ use chrono::NaiveDate;
+ use chrono::Timelike;
+ use chrono::Datelike;
+
+ macro_rules! generate_test_moment_operator_amount_and_end_of_minute {
+ {
+ name = $name:ident;
+ base = $base:expr;
+ amount = $amount:expr;
+ expected = $exp:expr;
+ operator = $op:expr;
+ } => {
+ #[test]
+ fn $name() {
+ let base = TT::moment($base);
+ let result = $op(base, $amount).end_of_minute().calculate();
+ assert!(result.is_ok(), "Operation failed: {:?}", result);
+ let result = result.unwrap();
+ let expected = $exp;
+
+ assert_eq!(expected, *result.get_moment().unwrap());