How to use a custom serde deserializer for chrono timestamps?
我正在尝试将JSON解析为具有
如何连接两者并使用
我正在使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | extern crate serde; extern crate serde_json; use serde::Deserialize; extern crate chrono; use chrono::NaiveDateTime; fn from_timestamp(time: &String) -> NaiveDateTime { NaiveDateTime::parse_from_str(time,"%Y-%m-%dT%H:%M:%S.%f").unwrap() } #[derive(Deserialize, Debug)] struct MyJson { name: String, #[serde(deserialize_with ="from_timestamp")] timestamp: NaiveDateTime, } fn main() { let result: MyJson = serde_json::from_str(r#"{"name":"asdf","timestamp":"2019-08-15T17:41:18.106108"}"#) .unwrap(); println!("{:?}", result); } |
我遇到了三种不同的编译错误:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | error[E0308]: mismatched types --> src/main.rs:11:10 | 11 | #[derive(Deserialize, Debug)] | ^^^^^^^^^^^ expected reference, found type parameter | = note: expected type `&std::string::String` found type `__D` error[E0308]: mismatched types --> src/main.rs:11:10 | 11 | #[derive(Deserialize, Debug)] | ^^^^^^^^^^- | | | | | this match expression has type `chrono::NaiveDateTime` | expected struct `chrono::NaiveDateTime`, found enum `std::result::Result` | in this macro invocation | = note: expected type `chrono::NaiveDateTime` found type `std::result::Result<_, _>` error[E0308]: mismatched types --> src/main.rs:11:10 | 11 | #[derive(Deserialize, Debug)] | ^^^^^^^^^^- | | | | | this match expression has type `chrono::NaiveDateTime` | expected struct `chrono::NaiveDateTime`, found enum `std::result::Result` | in this macro invocation | = note: expected type `chrono::NaiveDateTime` found type `std::result::Result<_, _>` |
我很确定
这相当复杂,但是可以进行以下工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | use chrono::NaiveDateTime; use serde::de; use serde::Deserialize; use std::fmt; struct NaiveDateTimeVisitor; impl<'de> de::Visitor<'de> for NaiveDateTimeVisitor { type Value = NaiveDateTime; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter,"a string represents chrono::NaiveDateTime") } fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: de::Error, { match NaiveDateTime::parse_from_str(s,"%Y-%m-%dT%H:%M:%S.%f") { Ok(t) => Ok(t), Err(_) => Err(de::Error::invalid_value(de::Unexpected::Str(s), &self)), } } } fn from_timestamp<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> where D: de::Deserializer<'de>, { d.deserialize_str(NaiveDateTimeVisitor) } #[derive(Deserialize, Debug)] struct MyJson { name: String, #[serde(deserialize_with ="from_timestamp")] timestamp: NaiveDateTime, } fn main() { let result: MyJson = serde_json::from_str(r#"{"name":"asdf","timestamp":"2019-08-15T17:41:18.106108"}"#) .unwrap(); println!("{:?}", result); } |
虽然@edwardw的答案在技术上是正确的,但恕我直言,它包含太多样板。
一个令人费解的示例-确实在JSON中添加了以字符串形式表示的
的任何内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | use std::fmt::Display; use std::str::FromStr; use chrono::NaiveDateTime; use serde::{de, Deserialize, Deserializer}; #[derive(Deserialize, Debug)] struct MyJson { name: String, #[serde(deserialize_with ="deserialize_from_str")] timestamp: NaiveDateTime, #[serde(deserialize_with ="deserialize_from_str")] age: u8, } // You can use this deserializer for any type that implements FromStr // and the FromStr::Err implements Display fn deserialize_from_str<'de, S, D>(deserializer: D) -> Result<S, D::Error> where S: FromStr, // Required for S::from_str... S::Err: Display, // Required for .map_err(de::Error::custom) D: Deserializer<'de>, { let s: String = Deserialize::deserialize(deserializer)?; S::from_str(&s).map_err(de::Error::custom) } fn main() { let result: MyJson = serde_json::from_str( r#"{"name":"asdf","timestamp":"2019-08-15T17:41:18.106108","age":"11"}"#, ) .unwrap(); println!("{:?}", result); } |
如果要指定格式(使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | use chrono::NaiveDateTime; use serde::{de, Deserialize, Deserializer}; #[derive(Deserialize, Debug)] struct MyJson { name: String, #[serde(deserialize_with ="naive_date_time_from_str")] timestamp: NaiveDateTime, } fn naive_date_time_from_str<'de, D>(deserializer: D) -> Result<NaiveDateTime, D::Error> where D: Deserializer<'de>, { let s: String = Deserialize::deserialize(deserializer)?; NaiveDateTime::parse_from_str(&s,"%Y-%m-%dT%H:%M:%S.%f").map_err(de::Error::custom) } fn main() { let result: MyJson = serde_json::from_str(r#"{"name":"asdf","timestamp":"2019-08-15T17:41:18.106108"}"#) .unwrap(); println!("{:?}", result); } |
Deserialize this field using a function that is different from its implementation of
Deserialize . The given function must be callable asfn<'de, D>(D) -> Result , although it may also be generic overwhere D: Deserializer<'de> T . Fields used withdeserialize_with are not required to implementDeserialize .