pbjson_types/
timestamp.rs1use crate::Timestamp;
2use chrono::{DateTime, Utc};
3use serde::de::Visitor;
4use serde::Serialize;
5
6impl TryFrom<Timestamp> for DateTime<Utc> {
7 type Error = &'static str;
8 fn try_from(value: Timestamp) -> Result<Self, Self::Error> {
9 let Timestamp { seconds, nanos } = value;
10
11 Self::from_timestamp(
12 seconds,
13 nanos
14 .try_into()
15 .map_err(|_| "out of range integral type conversion attempted")?,
16 )
17 .ok_or("invalid or out-of-range datetime")
18 }
19}
20
21impl From<DateTime<Utc>> for Timestamp {
22 fn from(value: DateTime<Utc>) -> Self {
23 Self {
24 seconds: value.timestamp(),
25 nanos: value.timestamp_subsec_nanos() as i32,
26 }
27 }
28}
29
30impl Serialize for Timestamp {
31 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
32 where
33 S: serde::Serializer,
34 {
35 let t: DateTime<Utc> = (*self).try_into().map_err(serde::ser::Error::custom)?;
36 serializer.serialize_str(t.to_rfc3339().as_str())
37 }
38}
39
40struct TimestampVisitor;
41
42impl<'de> Visitor<'de> for TimestampVisitor {
43 type Value = Timestamp;
44
45 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 formatter.write_str("a date string")
47 }
48
49 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
50 where
51 E: serde::de::Error,
52 {
53 let d = DateTime::parse_from_rfc3339(s).map_err(serde::de::Error::custom)?;
54 let d: DateTime<Utc> = d.into();
55 Ok(d.into())
56 }
57}
58
59impl<'de> serde::Deserialize<'de> for Timestamp {
60 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
61 where
62 D: serde::Deserializer<'de>,
63 {
64 deserializer.deserialize_str(TimestampVisitor)
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use chrono::{FixedOffset, TimeZone};
72 use serde::de::value::{BorrowedStrDeserializer, Error};
73 use serde::Deserialize;
74
75 #[test]
76 fn test_date() {
77 let datetime = FixedOffset::east_opt(5 * 3600)
78 .expect("time zone offset should be valid")
79 .with_ymd_and_hms(2016, 11, 8, 21, 7, 9)
80 .unwrap();
81 let encoded = datetime.to_rfc3339();
82 assert_eq!(&encoded, "2016-11-08T21:07:09+05:00");
83
84 let utc: DateTime<Utc> = datetime.into();
85 let utc_encoded = utc.to_rfc3339();
86 assert_eq!(&utc_encoded, "2016-11-08T16:07:09+00:00");
87
88 let deserializer = BorrowedStrDeserializer::<'_, Error>::new(&encoded);
89 let a: Timestamp = Timestamp::deserialize(deserializer).unwrap();
90 assert_eq!(a.seconds, utc.timestamp());
91 assert_eq!(a.nanos, utc.timestamp_subsec_nanos() as i32);
92
93 let encoded = serde_json::to_string(&a).unwrap();
94 assert_eq!(encoded, format!("\"{}\"", utc_encoded));
95 }
96}