简体   繁体   English

使用 `serde::Serialize` 和 `Option<chrono::datetime> `</chrono::datetime>

[英]Using `serde::Serialize` with `Option<chrono::DateTime>`

When trying to serializeOption<chrono::DateTime<Utc>> I'm encountering an error:尝试序列化Option<chrono::DateTime<Utc>>时遇到错误:

error[E0308]: mismatched types
  --> src/main.rs:39:14
   |
39 |     #[derive(Serialize, Debug)]
   |              ^^^^^^^^^ expected struct `DateTime`, found enum `std::option::Option`
   |
   = note: expected reference `&DateTime<Utc>`
              found reference `&'__a std::option::Option<DateTime<Utc>>`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

Code ( Playground ):代码( 游乐场):

use chrono::{serde::ts_seconds, DateTime, NaiveDate, Utc};
use serde::Serialize;

fn main() {
    let test_struct = TestStruct {
        a: 2.45,
        date: Some(DateTime::from_utc(
            NaiveDate::from_ymd(2000, 1, 1).and_hms(1, 1, 1),
            Utc,
        )),
    };
    let string = serde_json::to_string(&test_struct).unwrap();
    println!("default: {}", string);
    
    #[derive(Serialize, Debug)]
    struct TestStruct {
        pub a: f32,
        #[serde(with = "ts_seconds")]
        pub date: Option<DateTime<Utc>>,
    }
}

Looking at chrono::ts_seconds and serde_with I have no idea where to move forward here.看着chrono::ts_secondsserde_with我不知道该往哪里前进。

I would really appreciate any help with this.我真的很感激任何帮助。

Chrono already has a function for Option<DateTime<Utc>> , namely chrono::serde::ts_seconds_option . Chrono 已经有一个 function 用于Option<DateTime<Utc>> ,即chrono::serde::ts_seconds_option

#[derive(Serialize, Debug)]
struct TestStruct {
    pub a: f32,
    #[serde(with = "ts_seconds_option")]
    pub date: Option<DateTime<Utc>>,
}

The solution with serde_with looks like this:使用serde_with的解决方案如下所示:

#[serde_as]
#[derive(Serialize, Debug)]
struct TestStruct {
    pub a: f32,
    #[serde_as(as = "Option<DurationSeconds<i64>>")]
    pub date: Option<DateTime<Utc>>,
}

You can write your own wrapper and combine it with serialize_with and skip_serializing_if :您可以编写自己的包装器并将其与serialize_withskip_serializing_if结合使用:

pub fn serialize_dt<S>(
    dt: &Option<DateTime<Utc>>, 
    serializer: S
) -> Result<S::Ok, S::Error> 
where
    S: Serializer {
    match dt {
        Some(dt) => ts_seconds::serialize(dt, serializer),
        _ => unreachable!(),
    }
}

#[derive(Serialize, Debug)]
struct TestStruct {
    pub a: f32,
    #[serde(serialize_with = "serialize_dt", skip_serializing_if  = "Option::is_none")]
    pub date: Option<DateTime<Utc>>,
}

Playground 操场

For when you want to use DateTime<Utc> instead of a Unix timestamp.当您想使用DateTime<Utc>而不是 Unix 时间戳时。

const FORMAT: &str = "%Y-%m-%d %H:%M:%S";

pub fn serialize<S>(date: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    match date.is_some() {
        true => {
            let s = format!("{}", date.as_ref().unwrap().format(FORMAT));
            serializer.serialize_str(&s)
        }
        false => serializer.serialize_none(),
    }
}

"{\"a\":2.45,\"date\":\"2022-12-16 16:40:36\"}"
TestStruct { a: 2.45, date: Some(2022-12-16T16:40:36Z) }

"{\"a\":2.45,\"date\":null}"
TestStruct { a: 2.45, date: None }

Rust Playground 铁锈游乐场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM