Skip to main content

deep_time/dt/
ops.rs

1use crate::{Dt, TSpan};
2use core::cmp::Ordering;
3use core::ops::{Add, AddAssign, Sub, SubAssign};
4
5impl Add<TSpan> for Dt {
6    type Output = Self;
7
8    #[inline]
9    fn add(self, rhs: TSpan) -> Self {
10        self.add(rhs)
11    }
12}
13
14impl AddAssign<TSpan> for Dt {
15    #[inline]
16    fn add_assign(&mut self, rhs: TSpan) {
17        *self = self.add(rhs);
18    }
19}
20
21impl Sub<TSpan> for Dt {
22    type Output = Self;
23
24    #[inline]
25    fn sub(self, rhs: TSpan) -> Self {
26        self.sub(rhs)
27    }
28}
29
30impl SubAssign<TSpan> for Dt {
31    #[inline]
32    fn sub_assign(&mut self, rhs: TSpan) {
33        *self = self.sub(rhs);
34    }
35}
36
37impl Sub<Dt> for Dt {
38    type Output = TSpan;
39
40    #[inline]
41    fn sub(self, rhs: Dt) -> TSpan {
42        self.to_tai_since(rhs)
43    }
44}
45
46impl Dt {
47    /// Compares this `Dt` with another by converting both to the TAI timescale
48    /// (the library's canonical physical-time reference) and then comparing their
49    /// `(sec, attos)` pairs.
50    ///
51    /// This is a `const fn` so it can be used in const contexts and is allocation-free.
52    /// It provides the total order used by `<`, `>`, `<=`, `>=`, `cmp`, etc.
53    ///
54    /// Two `Dt`s that represent the exact same physical instant (after all
55    /// leap-second, relativistic, and scale conversions) compare as `Equal`, even if
56    /// they were constructed with different [`Scale`]s.
57    pub const fn cmp(self, other: Self) -> Ordering {
58        if self.sec < other.sec {
59            Ordering::Less
60        } else if self.sec > other.sec {
61            Ordering::Greater
62        } else if self.attos < other.attos {
63            Ordering::Less
64        } else if self.attos > other.attos {
65            Ordering::Greater
66        } else {
67            Ordering::Equal
68        }
69    }
70
71    /// Returns the smaller of two `Dt`s according to the total physical-time order
72    /// defined by [`Self::cmp`].
73    ///
74    /// Both instants are converted to TAI internally, so the result is the physically
75    /// earlier instant even when the two `Dt`s belong to different [`Scale`]s
76    /// (leap seconds, relativistic offsets, etc. are all taken into account).
77    ///
78    /// This is a `const fn` and can be used in const contexts.
79    #[inline]
80    pub const fn min(self, other: Self) -> Self {
81        match self.cmp(other) {
82            Ordering::Greater => other,
83            _ => self,
84        }
85    }
86
87    /// Returns the larger of two `Dt`s according to the total physical-time order
88    /// defined by [`Self::cmp`].
89    ///
90    /// See [`Self::min`] for more details.
91    #[inline]
92    pub const fn max(self, other: Self) -> Self {
93        match self.cmp(other) {
94            Ordering::Less => other,
95            _ => self,
96        }
97    }
98
99    #[inline]
100    pub const fn eq(&self, other: &Self) -> bool {
101        match Dt::cmp(*self, *other) {
102            Ordering::Equal => true,
103            _ => false,
104        }
105    }
106}
107
108impl PartialEq for Dt {
109    #[inline]
110    fn eq(&self, other: &Self) -> bool {
111        Dt::eq(self, other)
112    }
113}
114
115impl Eq for Dt {}
116
117impl PartialOrd for Dt {
118    #[inline]
119    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
120        Some(Dt::cmp(*self, *other))
121    }
122}
123
124impl Ord for Dt {
125    #[inline]
126    fn cmp(&self, other: &Self) -> Ordering {
127        Dt::cmp(*self, *other)
128    }
129}
130
131impl core::hash::Hash for Dt {
132    /// Hashes the canonical TAI representation so that two `Dt`s that are
133    /// physically equal (after conversion) produce the same hash, regardless of
134    /// the original [`Scale`].
135    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
136        self.sec.hash(state);
137        self.attos.hash(state);
138    }
139}