I receive a millisecond timestamp from an external API as a JSON string attribute.
{"time":"1526522699918"}
Whats the best way to use Serde to parse the millisecond timestamp as a string?
The ts_milliseconds
option works with a millisecond timestamp as an integer, but throws an error when using a string.
Example - Rust Playground
#[macro_use]
extern crate serde_derive;
extern crate chrono;
use chrono::serde::ts_milliseconds;
use chrono::{DateTime, Utc};
#[derive(Deserialize, Serialize)]
struct S {
#[serde(with = "ts_milliseconds")]
time: DateTime<Utc>,
}
fn main() {
serde_json::from_str::<S>(r#"{"time":1526522699918}"#).unwrap(); // millisecond timestamp as a integer
serde_json::from_str::<S>(r#"{"time":"1526522699918"}"#).unwrap(); // millisecond timestamp as an string
}
Error message:
Error("invalid type: string \"1526522699918\", expected a unix timestamp in milliseconds", line: 1, column: 23)'
Abstracting over the serialized for of DateTime
is possible using the TimestampMilliSeconds
type from serde_with
.
With it, you can serialize to / deserialize from floats, integers, or strings. You need to enable the chrono
feature for serde_with
.
The first argument (here String
) configures the serialization behavior. In case of String
this means the DateTime
will be serialized as a string containing a Unix timestamp in milliseconds.
The second argument (here Flexible
) allows configuring the deserialization behavior. Flexible
means that it will deserialize from floats, integers, and strings without returning an error. You can use that to get the main
function from the question to run. The other option is Strict
, which only deserializes the format from the first argument. For this example this means it would only deserialize the time as a string, but would return an error when encountering the integer.
use ::chrono::{DateTime, Utc};
use serde_with::TimestampMilliSeconds;
use serde_with::formats::Flexible;
#[serde_with::serde_as]
#[derive(serde::Deserialize, serde::Serialize)]
struct S {
#[serde_as(as = "TimestampMilliSeconds<String, Flexible>")]
time: DateTime<Utc>,
}
fn main() {
serde_json::from_str::<S>(r#"{"time":1526522699918}"#).unwrap(); // millisecond timestamp as a integer
serde_json::from_str::<S>(r#"{"time":"1526522699918"}"#).unwrap(); // millisecond timestamp as an string
}