-
-
Notifications
You must be signed in to change notification settings - Fork 84
Description
TimestampNanoSeconds has the following serialization behavior:
..1385-06-12T00:25:26.290448385Z: panicoverflow when multiplying duration by scalar1385-06-12T00:25:26.290448385Z..1677-09-21T00:12:43.145224192Z: incorrect positive value1677-09-21T00:12:43.145224192Z: panicattempt to negate with overflow1677-09-21T00:12:43.145224193Z..2262-04-11T23:47:16.854775808Z: correct2262-04-11T23:47:16.854775808Z..2554-07-21T23:34:33.709551616Z: incorrect negative value2554-07-21T23:34:33.709551616Z..: panicoverflow when multiplying duration by scalar
Not being able to serialize values outside the range 1677-09-21T00:12:43.145224193Z..2262-04-11T23:47:16.854775808Z is expected since it's serializing to an i64, but if the value is outside that range it should return an error, not panic or return incorrect values.
use chrono::{DateTime, Utc};
use serde::Serialize;
use serde_with::serde_as;
fn main() {
#[serde_as]
#[derive(Serialize)]
struct S(#[serde_as(as = "serde_with::TimestampNanoSeconds")] DateTime<Utc>);
fn try_serialize(v: DateTime<Utc>) {
let s = std::panic::catch_unwind(|| {
serde_json::to_string(&S(v)).unwrap_or_else(|e| format!("Serialization error: {e}"))
})
.unwrap_or_else(|p| {
format!(
"Panic: {}",
p.downcast_ref::<&str>()
.map(|s| &**s)
.unwrap_or_else(|| p.downcast_ref::<String>().map(|s| &**s).unwrap())
)
});
println!("{v}: {s}");
}
try_serialize(DateTime::<Utc>::MIN_UTC);
try_serialize("1385-06-12T00:25:26.290448384Z".parse().unwrap());
try_serialize("1385-06-12T00:25:26.290448385Z".parse().unwrap());
try_serialize("1677-09-21T00:12:43.145224191Z".parse().unwrap());
try_serialize("1677-09-21T00:12:43.145224192Z".parse().unwrap());
try_serialize("1677-09-21T00:12:43.145224193Z".parse().unwrap());
try_serialize("2262-04-11T23:47:16.854775807Z".parse().unwrap());
try_serialize("2262-04-11T23:47:16.854775808Z".parse().unwrap());
try_serialize("2554-07-21T23:34:33.709551615Z".parse().unwrap());
try_serialize("2554-07-21T23:34:33.709551616Z".parse().unwrap());
try_serialize(DateTime::<Utc>::MAX_UTC);
}-262143-01-01 00:00:00 UTC: Panic: overflow when multiplying duration by scalar
1385-06-12 00:25:26.290448384 UTC: Panic: overflow when multiplying duration by scalar
1385-06-12 00:25:26.290448385 UTC: 1
1677-09-21 00:12:43.145224191 UTC: 9223372036854775807
1677-09-21 00:12:43.145224192 UTC: Panic: attempt to negate with overflow
1677-09-21 00:12:43.145224193 UTC: -9223372036854775807
2262-04-11 23:47:16.854775807 UTC: 9223372036854775807
2262-04-11 23:47:16.854775808 UTC: -9223372036854775808
2554-07-21 23:34:33.709551615 UTC: -1
2554-07-21 23:34:33.709551616 UTC: Panic: overflow when multiplying duration by scalar
+262142-12-31 23:59:59.999999999 UTC: Panic: overflow when multiplying duration by scalar
A similar problem exists with TimestampNanoSecondsWithFrac:
..1385-06-12T00:25:26.290448385Z: panicoverflow when multiplying duration by scalar1385-06-12T00:25:26.290448385Z..2554-07-21T23:34:33.709551616Z: correct2554-07-21T23:34:33.709551616Z..: panicoverflow when multiplying duration by scalar
TimeStampNanoSecondsWithFrac should never fail because it is serializing to f64 and f64 can represent much larger values, at the expense of precision.
The other TimeStamp* serializers are not affected because the range of values that can be represented by DateTime is smaller than the range of values that can be represented by an i64.
DurationNanoSeconds and DurationNanoSecondsFrac also have a similar problem:
..18446744073.709551616s: correct18446744073.709551616s..: panic:overflow when multiplying duration by scalar
DurationNanoSeconds should return an error instead of panicking, and DurationNanoSecondsFrac should never fail.
DurationMicroSeconds and DurationMicroSecondsFrac fail the same way for 18446744073709.551616s... 18446744073709551.616s.. for DurationMilliSeconds and DurationMilliSecondsWithFrac. DurationSeconds and DurationSecondsWithFrac are unaffected.