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方法即可。