1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
use super::TimeSystem; use super::instant::{Era, Instant}; use super::{J1900_OFFSET, SECONDS_PER_DAY}; /// `ModifiedJulian` handles the Modified Julian Days as explained /// [here](http://tycho.usno.navy.mil/mjd.html). #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] pub struct ModifiedJulian { pub days: f64, } impl ModifiedJulian { /// `julian_days` returns the true Julian days from epoch 01 Jan -4713, 12:00 /// as explained in "Fundamentals of astrodynamics and applications", Vallado et al. /// 4th edition, page 182, and on [Wikipedia](https://en.wikipedia.org/wiki/Julian_day). pub fn julian_days(self) -> f64 { self.days + 2_400_000.5 } } impl TimeSystem for ModifiedJulian { /// `from_instant` converts an `Instant` to a ModifiedJulian as detailed in Vallado et al. /// 4th edition, page 182. /// /// [Leap second source](https://www.ietf.org/timezones/data/leap-seconds.list) contains /// information pertinent to the NTP time definition, whose epoch is twelve hours *ahead* of /// the Julian Day. Here is the relevant quote: /// > The NTP timestamps are in units of seconds since the NTP epoch, /// > which is 1 January 1900, 00:00:00. The Modified Julian Day number /// > corresponding to the NTP time stamp, X, can be computed as /// > /// > `X/86400 + 15020` /// > /// > where the first term converts seconds to days and the second /// > term adds the MJD corresponding to the time origin defined above. /// > The integer portion of the result is the integer MJD for that /// > day, and any remainder is the time of day, expressed as the /// > fraction of the day since 0 hours UTC. The conversion from day /// > fraction to seconds or to hours, minutes, and seconds may involve /// > rounding or truncation, depending on the method used in the /// > computation. fn from_instant(instant: Instant) -> ModifiedJulian { let modifier = if instant.era() == Era::Present { 1.0 } else { -1.0 }; ModifiedJulian { days: J1900_OFFSET + modifier * (instant.secs() as f64) / SECONDS_PER_DAY + f64::from(instant.nanos()) * 1e-9, } } /// `into_instant` returns an `Instant` from the ModifiedJulian. fn into_instant(self) -> Instant { let era: Era; let modifier = if self.days >= J1900_OFFSET { era = Era::Present; 1.0 } else { era = Era::Past; -1.0 }; let secs_frac = (self.days - J1900_OFFSET) * SECONDS_PER_DAY * modifier; let seconds = secs_frac.round(); let nanos = (secs_frac - seconds) * 1e9 / (SECONDS_PER_DAY * modifier); Instant::new(seconds as u64, nanos.round() as u32, era) } }