DateZ now supports arithmetic operations.

This commit is contained in:
Kang Seonghoon 2014-03-30 04:52:37 +09:00
parent 877ceaeca0
commit 49737e992f
1 changed files with 125 additions and 0 deletions

View File

@ -3,6 +3,7 @@
*/ */
use std::fmt; use std::fmt;
use duration::Duration;
use self::internals::{Of, Mdf, YearFlags}; use self::internals::{Of, Mdf, YearFlags};
use self::internals::{DateImpl, MIN_YEAR, MAX_YEAR}; use self::internals::{DateImpl, MIN_YEAR, MAX_YEAR};
@ -361,6 +362,49 @@ impl Datelike for DateZ {
} }
} }
impl Add<Duration,DateZ> for DateZ {
fn add(&self, rhs: &Duration) -> DateZ {
// TODO overflow
let year = self.year();
let mut year_div_400 = year / 400;
let year_mod_400 = (year % 400) as uint;
let mut cycle = internals::yo_to_cycle(year_mod_400, self.of().ordinal()) as int;
cycle += rhs.ndays();
year_div_400 += cycle / 146097;
cycle %= 146097;
if cycle < 0 {
cycle += 146097;
year_div_400 -= 400;
}
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as uint);
let flags = unsafe { YearFlags::from_year_mod_400(year_mod_400 as int) };
let mdf = Of::new(ordinal, flags).to_mdf();
DateZ::new(year_div_400 * 400 + year_mod_400 as int, mdf).unwrap()
}
}
/*
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
impl Add<DateZ,DateZ> for Duration {
#[inline]
fn add(&self, rhs: &DateZ) -> DateZ { rhs.add(self) }
}
*/
impl Sub<DateZ,Duration> for DateZ {
fn sub(&self, rhs: &DateZ) -> Duration {
let year1 = self.year();
let year2 = rhs.year();
let (year1_div_400, year1_mod_400) = (year1 / 400, year1 % 400);
let (year2_div_400, year2_mod_400) = (year2 / 400, year2 % 400);
let cycle1 = internals::yo_to_cycle(year1_mod_400 as uint, self.of().ordinal()) as int;
let cycle2 = internals::yo_to_cycle(year2_mod_400 as uint, rhs.of().ordinal()) as int;
Duration::days((year1_div_400 - year2_div_400) * 146097 + (cycle1 - cycle2))
}
}
impl fmt::Show for DateZ { impl fmt::Show for DateZ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let year = self.year(); let year = self.year();
@ -376,6 +420,7 @@ impl fmt::Show for DateZ {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use duration::Duration;
use std::{int, uint}; use std::{int, uint};
use std::iter::range_inclusive; use std::iter::range_inclusive;
@ -576,6 +621,41 @@ mod tests {
} }
} }
#[test]
fn test_date_add() {
fn check((y1,m1,d1): (int, uint, uint), rhs: Duration, (y,m,d): (int, uint, uint)) {
let lhs = DateZ::from_ymd(y1, m1, d1).unwrap();
let sum = DateZ::from_ymd(y, m, d).unwrap();
assert_eq!(lhs + rhs, sum);
//assert_eq!(rhs + lhs, sum);
}
check((2014, 1, 1), Duration::zero(), (2014, 1, 1));
check((2014, 1, 1), Duration::seconds(86399), (2014, 1, 1));
check((2014, 1, 1), Duration::days(1), (2014, 1, 2));
check((2014, 1, 1), Duration::days(-1), (2013, 12, 31));
check((2014, 1, 1), Duration::days(364), (2014, 12, 31));
check((2014, 1, 1), Duration::days(365*4 + 1), (2018, 1, 1));
check((2014, 1, 1), Duration::days(365*400 + 97), (2414, 1, 1));
}
#[test]
fn test_date_sub() {
fn check((y1,m1,d1): (int, uint, uint), (y2,m2,d2): (int, uint, uint), diff: Duration) {
let lhs = DateZ::from_ymd(y1, m1, d1).unwrap();
let rhs = DateZ::from_ymd(y2, m2, d2).unwrap();
assert_eq!(lhs - rhs, diff);
assert_eq!(rhs - lhs, -diff);
}
check((2014, 1, 1), (2014, 1, 1), Duration::zero());
check((2014, 1, 2), (2014, 1, 1), Duration::days(1));
check((2014, 12, 31), (2014, 1, 1), Duration::days(364));
check((2015, 1, 3), (2014, 1, 1), Duration::days(365 + 2));
check((2018, 1, 1), (2014, 1, 1), Duration::days(365*4 + 1));
check((2414, 1, 1), (2014, 1, 1), Duration::days(365*400 + 97));
}
#[test] #[test]
fn test_date_fmt() { fn test_date_fmt() {
assert_eq!(DateZ::from_ymd(2012, 3, 4).unwrap().to_str(), ~"2012-03-04"); assert_eq!(DateZ::from_ymd(2012, 3, 4).unwrap().to_str(), ~"2012-03-04");
@ -650,11 +730,56 @@ mod internals {
FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, // 400 FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, // 400
]; ];
static YEAR_DELTAS: [u8, ..401] = [
0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10,
10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15,
15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20,
20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, // 100
25, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29,
29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34,
34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39,
39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44,
44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, // 200
49, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53,
53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58,
58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63,
63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68,
68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, // 300
73, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77,
77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82,
82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87,
87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92,
92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97 // 400+1
];
pub fn cycle_to_yo(cycle: uint) -> (uint, uint) {
let mut year_mod_400 = cycle / 365;
let mut ordinal0 = cycle % 365;
let delta = YEAR_DELTAS[year_mod_400] as uint;
if ordinal0 < delta {
year_mod_400 -= 1;
ordinal0 += 365 - YEAR_DELTAS[year_mod_400] as uint;
} else {
ordinal0 -= delta;
}
(year_mod_400, ordinal0 + 1)
}
pub fn yo_to_cycle(year_mod_400: uint, ordinal: uint) -> uint {
year_mod_400 * 365 + YEAR_DELTAS[year_mod_400] as uint + ordinal - 1
}
impl YearFlags { impl YearFlags {
#[inline] #[inline]
pub fn from_year(year: int) -> YearFlags { pub fn from_year(year: int) -> YearFlags {
let mut year = year % 400; let mut year = year % 400;
if year < 0 { year += 400; } if year < 0 { year += 400; }
unsafe { YearFlags::from_year_mod_400(year) }
}
#[inline]
pub unsafe fn from_year_mod_400(year: int) -> YearFlags {
YEAR_TO_FLAGS[year] YEAR_TO_FLAGS[year]
} }