1use crate::date::Date;
6use crate::time::Time;
7
8use std::time::SystemTime;
9use std::fmt::{self, Display, Formatter};
10use std::error::Error;
11
12#[derive(Default, PartialEq, Debug)]
38pub struct Datetime {
39 pub date: Date,
40 pub time: Time,
41 pub secs: u64
42}
43
44impl Datetime {
45
46 pub fn new() -> Result<Self, Box<dyn Error>> {
47 let new = Self::default().now()?;
48 Ok (new)
49 }
50
51 pub fn raw() -> Result<u64, Box<dyn Error>> {
52 let raw = SystemTime::now()
53 .duration_since(SystemTime::UNIX_EPOCH)?
54 .as_secs();
55 Ok (raw)
56 }
57
58 pub fn now(&self) -> Result<Self, Box<dyn Error>> {
59 let raw = Self::raw()?;
60 let now = self.set(raw);
61 Ok (now)
62 }
63
64 pub fn set(&self, secs: u64) -> Self {
65 let date = self.date.skip(secs - self.secs);
66 let time = Time::from(secs);
67 Self { date, time, secs }
68 }
69
70 pub fn for_header(&self) -> String {
71 ImfFixdate(self).to_string()
72 }
73}
74
75struct ImfFixdate<'a>(&'a Datetime);
78
79impl Display for ImfFixdate<'_> {
80
81 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
82 let ImfFixdate(dt) = self;
83 write!(f, "{} {} GMT",
84 dt.date.for_header(),
85 dt.time.for_header()
86 )
87 }
88}
89
90#[cfg(test)]
91mod test {
92
93 use super::Datetime;
94 use crate::date::{self, D_AS_S, test::{M_28_AS_S, M_29_AS_S, M_30_AS_S, M_31_AS_S, Y_365_AS_S, Y_366_AS_S}};
95 use crate::time::{self, Time, M_AS_S, H_AS_M, D_AS_H};
96
97 use std::time::{SystemTime, Duration};
98 use std::thread::sleep;
99
100 const JAN_01_1970_00_00_00: Datetime = Datetime {
102 date: date::test::JAN_01_1970_00_00_00,
103 time: time::test::JAN_01_1970_00_00_00,
104 secs: 0
105 };
106 const FEB_28_1970_23_59_59: Datetime = Datetime {
107 date: date::test::FEB_28_1970_23_59_59,
108 time: Time { h: D_AS_H - 1, m: H_AS_M - 1, s: M_AS_S - 1, xs: M_31_AS_S + M_28_AS_S - D_AS_S },
109 secs: M_31_AS_S + M_28_AS_S - 1
110 };
111 const MAR_01_1970_00_00_00: Datetime = Datetime {
112 date: date::test::MAR_01_1970_00_00_00,
113 time: Time { h: 0, m: 0, s: 0, xs: M_31_AS_S + M_28_AS_S },
114 secs: M_31_AS_S + M_28_AS_S
115 };
116 const APR_30_1970_23_59_59: Datetime = Datetime {
117 date: date::test::APR_30_1970_23_59_59,
118 time: Time { h: D_AS_H - 1, m: H_AS_M - 1, s: M_AS_S - 1, xs: M_31_AS_S * 2 + M_30_AS_S + M_28_AS_S - D_AS_S },
119 secs: M_31_AS_S * 2 + M_30_AS_S + M_28_AS_S - 1
120 };
121 const MAY_01_1970_00_00_00: Datetime = Datetime {
122 date: date::test::MAY_01_1970_00_00_00,
123 time: Time { h: 0, m: 0, s: 0, xs: M_31_AS_S * 2 + M_30_AS_S + M_28_AS_S },
124 secs: M_31_AS_S * 2 + M_30_AS_S + M_28_AS_S
125 };
126 const JUL_31_1970_23_59_59: Datetime = Datetime {
127 date: date::test::JUL_31_1970_23_59_59,
128 time: Time { h: D_AS_H - 1, m: H_AS_M - 1, s: M_AS_S - 1, xs: M_31_AS_S * 4 + M_30_AS_S * 2 + M_28_AS_S - D_AS_S },
129 secs: M_31_AS_S * 4 + M_30_AS_S * 2 + M_28_AS_S - 1
130 };
131 const SEP_01_1970_00_00_00: Datetime = Datetime {
132 date: date::test::SEP_01_1970_00_00_00,
133 time: Time { h: 0, m: 0, s: 0, xs: M_31_AS_S * 5 + M_30_AS_S * 2 + M_28_AS_S },
134 secs: M_31_AS_S * 5 + M_30_AS_S * 2 + M_28_AS_S
135 };
136 const DEC_31_1970_23_59_59: Datetime = Datetime {
137 date: date::test::DEC_31_1970_23_59_59,
138 time: Time { h: D_AS_H - 1, m: H_AS_M - 1, s: M_AS_S - 1, xs: Y_365_AS_S - D_AS_S },
139 secs: Y_365_AS_S - 1
140 };
141
142 const JAN_01_1972_00_00_00: Datetime = Datetime {
144 date: date::test::JAN_01_1972_00_00_00,
145 time: Time { h: 0, m: 0, s: 0, xs: Y_365_AS_S * 2 },
146 secs: Y_365_AS_S * 2
147 };
148 const FEB_29_1972_23_59_59: Datetime = Datetime {
149 date: date::test::FEB_29_1972_23_59_59,
150 time: Time { h: D_AS_H - 1, m: H_AS_M - 1, s: M_AS_S - 1, xs: Y_365_AS_S * 2 + M_31_AS_S + M_29_AS_S - D_AS_S },
151 secs: Y_365_AS_S * 2 + M_31_AS_S + M_29_AS_S - 1
152 };
153 const MAR_01_1972_00_00_00: Datetime = Datetime {
154 date: date::test::MAR_01_1972_00_00_00,
155 time: Time { h: 0, m: 0, s: 0, xs: Y_365_AS_S * 2 + M_31_AS_S + M_29_AS_S },
156 secs: Y_365_AS_S * 2 + M_31_AS_S + M_29_AS_S
157 };
158 const DEC_31_1972_23_59_59: Datetime = Datetime {
159 date: date::test::DEC_31_1972_23_59_59,
160 time: Time { h: D_AS_H - 1, m: H_AS_M - 1, s: M_AS_S - 1, xs: Y_365_AS_S * 2 + Y_366_AS_S - D_AS_S },
161 secs: Y_365_AS_S * 2 + Y_366_AS_S - 1
162 };
163
164 const JAN_01_2000_00_00_00: Datetime = Datetime {
166 date: date::test::JAN_01_2000_00_00_00,
167 time: Time { h: 0, m: 0, s: 0, xs: Y_365_AS_S * 23 + Y_366_AS_S * 7 },
168 secs: Y_365_AS_S * 23 + Y_366_AS_S * 7
169 };
170 const DEC_31_2000_23_59_59: Datetime = Datetime {
171 date: date::test::DEC_31_2000_23_59_59,
172 time: Time { h: D_AS_H - 1, m: H_AS_M - 1, s: M_AS_S - 1, xs: Y_365_AS_S * 23 + Y_366_AS_S * 8 - D_AS_S },
173 secs: Y_365_AS_S * 23 + Y_366_AS_S * 8 - 1
174 };
175
176 const DEC_31_2024_23_59_59: Datetime = Datetime {
178 date: date::test::DEC_31_2024_23_59_59,
179 time: Time { h: D_AS_H - 1, m: H_AS_M - 1, s: M_AS_S - 1, xs: Y_365_AS_S * 41 + Y_366_AS_S * 14 - D_AS_S },
180 secs: Y_365_AS_S * 41 + Y_366_AS_S * 14 - 1
181 };
182
183 #[test]
184 fn datetime_default() {
185
186 assert_eq!(JAN_01_1970_00_00_00, Datetime::default());
187 }
188
189 #[test]
190 fn datetime_raw() {
191
192 let st_raw = SystemTime::now()
193 .duration_since(SystemTime::UNIX_EPOCH).unwrap()
194 .as_secs();
195
196 assert_eq!(st_raw, Datetime::raw().unwrap());
197 }
198
199 #[test]
200 fn datetime_new() {
201
202 let st_raw = SystemTime::now()
203 .duration_since(SystemTime::UNIX_EPOCH).unwrap()
204 .as_secs();
205
206 let dt_new = Datetime::new().unwrap();
207
208 assert_eq!(st_raw, dt_new.secs);
209 assert_eq!(st_raw, dt_new.date.xs + dt_new.time.xs);
210 }
211
212 #[test]
213 fn datetime_now() {
214
215 let dt_new = Datetime::new().unwrap();
216
217 sleep(Duration::from_secs(1));
218
219 let dt_now = dt_new.now().unwrap();
220
221 assert_eq!(dt_new.secs + 1, dt_now.secs);
222 assert_eq!(dt_new.date.xs + dt_new.time.xs + 1, dt_now.date.xs + dt_now.time.xs);
223 }
224
225 #[test]
226 fn datetime_set() {
227
228 assert_eq!(FEB_28_1970_23_59_59, JAN_01_1970_00_00_00.set( M_31_AS_S + M_28_AS_S - 1));
230 assert_eq!(MAR_01_1970_00_00_00, FEB_28_1970_23_59_59.set( M_31_AS_S + M_28_AS_S ));
231 assert_eq!(APR_30_1970_23_59_59, MAR_01_1970_00_00_00.set( M_31_AS_S * 2 + M_30_AS_S + M_28_AS_S - 1));
232 assert_eq!(MAY_01_1970_00_00_00, APR_30_1970_23_59_59.set( M_31_AS_S * 2 + M_30_AS_S + M_28_AS_S ));
233 assert_eq!(JUL_31_1970_23_59_59, MAY_01_1970_00_00_00.set( M_31_AS_S * 4 + M_30_AS_S * 2 + M_28_AS_S - 1));
234 assert_eq!(SEP_01_1970_00_00_00, JUL_31_1970_23_59_59.set( M_31_AS_S * 5 + M_30_AS_S * 2 + M_28_AS_S ));
235 assert_eq!(DEC_31_1970_23_59_59, SEP_01_1970_00_00_00.set(Y_365_AS_S - 1));
236
237 assert_eq!(JAN_01_1972_00_00_00, DEC_31_1970_23_59_59.set(Y_365_AS_S * 2 ));
239 assert_eq!(FEB_29_1972_23_59_59, JAN_01_1972_00_00_00.set(Y_365_AS_S * 2 + M_31_AS_S + M_29_AS_S - 1));
240 assert_eq!(MAR_01_1972_00_00_00, FEB_29_1972_23_59_59.set(Y_365_AS_S * 2 + M_31_AS_S + M_29_AS_S ));
241 assert_eq!(DEC_31_1972_23_59_59, MAR_01_1972_00_00_00.set(Y_365_AS_S * 2 + Y_366_AS_S - 1));
242
243 assert_eq!(JAN_01_2000_00_00_00, DEC_31_1972_23_59_59.set(Y_365_AS_S * 23 + Y_366_AS_S * 7 ));
245 assert_eq!(DEC_31_2000_23_59_59, JAN_01_2000_00_00_00.set(Y_365_AS_S * 23 + Y_366_AS_S * 8 - 1));
246
247 assert_eq!(DEC_31_2024_23_59_59, DEC_31_2000_23_59_59.set(Y_365_AS_S * 41 + Y_366_AS_S * 14 - 1));
249 }
250
251 #[test]
252 fn datetime_for_header() {
253
254 assert_eq!(String::from("Thu, 01 Jan 1970 00:00:00 GMT"), JAN_01_1970_00_00_00.for_header());
256 assert_eq!(String::from("Sat, 28 Feb 1970 23:59:59 GMT"), FEB_28_1970_23_59_59.for_header());
257 assert_eq!(String::from("Sun, 01 Mar 1970 00:00:00 GMT"), MAR_01_1970_00_00_00.for_header());
258 assert_eq!(String::from("Thu, 30 Apr 1970 23:59:59 GMT"), APR_30_1970_23_59_59.for_header());
259 assert_eq!(String::from("Fri, 01 May 1970 00:00:00 GMT"), MAY_01_1970_00_00_00.for_header());
260 assert_eq!(String::from("Fri, 31 Jul 1970 23:59:59 GMT"), JUL_31_1970_23_59_59.for_header());
261 assert_eq!(String::from("Tue, 01 Sep 1970 00:00:00 GMT"), SEP_01_1970_00_00_00.for_header());
262 assert_eq!(String::from("Thu, 31 Dec 1970 23:59:59 GMT"), DEC_31_1970_23_59_59.for_header());
263
264 assert_eq!(String::from("Sat, 01 Jan 1972 00:00:00 GMT"), JAN_01_1972_00_00_00.for_header());
266 assert_eq!(String::from("Tue, 29 Feb 1972 23:59:59 GMT"), FEB_29_1972_23_59_59.for_header());
267 assert_eq!(String::from("Wed, 01 Mar 1972 00:00:00 GMT"), MAR_01_1972_00_00_00.for_header());
268 assert_eq!(String::from("Sun, 31 Dec 1972 23:59:59 GMT"), DEC_31_1972_23_59_59.for_header());
269
270 assert_eq!(String::from("Sat, 01 Jan 2000 00:00:00 GMT"), JAN_01_2000_00_00_00.for_header());
272 assert_eq!(String::from("Sun, 31 Dec 2000 23:59:59 GMT"), DEC_31_2000_23_59_59.for_header());
273
274 assert_eq!(String::from("Tue, 31 Dec 2024 23:59:59 GMT"), DEC_31_2024_23_59_59.for_header());
276 }
277}