Skip to main content

deep_time/dt/
arithmetic.rs

1use crate::{
2    ATTOS_PER_FS, ATTOS_PER_MS, ATTOS_PER_NS, ATTOS_PER_PS, ATTOS_PER_SEC_I128, ATTOS_PER_SECF,
3    ATTOS_PER_US, ClockDrift, Dt, LocalSpacetime, Real, TSpan,
4};
5
6impl Dt {
7    #[inline]
8    pub const fn add(self, span: TSpan) -> Self {
9        let (sec, attos) = TSpan::add_time(self.sec, self.attos, span.sec, span.attos);
10        Self { sec, attos }
11    }
12
13    #[inline]
14    pub const fn sub(self, span: TSpan) -> Self {
15        let (sec, attos) = TSpan::sub_time(self.sec, self.attos, span.sec, span.attos);
16        Self { sec, attos }
17    }
18
19    /// Converts this `Dt` to a floating-point number of seconds since the reference epoch of its associated scale.
20    ///
21    /// The conversion is lossy by design, as `f64` (`Real`) provides approximately 15.95 decimal digits of precision.
22    /// For full exactness, use the integer components `sec` and `attos` directly or higher-precision arithmetic when available.
23    #[inline]
24    pub const fn to_sec_f(self) -> Real {
25        f!(self.sec) + f!(self.attos) / ATTOS_PER_SECF
26    }
27
28    /// Advances this `Dt` by the given elapsed duration while applying the relativistic proper-time correction
29    /// derived from the supplied `LocalSpacetime` model.
30    ///
31    /// This method is intended for simulation of remote clocks (e.g., Earth time as observed from a spacecraft).
32    /// For the spacecraft's own hardware proper-time clock, use the plain `add` method instead.
33    #[inline]
34    pub const fn adjusted_advance(&mut self, elapsed: &TSpan, local_spacetime: &LocalSpacetime) {
35        let dtau =
36            elapsed.add(ClockDrift::from_local_spacetime(local_spacetime).time_diff_after(elapsed));
37        *self = self.add(dtau);
38    }
39
40    /// Advances this `Dt` by the given elapsed duration while applying the relativistic proper-time correction
41    /// from a pre-computed `ClockDrift` value.
42    ///
43    /// This is an optimized variant of `adjusted_advance` for callers that already hold a `ClockDrift` instance.
44    /// It is intended for simulation of remote clocks; the spacecraft's own hardware clock should use the plain `add` method.
45    #[inline]
46    pub const fn adjusted_advance_using_drift(&mut self, elapsed: &TSpan, drift: &ClockDrift) {
47        let dtau = elapsed.add(drift.time_diff_after(elapsed));
48        *self = self.add(dtau);
49    }
50
51    /// Computes the TAI signed duration between this `Dt` and an earlier instant.
52    #[inline]
53    pub const fn to_tai_since(&self, earlier: Self) -> TSpan {
54        TSpan::diff_raw(self.sec, self.attos, earlier.sec, earlier.attos)
55    }
56
57    /// This method is lossy by design and is provided for testing and debugging purposes only.
58    /// For the exact duration, use `duration_since` or `duration_since_ref`.
59    #[inline]
60    pub const fn to_tai_since_f(&self, other: Self) -> Real {
61        self.to_sec_f() - other.to_sec_f()
62    }
63
64    /// Adds exactly 1 second to this time value using saturating arithmetic.
65    #[inline]
66    pub const fn add_1sec(&mut self) {
67        self.sec = self.sec.saturating_add(1);
68    }
69
70    /// Adds exactly 1 minute (60 seconds) to this time value using saturating arithmetic.
71    #[inline]
72    pub const fn add_1min(&mut self) {
73        self.sec = self.sec.saturating_add(60);
74    }
75
76    /// Adds exactly 1 hour (3600 seconds) to this time value using saturating arithmetic.
77    #[inline]
78    pub const fn add_1hr(&mut self) {
79        self.sec = self.sec.saturating_add(3600);
80    }
81
82    /// Adds exactly 1 millisecond to this time value.
83    ///
84    /// This affects the subsecond component and may cause a carry into the seconds field.
85    #[inline]
86    pub const fn add_1ms(&mut self) {
87        TSpan::add_attos_to(&mut self.sec, &mut self.attos, ATTOS_PER_MS);
88    }
89
90    /// Adds exactly 1 microsecond to this time value.
91    ///
92    /// This affects the subsecond component and may cause a carry into the seconds field.
93    #[inline]
94    pub const fn add_1us(&mut self) {
95        TSpan::add_attos_to(&mut self.sec, &mut self.attos, ATTOS_PER_US);
96    }
97
98    /// Adds exactly 1 nanosecond to this time value.
99    ///
100    /// This affects the subsecond component and may cause a carry into the seconds field.
101    #[inline]
102    pub const fn add_1ns(&mut self) {
103        TSpan::add_attos_to(&mut self.sec, &mut self.attos, ATTOS_PER_NS);
104    }
105
106    /// Adds the specified number of seconds to this time value using saturating arithmetic.
107    #[inline]
108    pub const fn add_sec(&mut self, n: i64) {
109        self.sec = self.sec.saturating_add(n);
110    }
111
112    /// Adds the specified number of minutes to this time value using saturating arithmetic.
113    #[inline]
114    pub const fn add_min(&mut self, n: i64) {
115        self.sec = self.sec.saturating_add(n.saturating_mul(60));
116    }
117
118    /// Adds the specified number of hours to this time value using saturating arithmetic.
119    #[inline]
120    pub const fn add_hr(&mut self, n: i64) {
121        self.sec = self.sec.saturating_add(n.saturating_mul(3600));
122    }
123
124    /// Adds the specified number of milliseconds to this time value.
125    ///
126    /// Handles carry into the seconds field using saturating logic.
127    #[inline]
128    pub const fn add_ms(&mut self, n: i64) {
129        TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_MS);
130    }
131
132    /// Adds the specified number of microseconds to this time value.
133    ///
134    /// Handles carry into the seconds field using saturating logic.
135    #[inline]
136    pub const fn add_us(&mut self, n: i64) {
137        TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_US);
138    }
139
140    /// Adds the specified number of nanoseconds to this time value.
141    ///
142    /// Handles carry into the seconds field using saturating logic.
143    #[inline]
144    pub const fn add_ns(&mut self, n: i64) {
145        TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_NS);
146    }
147
148    /// Adds the specified number of picoseconds to this time value.
149    ///
150    /// Handles carry into the seconds field using saturating logic.
151    #[inline]
152    pub const fn add_ps(&mut self, n: i64) {
153        TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_PS);
154    }
155
156    /// Adds the specified number of femtoseconds to this time value.
157    ///
158    /// Handles carry into the seconds field using saturating logic.
159    #[inline]
160    pub const fn add_fs(&mut self, n: i64) {
161        TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_FS);
162    }
163
164    /// Adds the specified number of attoseconds to this time value.
165    ///
166    /// Handles carry into the seconds field using saturating logic.
167    #[inline]
168    pub const fn add_attos(&mut self, n: i64) {
169        TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, 1);
170    }
171
172    // =====================================================================
173    // Single-unit subtraction methods (convenience methods for -1)
174    // =====================================================================
175
176    /// Subtracts exactly 1 hour (3600 seconds) from this time value using saturating arithmetic.
177    #[inline]
178    pub const fn sub_1hr(&mut self) {
179        self.sec = self.sec.saturating_sub(3600);
180    }
181
182    /// Subtracts exactly 1 minute (60 seconds) from this time value using saturating arithmetic.
183    #[inline]
184    pub const fn sub_1min(&mut self) {
185        self.sec = self.sec.saturating_sub(60);
186    }
187
188    /// Subtracts exactly 1 second from this time value using saturating arithmetic.
189    #[inline]
190    pub const fn sub_1sec(&mut self) {
191        self.sec = self.sec.saturating_sub(1);
192    }
193
194    /// Subtracts exactly 1 millisecond from this time value.
195    ///
196    /// This affects the subsecond component and may cause a borrow from the seconds field.
197    #[inline]
198    pub const fn sub_1ms(&mut self) {
199        TSpan::add_attos_span(&mut self.sec, &mut self.attos, -1, ATTOS_PER_MS);
200    }
201
202    /// Subtracts exactly 1 microsecond from this time value.
203    ///
204    /// This affects the subsecond component and may cause a borrow from the seconds field.
205    #[inline]
206    pub const fn sub_1us(&mut self) {
207        TSpan::add_attos_span(&mut self.sec, &mut self.attos, -1, ATTOS_PER_US);
208    }
209
210    /// Subtracts exactly 1 nanosecond from this time value.
211    ///
212    /// This affects the subsecond component and may cause a borrow from the seconds field.
213    #[inline]
214    pub const fn sub_1ns(&mut self) {
215        TSpan::add_attos_span(&mut self.sec, &mut self.attos, -1, ATTOS_PER_NS);
216    }
217
218    /// Subtracts the specified number of seconds from this time value using saturating arithmetic.
219    #[inline]
220    pub const fn sub_sec(&mut self, n: i64) {
221        self.sec = self.sec.saturating_sub(n);
222    }
223
224    /// Subtracts the specified number of minutes from this time value using saturating arithmetic.
225    #[inline]
226    pub const fn sub_min(&mut self, n: i64) {
227        self.sec = self.sec.saturating_sub(n.saturating_mul(60));
228    }
229
230    /// Subtracts the specified number of hours from this time value using saturating arithmetic.
231    #[inline]
232    pub const fn sub_hr(&mut self, n: i64) {
233        self.sec = self.sec.saturating_sub(n.saturating_mul(3600));
234    }
235
236    /// Subtracts the specified number of milliseconds from this time value.
237    ///
238    /// Handles borrow from the seconds field using saturating logic.
239    #[inline]
240    pub const fn sub_ms(&mut self, n: i64) {
241        TSpan::add_attos_span(
242            &mut self.sec,
243            &mut self.attos,
244            n.saturating_neg(),
245            ATTOS_PER_MS,
246        );
247    }
248
249    /// Subtracts the specified number of microseconds from this time value.
250    ///
251    /// Handles borrow from the seconds field using saturating logic.
252    #[inline]
253    pub const fn sub_us(&mut self, n: i64) {
254        TSpan::add_attos_span(
255            &mut self.sec,
256            &mut self.attos,
257            n.saturating_neg(),
258            ATTOS_PER_US,
259        );
260    }
261
262    /// Subtracts the specified number of nanoseconds from this time value.
263    ///
264    /// Handles borrow from the seconds field using saturating logic.
265    #[inline]
266    pub const fn sub_ns(&mut self, n: i64) {
267        TSpan::add_attos_span(
268            &mut self.sec,
269            &mut self.attos,
270            n.saturating_neg(),
271            ATTOS_PER_NS,
272        );
273    }
274
275    /// Subtracts the specified number of picoseconds from this time value.
276    ///
277    /// Handles borrow from the seconds field using saturating logic.
278    #[inline]
279    pub const fn sub_ps(&mut self, n: i64) {
280        TSpan::add_attos_span(
281            &mut self.sec,
282            &mut self.attos,
283            n.saturating_neg(),
284            ATTOS_PER_PS,
285        );
286    }
287
288    /// Subtracts the specified number of femtoseconds from this time value.
289    ///
290    /// Handles borrow from the seconds field using saturating logic.
291    #[inline]
292    pub const fn sub_fs(&mut self, n: i64) {
293        TSpan::add_attos_span(
294            &mut self.sec,
295            &mut self.attos,
296            n.saturating_neg(),
297            ATTOS_PER_FS,
298        );
299    }
300
301    /// Subtracts the specified number of attoseconds from this time value.
302    ///
303    /// Handles borrow from the seconds field using saturating logic.
304    #[inline]
305    pub const fn sub_attos(&mut self, n: i64) {
306        TSpan::add_attos_span(&mut self.sec, &mut self.attos, n.saturating_neg(), 1);
307    }
308
309    /// Total attoseconds (exact i128 representation within the representable range).
310    #[inline]
311    pub const fn to_attos(self) -> i128 {
312        (self.sec as i128) * ATTOS_PER_SEC_I128 + (self.attos as i128)
313    }
314
315    /// Returns the total duration in milliseconds.
316    #[inline]
317    pub const fn to_ms(self) -> i128 {
318        self.to_attos() / (ATTOS_PER_MS as i128)
319    }
320
321    /// Returns the total duration in microseconds.
322    #[inline]
323    pub const fn to_us(self) -> i128 {
324        self.to_attos() / (ATTOS_PER_US as i128)
325    }
326
327    /// Returns the total duration in nanoseconds.
328    #[inline]
329    pub const fn to_ns(self) -> i128 {
330        self.to_attos() / (ATTOS_PER_NS as i128)
331    }
332
333    /// Returns the total duration in picoseconds.
334    #[inline]
335    pub const fn to_ps(self) -> i128 {
336        self.to_attos() / (ATTOS_PER_PS as i128)
337    }
338
339    /// Returns the total duration in femtoseconds.
340    #[inline]
341    pub const fn to_fs(self) -> i128 {
342        self.to_attos() / (ATTOS_PER_FS as i128)
343    }
344}