pub mod coordinates;
pub mod moon;
pub mod planets;
pub mod seasons;
pub mod sun;
pub mod time_utils;
pub mod units;
use chrono::{DateTime, Datelike, TimeZone, Timelike};
use units::{Latitude, Longitude};
pub use units::{Altitude, Azimuth, DEG_TO_RAD, Degrees, RAD_TO_DEG, Radians};
#[derive(Debug, Clone, Copy)]
pub struct Location {
pub latitude: Latitude,
pub longitude: Longitude,
}
impl Location {
pub fn new(lat: f64, lon: f64) -> Result<Self, String> {
Ok(Self {
latitude: Latitude::new(lat)?,
longitude: Longitude::new(lon)?,
})
}
pub fn new_unchecked(lat: f64, lon: f64) -> Self {
Self {
latitude: Latitude::new_unchecked(lat),
longitude: Longitude::new_unchecked(lon),
}
}
pub fn lat_degrees(&self) -> f64 {
self.latitude.value()
}
pub fn lon_degrees(&self) -> f64 {
self.longitude.value()
}
}
#[must_use]
pub fn julian_day<T: TimeZone>(dt: &DateTime<T>) -> f64 {
let utc_dt = dt.with_timezone(&chrono::Utc);
let year = utc_dt.year() as f64;
let month = utc_dt.month() as f64;
let day = utc_dt.day() as f64
+ utc_dt.hour() as f64 / 24.0
+ utc_dt.minute() as f64 / 1440.0
+ utc_dt.second() as f64 / 86400.0;
let mut y = year;
let mut m = month;
if month <= 2.0 {
y -= 1.0;
m += 12.0;
}
let a = (y / 100.0).floor();
let b = 2.0 - a + (a / 4.0).floor();
(365.25 * (y + 4716.0)).floor() + (30.6001 * (m + 1.0)).floor() + day + b - 1524.5
}
#[must_use]
pub fn julian_century(jd: f64) -> f64 {
(jd - 2451545.0) / 36525.0
}
#[must_use]
pub fn normalize_degrees(angle: f64) -> f64 {
Degrees::new(angle).normalized().value()
}
#[must_use]
pub fn normalize_degrees_signed(angle: f64) -> f64 {
Degrees::new(angle).normalized_signed().value()
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Utc;
#[test]
fn test_julian_day() {
let dt = Utc.with_ymd_and_hms(2000, 1, 1, 12, 0, 0).unwrap();
let jd = julian_day(&dt);
assert!((jd - 2451545.0).abs() < 0.001);
}
#[test]
fn test_normalize_degrees() {
assert_eq!(normalize_degrees(370.0), 10.0);
assert_eq!(normalize_degrees(-10.0), 350.0);
assert_eq!(normalize_degrees(0.0), 0.0);
}
}