diff options
Diffstat (limited to 'src/stream/datetime.rs')
-rw-r--r-- | src/stream/datetime.rs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/stream/datetime.rs b/src/stream/datetime.rs new file mode 100644 index 0000000..8b67e78 --- /dev/null +++ b/src/stream/datetime.rs @@ -0,0 +1,93 @@ +/** + * Date and time representation in the stream. + * + * SPDX-FileCopyrightText: 2023 Eilertsens Kodeknekkeri + * SPDX-FileCopyrightText: 2023 Harald Eilertsen <haraldei@anduin.net> + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +use chrono::NaiveDateTime; +use serde::Deserialize; + +/** + * Handle date and time. + * + * This is mainly a wrapper around the chrono::NaiveDateTime struct, + * as the date and time returned by the json data from the zot stream + * API's does not contain any timezone information. + */ +#[derive(Debug, PartialEq)] +pub struct DateTime { + datetime: Option<NaiveDateTime> +} + +/* + * Implement Display for the DateTime type, so that it will display + * using the correct time and date format by default. + */ +impl std::fmt::Display for DateTime { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.datetime { + Some(dt) => write!(f, "{}", dt.format("%Y-%m-%d %H:%M:%S")), + None => write!(f, "0000-00-00 00:00:00"), + } + } +} + +/* + * Since the date and time format returned in the json from the + * stream API, does not conform to the RFC3339 format expected by + * the default chrono deserializer, we have to implement our own + * deserializer. + */ +impl<'de> Deserialize<'de> for DateTime { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::de::Deserializer<'de>, + { + Ok(deserializer.deserialize_str(DateTimeVisitor)?) + } +} + +struct DateTimeVisitor; + +impl<'de> serde::de::Visitor<'de> for DateTimeVisitor { + type Value = DateTime; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "a date and time formatted string") + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + let datetime = if s == "0000-00-00 00:00:00" { + None + } else { + Some(NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") + .map_err(|_| E::custom(format!("invalid date time format: {}", s)))?) + }; + + Ok(Self::Value{ datetime }) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_deserialize_datetime() { + let tests = vec![ + r#""0000-00-00 00:00:00""#, + r#""2016-12-17 13:37:00""#, + ]; + + for test in tests { + let datetime: DateTime = serde_json::from_str(test).unwrap(); + assert_eq!(test.trim_matches('"'), datetime.to_string()); + } + } +} |