moon_calc/
lib.rs

1use std::f64::consts::TAU;
2use std::time::SystemTime;
3
4mod consts;
5pub use consts::*;
6/// Calculates the Julian date of the moon based on the provided `SystemTime`.
7fn julian_date(time: SystemTime) -> f64 {
8    let unix_time: f64 = match time.duration_since(SystemTime::UNIX_EPOCH) {
9        Ok(duration) => duration.as_secs_f64(),
10        Err(earlier) => -1. * earlier.duration().as_secs_f64(),
11    };
12    unix_time / 86400. + 2440587.5
13}
14/// Calculates the illumination of the moon based on the given phase.
15fn illumination(phase: f64) -> f64 {
16    0.5 * (1.0 - (TAU * phase).cos())
17}
18
19/// Calculates the lunation (lunar month count) based on the provided Julian date.
20fn lunation(julian_date: f64) -> u16 {
21    (1. + (julian_date - LUNATION_BASE) / ORBIT_PERIOD).floor() as u16
22}
23
24/// Calculates the phase of the moon based on the provided Julian date.
25fn phase(julian_date: f64) -> f64 {
26    ((julian_date - ORBIT_OFFSET) / ORBIT_PERIOD).fract()
27}
28/// Calculates the distance phase of the moon based on the provided Julian date.
29fn distance_phase(julian_date: f64) -> f64 {
30    ((julian_date - DISTANCE_OFFSET) / DISTANCE_PERIOD).fract()
31}
32fn distance(phase: f64, julian_date: f64) -> f64 {
33    let distance_p = distance_phase(julian_date);
34    let distance_p_tau: f64 = TAU * distance_p;
35    let p_tau: f64 = 2.0 * TAU * phase;
36    let p_distance_tau_diff = p_tau - distance_p_tau;
37
38    60.4 - 3.3 * distance_p_tau.cos() - 0.6 * (p_distance_tau_diff).cos() - 0.5 * (p_tau).cos()
39}
40impl Moon {
41    pub fn new(time: SystemTime) -> Moon {
42        let julian_date: f64 = julian_date(time);
43        let phase: f64 = phase(julian_date);
44        let age: f64 = phase * ORBIT_PERIOD;
45        let illumination: f64 = illumination(phase);
46        let lunation: u16 = lunation(julian_date);
47        let distance: f64 = distance(phase, julian_date);
48
49        Moon {
50            julian_date,
51            age,
52            phase,
53            illumination,
54            distance,
55            lunation,
56        }
57    }
58
59    /// Returns the distance of the moon in kilometers.
60    pub fn distance_km(&self) -> f64 {
61        self.distance * EARTH_RADIUS_KM
62    }
63
64    /// Checks if the moon is in the waning phase.
65    pub fn is_waning(&self) -> bool {
66        self.age < 0.5
67    }
68    /// Checks if the moon is in the waxing phase.
69    pub fn is_waxing(&self) -> bool {
70        self.age > 0.5
71    }
72    /// Returns the name of the moon phase.
73    pub fn phase_name(&self) -> &'static str {
74        for phase in PHASES.iter() {
75            if self.phase >= phase.start && self.phase < phase.end {
76                return phase.name;
77            }
78        }
79        "Unknown"
80    }
81
82    /// Returns the emoji representation of the moon phase.
83    pub fn phase_emoji(&self) -> &'static str {
84        for phase in PHASES.iter() {
85            if self.phase >= phase.start && self.phase < phase.end {
86                return phase.emoji;
87            }
88        }
89        "Unknown"
90    }
91}