1mod helper_traits;
2pub use self::helper_traits::{RefHelper as SolarRefHelper, SolarRef};
3use crate::{
4 lunar::LunarRefHelper,
5 util::lunar_util::{LunarUtil, ZHI},
6};
7use chrono::{Datelike, Local, NaiveDateTime, Timelike};
8use once_cell::sync::Lazy;
9use std::{
10 collections::HashMap,
11 sync::{Arc, Mutex},
12 thread::{self},
13};
14
15pub fn from_ymdhms(
17 year: i64,
18 month: i64,
19 day: i64,
20 hour: i64,
21 minute: i64,
22 second: i64,
23) -> SolarRef {
24 Solar::__new(year, month, day, hour, minute, second, None)
25}
26
27#[allow(non_snake_case)]
28pub fn J2000() -> i64 {
29 __J2000
30}
31
32pub fn from_date(date: NaiveDateTime) -> SolarRef {
33 Solar::__new(
34 date.year() as i64,
35 date.month() as i64,
36 (date.day0() + 1) as i64,
37 date.hour() as i64,
38 date.minute() as i64,
39 date.second() as i64,
40 None,
41 )
42}
43
44pub fn from_julian_day(julian_day: f64) -> SolarRef {
48 let mut d = (julian_day + 0.5).floor();
49 let mut f = (julian_day + 0.5) - d;
50 if d >= 2299161. {
51 let c = ((d - 1867216.25) / 36524.25).floor();
52 d = d + 1. + c - (c / 4.0).floor();
53 }
54 d = d + 1524.;
55 let mut year = ((d - 122.1) / 365.25).floor();
56 d = d - (365.25 * year).floor();
57 let mut month = (d / 30.601).floor();
58 d = d - (30.601 * month).floor();
59
60 let mut day = d;
61 if month > 13. {
62 month = month - 13.;
63 year = year - 4715.;
64 } else {
65 month = month - 1.;
66 year = year - 4716.;
67 }
68 f = f * 24.;
69 let mut hour = f.floor();
70
71 f = f - hour;
72 f = f * 60.;
73 let mut minute = f.floor();
74
75 f = f - minute;
76 f = f * 60.;
77 let mut second = f.round().floor();
78 if second > 59. {
79 second = second - 60.;
80 minute = minute + 1.;
81 }
82 if minute > 59. {
83 minute = minute - 60.;
84 hour = hour + 1.;
85 }
86 if hour > 23. {
87 hour = hour - 24.;
88 day = day + 1.;
89 }
90
91 let s = Solar::__new(
92 year as i64,
93 month as i64,
94 day as i64,
95 hour as i64,
96 minute as i64,
97 second as i64,
98 Some(julian_day),
99 );
100 s
101}
102
103pub fn from_ymd(year: i64, month: i64, day: i64) -> SolarRef {
104 Solar::__new(year, month, day, 0, 0, 0, None)
105}
106
107pub fn from_bazi(
108 year_gan_zhi: &str,
109 month_gan_zhi: &str,
110 day_gan_zhi: &str,
111 time_gan_zhi: &str,
112 sect: Option<i64>,
113 base_year: Option<i64>,
114) -> Vec<SolarRef> {
115 let sect = (match sect.unwrap_or(2) {
118 1 => 1,
119 _ => 2,
120 }) as i64;
121 let base_year = base_year.unwrap_or(1900);
122 let mut years: Vec<i64> = vec![];
123 let today = from_date({
124 let date = Local::now().date_naive();
125 let time = Local::now().time();
126 date.and_time(time)
127 });
128
129 let mut offset_year = LunarUtil::get_jia_zi_index(
133 &today.get_lunar().get_year_in_gan_zhi_exact(),
134 ) - LunarUtil::get_jia_zi_index(year_gan_zhi);
135
136 if offset_year < 0 {
139 offset_year = offset_year + 60;
140 }
141 let mut start_year = today.get_year() - offset_year - 1;
142 let min_year = base_year - 2;
143 while start_year >= min_year {
144 years.push(start_year);
145 start_year = start_year - 60;
146 }
147
148 let mut hours: Vec<i64> = vec![];
151 let time_zhi = LunarUtil::split_ganzhi(time_gan_zhi).1;
152 for (i, zhi) in ZHI().iter().enumerate() {
153 if *zhi == time_zhi {
154 hours.push((i - 1) as i64 * 2);
155 break;
156 }
157 }
158 if "子" == &time_zhi {
159 hours.push(23);
160 }
161
162 #[derive(Debug, Clone)]
164 struct Zipped {
165 solar: SolarRef,
166 year_gan_zhi: String,
167 month_gan_zhi: String,
168 day_gan_zhi: String,
169 time_gan_zhi: String,
170 sect: i64,
171 }
172
173 let handle_zipped = |item: Zipped| {
174 let mut collected = vec![];
175 let lunar = item.solar.get_lunar();
176 let dgz = match item.sect == 2 {
177 true => lunar.get_day_in_gan_zhi_exact2(),
178 _ => lunar.get_day_in_gan_zhi_exact(),
179 };
180 if lunar.get_year_in_gan_zhi_exact() == item.year_gan_zhi
181 && lunar.get_month_in_gan_zhi_exact() == item.month_gan_zhi
182 && dgz == item.day_gan_zhi
183 && lunar.get_time_in_gan_zhi() == item.time_gan_zhi
184 {
185 collected.push(item.solar.clone());
186 }
187 collected
188 };
189
190 let mut zippeds = vec![];
191 for hour in hours {
192 for y in years.clone() {
193 let max_year = y + 3;
194 let mut year = y;
195 let mut month = 11 as i64;
196 if year < base_year {
197 year = base_year;
198 month = 1;
199 }
200 let mut solar = Solar::__new(year, month, 1, hour, 0, 0, None);
201
202 while solar.get_year() <= max_year {
203 zippeds.push(Zipped {
204 solar: solar.clone(),
205 year_gan_zhi: year_gan_zhi.to_string(),
206 month_gan_zhi: month_gan_zhi.to_string(),
207 day_gan_zhi: day_gan_zhi.to_string(),
208 time_gan_zhi: time_gan_zhi.to_string(),
209 sect: sect.clone(),
210 });
211 solar = solar.next(1, None);
212 }
213 }
214 }
215
216 let zipped_chunks =
217 zippeds.chunks(10).map(|z| z.to_vec()).collect::<Vec<_>>();
218 let mut join_handles = vec![];
219 for (_i, zipped_chunk) in zipped_chunks.into_iter().enumerate() {
220 let zipped_chunk = zipped_chunk.clone();
221 let join_handle = thread::spawn(move || {
222 let mut collected = vec![];
223 for zipped in zipped_chunk {
224 collected.push(handle_zipped(zipped.clone()));
225 }
226 collected.into_iter().flatten().collect::<Vec<_>>()
227 });
228 join_handles.push(join_handle);
229 }
230 let _total_handles = join_handles.len();
231 let mut solar_vecs = vec![];
232 for (_i, join_handle) in join_handles.into_iter().enumerate() {
233 solar_vecs.push(join_handle.join().unwrap());
234 }
235 solar_vecs.into_iter().flatten().collect::<Vec<_>>()
236}
237
238#[derive(Clone, Debug)]
239pub struct Solar {
240 __year: i64,
241 __month: i64,
242 __day: i64,
243 __hour: i64,
244 __minute: i64,
245 __second: i64,
246 __julian_day: Option<f64>,
247}
248
249impl Solar {
250 fn __cache() -> Arc<Mutex<HashMap<String, SolarRef>>> {
251 static __SOLAR_CACHE: Lazy<Arc<Mutex<HashMap<String, SolarRef>>>> =
252 Lazy::new(|| Arc::new(Mutex::new(HashMap::new())));
253 __SOLAR_CACHE.clone()
254 }
255
256 fn __new(
257 year: i64,
258 month: i64,
259 day: i64,
260 hour: i64,
261 minute: i64,
262 second: i64,
263 julian_day: Option<f64>,
264 ) -> SolarRef {
265 let key = format!(
266 "{}-{}-{} {}:{}:{}",
267 year, month, day, hour, minute, second
268 );
269
270 {
271 let s = Self::__cache();
272 let s = s.lock().unwrap();
273 let s = s.get(&key);
274 if s.is_some() {
275 return s.unwrap().clone();
276 }
277 };
278
279 let s = Arc::new(Mutex::new(Self {
280 __year: year,
281 __month: month,
282 __day: day,
283 __hour: hour,
284 __minute: minute,
285 __second: second,
286 __julian_day: julian_day,
287 }));
288
289 {
290 Self::__cache().lock().unwrap().insert(key, s.clone());
291 }
292
293 if julian_day.is_none() {
294 s.get_julian_day();
295 }
296
297 s
298 }
299}
300
301const __J2000: i64 = 2451545;