Skip to main content

activitystreams/primitives/
xsd_datetime.rs

1/*
2 * This file is part of ActivityStreams.
3 *
4 * Copyright © 2020 Riley Trautman
5 *
6 * ActivityStreams is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ActivityStreams is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with ActivityStreams.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/// The type xsd:dateTime represents a specific date and time in the format
21/// CCYY-MM-DDThh:mm:ss.sss, which is a concatenation of the date and time forms, separated by a
22/// literal letter "T".
23///
24/// All of the same rules that apply to the date and time types are applicable
25/// to xsd:dateTime as well.
26///
27/// An optional time zone expression may be added at the end of the value. The letter Z is used to
28/// indicate Coordinated Universal Time (UTC). All other time zones are represented by their
29/// difference from Coordinated Universal Time in the format +hh:mm, or -hh:mm. These values may
30/// range from -14:00 to 14:00. For example, US Eastern Standard Time, which is five hours behind
31/// UTC, is represented as -05:00. If no time zone value is present, it is considered unknown; it
32/// is not assumed to be UTC.
33#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
34pub struct XsdDateTime(chrono::DateTime<chrono::FixedOffset>);
35
36/// The error type produced when an XsdDateTime cannot be parsed
37#[derive(Clone, Debug, thiserror::Error)]
38#[error("Error parsing DateTime")]
39pub struct XsdDateTimeError;
40
41impl XsdDateTime {
42    /// Borrow the underlying `chrono::DateTime<chrono::FixedOffset>`
43    pub fn as_datetime(&self) -> &chrono::DateTime<chrono::FixedOffset> {
44        self.as_ref()
45    }
46
47    /// Mutably borrow the underlying `chrono::DateTime<chrono::FixedOffset>`
48    pub fn as_datetime_mut(&mut self) -> &mut chrono::DateTime<chrono::FixedOffset> {
49        self.as_mut()
50    }
51}
52
53impl From<chrono::DateTime<chrono::FixedOffset>> for XsdDateTime {
54    fn from(d: chrono::DateTime<chrono::FixedOffset>) -> Self {
55        XsdDateTime(d)
56    }
57}
58
59impl From<XsdDateTime> for chrono::DateTime<chrono::FixedOffset> {
60    fn from(d: XsdDateTime) -> Self {
61        d.0
62    }
63}
64
65impl AsRef<chrono::DateTime<chrono::FixedOffset>> for XsdDateTime {
66    fn as_ref(&self) -> &chrono::DateTime<chrono::FixedOffset> {
67        &self.0
68    }
69}
70
71impl AsMut<chrono::DateTime<chrono::FixedOffset>> for XsdDateTime {
72    fn as_mut(&mut self) -> &mut chrono::DateTime<chrono::FixedOffset> {
73        &mut self.0
74    }
75}
76
77impl std::convert::TryFrom<String> for XsdDateTime {
78    type Error = XsdDateTimeError;
79
80    fn try_from(s: String) -> Result<Self, Self::Error> {
81        s.parse()
82    }
83}
84
85impl std::convert::TryFrom<&str> for XsdDateTime {
86    type Error = XsdDateTimeError;
87
88    fn try_from(s: &str) -> Result<Self, Self::Error> {
89        s.parse()
90    }
91}
92
93impl std::convert::TryFrom<&mut str> for XsdDateTime {
94    type Error = XsdDateTimeError;
95
96    fn try_from(s: &mut str) -> Result<Self, Self::Error> {
97        s.parse()
98    }
99}
100
101impl std::str::FromStr for XsdDateTime {
102    type Err = XsdDateTimeError;
103
104    fn from_str(s: &str) -> Result<Self, Self::Err> {
105        Ok(XsdDateTime(
106            chrono::DateTime::parse_from_rfc3339(s).map_err(|_| XsdDateTimeError)?,
107        ))
108    }
109}
110
111impl std::fmt::Display for XsdDateTime {
112    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
113        let s = self.0.to_rfc3339();
114        std::fmt::Display::fmt(&s, f)
115    }
116}
117
118impl serde::ser::Serialize for XsdDateTime {
119    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
120    where
121        S: serde::ser::Serializer,
122    {
123        serializer.serialize_str(&self.to_string())
124    }
125}
126
127impl<'de> serde::de::Deserialize<'de> for XsdDateTime {
128    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
129    where
130        D: serde::de::Deserializer<'de>,
131    {
132        let s = String::deserialize(deserializer)?;
133        s.parse().map_err(serde::de::Error::custom)
134    }
135}