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}