use chrono::prelude::*;
use serde::{Deserialize, Serialize};
fn main() {
// let date: DateTime<Local> = Local::now();
// println!("{}", date.format("%Y-%m-%d %H:%M:%S").to_string())
// println!("{}",Local.timestamp_millis(1588325921426).format("%Y-%m-%d %H:%M:%S").to_string())
let json_str = r#"
{
"name": "Skrillex",
"create_time": 1588325921426//第三方對接時,對方給的時間爲時間戳格式
}
"#;
let data: Person = serde_json::from_str(json_str).unwrap();
println!("{:#?}", data);
println!("{:#?}", data.create_time.format("%Y-%m-%d %H:%M:%S").to_string());
let serialized = serde_json::to_string_pretty(&data).unwrap();
println!("{}", serialized);
}
#[derive(Serialize, Deserialize, Debug)]
struct Person {
name: String,
#[serde(with = "my_date_format")]//序列化和反序列化時,調用my_date_format模塊中定義的序列化和反序列化方法來處理
create_time: DateTime<Local>,
}
mod my_date_format {
use std::error::Error;
use chrono::{DateTime, Local, TimeZone};
use serde::{self, Deserialize, Deserializer, Serializer};
use serde::de::{Unexpected, Visitor};
use serde::export::Formatter;
pub fn serialize<S>(
date: &DateTime<Local>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_i64(date.timestamp_millis())//序列化直接轉爲時間戳
}
pub fn deserialize<'de, D>(
deserializer: D,
) -> Result<DateTime<Local>, D::Error>
where
D: Deserializer<'de>,
{
let timestamp = deserializer.deserialize_any(I64)?;//定義了I64訪問者來處理格式轉換
Ok(Local.timestamp_millis(timestamp))
}
struct I64;
impl<'de> Visitor<'de> for I64 {
type Value = i64;
fn expecting<'a>(&self, formatter: &mut Formatter<'a>) -> std::fmt::Result {
write!(formatter, "is an integer")
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E> where
E: Error, {//這個方法在這個業務裏沒有實現必要,只是爲了例子解釋
println!("v {}", v);
Ok(v as i64)
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> where
E: Error, {
println!("v {}", v);
Ok(v)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> where
E: Error, {//這個例子如果不實現這個方法,就會報錯
println!("v {}", v);
Ok(v as i64)
}
}
}
serde框架使用了訪問者模式來定義數據處理【可以參考《Rust編程之道》中7.2.2訪問者模式中有對serde框架的源碼分析】。
先說下實現 impl<'de> Visitor<'de> for I64的默認轉換方法,剛開始我想着DateTime<Local>的timestamp_millis方法返回的時間戳是i64,所以只實現了visit_i64方法
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> where
E: Error,
,後來還是提示轉換失敗,就去看了Visitor<'de> 的源碼,發現visit_i8、visit_i16、visit_i32都是調用visit_i64方法,而visit_i64方法默認是返回一個error類型
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: Error,
{
Err(Error::invalid_type(Unexpected::Signed(v), &self))//重點在這裏 Unexpected類型不對
}
但是我明明又重寫了visit_i64方法,但還是報這樣的錯誤。所以這時我就懷疑是不是serde框架先轉換成u64類型了。
同樣的,visit_u8、visit_u16、visit_u32都是調用visit_u64方法。我就懷疑serde框架是先調用了visit_u64方法,所以就重寫了visit_u64,加日誌發現對於"create_time": 1588325921426,1588325921426會優先解析爲u64類型,故只實現visit_u64方法即可。