Skip to main content

deep_time/dt/
chrono.rs

1use crate::{Dt, Scale};
2use chrono::{DateTime, Datelike, Duration, TimeDelta, Timelike, Utc};
3use core::convert::From;
4
5impl Dt {
6    /// Converts this [`Dt`] to a [`chrono::DateTime`].
7    ///
8    /// - Sub-nanosecond attoseconds are truncated toward zero.
9    /// - Saturates at the minimum/maximum representable `DateTime<Utc>`
10    ///   (roughly years 1678–2262) if the instant is out of range.
11    #[inline]
12    pub fn to_chrono_datetime_utc(&self) -> DateTime<Utc> {
13        DateTime::<Utc>::from_timestamp_nanos(Dt::to_i64(
14            self.target(Scale::UTC).to_unix().to_ns().0,
15        ))
16    }
17
18    /// Creates a TAI [`Dt`] from a [`chrono::DateTime`].
19    ///
20    /// This is the inverse of [`Dt::to_chrono_datetime_utc`].
21    pub fn from_chrono_datetime_utc(dt: DateTime<Utc>) -> Dt {
22        let yr = dt.year() as i64;
23        let mo = dt.month().clamp(1, 12) as u8;
24        let day = dt.day().clamp(1, 31) as u8;
25        let hr = dt.hour().clamp(0, 23) as u8;
26        let min = dt.minute().clamp(0, 59) as u8;
27        let sec = dt.second().clamp(0, 60) as u8;
28        let subsec_nanos = dt.nanosecond();
29        let attos = Dt::from_ns(subsec_nanos as i128, 0, Scale::TAI, Scale::TAI).to_attos();
30
31        Dt::from_ymd(yr, mo, day, Scale::UTC, hr, min, sec, Dt::to_u64(attos))
32    }
33
34    /// Creates a [`Dt`] from a [`chrono::Duration`] (nanosecond precision).
35    pub fn from_chrono_duration(dur: Duration) -> Dt {
36        match dur.num_nanoseconds() {
37            Some(ns) => Self::from_ns(ns as i128, 0, Scale::TAI, Scale::TAI),
38            None => {
39                let ns = if dur > Duration::zero() {
40                    i64::MAX
41                } else {
42                    i64::MIN
43                };
44                Self::from_ns(ns as i128, 0, Scale::TAI, Scale::TAI)
45            }
46        }
47    }
48
49    /// Converts this [`Dt`] to a `chrono::Duration` (nanosecond precision).
50    ///
51    /// - Sub-nanosecond attoseconds are **truncated toward zero**.
52    /// - The conversion is fully exact up to the nanosecond (128-bit integer arithmetic).
53    /// - **Saturates** at `chrono::Duration::MIN` / `chrono::Duration::MAX`
54    ///   (roughly ±292 million years) if the value is out of range.
55    #[inline]
56    pub fn to_chrono_duration(&self) -> Duration {
57        TimeDelta::nanoseconds(Dt::to_i64(self.to_ns().0))
58    }
59}
60
61impl From<DateTime<Utc>> for Dt {
62    #[inline]
63    fn from(dt: DateTime<Utc>) -> Self {
64        Self::from_chrono_datetime_utc(dt)
65    }
66}
67
68impl From<Dt> for DateTime<Utc> {
69    #[inline]
70    fn from(dt: Dt) -> Self {
71        dt.to_chrono_datetime_utc()
72    }
73}
74
75impl From<Duration> for Dt {
76    #[inline]
77    fn from(dur: Duration) -> Self {
78        Self::from_chrono_duration(dur)
79    }
80}
81
82impl From<Dt> for Duration {
83    #[inline]
84    fn from(dt: Dt) -> Self {
85        dt.to_chrono_duration()
86    }
87}