Skip to main content

deep_time/dt/
numbers_traits.rs

1//! Ergonomic time-unit constructors (optional import).
2//!
3//! ```
4//! use deep_time::{Scale, TraitsTime};
5//!
6//! let span = 5.sec() + 250.ms() + 123_456.ns();
7//! let stamp = 3.days().before_zero(Scale::UTC);
8//!
9//! // Wall-clock relative (requires the `std` feature):
10//! // let past = 3.days().ago();
11//! // let future = 3.days().from_now();
12//! ```
13
14use crate::{Dt, SEC_PER_DAY, SEC_PER_DAY_F, Scale};
15
16/// Trait that adds ergonomic attosecond conversions on integer values.
17///
18/// Covers both directions:
19/// - `attos_to_*` — total attoseconds → whole units (truncating division)
20/// - `*_to_attos` — whole units → total attoseconds (saturating multiply)
21///
22/// ## Examples
23///
24/// ```rust
25/// use deep_time::TraitsAttos;
26///
27/// let attos: i128 = -5_600_000_000_000_000_000;
28/// let seconds = attos.attos_to_sec();
29/// assert_eq!(seconds, -5);
30///
31/// assert_eq!(5_i128.ns_to_attos(), 5_000_000_000);
32/// assert_eq!(1_i128.ms_to_attos().attos_to_ms(), 1);
33/// ```
34pub trait TraitsAttos: Copy + Sized {
35    /// attoseconds → seconds (s)
36    fn attos_to_sec(self) -> i128;
37
38    /// attoseconds → milliseconds (ms)
39    fn attos_to_ms(self) -> i128;
40
41    /// attoseconds → microseconds (us)
42    fn attos_to_us(self) -> i128;
43
44    /// attoseconds → nanoseconds (ns)
45    fn attos_to_ns(self) -> i128;
46
47    /// attoseconds → picoseconds (ps)
48    fn attos_to_ps(self) -> i128;
49
50    /// attoseconds → femtoseconds (fs)
51    fn attos_to_fs(self) -> i128;
52
53    /// attoseconds → float seconds (s)
54    fn attos_to_sec_f(self) -> f64;
55
56    /// femtoseconds → attoseconds (`× 10³`)
57    fn fs_to_attos(self) -> i128;
58
59    /// picoseconds → attoseconds (`× 10⁶`)
60    fn ps_to_attos(self) -> i128;
61
62    /// nanoseconds → attoseconds (`× 10⁹`)
63    fn ns_to_attos(self) -> i128;
64
65    /// microseconds → attoseconds (`× 10¹²`)
66    fn us_to_attos(self) -> i128;
67
68    /// milliseconds → attoseconds (`× 10¹⁵`)
69    fn ms_to_attos(self) -> i128;
70
71    /// seconds → attoseconds (`× 10¹⁸`)
72    fn sec_to_attos(self) -> i128;
73
74    /// minutes → attoseconds (`× 60 × 10¹⁸`)
75    fn mins_to_attos(self) -> i128;
76
77    /// hours → attoseconds (`× 3600 × 10¹⁸`)
78    fn hours_to_attos(self) -> i128;
79}
80
81impl TraitsAttos for i128 {
82    #[inline]
83    fn attos_to_sec_f(self) -> f64 {
84        Dt::attos_to_sec_f(self)
85    }
86
87    #[inline]
88    fn attos_to_sec(self) -> i128 {
89        Dt::attos_to_sec(self)
90    }
91
92    #[inline]
93    fn attos_to_ms(self) -> i128 {
94        Dt::attos_to_ms(self)
95    }
96
97    #[inline]
98    fn attos_to_us(self) -> i128 {
99        Dt::attos_to_us(self)
100    }
101
102    #[inline]
103    fn attos_to_ns(self) -> i128 {
104        Dt::attos_to_ns(self)
105    }
106
107    #[inline]
108    fn attos_to_ps(self) -> i128 {
109        Dt::attos_to_ps(self)
110    }
111
112    #[inline]
113    fn attos_to_fs(self) -> i128 {
114        Dt::attos_to_fs(self)
115    }
116
117    #[inline]
118    fn fs_to_attos(self) -> i128 {
119        Dt::fs_to_attos(self)
120    }
121
122    #[inline]
123    fn ps_to_attos(self) -> i128 {
124        Dt::ps_to_attos(self)
125    }
126
127    #[inline]
128    fn ns_to_attos(self) -> i128 {
129        Dt::ns_to_attos(self)
130    }
131
132    #[inline]
133    fn us_to_attos(self) -> i128 {
134        Dt::us_to_attos(self)
135    }
136
137    #[inline]
138    fn ms_to_attos(self) -> i128 {
139        Dt::ms_to_attos(self)
140    }
141
142    #[inline]
143    fn sec_to_attos(self) -> i128 {
144        Dt::sec_to_attos(self)
145    }
146
147    #[inline]
148    fn mins_to_attos(self) -> i128 {
149        Dt::mins_to_attos(self)
150    }
151
152    #[inline]
153    fn hours_to_attos(self) -> i128 {
154        Dt::hours_to_attos(self)
155    }
156}
157
158/// Trait that adds ergonomic time-unit methods to integers and floats.
159///
160/// ## Examples
161///
162/// ```rust
163/// use deep_time::TraitsTime;
164///
165/// let dt = 500.ns();
166/// let dt = 500.us();
167/// let dt = 500.ms();
168/// let dt = 30.sec();
169/// let dt = 30.mins();
170/// let dt = 2.hours();
171/// let dt = 5.days();
172/// let dt = 4.weeks();
173/// let dt = 10.years();
174/// ```
175pub trait TraitsTime: Copy + Sized {
176    fn ns(self) -> Dt;
177    fn us(self) -> Dt;
178    fn ms(self) -> Dt;
179    fn sec(self) -> Dt;
180    fn mins(self) -> Dt;
181    fn hours(self) -> Dt;
182    fn days(self) -> Dt; // 86400 s (civil day, not leap-second aware)
183    fn weeks(self) -> Dt;
184    fn years(self) -> Dt; // 365.25 days (standard approximation)
185}
186
187// Integer implementations (all common signed/unsigned types)
188macro_rules! impl_time_units_int {
189    ($($ty:ty),* $(,)?) => {
190        $(
191            impl TraitsTime for $ty {
192                #[inline]
193                fn ns(self) -> Dt { Dt::from_ns(self as i128, 0, Scale::TAI, Scale::TAI) }
194
195                #[inline]
196                fn us(self) -> Dt { Dt::from_us(self as i128, 0, Scale::TAI, Scale::TAI) }
197
198                #[inline]
199                fn ms(self) -> Dt { Dt::from_ms(self as i128, 0, Scale::TAI, Scale::TAI) }
200
201                #[inline]
202                fn sec(self) -> Dt { Dt::from_sec(self as i128, Scale::TAI, Scale::TAI) }
203
204                #[inline]
205                fn mins(self) -> Dt { Dt::from_mins(self as i128, 0, Scale::TAI, Scale::TAI) }
206
207                #[inline]
208                fn hours(self) -> Dt { Dt::from_hours(self as i128, 0, Scale::TAI, Scale::TAI) }
209
210                #[inline]
211                fn days(self) -> Dt { Dt::from_sec((self as i128).saturating_mul(SEC_PER_DAY), Scale::TAI, Scale::TAI) }
212
213                #[inline]
214                fn weeks(self) -> Dt { Dt::from_sec((self  as i128).saturating_mul(604_800), Scale::TAI, Scale::TAI) }
215
216                #[inline]
217                fn years(self) -> Dt { Dt::from_sec((self  as i128).saturating_mul(31_557_600), Scale::TAI, Scale::TAI) }
218            }
219        )*
220    };
221}
222
223impl_time_units_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64);
224
225// `u128` alone among the integer impls can exceed `i128::MAX`; saturate instead of wrapping.
226impl TraitsTime for u128 {
227    #[inline]
228    fn ns(self) -> Dt {
229        Dt::from_ns(Dt::to_i128(self), 0, Scale::TAI, Scale::TAI)
230    }
231
232    #[inline]
233    fn us(self) -> Dt {
234        Dt::from_us(Dt::to_i128(self), 0, Scale::TAI, Scale::TAI)
235    }
236
237    #[inline]
238    fn ms(self) -> Dt {
239        Dt::from_ms(Dt::to_i128(self), 0, Scale::TAI, Scale::TAI)
240    }
241
242    #[inline]
243    fn sec(self) -> Dt {
244        Dt::from_sec(Dt::to_i128(self), Scale::TAI, Scale::TAI)
245    }
246
247    #[inline]
248    fn mins(self) -> Dt {
249        Dt::from_mins(Dt::to_i128(self), 0, Scale::TAI, Scale::TAI)
250    }
251
252    #[inline]
253    fn hours(self) -> Dt {
254        Dt::from_hours(Dt::to_i128(self), 0, Scale::TAI, Scale::TAI)
255    }
256
257    #[inline]
258    fn days(self) -> Dt {
259        Dt::from_sec(
260            Dt::to_i128(self).saturating_mul(SEC_PER_DAY),
261            Scale::TAI,
262            Scale::TAI,
263        )
264    }
265
266    #[inline]
267    fn weeks(self) -> Dt {
268        Dt::from_sec(
269            Dt::to_i128(self).saturating_mul(604_800),
270            Scale::TAI,
271            Scale::TAI,
272        )
273    }
274
275    #[inline]
276    fn years(self) -> Dt {
277        Dt::from_sec(
278            Dt::to_i128(self).saturating_mul(31_557_600),
279            Scale::TAI,
280            Scale::TAI,
281        )
282    }
283}
284
285impl TraitsTime for f64 {
286    #[inline]
287    fn ns(self) -> Dt {
288        crate::from_sec_f!(self * 1e-9)
289    }
290
291    #[inline]
292    fn us(self) -> Dt {
293        crate::from_sec_f!(self * 1e-6)
294    }
295
296    #[inline]
297    fn ms(self) -> Dt {
298        crate::from_sec_f!(self * 1e-3)
299    }
300
301    #[inline]
302    fn sec(self) -> Dt {
303        crate::from_sec_f!(self)
304    }
305
306    #[inline]
307    fn mins(self) -> Dt {
308        (self * 60.0).sec()
309    }
310
311    #[inline]
312    fn hours(self) -> Dt {
313        (self * 3600.0).sec()
314    }
315
316    #[inline]
317    fn days(self) -> Dt {
318        (self * SEC_PER_DAY_F).sec()
319    }
320
321    #[inline]
322    fn weeks(self) -> Dt {
323        (self * 604_800.0).sec()
324    }
325
326    #[inline]
327    fn years(self) -> Dt {
328        (self * 31_557_600.0).sec()
329    }
330}
331
332impl TraitsTime for f32 {
333    #[inline]
334    fn ns(self) -> Dt {
335        crate::from_sec_f!(self as f64 * 1e-9)
336    }
337
338    #[inline]
339    fn us(self) -> Dt {
340        crate::from_sec_f!(self as f64 * 1e-6)
341    }
342
343    #[inline]
344    fn ms(self) -> Dt {
345        crate::from_sec_f!(self as f64 * 1e-3)
346    }
347
348    #[inline]
349    fn sec(self) -> Dt {
350        crate::from_sec_f!(self as f64)
351    }
352
353    #[inline]
354    fn mins(self) -> Dt {
355        (self * 60.0f32).sec()
356    }
357
358    #[inline]
359    fn hours(self) -> Dt {
360        (self * 3600.0f32).sec()
361    }
362
363    #[inline]
364    fn days(self) -> Dt {
365        (self * SEC_PER_DAY as f32).sec()
366    }
367
368    #[inline]
369    fn weeks(self) -> Dt {
370        (self * 604_800.0f32).sec()
371    }
372
373    #[inline]
374    fn years(self) -> Dt {
375        (self * 31_557_600.0f32).sec()
376    }
377}