1use earth_orbit::*;
2use moon_phase::*;
3use sun_transit::*;
4
5use alloc::string::String;
6#[cfg(not(feature = "std"))]
7use num_traits::Float;
8
9#[derive(Clone, Copy)]
10pub enum Epoch {
11 Gregorian,
12 Unix
13}
14
15#[derive(Clone, Copy)]
16pub enum Calendar {
17 Lunisolar,
18 Solar
19}
20
21static ZEROS: [i64; 6] = [
22 0, -410227200, -1009843200, -2208988800, -8551872000, -10950249600 ];
30
31pub fn get_formatted_date(format: &str, timestamp: i64, longitude: f64) -> String {
46 let mut res = String::from(format);
47 let now = timestamp;
48 let lon = longitude;
49
50 if format.contains("%x") {
51 res = res.replace("%x", &format!("{}", now));
52
53 if !format.contains("%") {
54 return res;
55 }
56 }
57
58 let epoch = if format.contains("%u") {
59 Epoch::Unix
60 } else {
61 Epoch::Gregorian
62 };
63
64 let calendar = if format.contains("%s") {
65 Calendar::Solar
66 } else {
67 Calendar::Lunisolar
68 };
69
70 let mut first_new_moon = 0;
71 let mut zero = 0;
72 for &e in &ZEROS {
73 first_new_moon = get_next_new_moon(e);
75 zero = get_midnight(first_new_moon, lon);
76 if zero < now {
77 break;
78 }
79 }
80 if now < zero {
81 panic!("too far back in time");
82 }
83
84 let mut new_year = get_next_december_solstice(zero);
85 let mut new_month = match calendar {
86 Calendar::Solar => get_next_march_equinox(zero),
87 Calendar::Lunisolar => get_next_new_moon(first_new_moon)
88 };
89
90 let mut midnight = get_midnight(now, lon);
91 if midnight > now {
92 midnight -= 86400;
93 } else if midnight <= now - 86400 {
94 midnight += 86400;
95 }
96
97 let mut d = 0;
98 let mut m = 0;
99 let mut y = 0;
100 let mut t = zero;
101 while t < midnight - 2000 { d += 1;
103 t += 86400;
104 if new_month < t + 86400 {
105 new_month = match calendar {
106 Calendar::Solar => {
107 match m {
108 0 => get_next_june_solstice(new_month),
109 1 => get_next_september_equinox(new_month),
110 2 => get_next_december_solstice(new_month),
111 3 => get_next_march_equinox(new_month),
112 _ => unreachable!()
113 }
114 },
115 Calendar::Lunisolar => {
116 get_next_new_moon(new_month)
117 }
118 };
119 d = 0;
120 m += 1;
121 if new_year < t + 86400 {
122 new_year = get_next_december_solstice(new_year);
123 m = 0;
124 y += 1;
125 }
126 }
127 }
128
129 let epoch_zero = match epoch {
130 Epoch::Unix => ZEROS[0],
131 Epoch::Gregorian => ZEROS[3]
132 };
133
134 y += ((zero - epoch_zero) as f64 / 86400.0 / 365.25).round() as i64;
135
136 if y < 0 {
137 y = y.abs();
138 if res.contains("%h") || res.contains("%y") || res.contains("%u") {
139 res.insert(0, '-');
140 }
141 }
142
143 if res.contains("%h") {
144 let h = y / 100;
145 res = res.replace("%h", &format!("{:02}", h));
146 }
147 y = y % 100;
148
149 res = res.replace("%u", &format!("{:02}", y));
150 res = res.replace("%y", &format!("{:02}", y));
151
152 res = res.replace("%m", &format!("{:02}", m));
153 res = res.replace("%s", &format!("{:02}", m));
154 res = res.replace("%d", &format!("{:02}", d));
155
156 let e = (10000 * (now - midnight)) / 86400;
157 let c = e / 100;
158 let b = e % 100;
159 res = res.replace("%c", &format!("{:02}", c));
160 res = res.replace("%b", &format!("{:02}", b));
161
162 res
163}
164
165pub fn get_date(timestamp: i64, longitude: f64) -> String {
167 get_formatted_date("%h:%y:%m:%d:%c:%b", timestamp, longitude)
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173 use utils::*;
174
175 #[test]
176 fn get_date_test() {
177 assert_eq!("01:14:05:24:15:42", get_date(1403322675, -1.826189));
178 }
179
180 #[test]
181 fn get_solar_date_test() {
182 let format = "%u:%s:%d:%c:%b";
183 assert_eq!("44:02:00:15:42", get_formatted_date(format, 1403322675, -1.826189));
185 }
186
187 #[test]
188 fn get_lunisolar_date_test() {
189 let format = "%u:%m:%d:%c:%b";
190 assert_eq!("00:00:00:00:00", get_formatted_date(format, parse_time("1970-01-07T00:06:15+00:00"), 0.0));
191 assert_eq!("00:11:29:99:99", get_formatted_date(format, parse_time("1970-12-28T00:01:20+00:00"), 0.0));
192 assert_eq!("01:00:00:00:00", get_formatted_date(format, parse_time("1970-12-28T00:01:30+00:00"), 0.0));
193 assert_eq!("06:00:00:00:00", get_formatted_date(format, parse_time("1976-01-01T00:03:20+00:00"), 0.0));
194 assert_eq!("14:03:03:71:59", get_formatted_date(format, 449947500, -2.7653));
195 assert_eq!("43:11:28:99:98", get_formatted_date(format, parse_time("2014-01-01T00:03:20+00:00"), 0.0));
196 assert_eq!("43:11:28:99:99", get_formatted_date(format, parse_time("2014-01-01T00:03:30+00:00"), 0.0));
197 assert_eq!("44:00:00:00:00", get_formatted_date(format, parse_time("2014-01-01T00:03:40+00:00"), 0.0));
198
199 let format = "%h:%u:%m:%d:%c:%b";
200 assert_eq!("00:63:00:00:00:00", get_formatted_date(format, parse_time("2033-01-01T00:03:45+00:00"), 0.0));
201 assert_eq!("01:01:00:00:00:00", get_formatted_date(format, parse_time("2071-01-01T00:03:30+00:00"), 0.0));
202 assert_eq!("01:50:00:00:00:00", get_formatted_date(format, parse_time("2120-01-01T00:03:00+00:00"), 0.0));
203 assert_eq!("02:15:00:00:00:00", get_formatted_date(format, parse_time("2185-01-01T00:03:30+00:00"), 0.0));
204 assert_eq!("03:40:00:00:00:00", get_formatted_date(format, parse_time("2310-01-01T00:02:30+00:00"), 0.0));
205 assert_eq!("05:30:00:00:00:00", get_formatted_date(format, parse_time("2500-01-01T00:02:30+00:00"), 0.0));
206
207 let format = "%u:%m:%d:%c:%b";
208 assert_eq!("63:00:00:00:00", get_formatted_date(format, parse_time("2033-01-01T00:03:45+00:00"), 0.0));
209 assert_eq!("01:00:00:00:00", get_formatted_date(format, parse_time("2071-01-01T00:03:30+00:00"), 0.0));
210 assert_eq!("50:00:00:00:00", get_formatted_date(format, parse_time("2120-01-01T00:03:00+00:00"), 0.0));
211 assert_eq!("15:00:00:00:00", get_formatted_date(format, parse_time("2185-01-01T00:03:30+00:00"), 0.0));
212 assert_eq!("40:00:00:00:00", get_formatted_date(format, parse_time("2310-01-01T00:02:30+00:00"), 0.0));
213 assert_eq!("30:00:00:00:00", get_formatted_date(format, parse_time("2500-01-01T00:02:30+00:00"), 0.0));
214
215 assert_eq!("46:02:10:49:46", get_formatted_date(format, parse_time("2016-03-19T12:00:00+00:00"), 0.0));
217 assert_eq!("46:02:11:80:04", get_formatted_date(format, parse_time("2016-03-20T08:00:00+00:00"), 170.0));
218 assert_eq!("30:04:28:99:99", get_formatted_date(format, parse_time("2000-06-01T17:57:50+00:00"), 90.0));
219 assert_eq!("30:05:00:00:00", get_formatted_date(format, parse_time("2000-06-01T17:58:00+00:00"), 90.0));
220
221 assert_eq!("00:11:29:99:99", get_formatted_date(format, parse_time("1970-12-28T00:08:40+00:00"), -1.8262));
223 assert_eq!("01:00:00:00:00", get_formatted_date(format, parse_time("1970-12-28T00:08:50+00:00"), -1.8262)); assert_eq!("01:00:01:49:35", get_formatted_date(format, parse_time("1970-12-29T12:00:00+00:00"), -1.8262)); assert_eq!("01:00:02:49:32", get_formatted_date(format, parse_time("1970-12-30T12:00:00+00:00"), -1.8262)); assert_eq!("01:00:03:99:28", get_formatted_date(format, parse_time("1970-12-31T23:59:59+00:00"), -1.8262)); assert_eq!("01:00:03:99:29", get_formatted_date(format, parse_time("1971-01-01T00:00:00+00:00"), -1.8262));
228
229 let format = "%h:%u:%m:%d:%c:%b";
231 assert_eq!("-00:01:11:22:99:75", get_formatted_date(format, 0, 0.0)); assert_eq!("-00:13:00:00:00:00", get_formatted_date(format, parse_time("1957-01-01T00:03:40+00:00"), 0.0));
233 assert_eq!("-00:70:00:00:00:00", get_formatted_date(format, parse_time("1900-01-01T00:03:40+00:00"), 0.0));
234 assert_eq!("-02:71:00:00:00:00", get_formatted_date(format, parse_time("1699-01-01T00:04:35+00:00"), 0.0));
235 assert_eq!("-03:28:00:00:00:00", get_formatted_date(format, parse_time("1642-01-01T00:04:40+00:00"), 0.0));
236 assert_eq!("-03:47:00:00:00:00", get_formatted_date(format, parse_time("1623-01-01T00:04:30+00:00"), 0.0));
237
238 let format = "%u:%m:%d:%c:%b";
239 assert_eq!("-01:11:22:99:75", get_formatted_date(format, 0, 0.0)); assert_eq!("-13:00:00:00:00", get_formatted_date(format, parse_time("1957-01-01T00:03:40+00:00"), 0.0));
241 assert_eq!("-70:00:00:00:00", get_formatted_date(format, parse_time("1900-01-01T00:03:40+00:00"), 0.0));
242 assert_eq!("-71:00:00:00:00", get_formatted_date(format, parse_time("1699-01-01T00:04:35+00:00"), 0.0));
243 assert_eq!("-28:00:00:00:00", get_formatted_date(format, parse_time("1642-01-01T00:04:40+00:00"), 0.0));
244 assert_eq!("-47:00:00:00:00", get_formatted_date(format, parse_time("1623-01-01T00:04:30+00:00"), 0.0));
245
246 assert_eq!("-30:11:28:99:99", get_formatted_date(format, parse_time("1940-12-28T00:01:39+00:00"), 0.0)); assert_eq!("-29:00:00:00:00", get_formatted_date(format, parse_time("1940-12-28T00:01:40+00:00"), 0.0)); assert_eq!("50:08:27:99:99", get_formatted_date(format, parse_time("2020-09-15T23:55:01+00:00"), 0.0));
252 assert_eq!("50:08:28:00:00", get_formatted_date(format, parse_time("2020-09-15T23:55:02+00:00"), 0.0));
253 assert_eq!("50:08:28:00:00", get_formatted_date(format, parse_time("2020-09-15T23:55:03+00:00"), 0.0));
254 }
255}