Skip to main content

deep_time/dt/
chrono.rs

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