expedite/datetime/
date.rs

1use time::{Tm};
2use datetime::time_change::TimeChange;
3
4#[derive(Clone, Debug)]
5#[derive(Eq, PartialEq)]
6pub struct Date {
7    pub year: u32,
8    pub month: u32,
9    pub day: u32,
10}
11
12// Magic variables from http://en.wikipedia.org/wiki/Julian_day#Gregorian_calendar_from_Julian_day_number
13
14static Y: u32 = 4716;
15static J: u32 = 1401;
16static M: u32 = 2;
17static N: u32 = 12;
18static R: u32 = 4;
19static P: u32 = 1461;
20static V: u32 = 3;
21static U: u32 = 5;
22static S: u32 = 153;
23static W: u32 = 2;
24static B: u32 = 274277;
25static C: u32 = 38;
26
27impl Date {
28    fn from_jdn(jdn: u32) -> Date {
29        let f = jdn + J + (((4u32.wrapping_mul(jdn) + B) / 146097) * 3) / 4 - C;
30        let e = R.wrapping_mul(f) + V;
31        let g = (e % P) / R;
32        let h = U * g + W;
33        let day = (h % S) / U + 1;
34        let month = ((h / S + M) % N) + 1;
35        let year = e / P - Y + (N + M - month) / N;
36
37        Date {
38            day: day,
39            month: month,
40            year: year as u32,
41        }
42    }
43
44    pub fn new(year: u32, month: u32, day: u32) -> Date {
45        Date {
46            day: day,
47            month: month,
48            year: year,
49        }
50    }
51
52    pub fn advance_days(&self, n: u32) -> Date {
53        let jdn = self.to_jdn() as u32;
54        Date::from_jdn((jdn + n) as u32)
55    }
56
57    pub fn advance_years(&self, n: u32) -> Date {
58        Date::new(self.year + n, self.month, self.day)
59    }
60
61    pub fn advance_months(&self, n: i32) -> Date {
62        if (n >= 0) {
63            self.add_months(n as u32)
64        } else {
65            self.subtract_months(-n as u32)
66        }
67    }
68
69    fn add_months(&self, n: u32) -> Date {
70        let remaining_in_year = 12 - self.month;
71        let after_this_year = n.wrapping_sub(remaining_in_year);
72
73        if (after_this_year > 0) {
74            let years = after_this_year / 12 + 1;
75            let months = after_this_year % 12;
76
77            Date::new(self.year + years as u32, months, self.day)
78        } else {
79            Date::new(self.year, self.month + n, self.day)
80        }
81    }
82
83    fn subtract_months(&self, n: u32) -> Date {
84        if (n > self.month) {
85            let years = n / 12;
86            let remaining_in_year = n % 12;
87            Date::new(self.year - years as u32,
88                      12 - remaining_in_year + self.month,
89                      self.day)
90        } else {
91            Date::new(self.year, self.month - n, self.day)
92        }
93    }
94
95    pub fn to_jdn(&self) -> u32 {
96        let month = self.month;
97
98        let a = (14 - self.month) / 12;    // 1 for Jan/Feb, 0 otherwise
99        let y: u32 = (self.year as u32) + 4800 - a;
100        let m = self.month + (12 * a) - 3; // 0 for Mar, 11 for Feb
101
102        let mut jdn: u32 = self.day;
103        jdn += ((153 * m) + 2) / 5;
104        jdn += (365u32.wrapping_mul(y));
105        jdn += (y / 4);
106        jdn -= (y / 100);
107        jdn += (y / 400);
108        jdn -= 32045;
109
110        jdn as u32
111    }
112}
113
114pub trait ToDate {
115    fn to_date(&self) -> Date;
116}
117
118impl ToDate for Tm {
119    fn to_date(&self) -> Date {
120        Date {
121            day: self.tm_mday as u32,
122            month: self.tm_mon as u32,
123            year: self.tm_year as u32,
124        }
125    }
126}