Skip to main content

deep_time/dt/
to_unit.rs

1use crate::{
2    ATTOS_PER_DAY, ATTOS_PER_FS_I128, ATTOS_PER_HOUR, ATTOS_PER_MIN, ATTOS_PER_MS_I128,
3    ATTOS_PER_NS_I128, ATTOS_PER_PS_I128, ATTOS_PER_SEC_I128, ATTOS_PER_SECF, ATTOS_PER_US_I128,
4    Dt, Real, dt,
5};
6
7impl Dt {
8    /// Returns the whole seconds portion of this [`Dt`] using truncation towards zero
9    /// (i.e., the integer part obtained via truncating division, without rounding).
10    ///
11    /// This is equivalent to `self.attos / ATTOS_PER_SEC_I128`.
12    ///
13    /// Unlike
14    /// [`to_sec_floor`](../struct.Dt.html#method.to_sec_floor)
15    /// (which uses Euclidean division, flooring towards
16    /// negative infinity for negative values to keep the fractional part non-negative),
17    /// this version truncates towards zero.
18    ///
19    /// Consequently, for values in `(-1, 0)` seconds (e.g. -0.3 s or -0.8 s),
20    /// both return `0`.
21    ///
22    /// ## Examples
23    ///
24    /// ```rust
25    /// use deep_time::Dt;
26    /// use deep_time::macros::{from_sec, ms};
27    ///
28    /// // -0.3 seconds → truncates to 0
29    /// let dt = from_sec!(0, -ms!(300));
30    /// assert_eq!(dt.to_sec(), 0);
31    ///
32    /// // -0.8 seconds → truncates to 0
33    /// let dt = from_sec!(0, -ms!(800));
34    /// assert_eq!(dt.to_sec(), 0);
35    ///
36    /// // -1.3 seconds → truncates to -1 (while to_sec_floor gives -2)
37    /// let dt = from_sec!(-1, -ms!(300));
38    /// assert_eq!(dt.to_sec(), -1);
39    /// assert_eq!(dt.to_sec_floor(), -2);
40    ///
41    /// // Positive values behave the same as `to_sec_floor`
42    /// let dt = from_sec!(1, ms!(300));
43    /// assert_eq!(dt.to_sec(), 1);
44    /// assert_eq!(dt.to_sec_floor(), 1);
45    /// ```
46    #[inline(always)]
47    pub const fn to_sec(&self) -> i128 {
48        self.attos / ATTOS_PER_SEC_I128
49    }
50
51    /// Returns the whole seconds portion of this [`Dt`] using truncation towards zero,
52    /// then clamped to an [`i64`].
53    ///
54    /// If the truncated seconds value lies outside the `i64` range, the result
55    /// saturates to [`i64::MAX`] or [`i64::MIN`].
56    ///
57    /// See
58    /// [`to_sec`](../struct.Dt.html#method.to_sec)
59    /// for the truncation semantics
60    /// (towards zero, no rounding).
61    ///
62    /// ## Examples
63    ///
64    /// ```rust
65    /// use deep_time::Dt;
66    /// use deep_time::macros::{from_sec, ms};
67    ///
68    /// let dt = from_sec!(-1, -ms!(300));
69    /// assert_eq!(dt.to_sec64(), -1);
70    ///
71    /// let dt = from_sec!(1, ms!(300));
72    /// assert_eq!(dt.to_sec64_floor(), 1);
73    /// ```
74    #[inline(always)]
75    pub const fn to_sec64(&self) -> i64 {
76        Self::to_i64(self.attos / ATTOS_PER_SEC_I128)
77    }
78
79    /// If this time were turned into [`i128`] seconds and [`u64`] (always
80    /// pushing to the positive) fractional attoseconds, this returns the
81    /// whole seconds part.
82    ///
83    /// To just get seconds rounded to the nearest second use
84    /// [`Dt::to_sec_round`](../struct.Dt.html#method.to_sec_round)
85    /// instead.
86    ///
87    /// ## Examples
88    ///
89    /// ```rust
90    /// use deep_time::Dt;
91    /// use deep_time::macros::{from_sec, ms};
92    ///
93    /// // negative 1.3 seconds
94    /// let dt = from_sec!(-1, -ms!(300));
95    ///
96    /// // becomes positive 700ms
97    /// let frac = dt.to_sec_ufrac();
98    /// assert_eq!(frac, ms!(700) as u64);
99    ///
100    /// // becomes negative 2 seconds
101    /// let sec = dt.to_sec_floor();
102    /// assert_eq!(sec, -2);
103    ///
104    /// let dt = from_sec!(1, ms!(300));
105    ///
106    /// assert_eq!(dt.to_sec_floor(), 1);
107    /// assert_eq!(dt.to_sec_ufrac(), ms!(300) as u64);
108    ///
109    /// // if you just want rounded seconds
110    /// // use to_sec_round() instead
111    /// let dt = from_sec!(-1, -ms!(300));
112    /// let sec = dt.to_sec_round();
113    /// assert_eq!(sec, -1);
114    /// ```
115    #[inline(always)]
116    pub const fn to_sec_floor(&self) -> i128 {
117        self.attos.div_euclid(ATTOS_PER_SEC_I128)
118    }
119
120    /// If this time were turned into [`i64`] seconds and [`u64`] (always
121    /// pushing to the positive) fractional attoseconds, this returns the
122    /// whole seconds part.
123    ///
124    /// To just get seconds rounded to the nearest second use
125    /// [`Dt::to_sec_round`](../struct.Dt.html#method.to_sec_round)
126    /// instead.
127    ///
128    /// ## Examples
129    ///
130    /// ```rust
131    /// use deep_time::Dt;
132    /// use deep_time::macros::{from_sec, ms};
133    ///
134    /// // negative 1.3 seconds
135    /// let dt = from_sec!(-1, -ms!(300));
136    ///
137    /// // becomes positive 700ms
138    /// let frac = dt.to_sec_ufrac();
139    /// assert_eq!(frac, ms!(700) as u64);
140    ///
141    /// // becomes negative 2 seconds
142    /// let sec = dt.to_sec64_floor();
143    /// assert_eq!(sec, -2);
144    ///
145    /// let dt = from_sec!(1, ms!(300));
146    ///
147    /// assert_eq!(dt.to_sec64_floor(), 1);
148    /// assert_eq!(dt.to_sec_ufrac(), ms!(300) as u64);
149    ///
150    /// // if you just want rounded seconds
151    /// // use to_sec_round() instead
152    /// let dt = from_sec!(-1, -ms!(300));
153    /// let sec = dt.to_sec_round();
154    /// assert_eq!(sec, -1);
155    /// ```
156    #[inline(always)]
157    pub const fn to_sec64_floor(&self) -> i64 {
158        Self::to_i64(self.attos.div_euclid(ATTOS_PER_SEC_I128))
159    }
160
161    /// Returns this [`Dt`] rounded to the nearest whole second, then
162    /// converted to an [`i128`] number of seconds.
163    ///
164    /// - Exactly halfway cases (e.g. 0.5 s, -0.5 s) round as follows:
165    ///   0.5 becomes 1 and -0.5 becomes -1.
166    /// - Matches the behavior of [`Dt::round`].
167    ///
168    /// ## Examples
169    ///
170    /// ```rust
171    /// use deep_time::Dt;
172    /// use deep_time::macros::{from_sec, ms};
173    ///
174    /// // 1.3 seconds → rounds to 1
175    /// assert_eq!(from_sec!(1, ms!(300)).to_sec_round(), 1);
176    ///
177    /// // -1.3 seconds → rounds to -1
178    /// assert_eq!(from_sec!(-1, -ms!(300)).to_sec_round(), -1);
179    ///
180    /// // 1.6 seconds → rounds to 2
181    /// assert_eq!(from_sec!(1, ms!(600)).to_sec_round(), 2);
182    ///
183    /// // Halfway cases
184    /// assert_eq!(from_sec!(0, ms!(500)).to_sec_round(), 1);
185    /// assert_eq!(from_sec!(0, -ms!(500)).to_sec_round(), -1);
186    /// ```
187    #[inline(always)]
188    pub const fn to_sec_round(&self) -> i128 {
189        self.round_to_sec().to_sec()
190    }
191
192    /// Returns this [`Dt`] rounded to the nearest whole second, then
193    /// converted to an [`i64`] number of seconds.
194    ///
195    /// - Exactly halfway cases round as follows: 0.5 becomes 1 and -0.5 becomes -1,
196    ///   same as
197    ///   [`to_sec_round`](../struct.Dt.html#method.to_sec_round).
198    /// - If the rounded value is outside the representable `i64` range,
199    ///   it saturates to [`i64::MAX`] or [`i64::MIN`].
200    ///
201    /// ## Examples
202    ///
203    /// ```rust
204    /// use deep_time::Dt;
205    /// use deep_time::macros::{from_sec, ms};
206    ///
207    /// let dt = from_sec!(1, ms!(300));
208    /// assert_eq!(dt.to_sec64_round(), 1);
209    ///
210    /// let dt = from_sec!(-1, -ms!(300));
211    /// assert_eq!(dt.to_sec64_round(), -1);
212    /// ```
213    #[inline(always)]
214    pub const fn to_sec64_round(&self) -> i64 {
215        Self::to_i64(self.round_to_sec().to_sec())
216    }
217
218    /// Converts this [`Dt`] to an f64 number of seconds.
219    #[inline(always)]
220    pub const fn to_f64(&self) -> f64 {
221        self.to_sec_f()
222    }
223
224    /// Converts this [`Dt`] to a float number of seconds.
225    pub const fn to_sec_f(&self) -> Real {
226        if self.attos == 0 {
227            return 0.0;
228        }
229        let sec = self.attos.div_euclid(ATTOS_PER_SEC_I128);
230        let rem = self.attos.rem_euclid(ATTOS_PER_SEC_I128); // always in [0, aps)
231
232        if sec < 0 && rem > ATTOS_PER_SEC_I128 / 2 {
233            // original cancellation-avoidance path
234            let small = ATTOS_PER_SEC_I128 - rem;
235            let small_f = f!(small as u64) / ATTOS_PER_SECF;
236            f!(sec) + 1.0 - small_f
237        } else {
238            f!(sec) + f!(rem as u64) / ATTOS_PER_SECF
239        }
240    }
241
242    /// If this time were turned into seconds, this returns the signed fractional
243    /// attoseconds part — the amount left over after removing whole seconds, with the
244    /// same sign as the original value when non-zero.
245    ///
246    /// Pairs with [`from_sec_and_frac`](../struct.Dt.html#method.from_sec_and_frac).
247    #[inline(always)]
248    pub const fn to_sec_frac(&self) -> i64 {
249        (self.attos % ATTOS_PER_SEC_I128) as i64
250    }
251
252    /// If this time were turned into i64 seconds and u64 (always pushing to the positive)
253    /// fractional attoseconds, this returns the fractional attoseconds part.
254    ///
255    /// - Always returns a value in the range `0 ≤ x < ATTOS_PER_SEC`.
256    /// - For negative [`Dt`]s this is **not** simply the decimal part of the time in seconds.
257    ///
258    /// ## Examples
259    ///
260    /// ```rust
261    /// use deep_time::Dt;
262    /// use deep_time::macros::{from_sec, ms};
263    ///
264    /// // negative 1.3 seconds
265    /// let dt = from_sec!(-1, -ms!(300));
266    ///
267    /// // becomes positive 700ms
268    /// let frac = dt.to_sec_ufrac();
269    /// assert_eq!(frac, ms!(700) as u64);
270    ///
271    /// // becomes -2 seconds
272    /// let sec = dt.to_sec64_floor();
273    /// assert_eq!(sec, -2);
274    ///
275    /// let dt = from_sec!(1, ms!(300));
276    ///
277    /// assert_eq!(dt.to_sec64_floor(), 1);
278    /// assert_eq!(dt.to_sec_ufrac(), ms!(300) as u64);
279    /// ```
280    #[inline(always)]
281    pub const fn to_sec_ufrac(&self) -> u64 {
282        self.attos.rem_euclid(ATTOS_PER_SEC_I128) as u64
283    }
284
285    /// Returns a new [`Dt`] rounded to the nearest second.
286    #[inline(always)]
287    pub const fn round_to_sec(&self) -> Dt {
288        self.round(dt!(ATTOS_PER_SEC_I128))
289    }
290
291    /// Returns the total time in attoseconds.
292    #[inline(always)]
293    pub const fn to_attos(&self) -> i128 {
294        self.attos
295    }
296
297    /// Converts this [`Dt`] into whole femtoseconds and a fractional part within one femtosecond.
298    ///
299    /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
300    /// - For negative values this does **not** split at the decimal point — see
301    ///   [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
302    ///   [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
303    /// - For truncation toward zero, use [`to_fs`](../struct.Dt.html#method.to_fs).
304    #[inline(always)]
305    pub const fn to_fs_floor(&self) -> (i128, i128) {
306        (
307            self.attos.div_euclid(ATTOS_PER_FS_I128),
308            self.attos.rem_euclid(ATTOS_PER_FS_I128),
309        )
310    }
311
312    /// Converts this [`Dt`] into whole picoseconds and a fractional part within one picosecond.
313    ///
314    /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
315    /// - For negative values this does **not** split at the decimal point — see
316    ///   [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
317    ///   [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
318    /// - For truncation toward zero, use [`to_ps`](../struct.Dt.html#method.to_ps).
319    #[inline(always)]
320    pub const fn to_ps_floor(&self) -> (i128, i128) {
321        (
322            self.attos.div_euclid(ATTOS_PER_PS_I128),
323            self.attos.rem_euclid(ATTOS_PER_PS_I128),
324        )
325    }
326
327    /// Converts this [`Dt`] into whole nanoseconds and a fractional part within one nanosecond.
328    ///
329    /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
330    /// - For negative values this does **not** split at the decimal point — see
331    ///   [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
332    ///   [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
333    /// - For truncation toward zero, use [`to_ns`](../struct.Dt.html#method.to_ns).
334    #[inline(always)]
335    pub const fn to_ns_floor(&self) -> (i128, i128) {
336        (
337            self.attos.div_euclid(ATTOS_PER_NS_I128),
338            self.attos.rem_euclid(ATTOS_PER_NS_I128),
339        )
340    }
341
342    /// Converts this [`Dt`] into whole microseconds and a fractional part within one microsecond.
343    ///
344    /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
345    /// - For negative values this does **not** split at the decimal point — see
346    ///   [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
347    ///   [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
348    /// - For truncation toward zero, use [`to_us`](../struct.Dt.html#method.to_us).
349    #[inline(always)]
350    pub const fn to_us_floor(&self) -> (i128, i128) {
351        (
352            self.attos.div_euclid(ATTOS_PER_US_I128),
353            self.attos.rem_euclid(ATTOS_PER_US_I128),
354        )
355    }
356
357    /// Converts this [`Dt`] into whole milliseconds and a fractional part within one millisecond.
358    ///
359    /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
360    /// - For negative values this does **not** split at the decimal point — see
361    ///   [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
362    ///   [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
363    /// - For truncation toward zero, use [`to_ms`](../struct.Dt.html#method.to_ms).
364    #[inline(always)]
365    pub const fn to_ms_floor(&self) -> (i128, i128) {
366        (
367            self.attos.div_euclid(ATTOS_PER_MS_I128),
368            self.attos.rem_euclid(ATTOS_PER_MS_I128),
369        )
370    }
371
372    /// Converts this [`Dt`] into whole minutes and a fractional part within one minute.
373    ///
374    /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
375    /// - For negative values this does **not** split at the decimal point — see
376    ///   [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
377    ///   [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
378    #[inline(always)]
379    pub const fn to_mins_floor(&self) -> (i128, i128) {
380        (
381            self.attos.div_euclid(ATTOS_PER_MIN),
382            self.attos.rem_euclid(ATTOS_PER_MIN),
383        )
384    }
385
386    /// Converts this [`Dt`] to a float number of minutes.
387    ///
388    /// ## Examples
389    ///
390    /// ```rust
391    /// use deep_time::Dt;
392    /// use deep_time::macros::from_sec;
393    ///
394    /// assert_eq!(Dt::ZERO.to_mins_f(), 0.0);
395    ///
396    /// let dt = from_sec!(90);
397    /// assert_eq!(dt.to_mins_f(), 1.5);
398    ///
399    /// let dt = from_sec!(-90);
400    /// assert_eq!(dt.to_mins_f(), -1.5);
401    /// ```
402    pub const fn to_mins_f(&self) -> Real {
403        if self.attos == 0 {
404            return 0.0;
405        }
406        let mins = self.attos.div_euclid(ATTOS_PER_MIN);
407        let rem = self.attos.rem_euclid(ATTOS_PER_MIN);
408
409        if mins < 0 && rem > ATTOS_PER_MIN / 2 {
410            let small = ATTOS_PER_MIN - rem;
411            let small_f = f!(small as u128) / f!(ATTOS_PER_MIN);
412            f!(mins) + 1.0 - small_f
413        } else {
414            f!(mins) + f!(rem as u128) / f!(ATTOS_PER_MIN)
415        }
416    }
417
418    /// Converts this [`Dt`] into whole hours and a fractional part within one hour.
419    ///
420    /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
421    /// - For negative values this does **not** split at the decimal point — see
422    ///   [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
423    ///   [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
424    #[inline(always)]
425    pub const fn to_hours_floor(&self) -> (i128, i128) {
426        (
427            self.attos.div_euclid(ATTOS_PER_HOUR),
428            self.attos.rem_euclid(ATTOS_PER_HOUR),
429        )
430    }
431
432    /// Converts this [`Dt`] to a float number of hours.
433    ///
434    /// ## Examples
435    ///
436    /// ```rust
437    /// use deep_time::Dt;
438    ///
439    /// assert_eq!(Dt::ZERO.to_hours_f(), 0.0);
440    ///
441    /// let dt = Dt::from_str_iso("2000-01-01 10:30:00 TAI").unwrap();
442    /// assert_eq!(dt.to_hours_f(), -1.5);
443    /// ```
444    pub const fn to_hours_f(&self) -> Real {
445        if self.attos == 0 {
446            return 0.0;
447        }
448        let hours = self.attos.div_euclid(ATTOS_PER_HOUR);
449        let rem = self.attos.rem_euclid(ATTOS_PER_HOUR);
450
451        if hours < 0 && rem > ATTOS_PER_HOUR / 2 {
452            let small = ATTOS_PER_HOUR - rem;
453            let small_f = f!(small as u128) / f!(ATTOS_PER_HOUR);
454            f!(hours) + 1.0 - small_f
455        } else {
456            f!(hours) + f!(rem as u128) / f!(ATTOS_PER_HOUR)
457        }
458    }
459
460    /// Converts this [`Dt`] into whole days and a fractional part within one day,
461    /// truncating toward zero.
462    ///
463    /// Returns `(whole, frac_attos)`. When the value is negative and has a fractional
464    /// part, `frac_attos` is negative too — e.g. `-1.25` days is
465    /// `(-1, -ATTOS_PER_DAY / 4)`.
466    ///
467    /// For a non-negative fractional part, use [`to_days_floor`](#method.to_days_floor).
468    ///
469    /// ## Examples
470    ///
471    /// ```rust
472    /// use deep_time::{Dt, Scale, consts::ATTOS_PER_DAY};
473    ///
474    /// let dt = Dt::from_days_f(1.25, Scale::TAI, Scale::TAI);
475    /// assert_eq!(dt.to_days(), (1, ATTOS_PER_DAY / 4));
476    ///
477    /// let dt = Dt::from_days_f(-1.25, Scale::TAI, Scale::TAI);
478    /// assert_eq!(dt.to_days(), (-1, -ATTOS_PER_DAY / 4));
479    /// ```
480    ///
481    /// ## See also
482    ///
483    /// - [`Dt::to_days_floor`](#method.to_days_floor)
484    /// - [`Dt::from_days`](../struct.Dt.html#method.from_days)
485    #[inline(always)]
486    pub const fn to_days(&self) -> (i128, i128) {
487        (self.attos / ATTOS_PER_DAY, self.attos % ATTOS_PER_DAY)
488    }
489
490    /// Converts this [`Dt`] into whole days and a fractional part within one day.
491    ///
492    /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
493    /// - For negative values this does **not** split at the decimal point — see
494    ///   [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
495    ///   [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
496    ///
497    /// ## Examples
498    ///
499    /// ```rust
500    /// use deep_time::{Dt, Scale, consts::ATTOS_PER_HALF_DAY};
501    ///
502    /// // library epoch is 2000-01-01 12:00:00 TAI
503    /// // so result will be negative 2 + half a day
504    /// // effectively -1.5 days
505    /// let dt = Dt::from_ymd(1999, 12, 31, Scale::TAI, 0, 0, 0, 0);
506    /// let (days, attos) = dt.to_days_floor();
507    /// assert_eq!(days, -2);
508    /// assert_eq!(attos, ATTOS_PER_HALF_DAY);
509    /// ```
510    ///
511    /// ## See also
512    ///
513    /// - [`Dt::to_days`](#method.to_days)
514    #[inline(always)]
515    pub const fn to_days_floor(&self) -> (i128, i128) {
516        (
517            self.attos.div_euclid(ATTOS_PER_DAY),
518            self.attos.rem_euclid(ATTOS_PER_DAY),
519        )
520    }
521
522    /// Converts this [`Dt`] to a float number of days.
523    ///
524    /// ## Examples
525    ///
526    /// ```rust
527    /// use deep_time::{Dt, Scale, consts::ATTOS_PER_HALF_DAY_U128};
528    ///
529    /// assert_eq!(Dt::ZERO.to_days_f(), 0.0);
530    ///
531    /// // library epoch is 2000-01-01 12:00:00 TAI
532    /// // so -1.5 days
533    /// let dt = Dt::from_ymd(1999, 12, 31, Scale::TAI, 0, 0, 0, 0);
534    /// assert_eq!(dt.to_days_f(), -1.5);
535    /// ```
536    ///
537    /// ## See also
538    ///
539    /// - [`Dt::from_days_f`](../struct.Dt.html#method.from_days_f)
540    pub const fn to_days_f(&self) -> Real {
541        if self.attos == 0 {
542            return 0.0;
543        }
544        let days = self.attos.div_euclid(ATTOS_PER_DAY);
545        let rem = self.attos.rem_euclid(ATTOS_PER_DAY);
546
547        if days < 0 && rem > ATTOS_PER_DAY / 2 {
548            let small = ATTOS_PER_DAY - rem;
549            let small_f = f!(small as u128) / f!(ATTOS_PER_DAY);
550            f!(days) + 1.0 - small_f
551        } else {
552            f!(days) + f!(rem as u128) / f!(ATTOS_PER_DAY)
553        }
554    }
555
556    /// Converts this [`Dt`] into whole milliseconds and a fractional part within one millisecond,
557    /// truncating toward zero.
558    ///
559    /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
560    /// there is a non-zero fraction. See
561    /// [`to_sec`](../struct.Dt.html#method.to_sec)
562    /// for the same rule in seconds.
563    #[inline(always)]
564    pub const fn to_ms(&self) -> (i128, i128) {
565        (
566            self.attos / ATTOS_PER_MS_I128,
567            self.attos % ATTOS_PER_MS_I128,
568        )
569    }
570
571    /// Converts this [`Dt`] into whole microseconds and a fractional part within one microsecond,
572    /// truncating toward zero.
573    ///
574    /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
575    /// there is a non-zero fraction. See
576    /// [`to_sec`](../struct.Dt.html#method.to_sec)
577    /// for the same rule in seconds.
578    #[inline(always)]
579    pub const fn to_us(&self) -> (i128, i128) {
580        (
581            self.attos / ATTOS_PER_US_I128,
582            self.attos % ATTOS_PER_US_I128,
583        )
584    }
585
586    /// Converts this [`Dt`] into whole nanoseconds and a fractional part within one nanosecond,
587    /// truncating toward zero.
588    ///
589    /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
590    /// there is a non-zero fraction. See
591    /// [`to_sec`](../struct.Dt.html#method.to_sec)
592    /// for the same rule in seconds.
593    #[inline(always)]
594    pub const fn to_ns(&self) -> (i128, i128) {
595        (
596            self.attos / ATTOS_PER_NS_I128,
597            self.attos % ATTOS_PER_NS_I128,
598        )
599    }
600
601    /// Converts this [`Dt`] into whole picoseconds and a fractional part within one picosecond,
602    /// truncating toward zero.
603    ///
604    /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
605    /// there is a non-zero fraction. See
606    /// [`to_sec`](../struct.Dt.html#method.to_sec)
607    /// for the same rule in seconds.
608    #[inline(always)]
609    pub const fn to_ps(&self) -> (i128, i128) {
610        (
611            self.attos / ATTOS_PER_PS_I128,
612            self.attos % ATTOS_PER_PS_I128,
613        )
614    }
615
616    /// Converts this [`Dt`] into whole femtoseconds and a fractional part within one femtosecond,
617    /// truncating toward zero.
618    ///
619    /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
620    /// there is a non-zero fraction. See
621    /// [`to_sec`](../struct.Dt.html#method.to_sec)
622    /// for the same rule in seconds.
623    #[inline(always)]
624    pub const fn to_fs(&self) -> (i128, i128) {
625        (
626            self.attos / ATTOS_PER_FS_I128,
627            self.attos % ATTOS_PER_FS_I128,
628        )
629    }
630}