Skip to main content

deep_time/t_span/
time_units.rs

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