1use anyhow::anyhow;
2use serde::{de::Visitor, Deserialize, Serialize};
3use std::fmt::Display;
4use time::{
5 format_description::FormatItem, macros::format_description, OffsetDateTime, PrimitiveDateTime,
6};
7
8static VERSION_TIME_FORMAT: &[FormatItem<'static>] =
9 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]Z");
10
11#[derive(Clone, Debug, Hash, PartialOrd, Ord, Eq, PartialEq)]
15pub struct VersionTime(pub OffsetDateTime);
16
17impl Default for VersionTime {
18 fn default() -> Self {
19 VersionTime(OffsetDateTime::from_unix_timestamp(0).unwrap())
20 }
21}
22
23impl Display for VersionTime {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.write_str(&format!(
26 "{}-{:02}-{:02}T{:02}:{:02}:{:02}Z",
27 self.0.year(),
28 u8::from(self.0.month()),
29 self.0.day(),
30 self.0.hour(),
31 self.0.minute(),
32 self.0.second()
33 ))
34 }
35}
36
37impl Serialize for VersionTime {
38 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
39 where
40 S: serde::Serializer,
41 {
42 serializer.serialize_str(&self.to_string())
43 }
44}
45
46impl Visitor<'_> for VersionTime {
47 type Value = VersionTime;
48
49 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
50 formatter.write_str("Expecting a datetime in DID specification format")
51 }
52
53 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
54 where
55 E: serde::de::Error,
56 {
57 match Self::parse(v) {
58 Ok(v) => Ok(v),
59 Err(e) => Err(E::custom(e)),
60 }
61 }
62}
63
64impl<'de> Deserialize<'de> for VersionTime {
65 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
66 where
67 D: serde::Deserializer<'de>,
68 {
69 deserializer.deserialize_str::<VersionTime>(Default::default())
70 }
71}
72
73impl VersionTime {
74 pub fn parse(s: &str) -> Result<Self, anyhow::Error> {
76 match PrimitiveDateTime::parse(s, VERSION_TIME_FORMAT) {
77 Ok(dt) => Ok(VersionTime(dt.assume_utc())),
78 Err(e) => Err(anyhow!(e)),
79 }
80 }
81}