Skip to main content

tempoch_core/
ext.rs

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