serde_chrono_str/
ts_milliseconds_str.rs1use chrono::NaiveDateTime;
2use serde::{de::Visitor, Deserializer, Serializer};
3
4pub fn serialize<S: Serializer>(date_time: &NaiveDateTime, s: S) -> Result<S::Ok, S::Error> {
5 s.serialize_str(&i64::to_string(&date_time.timestamp_millis()))
6}
7
8pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<NaiveDateTime, D::Error> {
9 struct V;
10
11 impl Visitor<'_> for V {
12 type Value = NaiveDateTime;
13
14 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
15 formatter.write_str("a string containing a millisecond timestamp")
16 }
17
18 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
19 where
20 E: serde::de::Error,
21 {
22 let milliseconds = v.parse::<i64>().map_err(E::custom)?;
23 let seconds = milliseconds / 1000;
24 let milliseconds = (milliseconds % 1000) as u32;
25 let nanos = milliseconds * 1_000_000;
26
27 Ok(NaiveDateTime::from_timestamp(seconds, nanos))
28 }
29 }
30
31 d.deserialize_str(V)
32}
33
34#[cfg(test)]
35mod tests {
36 use chrono::{NaiveDateTime, Utc, TimeZone, DateTime};
37 use serde::{Deserialize, Serialize};
38 use serde_json::{from_str, from_value, json, to_string};
39
40 #[derive(Deserialize, Serialize)]
41 struct Foo {
42 #[serde(with = "crate::ts_milliseconds_str")]
43 time: NaiveDateTime,
44 }
45
46 const TIMESTAMP_MS: i64 = 1640995200000;
47
48
49 #[test]
50 fn can_deserialize() {
51 let date_time = Utc.ymd(2022, 1, 1).and_hms(0, 0, 0);
52 let foo: Foo = from_value(json!({"time": TIMESTAMP_MS.to_string()})).unwrap();
53 let time = Utc.from_utc_datetime(&foo.time);
54 assert_eq!(time, date_time);
55 }
56
57 #[test]
58 fn round_trip() {
59 let foo: Foo = from_value(json!({"time": TIMESTAMP_MS.to_string()})).unwrap();
60 let s = to_string(&foo).unwrap();
61 let foo_again: Foo = from_str(&s).unwrap();
62 assert_eq!(foo.time, foo_again.time);
63 }
64}