chrono_systemd_time/
local_datetime.rs

1use std::ops::{Add, Sub};
2
3use chrono::LocalResult;
4use chrono::{DateTime, Duration, NaiveDate, NaiveDateTime, TimeZone};
5
6use crate::Error;
7
8/// The conversion time returned by [`NaiveDateTime::and_local_timezone`]
9///
10/// [`NaiveDateTime::and_local_timezone`]: chrono::NaiveDateTime::and_local_timezone
11#[derive(Debug, PartialEq, Eq)]
12pub enum LocalDateTime<Tz: TimeZone> {
13    Single(DateTime<Tz>),
14    Ambiguous(DateTime<Tz>, DateTime<Tz>),
15}
16
17impl<Tz: TimeZone> TryFrom<LocalResult<DateTime<Tz>>> for LocalDateTime<Tz> {
18    type Error = Error;
19
20    fn try_from(res: LocalResult<DateTime<Tz>>) -> Result<Self, Self::Error> {
21        match res {
22            LocalResult::None => Err(Error::Never),
23            LocalResult::Single(dt) => Ok(LocalDateTime::Single(dt)),
24            LocalResult::Ambiguous(dt1, dt2) => Ok(LocalDateTime::Ambiguous(dt1, dt2)),
25        }
26    }
27}
28
29impl<Tz: TimeZone> LocalDateTime<Tz> {
30    /// Returns `Some` when the conversion time is unique, or `None` otherwise.
31    pub fn single(self) -> Option<DateTime<Tz>> {
32        match self {
33            Self::Single(dt) => Some(dt),
34            _ => None,
35        }
36    }
37
38    /// Returns the earliest possible conversion time.
39    pub fn earliest(self) -> DateTime<Tz> {
40        match self {
41            Self::Single(dt) | Self::Ambiguous(dt, _) => dt,
42        }
43    }
44
45    /// Returns the latest possible conversion time.
46    pub fn latest(self) -> DateTime<Tz> {
47        match self {
48            Self::Single(dt) | Self::Ambiguous(_, dt) => dt,
49        }
50    }
51}
52
53impl<Tz: TimeZone> LocalDateTime<Tz> {
54    pub(super) fn from_date(date: NaiveDate, tz: &Tz) -> Result<LocalDateTime<Tz>, Error> {
55        tz.from_local_datetime(&date.and_hms_opt(0, 0, 0).unwrap())
56            .try_into()
57    }
58
59    pub(super) fn from_datetime(
60        datetime: NaiveDateTime,
61        tz: &Tz,
62    ) -> Result<LocalDateTime<Tz>, Error> {
63        tz.from_local_datetime(&datetime).try_into()
64    }
65}
66
67impl<Tz: TimeZone> Add<Duration> for LocalDateTime<Tz> {
68    type Output = Self;
69
70    fn add(self, rhs: Duration) -> Self::Output {
71        match self {
72            Self::Single(dt) => Self::Single(dt + rhs),
73            Self::Ambiguous(dt1, dt2) => Self::Ambiguous(dt1 + rhs, dt2 + rhs),
74        }
75    }
76}
77
78impl<Tz: TimeZone> Sub<Duration> for LocalDateTime<Tz> {
79    type Output = Self;
80
81    fn sub(self, rhs: Duration) -> Self::Output {
82        match self {
83            Self::Single(dt) => Self::Single(dt - rhs),
84            Self::Ambiguous(dt1, dt2) => Self::Ambiguous(dt1 - rhs, dt2 - rhs),
85        }
86    }
87}