libtad_models/time/
datetime.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2
3#[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize)]
4#[serde(default)]
5/// Date and time, split up into components.
6pub struct DateTime {
7    /// The year component of the timestamp.
8    pub year: i32,
9
10    /// The month component of the timestamp.
11    pub month: i32,
12
13    /// The day component of the timestamp.
14    pub day: i32,
15
16    /// The hour component of the timestamp.
17    pub hour: i32,
18
19    /// The minute component of the timestamp.
20    pub minute: i32,
21
22    /// The second component of the timestamp.
23    pub second: i32,
24}
25
26impl Serialize for DateTime {
27    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
28    where
29        S: Serializer,
30    {
31        serializer.serialize_str(&self.to_string())
32    }
33}
34
35impl DateTime {
36    pub(crate) fn option_deserialize_from_str<'a, D>(
37        deserializer: D,
38    ) -> Result<Option<Self>, D::Error>
39    where
40        D: Deserializer<'a>,
41    {
42        let s: Option<String> = Option::deserialize(deserializer)?;
43        if let Some(inner) = s {
44            Ok(Some(DateTime::from(&inner)))
45        } else {
46            Ok(None)
47        }
48    }
49
50    pub(crate) fn deserialize_from_str<'a, D>(deserializer: D) -> Result<Self, D::Error>
51    where
52        D: Deserializer<'a>,
53    {
54        let s = String::deserialize(deserializer)?;
55
56        Ok(DateTime::from(&s))
57    }
58}
59
60impl std::fmt::Display for DateTime {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(
63            f,
64            "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
65            self.year, self.month, self.day, self.hour, self.minute, self.second
66        )
67    }
68}
69
70impl<A: AsRef<str>> From<A> for DateTime {
71    fn from(s: A) -> Self {
72        fn alt(s: &str) -> (&str, &str) {
73            if let Some(d) = s.split_once('-') {
74                return d;
75            }
76
77            if let Some(m) = s.split_once('T') {
78                return m;
79            }
80
81            if let Some(t) = s.split_once(':') {
82                return t;
83            }
84
85            (s, "")
86        }
87
88        let (year, rest) = alt(s.as_ref());
89        let (month, rest) = alt(rest);
90        let (day, rest) = alt(rest);
91        let (hour, rest) = alt(rest);
92        let (minute, rest) = alt(rest);
93        let (second, _) = alt(rest);
94
95        Self {
96            year: year.parse().unwrap_or_default(),
97            month: month.parse().unwrap_or_default(),
98            day: day.parse().unwrap_or_default(),
99            hour: hour.parse().unwrap_or_default(),
100            minute: minute.parse().unwrap_or_default(),
101            second: second.parse().unwrap_or_default(),
102        }
103    }
104}
105
106#[test]
107fn parse_datetime() {
108    let datetime_str = "2021-04-04T16:42:21";
109
110    let datetime = DateTime::from(datetime_str.to_string());
111
112    assert!(datetime.year == 2021);
113    assert!(datetime.month == 4);
114    assert!(datetime.day == 4);
115    assert!(datetime.hour == 16);
116    assert!(datetime.minute == 42);
117    assert!(datetime.second == 21);
118}
119
120#[test]
121fn parse_date_only() {
122    let datetime_str = "2021-04-04";
123
124    let datetime = DateTime::from(datetime_str.to_string());
125
126    assert!(datetime.year == 2021);
127    assert!(datetime.month == 4);
128    assert!(datetime.day == 4);
129    assert!(datetime.hour == 0);
130    assert!(datetime.minute == 0);
131    assert!(datetime.second == 0);
132}