earths 0.0.1

High-fidelity Earth simulation engine — orbit, atmosphere, geology, hydrology, biosphere, terrain, lighting, rendering, satellites, and temporal systems with full scientific coupling
Documentation
pub use super::epoch::J2000_EPOCH as J2000_JD;
pub const UNIX_EPOCH_JD: f64 = 2440587.5;
pub const SECONDS_PER_DAY: f64 = 86400.0;
#[derive(Debug, Clone, Copy)]
pub struct DateTime {
    pub year: i32,
    pub month: u8,
    pub day: u8,
    pub hour: u8,
    pub minute: u8,
    pub second: f64,
}
impl DateTime {
    pub fn new(year: i32, month: u8, day: u8, hour: u8, minute: u8, second: f64) -> Self {
        Self {
            year,
            month,
            day,
            hour,
            minute,
            second,
        }
    }
    pub fn to_julian_date(&self) -> f64 {
        let y = if self.month <= 2 {
            self.year - 1
        } else {
            self.year
        } as f64;
        let m = if self.month <= 2 {
            self.month as f64 + 12.0
        } else {
            self.month as f64
        };
        let d = self.day as f64
            + self.hour as f64 / 24.0
            + self.minute as f64 / 1440.0
            + self.second / SECONDS_PER_DAY;
        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() + d + b - 1524.5
    }
    pub fn from_julian_date(jd: f64) -> Self {
        let z = (jd + 0.5).floor();
        let f = jd + 0.5 - z;
        let a = if z < 2299161.0 {
            z
        } else {
            let alpha = ((z - 1867216.25) / 36524.25).floor();
            z + 1.0 + alpha - (alpha / 4.0).floor()
        };
        let b = a + 1524.0;
        let c = ((b - 122.1) / 365.25).floor();
        let d = (365.25 * c).floor();
        let e = ((b - d) / 30.6001).floor();
        let day = (b - d - (30.6001 * e).floor() + f) as u8;
        let month = if e < 14.0 { e - 1.0 } else { e - 13.0 } as u8;
        let year = if month > 2 { c - 4716.0 } else { c - 4715.0 } as i32;
        let day_frac = f * 24.0;
        let hour = day_frac as u8;
        let min_frac = (day_frac - hour as f64) * 60.0;
        let minute = min_frac as u8;
        let second = (min_frac - minute as f64) * 60.0;
        Self {
            year,
            month,
            day,
            hour,
            minute,
            second,
        }
    }
    pub fn to_unix_timestamp(&self) -> f64 {
        (self.to_julian_date() - UNIX_EPOCH_JD) * SECONDS_PER_DAY
    }
    pub fn from_unix_timestamp(ts: f64) -> Self {
        Self::from_julian_date(ts / SECONDS_PER_DAY + UNIX_EPOCH_JD)
    }
    pub fn delta_t_seconds(&self) -> f64 {
        let y = self.year as f64 + (self.month as f64 - 0.5) / 12.0;
        if y < 1900.0 {
            let u = (y - 1820.0) / 100.0;
            -20.0 + 32.0 * u * u
        } else if y < 1941.0 {
            let t = y - 1900.0;
            -0.02 + 0.297 * t + 0.025184 * t * t - 0.181333 * t * t * t * 1e-2
                + 0.553040 * t * t * t * t * 1e-4
                - 0.861938 * t * t * t * t * t * 1e-6
                + 0.677066 * t * t * t * t * t * t * 1e-8
                - 0.212591 * t * t * t * t * t * t * t * 1e-10
        } else if y < 1961.0 {
            let t = y - 1950.0;
            29.07 + 0.407 * t - t * t / 233.0 + t * t * t / 2547.0
        } else if y < 1986.0 {
            let t = y - 1975.0;
            45.45 + 1.067 * t - t * t / 260.0 - t * t * t / 718.0
        } else if y < 2005.0 {
            let t = y - 2000.0;
            63.86 + 0.3345 * t - 0.060374 * t * t
                + 0.0017275 * t * t * t
                + 0.000651814 * t * t * t * t
                + 0.00002373599 * t * t * t * t * t
        } else if y < 2050.0 {
            let t = y - 2000.0;
            62.92 + 0.32217 * t + 0.005589 * t * t
        } else {
            let u = (y - 1820.0) / 100.0;
            -20.0 + 32.0 * u * u - 0.5628 * (2150.0 - y)
        }
    }
    pub fn to_julian_date_tt(&self) -> f64 {
        self.to_julian_date() + self.delta_t_seconds() / SECONDS_PER_DAY
    }
    pub fn delta_t_uncertainty_seconds(&self) -> f64 {
        let y = self.year as f64 + (self.month as f64 - 0.5) / 12.0;
        if y < 1900.0 {
            let u = (y - 1820.0).abs() / 100.0;
            0.5 + 1.5 * u * u
        } else if y < 1986.0 {
            0.5
        } else if y <= 2025.0 {
            0.1
        } else if y <= 2050.0 {
            let t = y - 2025.0;
            0.1 + 0.016 * t
        } else {
            let u = (y - 2050.0) / 100.0;
            0.5 + 0.9 * u * u
        }
    }
}