lunar_rust/
solar.rs

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
15// 阳历日期
16pub 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
44///
45/// be very careful, this function is **VERY SENSITIVE**
46///
47pub 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 mut measurement = TimeElapsed::start_print("from_bazi 01");
116
117  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  // measurement.end_print_delta(true);
130
131  // ---------------------------
132  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  // measurement.end_print_delta(true);
137
138  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  // measurement.end_print_delta(true);
149
150  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  // measurement.end_print_delta(false);
163  #[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;