Skip to main content

tempoch_core/features/
time_instant.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 Vallés Puig, Ramon
3
4//! Feature-style extension traits for time-adjacent algorithms.
5
6use qtty::Day;
7
8use crate::format::{JulianDate, ModifiedJulianDate};
9use crate::format::{JD, MJD};
10use crate::model::scale::CoordinateScale;
11use crate::model::scale::TT;
12use crate::model::time::Time;
13use crate::InfallibleFormatForScale;
14use qtty::Second;
15
16/// Provides arithmetic on [`Time<S>`] values via seconds duration.
17///
18/// Used by root-finding algorithms that bisect over a time interval.
19pub trait TimeInstant: Copy + PartialOrd {
20    /// Duration type produced by subtracting two instants.
21    type Duration;
22
23    /// Signed duration from `other` to `self` (`self − other`).
24    fn difference(&self, other: &Self) -> Self::Duration;
25
26    /// Shift this instant forward by `duration`.
27    fn add_duration(&self, duration: Self::Duration) -> Self;
28}
29
30impl TimeInstant for Time<TT> {
31    type Duration = Second;
32
33    #[inline]
34    fn difference(&self, other: &Self) -> Second {
35        *self - *other
36    }
37
38    #[inline]
39    fn add_duration(&self, dur: Second) -> Self {
40        *self + dur
41    }
42}
43
44impl<S: CoordinateScale> TimeInstant for ModifiedJulianDate<S> {
45    type Duration = Day;
46
47    #[inline]
48    fn difference(&self, other: &Self) -> Day {
49        Day::new(self.raw().value() - other.raw().value())
50    }
51
52    #[inline]
53    fn add_duration(&self, duration: Day) -> Self {
54        MJD::into_time(Day::new(self.raw().value() + duration.value()))
55    }
56}
57
58impl<S: CoordinateScale> TimeInstant for JulianDate<S> {
59    type Duration = Day;
60
61    #[inline]
62    fn difference(&self, other: &Self) -> Day {
63        Day::new(self.raw().value() - other.raw().value())
64    }
65
66    #[inline]
67    fn add_duration(&self, duration: Day) -> Self {
68        JD::into_time(Day::new(self.raw().value() + duration.value()))
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use crate::format::{J2000Seconds, JulianDate, ModifiedJulianDate};
76    use crate::model::scale::TT;
77
78    #[test]
79    fn time_instant_trait_supports_time_and_encoded_dates() {
80        let tt = J2000Seconds::<TT>::new(10.0).to_j2000s();
81        let tt_later = tt.add_duration(Second::new(2.5));
82        assert_eq!(tt_later.difference(&tt), Second::new(2.5));
83
84        let mjd = ModifiedJulianDate::<TT>::new(60_000.0);
85        let mjd_later = mjd.add_duration(Day::new(1.25));
86        assert_eq!(mjd_later.difference(&mjd), Day::new(1.25));
87
88        let jd = JulianDate::<TT>::new(2_460_000.0);
89        let jd_later = jd.add_duration(Day::new(0.5));
90        assert_eq!(jd_later.difference(&jd), Day::new(0.5));
91    }
92}