From 4296f0d778430316fa93f23d229835dd5e2ace08 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Wed, 26 Apr 2023 22:02:07 +0200 Subject: [PATCH] Round seconds to nearest minute when serializing offsets --- src/datetime/mod.rs | 4 +++- src/datetime/serde.rs | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index bf9c16ad5d..f32a1cc6a4 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1447,7 +1447,9 @@ where &FixedOffset::east_opt(3650).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() ) .ok(), - Some(r#""2014-07-24T12:34:06+01:00:50""#.into()) + // Seconds are not allowed by RFC 3339, offset should be rounded to the nearest minute. + // In this case +01:01 + Some(r#""2014-07-24T12:34:06+01:01""#.into()) ); } diff --git a/src/datetime/serde.rs b/src/datetime/serde.rs index 28d3b9f6ed..5f607fceba 100644 --- a/src/datetime/serde.rs +++ b/src/datetime/serde.rs @@ -41,14 +41,23 @@ impl ser::Serialize for DateTime { impl<'a, Tz: TimeZone> fmt::Display for DisplayModifiedRfc3339<'a, Tz> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Reuse `Debug` impls, which is faster. + // Don't use DateTime::to_rfc3339 because we want to use a more compact + // representation (`Z`) for UTC datetimes. + + // Reuse the `Debug` impl of `NaiveDateTime`. Debug::fmt(&self.inner.naive_local(), f)?; let offset = (*self.inner.offset()).fix(); - // Choose a more compact representation (`Z`) for UTC datetimes. if Some(offset) == FixedOffset::east_opt(0) { f.write_char('Z') } else { - Debug::fmt(&offset, f) + // We do not reuse the `Debug` implementation of `FixedOffset` because that may + // contain seconds, which are not allowed by RFC 3339. + let offset = offset.local_minus_utc(); + let (sign, offset) = if offset < 0 { ('-', -offset) } else { ('+', offset) }; + let mins = (offset + 30) / 60; + let hour = mins / 60; + let min = mins % 60; + write!(f, "{}{:02}:{:02}", sign, hour, min) } } }