Skip to main content

deep_time/dt/
numbers_traits.rs

1//! Ergonomic time-unit constructors (optional import).
2//!
3//! ```
4//! use deep_time::{Scale, TimeTraits};
5//!
6//! let span = 5.sec() + 250.ms() + 123_456.ns();
7//! let stamp = 3.days().ago(Scale::UTC);
8//! ```
9
10use crate::{
11    ATTOS_PER_FS_I128, ATTOS_PER_MS_I128, ATTOS_PER_NS_I128, ATTOS_PER_PS_I128, ATTOS_PER_SEC_I128,
12    ATTOS_PER_SECF, ATTOS_PER_US_I128, Dt, SEC_PER_DAY, SEC_PER_DAY_F, SEC_PER_DAYI128, Scale,
13};
14
15/// Trait that adds ergonomic conversions from attoseconds values
16/// for i64, i128, and f64.
17///
18/// ## Examples
19///
20/// ```rust
21/// use deep_time::AttosTraits;
22///
23/// let attos: i128 = 5;
24/// let seconds = attos.attos_to_sec();
25/// ```
26pub trait AttosTraits: Copy + Sized {
27    /// attoseconds → seconds (s)
28    fn attos_to_sec(self) -> i64;
29
30    /// attoseconds → milliseconds (ms)
31    fn attos_to_ms(self) -> i128;
32
33    /// attoseconds → microseconds (us)
34    fn attos_to_us(self) -> i128;
35
36    /// attoseconds → nanoseconds (ns)
37    fn attos_to_ns(self) -> i128;
38
39    /// attoseconds → picoseconds (ps)
40    fn attos_to_ps(self) -> i128;
41
42    /// attoseconds → femtoseconds (fs)
43    fn attos_to_fs(self) -> i128;
44
45    /// attoseconds → float seconds (s)
46    fn attos_to_sec_f(self) -> f64;
47}
48
49impl AttosTraits for i128 {
50    #[inline]
51    fn attos_to_sec_f(self) -> f64 {
52        self as f64 / ATTOS_PER_SECF
53    }
54
55    #[inline]
56    fn attos_to_sec(self) -> i64 {
57        (self / ATTOS_PER_SEC_I128) as i64
58    }
59
60    #[inline]
61    fn attos_to_ms(self) -> i128 {
62        self / ATTOS_PER_MS_I128
63    }
64
65    #[inline]
66    fn attos_to_us(self) -> i128 {
67        self / ATTOS_PER_US_I128
68    }
69
70    #[inline]
71    fn attos_to_ns(self) -> i128 {
72        self / ATTOS_PER_NS_I128
73    }
74
75    #[inline]
76    fn attos_to_ps(self) -> i128 {
77        self / ATTOS_PER_PS_I128
78    }
79
80    #[inline]
81    fn attos_to_fs(self) -> i128 {
82        self / ATTOS_PER_FS_I128
83    }
84}
85
86/// Trait that adds ergonomic time-unit methods to integers and floats.
87///
88/// ## Examples
89///
90/// ```rust
91/// use deep_time::TimeTraits;
92///
93/// let dt = 5.days();
94/// ```
95pub trait TimeTraits: Copy + Sized {
96    fn ns(self) -> Dt;
97    fn us(self) -> Dt;
98    fn ms(self) -> Dt;
99    fn sec(self) -> Dt;
100    fn min(self) -> Dt;
101    fn hr(self) -> Dt;
102    fn days(self) -> Dt; // 86400 s (civil day, not leap-second aware)
103    fn wk(self) -> Dt;
104    fn yr(self) -> Dt; // 365.25 days (standard approximation)
105
106    fn ago(self, scale: Scale) -> Dt;
107    fn from_now(self, scale: Scale) -> Dt;
108}
109
110// Integer implementations (all common signed/unsigned types)
111macro_rules! impl_time_units_int {
112    ($($ty:ty),* $(,)?) => {
113        $(
114            impl TimeTraits for $ty {
115                #[inline]
116                fn ns(self) -> Dt { Dt::from_ns(self as i128, Scale::TAI) }
117
118                #[inline]
119                fn us(self) -> Dt { Dt::from_us(self as i128, Scale::TAI) }
120
121                #[inline]
122                fn ms(self) -> Dt { Dt::from_ms(self as i128, Scale::TAI) }
123
124                #[inline]
125                fn sec(self) -> Dt { Dt::from_sec(self as i128, Scale::TAI) }
126
127                #[inline]
128                fn min(self) -> Dt { Dt::from_min(self as i64, Scale::TAI) }
129
130                #[inline]
131                fn hr(self) -> Dt { Dt::from_hr(self as i64, Scale::TAI) }
132
133                #[inline]
134                fn days(self) -> Dt { Dt::from_sec((self as i128).saturating_mul(SEC_PER_DAYI128), Scale::TAI) }
135
136                #[inline]
137                fn wk(self) -> Dt { Dt::from_sec((self  as i128).saturating_mul(604_800), Scale::TAI) }
138
139                #[inline]
140                fn yr(self) -> Dt { Dt::from_sec((self  as i128).saturating_mul(31_557_600), Scale::TAI) }
141
142                #[inline]
143                fn ago(self, scale: Scale) -> Dt {
144                    Dt::from_attos(0, scale).sub(self.sec())
145                }
146
147                #[inline]
148                fn from_now(self, scale: Scale) -> Dt {
149                    Dt::from_attos(0, scale).add(self.sec())
150                }
151            }
152        )*
153    };
154}
155
156impl_time_units_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
157
158impl TimeTraits for f64 {
159    #[inline]
160    fn ns(self) -> Dt {
161        Dt::from_ns(self as i128, Scale::TAI)
162    }
163
164    #[inline]
165    fn us(self) -> Dt {
166        Dt::from_us(self as i128, Scale::TAI)
167    }
168
169    #[inline]
170    fn ms(self) -> Dt {
171        Dt::from_ms(self as i128, Scale::TAI)
172    }
173
174    #[inline]
175    fn sec(self) -> Dt {
176        Dt::from_sec(self as i128, Scale::TAI)
177    }
178
179    #[inline]
180    fn min(self) -> Dt {
181        (self * 60.0).sec()
182    }
183
184    #[inline]
185    fn hr(self) -> Dt {
186        (self * 3600.0).sec()
187    }
188
189    #[inline]
190    fn days(self) -> Dt {
191        (self * SEC_PER_DAY_F).sec()
192    }
193
194    #[inline]
195    fn wk(self) -> Dt {
196        (self * 604_800.0).sec()
197    }
198
199    #[inline]
200    fn yr(self) -> Dt {
201        (self * 31_557_600.0).sec()
202    }
203
204    #[inline]
205    fn ago(self, scale: Scale) -> Dt {
206        Dt::from_attos(0, scale).sub(self.sec())
207    }
208
209    #[inline]
210    fn from_now(self, scale: Scale) -> Dt {
211        Dt::from_attos(0, scale).add(self.sec())
212    }
213}
214
215impl TimeTraits for f32 {
216    #[inline]
217    fn ns(self) -> Dt {
218        Dt::from_ns(self as i128, Scale::TAI)
219    }
220
221    #[inline]
222    fn us(self) -> Dt {
223        Dt::from_us(self as i128, Scale::TAI)
224    }
225
226    #[inline]
227    fn ms(self) -> Dt {
228        Dt::from_ms(self as i128, Scale::TAI)
229    }
230
231    #[inline]
232    fn sec(self) -> Dt {
233        Dt::from_sec(self as i128, Scale::TAI)
234    }
235
236    #[inline]
237    fn min(self) -> Dt {
238        (self * 60.0f32).sec()
239    }
240
241    #[inline]
242    fn hr(self) -> Dt {
243        (self * 3600.0f32).sec()
244    }
245
246    #[inline]
247    fn days(self) -> Dt {
248        (self * SEC_PER_DAY as f32).sec()
249    }
250
251    #[inline]
252    fn wk(self) -> Dt {
253        (self * 604_800.0f32).sec()
254    }
255
256    #[inline]
257    fn yr(self) -> Dt {
258        (self * 31_557_600.0f32).sec()
259    }
260
261    #[inline]
262    fn ago(self, scale: Scale) -> Dt {
263        Dt::from_attos(0, scale).sub(self.sec())
264    }
265
266    #[inline]
267    fn from_now(self, scale: Scale) -> Dt {
268        Dt::from_attos(0, scale).add(self.sec())
269    }
270}