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`] into whole minutes and a fractional part within one minute,
387 /// truncating toward zero.
388 ///
389 /// Returns `(whole, frac_attos)`. When the value is negative and has a fractional
390 /// part, `frac_attos` is negative too.
391 ///
392 /// For a non-negative fractional part, use
393 /// [`Dt::to_mins_floor`](#method.to_mins_floor).
394 ///
395 /// ## Examples
396 ///
397 /// ```rust
398 /// use deep_time::Dt;
399 /// use deep_time::macros::{from_sec, sec};
400 ///
401 /// let dt = from_sec!(90);
402 /// assert_eq!(dt.to_mins(), (1, sec!(30)));
403 ///
404 /// let dt = from_sec!(-90);
405 /// assert_eq!(dt.to_mins(), (-1, sec!(-30)));
406 /// ```
407 #[inline(always)]
408 pub const fn to_mins(&self) -> (i128, i128) {
409 (self.attos / ATTOS_PER_MIN, self.attos % ATTOS_PER_MIN)
410 }
411
412 /// Converts this [`Dt`] to a float number of minutes.
413 ///
414 /// ## Examples
415 ///
416 /// ```rust
417 /// use deep_time::Dt;
418 /// use deep_time::macros::from_sec;
419 ///
420 /// assert_eq!(Dt::ZERO.to_mins_f(), 0.0);
421 ///
422 /// let dt = from_sec!(90);
423 /// assert_eq!(dt.to_mins_f(), 1.5);
424 ///
425 /// let dt = from_sec!(-90);
426 /// assert_eq!(dt.to_mins_f(), -1.5);
427 /// ```
428 pub const fn to_mins_f(&self) -> Real {
429 if self.attos == 0 {
430 return 0.0;
431 }
432 let mins = self.attos.div_euclid(ATTOS_PER_MIN);
433 let rem = self.attos.rem_euclid(ATTOS_PER_MIN);
434
435 if mins < 0 && rem > ATTOS_PER_MIN / 2 {
436 let small = ATTOS_PER_MIN - rem;
437 let small_f = f!(small as u128) / f!(ATTOS_PER_MIN);
438 f!(mins) + 1.0 - small_f
439 } else {
440 f!(mins) + f!(rem as u128) / f!(ATTOS_PER_MIN)
441 }
442 }
443
444 /// Converts this [`Dt`] into whole hours and a fractional part within one hour.
445 ///
446 /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
447 /// - For negative values this does **not** split at the decimal point — see
448 /// [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
449 /// [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
450 #[inline(always)]
451 pub const fn to_hours_floor(&self) -> (i128, i128) {
452 (
453 self.attos.div_euclid(ATTOS_PER_HOUR),
454 self.attos.rem_euclid(ATTOS_PER_HOUR),
455 )
456 }
457
458 /// Converts this [`Dt`] into whole hours and a fractional part within one hour,
459 /// truncating toward zero.
460 ///
461 /// Returns `(whole, frac_attos)`. When the value is negative and has a fractional
462 /// part, `frac_attos` is negative too.
463 ///
464 /// For a non-negative fractional part, use
465 /// [`Dt::to_hours_floor`](#method.to_hours_floor).
466 #[inline(always)]
467 pub const fn to_hours(&self) -> (i128, i128) {
468 (self.attos / ATTOS_PER_HOUR, self.attos % ATTOS_PER_HOUR)
469 }
470
471 /// Converts this [`Dt`] to a float number of hours.
472 ///
473 /// ## Examples
474 ///
475 /// ```rust
476 /// use deep_time::Dt;
477 ///
478 /// assert_eq!(Dt::ZERO.to_hours_f(), 0.0);
479 ///
480 /// let dt = Dt::from_str("2000-01-01 10:30:00 TAI").unwrap();
481 /// assert_eq!(dt.to_hours_f(), -1.5);
482 /// ```
483 pub const fn to_hours_f(&self) -> Real {
484 if self.attos == 0 {
485 return 0.0;
486 }
487 let hours = self.attos.div_euclid(ATTOS_PER_HOUR);
488 let rem = self.attos.rem_euclid(ATTOS_PER_HOUR);
489
490 if hours < 0 && rem > ATTOS_PER_HOUR / 2 {
491 let small = ATTOS_PER_HOUR - rem;
492 let small_f = f!(small as u128) / f!(ATTOS_PER_HOUR);
493 f!(hours) + 1.0 - small_f
494 } else {
495 f!(hours) + f!(rem as u128) / f!(ATTOS_PER_HOUR)
496 }
497 }
498
499 /// Converts this [`Dt`] into whole days and a fractional part within one day,
500 /// truncating toward zero.
501 ///
502 /// Returns `(whole, frac_attos)`. When the value is negative and has a fractional
503 /// part, `frac_attos` is negative too — e.g. `-1.25` days is
504 /// `(-1, -ATTOS_PER_DAY / 4)`.
505 ///
506 /// For a non-negative fractional part, use [`to_days_floor`](#method.to_days_floor).
507 ///
508 /// ## Examples
509 ///
510 /// ```rust
511 /// use deep_time::{Dt, Scale, consts::ATTOS_PER_DAY};
512 ///
513 /// let dt = Dt::from_days_f(1.25, Scale::TAI, Scale::TAI);
514 /// assert_eq!(dt.to_days(), (1, ATTOS_PER_DAY / 4));
515 ///
516 /// let dt = Dt::from_days_f(-1.25, Scale::TAI, Scale::TAI);
517 /// assert_eq!(dt.to_days(), (-1, -ATTOS_PER_DAY / 4));
518 /// ```
519 ///
520 /// ## See also
521 ///
522 /// - [`Dt::to_days_floor`](#method.to_days_floor)
523 /// - [`Dt::from_days`](../struct.Dt.html#method.from_days)
524 #[inline(always)]
525 pub const fn to_days(&self) -> (i128, i128) {
526 (self.attos / ATTOS_PER_DAY, self.attos % ATTOS_PER_DAY)
527 }
528
529 /// Converts this [`Dt`] into whole days and a fractional part within one day.
530 ///
531 /// - Returns `(whole, frac_attos)` where `frac_attos` is always non-negative.
532 /// - For negative values this does **not** split at the decimal point — see
533 /// [`to_sec64_floor`](../struct.Dt.html#method.to_sec64_floor) and
534 /// [`to_sec_ufrac`](../struct.Dt.html#method.to_sec_ufrac).
535 ///
536 /// ## Examples
537 ///
538 /// ```rust
539 /// use deep_time::{Dt, Scale, consts::ATTOS_PER_HALF_DAY};
540 ///
541 /// // library epoch is 2000-01-01 12:00:00 TAI
542 /// // so result will be negative 2 + half a day
543 /// // effectively -1.5 days
544 /// let dt = Dt::from_ymd(1999, 12, 31, Scale::TAI, 0, 0, 0, 0);
545 /// let (days, attos) = dt.to_days_floor();
546 /// assert_eq!(days, -2);
547 /// assert_eq!(attos, ATTOS_PER_HALF_DAY);
548 /// ```
549 ///
550 /// ## See also
551 ///
552 /// - [`Dt::to_days`](#method.to_days)
553 #[inline(always)]
554 pub const fn to_days_floor(&self) -> (i128, i128) {
555 (
556 self.attos.div_euclid(ATTOS_PER_DAY),
557 self.attos.rem_euclid(ATTOS_PER_DAY),
558 )
559 }
560
561 /// Converts this [`Dt`] to a float number of days.
562 ///
563 /// ## Examples
564 ///
565 /// ```rust
566 /// use deep_time::{Dt, Scale, consts::ATTOS_PER_HALF_DAY_U128};
567 ///
568 /// assert_eq!(Dt::ZERO.to_days_f(), 0.0);
569 ///
570 /// // library epoch is 2000-01-01 12:00:00 TAI
571 /// // so -1.5 days
572 /// let dt = Dt::from_ymd(1999, 12, 31, Scale::TAI, 0, 0, 0, 0);
573 /// assert_eq!(dt.to_days_f(), -1.5);
574 /// ```
575 ///
576 /// ## See also
577 ///
578 /// - [`Dt::from_days_f`](../struct.Dt.html#method.from_days_f)
579 pub const fn to_days_f(&self) -> Real {
580 if self.attos == 0 {
581 return 0.0;
582 }
583 let days = self.attos.div_euclid(ATTOS_PER_DAY);
584 let rem = self.attos.rem_euclid(ATTOS_PER_DAY);
585
586 if days < 0 && rem > ATTOS_PER_DAY / 2 {
587 let small = ATTOS_PER_DAY - rem;
588 let small_f = f!(small as u128) / f!(ATTOS_PER_DAY);
589 f!(days) + 1.0 - small_f
590 } else {
591 f!(days) + f!(rem as u128) / f!(ATTOS_PER_DAY)
592 }
593 }
594
595 /// Converts this [`Dt`] into whole milliseconds and a fractional part within one millisecond,
596 /// truncating toward zero.
597 ///
598 /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
599 /// there is a non-zero fraction. See
600 /// [`to_sec`](../struct.Dt.html#method.to_sec)
601 /// for the same rule in seconds.
602 #[inline(always)]
603 pub const fn to_ms(&self) -> (i128, i128) {
604 (
605 self.attos / ATTOS_PER_MS_I128,
606 self.attos % ATTOS_PER_MS_I128,
607 )
608 }
609
610 /// Converts this [`Dt`] into whole microseconds and a fractional part within one microsecond,
611 /// truncating toward zero.
612 ///
613 /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
614 /// there is a non-zero fraction. See
615 /// [`to_sec`](../struct.Dt.html#method.to_sec)
616 /// for the same rule in seconds.
617 #[inline(always)]
618 pub const fn to_us(&self) -> (i128, i128) {
619 (
620 self.attos / ATTOS_PER_US_I128,
621 self.attos % ATTOS_PER_US_I128,
622 )
623 }
624
625 /// Converts this [`Dt`] into whole nanoseconds and a fractional part within one nanosecond,
626 /// truncating toward zero.
627 ///
628 /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
629 /// there is a non-zero fraction. See
630 /// [`to_sec`](../struct.Dt.html#method.to_sec)
631 /// for the same rule in seconds.
632 #[inline(always)]
633 pub const fn to_ns(&self) -> (i128, i128) {
634 (
635 self.attos / ATTOS_PER_NS_I128,
636 self.attos % ATTOS_PER_NS_I128,
637 )
638 }
639
640 /// Converts this [`Dt`] into whole picoseconds and a fractional part within one picosecond,
641 /// truncating toward zero.
642 ///
643 /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
644 /// there is a non-zero fraction. See
645 /// [`to_sec`](../struct.Dt.html#method.to_sec)
646 /// for the same rule in seconds.
647 #[inline(always)]
648 pub const fn to_ps(&self) -> (i128, i128) {
649 (
650 self.attos / ATTOS_PER_PS_I128,
651 self.attos % ATTOS_PER_PS_I128,
652 )
653 }
654
655 /// Converts this [`Dt`] into whole femtoseconds and a fractional part within one femtosecond,
656 /// truncating toward zero.
657 ///
658 /// Returns `(whole, frac_attos)`. `frac_attos` will be negative when `whole` is negative and
659 /// there is a non-zero fraction. See
660 /// [`to_sec`](../struct.Dt.html#method.to_sec)
661 /// for the same rule in seconds.
662 #[inline(always)]
663 pub const fn to_fs(&self) -> (i128, i128) {
664 (
665 self.attos / ATTOS_PER_FS_I128,
666 self.attos % ATTOS_PER_FS_I128,
667 )
668 }
669}