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
}
}
}