如何在Serde中将Map的整数值反序列化为SystemTime类型?
问题描述
我有如下JSON文件,希望将其反序列化为Rust结构体:
{ "name": "Manuel", "friends": { "id1": 1703692376, ... } ... }
其中friends字段包含ID和秒级时间戳。我已创建如下可正常运行的Rust结构体,但希望将friends字段改为HashMap<String, SystemTime>类型,把JSON中的整数值转换为SystemTime类型,请问能否通过Serde实现这一需求?
use std::collections::HashMap; use serde::{Deserialize, Serialize}; #[derive(Debug,Clone,Serialize,Deserialize)] pub struct MyStruct{ name: String, friends: HashMap<String, i64> }
解决方案
完全可以通过Serde实现,核心是为SystemTime添加序列化/反序列化的适配逻辑,以下是两种可行方案:
方案一:手动实现自定义序列化逻辑
通过Serde的Deserialize和Serialize trait,手动完成整数时间戳与SystemTime的转换:
- 导入所需依赖:
use std::collections::HashMap; use std::time::{SystemTime, UNIX_EPOCH}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::de::Error;
- 为
SystemTime实现序列化和反序列化逻辑:
// 反序列化:秒级时间戳转SystemTime impl<'de> Deserialize<'de> for SystemTime { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let timestamp = i64::deserialize(deserializer)?; UNIX_EPOCH.checked_add(std::time::Duration::from_secs(timestamp as u64)) .ok_or_else(|| D::Error::custom("无效时间戳:超出SystemTime范围")) } } // 序列化:SystemTime转秒级时间戳(若需要将结构体序列化为JSON则添加此实现) impl Serialize for SystemTime { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { self.duration_since(UNIX_EPOCH) .map(|d| d.as_secs() as i64) .map_err(|e| S::Error::custom(format!("SystemTime转时间戳失败:{}", e))) } }
- 修改结构体使用目标类型:
#[derive(Debug, Clone, Serialize, Deserialize)] pub struct MyStruct { name: String, friends: HashMap<String, SystemTime>, }
方案二:使用serde_with库简化实现
借助serde_with库提供的现成适配逻辑,无需手动编写大量代码:
- 在
Cargo.toml中添加依赖:
serde_with = "3.0"
- 利用库中
Timestamp模块完成转换:
use std::collections::HashMap; use std::time::SystemTime; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use serde_with::Timestamp; #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MyStruct { name: String, // 指定以秒级时间戳格式序列化/反序列化SystemTime #[serde_as(as = "HashMap<String, Timestamp<i64, serde_with::format::Seconds>>")] friends: HashMap<String, SystemTime>, }
如果你的时间戳是毫秒级,只需将Seconds替换为Milliseconds即可,serde_with支持多种时间戳精度格式。
内容的提问来源于stack exchange,提问作者Manuelarte
相关产品推荐
相关产品推荐

