summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2017-09-16 10:47:03 +0200
committerMatthias Beyer <mail@beyermatthias.de>2017-09-16 10:47:11 +0200
commit3660f0608e25cf0c48561a5c89f4fa080a0eb564 (patch)
treeb090a8f2b36f5de42cd40fe3a07684d5d9143b1d
parent98bab48b8c900e32b0b8d6108262ffe6606b51aa (diff)
Add end-of-month type/calc
Adds util module
-rw-r--r--src/error.rs5
-rw-r--r--src/lib.rs1
-rw-r--r--src/timetype.rs88
-rw-r--r--src/util.rs36
4 files changed, 116 insertions, 14 deletions
diff --git a/src/error.rs b/src/error.rs
index 00fad98..4d4a0af 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -38,6 +38,11 @@ error_chain! {
display("Argument Error: Cannot calculate end-of-year on a {:?}", tt)
}
+ CannotCalculateEndOfMonthOn(tt: TimeType) {
+ description("Argument Error: Cannot calculate end-of-month")
+ display("Argument Error: Cannot calculate end-of-month on a {:?}", tt)
+ }
+
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 2f59f3f..624ce64 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,4 +6,5 @@ pub mod error;
pub mod iter;
pub mod result;
pub mod timetype;
+mod util;
diff --git a/src/timetype.rs b/src/timetype.rs
index 67c9229..961a9b3 100644
--- a/src/timetype.rs
+++ b/src/timetype.rs
@@ -15,6 +15,7 @@ use result::Result;
use error::KairosErrorKind as KEK;
use error::KairosError as KE;
use error_chain::ChainedError;
+use util::*;
/// A Type of Time, currently based on chrono::NaiveDateTime
#[derive(Debug, Clone)]
@@ -32,6 +33,7 @@ pub enum TimeType {
Subtraction(Box<TimeType>, Box<TimeType>),
EndOfYear(Box<TimeType>),
+ EndOfMonth(Box<TimeType>),
}
impl Add for TimeType {
@@ -165,6 +167,16 @@ impl TimeType {
TimeType::EndOfYear(Box::new(self))
}
+ /// Calculate the end of the month based on the current TimeType
+ ///
+ /// # Warning
+ ///
+ /// If the current TimeType does _not_ evaluate to a `TimeType::Moment`, calculating the end of
+ /// the month will fail
+ pub fn end_of_month(self) -> TimeType {
+ TimeType::EndOfMonth(Box::new(self))
+ }
+
/// Get the number of seconds, if the TimeType is not a duration type, zero is returned
///
/// # Warning
@@ -340,6 +352,7 @@ fn do_calculate(tt: TimeType) -> Result<TimeType> {
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)
}
}
@@ -362,6 +375,32 @@ fn end_of_year(tt: TimeType) -> Result<TimeType> {
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),
+ }
+}
+
+/// Evaluates the passed argument and if it is a `TT::Moment` it adjust its to the end of the month
+/// else returns an error
+///
+/// Calling a end-of-month on a end-of-month yields end-of-month applied only once.
+fn end_of_month(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) => {
+ let last_day = get_num_of_days_in_month(m.year(), m.month());
+ 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),
}
}
@@ -407,6 +446,9 @@ fn add(a: Box<TimeType>, b: Box<TimeType>) -> Result<TimeType> {
(TT::EndOfYear(e), other) => Err(KE::from_kind(KEK::CannotAdd(other, TT::EndOfYear(e)))),
(other, TT::EndOfYear(e)) => Err(KE::from_kind(KEK::CannotAdd(other, TT::EndOfYear(e)))),
+ (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)))),
+
others => unimplemented!(),
}
}
@@ -423,6 +465,7 @@ fn add_to_seconds(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Years(a) => Ok(TT::Seconds(a * 60 * 60 * 24 * 30 * 12 + amount)),
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::Addition(b, c) => add_to_seconds(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_seconds(amount, try!(sub(b, c))),
}
@@ -440,6 +483,7 @@ fn add_to_minutes(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Years(a) => Ok(TT::Minutes(a * 60 * 24 * 30 * 12 + amount)),
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::Addition(b, c) => add_to_minutes(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_minutes(amount, try!(sub(b, c))),
}
@@ -457,6 +501,7 @@ fn add_to_hours(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Years(a) => Ok(TT::Hours( a * 24 * 30 * 12 + amount)),
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::Addition(b, c) => add_to_hours(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_hours(amount, try!(sub(b, c))),
}
@@ -474,6 +519,7 @@ fn add_to_days(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Years(a) => Ok(TT::Days( a * 30 * 12 + amount)),
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::Addition(b, c) => add_to_days(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_days(amount, try!(sub(b, c))),
}
@@ -491,6 +537,7 @@ fn add_to_months(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Years(a) => Ok(TT::Months( a * 12 + amount)),
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::Addition(b, c) => add_to_months(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_months(amount, try!(sub(b, c))),
}
@@ -508,6 +555,7 @@ fn add_to_years(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Years(a) => Ok(TT::Years( a + amount)),
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::Addition(b, c) => add_to_years(amount, try!(add(b, c))),
TT::Subtraction(b, c) => add_to_years(amount, try!(sub(b, c))),
}
@@ -635,6 +683,7 @@ 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::Addition(a, b) => add_to_moment(mom, try!(add(a, b))),
TT::Subtraction(a, b) => add_to_moment(mom, try!(sub(a, b))),
}
@@ -694,6 +743,10 @@ fn sub(a: Box<TimeType>, b: Box<TimeType>) -> Result<TimeType> {
(TT::EndOfYear(e), other) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfYear(e)))),
(other, TT::EndOfYear(e)) => Err(KE::from_kind(KEK::CannotSub(other, TT::EndOfYear(e)))),
+ (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)))),
+
+
others => unimplemented!(),
}
}
@@ -708,8 +761,9 @@ fn sub_from_seconds(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Days(a) => Ok(TT::Seconds(amount - a * 60 * 60 * 24)),
TT::Months(a) => Ok(TT::Seconds(amount - a * 60 * 60 * 24 * 30)),
TT::Years(a) => Ok(TT::Seconds(amount - a * 60 * 60 * 24 * 30 * 12)),
- 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::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::Addition(b, c) => sub_from_seconds(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_seconds(amount, try!(sub(b, c))),
}
@@ -725,8 +779,9 @@ fn sub_from_minutes(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Days(a) => Ok(TT::Minutes(amount - a * 60 * 24)),
TT::Months(a) => Ok(TT::Minutes(amount - a * 60 * 24 * 30)),
TT::Years(a) => Ok(TT::Minutes(amount - a * 60 * 24 * 30 * 12)),
- 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::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::Addition(b, c) => sub_from_minutes(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_minutes(amount, try!(sub(b, c))),
}
@@ -742,8 +797,9 @@ fn sub_from_hours(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Days(a) => Ok(TT::Hours(amount - a * 24)),
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::CannotAdd(TT::Hours(amount), TT::Moment(m)))),
- TT::EndOfYear(e) => Err(KE::from_kind(KEK::CannotAdd(TT::Hours(amount), TT::EndOfYear(e)))),
+ 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::EndOfMonth(e) => Err(KE::from_kind(KEK::CannotSub(TT::Hours(amount), TT::EndOfMonth(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))),
}
@@ -759,8 +815,9 @@ fn sub_from_days(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Days(a) => Ok(TT::Days(amount - a)),
TT::Months(a) => Ok(TT::Days(amount - a * 30)),
TT::Years(a) => Ok(TT::Days(amount - a * 30 * 12)),
- 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::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::Addition(b, c) => sub_from_days(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_days(amount, try!(sub(b, c))),
}
@@ -776,8 +833,9 @@ fn sub_from_months(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Days(a) => Ok(TT::Days(amount * 30 - a)),
TT::Months(a) => Ok(TT::Months(amount - a)),
TT::Years(a) => Ok(TT::Months(amount - a * 12)),
- 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::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::Addition(b, c) => sub_from_months(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_months(amount, try!(sub(b, c))),
}
@@ -793,8 +851,9 @@ fn sub_from_years(amount: i64, tt: TimeType) -> Result<TimeType> {
TT::Days(a) => Ok(TT::Days(amount * 12 * 30 - a)),
TT::Months(a) => Ok(TT::Months(amount * 12 - a)),
TT::Years(a) => Ok(TT::Years(amount - a)),
- 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::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::Addition(b, c) => sub_from_years(amount, try!(add(b, c))),
TT::Subtraction(b, c) => sub_from_years(amount, try!(sub(b, c))),
}
@@ -945,8 +1004,9 @@ fn sub_from_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> {
.and_hms(h as u32, mi as u32, s as u32);
Ok(TimeType::moment(tt))
},
- 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::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::Addition(a, b) => sub_from_moment(mom, try!(add(a, b))),
TT::Subtraction(a, b) => sub_from_moment(mom, try!(sub(a, b))),
}
diff --git a/src/util.rs b/src/util.rs
new file mode 100644
index 0000000..3062c84
--- /dev/null
+++ b/src/util.rs
@@ -0,0 +1,36 @@
+
+#[inline]
+pub fn get_num_of_days_in_month(y: i32, m: u32) -> u32 {
+ if m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12 {
+ 31
+ } else if m == 2 {
+ if is_leap_year(y) {
+ 29
+ } else {
+ 28
+ }
+ } else {
+ 30
+ }
+}
+
+#[inline]
+pub fn is_leap_year(y: i32) -> bool {
+ (y % 4 == 0) && (y % 100 != 0 || y % 400 == 0)
+}
+
+#[test]
+fn test_is_leap_year() {
+ let leaps = [ 1880, 1884, 1888, 1892, 1896, 1904, 1908, 1912, 1916, 1920, 1924, 1928, 1932,
+ 1936, 1940, 1944, 1948, 1952, 1956, 1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992,
+ 1996, 2000, 2004, 2008, 2012, 2020, 2024, 2028, 2032, 2036, 2040, 2044, 2048, 2052, 2056,
+ 2060, 2064, 2068, 2072, 2076, 2080, 2084, 2088, 2092, 2096, 2104, 2108, 2112, 2116, 2120,
+ 2124, 2128, 2132, 2136, 2140, 2144, 2148, 2152, 2156, 2160, 2164, 2168, 2172, 2176, 2180,
+ 2184, 2188, 2192, 2196, 2204, 2208 ];
+
+ for i in leaps.iter() {
+ assert!(is_leap_year(*i), "Is no leap year: {}", i);
+ assert!(!is_leap_year(*i + 1), "Seems to be leap year: {}, but should not be", i + 1);
+ }
+
+}