1use std::time::{Duration, SystemTime};
9
10pub type Date = (i64, u64, u64, u64, u64, u64, u32);
14
15
16pub fn days_from_civil(mut y:i64, m: u64, d: u64) -> i64 {
18
19 if m <= 2 {
20 y -= 1;
21 }
22
23 let era: i64 = ( if y >= 0 { y } else { y - 399 } ).div_euclid(400);
24 let yoe: u64 = (y - era * 400) as u64;
25 let doy = ( 153* ( if m > 2 { m - 3 } else { m + 9 }) + 2 ) / 5 + d -1 ;
26 let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
27
28 let r = era * 146097 + (doe as i64) - 719468;
29
30 r
31}
32
33pub fn civil_from_days(mut z: i64) -> (i64, u64, u64) {
35
36 z += 719468;
37 let era: i64 = ( if z >= 0 { z } else { z - 146096 } ).div_euclid(146097);
38 let doe: u64 = ( z - era * 146097) as u64;
39 let yoe = ( doe - doe / 1460 + doe / 36524 - doe / 146096 ) / 365;
40 let mut y: i64 = yoe as i64 + era * 400;
41
42 let doy: u64 = doe - ( 365 * yoe + yoe / 4 - yoe /100);
43 let mp: u64 = (5 * doy + 2) / 153;
44 let d: u64 = doy - (153*mp+2)/5 + 1;
45 let m: u64 = if mp < 10 { mp + 3 } else { mp - 9 };
46
47 if m <= 2 {
48 y+=1;
49 }
50 (y, m, d)
51
52}
53
54pub fn date_from_duration(d: Duration) -> Date {
55
56 let ms = d.subsec_millis();
57
58 let seconds = d.as_secs();
59
60 date_from_timestamp(seconds as i64, ms)
61
62}
63pub fn date_from_timestamp(ts: i64, millis: u32) -> Date {
64
65 let mut seconds = ts;
66 let days = ts.div_euclid(86400);
67 let today = days * 86400;
68
69 seconds -= today;
70
71 if seconds < 0 {
72 seconds = 86400 + seconds;
73 }
74
75 let mut seconds_u64 = seconds as u64;
76
77 let hour = seconds_u64 / 3600;
78 seconds_u64 -= hour * 3600;
79
80 let min = seconds_u64 / 60;
81 seconds_u64 -= min * 60;
82
83 let sec = seconds_u64;
84
85
86 let (year, month, day) = civil_from_days(days);
87 (year, month, day, hour, min, sec, millis)
88
89}
90
91pub fn date_now(utc_offset: i64) -> Date {
108 let mut now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).expect("could not get system time since unix epoch");
109
110 if utc_offset < 0 {
111 let offset = utc_offset.abs() as u64;
112 now = now.saturating_sub(Duration::new(offset*60*60, 0));
113 } else if utc_offset > 0 {
114 now = now.saturating_add(Duration::new(utc_offset as u64 *60*60, 0));
115 }
116 date_from_duration(now)
117
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_days_from_civil() {
126 let r = days_from_civil(1970, 1, 1);
127 assert_eq!(r, 0);
128
129 let r = days_from_civil(1971, 1, 1);
130 assert_eq!(r, 365);
131
132 let r = days_from_civil(1969, 1, 1);
133 assert_eq!(r, -365);
134 }
135
136 #[test]
137 fn test_civil_from_days() {
138 let r = civil_from_days(0);
139 assert_eq!(r, (1970, 1, 1));
140 }
141
142 #[test]
143 fn test_date_from_timestamp() {
144
145
146 let ts = 939945600;
147 let r = date_from_timestamp(ts, 0);
148 assert_eq!(r, (1999, 10, 15, 0, 0, 0, 0));
149 let ts = -14182940;
150 let r = date_from_timestamp(ts, 0);
151 assert_eq!(r, (1969, 7, 20, 20, 17, 40, 0));
152
153 let r = date_now(2);
154 println!("Now Utc(+2): {}/{:0>2}/{:0>2} {:0>2}:{:0>2}:{:0>2}.{:0>3}", r.0, r.1, r.2, r.3, r.4, r.5, r.6);
155
156 let r = date_now(-8);
157 println!("Now Utc(-8): {}/{:0>2}/{:0>2} {:0>2}:{:0>2}:{:0>2}.{:0>3}", r.0, r.1, r.2, r.3, r.4, r.5, r.6);
158 }
159}