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