How to make chrono NaiveDateTime with only ms resolution?

I am creating message structs and serialising them to JSON something like the following:

    let message = MyMessageStruct {
        id: ...,
        tstamp: Local::now().naive_local(),
        other_stuff: ...,
    };
    let my_message_json = serde_json::to_string(&message)?;

Which results in JSON messages that contain tstamp fields which look like this:

{
    "id":"group.status.270.11",
    "tstamp":"2024-12-14T19:38:27.539327501",
    ...
}

Which is nice. Except those messages end up in my colleagues Python code where the Python naive date time deserialisation rejects it as it is expecting only 6 decimal places in the seconds.

My colleague has butchered his Python to manually chop off the spare digits but it would be better if I did not send them in the first place. In fact 2 decimal paces would do for us.

I'm sure chrono has a neat way to achieve this but darned if I can figure it out from all the docs.

I notice Chrono's NaiveDateTime has a from_timestamp_millis()method but that is deprecated.

Any suggestions?

I think you have to manually format your timestamp. You can do so rather conveniently during serialization using #[serde(serialize_with = "...")]:

use chrono::naive::NaiveDateTime;
use chrono::Local;

use serde::{Serialize, Serializer};

#[derive(Serialize)]
struct Foo {
    #[serde(serialize_with = "serialize_tstamp")]
    tstamp: NaiveDateTime,
}

fn serialize_tstamp<S>(v: &NaiveDateTime, s: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    s.collect_str(&v.format("%Y-%m-%dT%H:%M:%S%.6f"))
}

fn main() {
    let f = Foo {
        tstamp: Local::now().naive_local(),
    };

    println!("{}", serde_json::to_string_pretty(&f).unwrap());
}

Playground.

Or create your own wrapper type around NaiveDateTime that serializes using a decimal precision of only six digits.

5 Likes

That works. Amazing. Big thanks.

2 Likes

Please mark their reply as the solution.

I did already. An hour ago!

Sorry. It showed up on your reply for me until just now. I should have refreshed.

It still shows the wrong post marked as the solution for me.

Ah, sorry, now I see the problem. Fixed. Thanks.

1 Like