diff --git a/CHANGELOG.md b/CHANGELOG.md index 525db47c0d..5bf22e8bf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Versions with only mechanical changes will be omitted from the following list. * Add more formatting documentation and examples. * Add support for microseconds timestamps serde serialization/deserialization (#304) +* Fix `chrono::DurationRound` is not TZ aware (#495) ## 0.4.19 diff --git a/src/round.rs b/src/round.rs index 92d7c3a504..f391d1d8d1 100644 --- a/src/round.rs +++ b/src/round.rs @@ -151,10 +151,12 @@ impl DurationRound for DateTime { fn duration_round(self, duration: Duration) -> Result { if let Some(span) = duration.num_nanoseconds() { - if self.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { + let naive = self.naive_local(); + + if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { return Err(RoundingError::TimestampExceedsLimit); } - let stamp = self.timestamp_nanos(); + let stamp = naive.timestamp_nanos(); if span > stamp.abs() { return Err(RoundingError::DurationExceedsTimestamp); } @@ -180,10 +182,12 @@ impl DurationRound for DateTime { fn duration_trunc(self, duration: Duration) -> Result { if let Some(span) = duration.num_nanoseconds() { - if self.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { + let naive = self.naive_local(); + + if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { return Err(RoundingError::TimestampExceedsLimit); } - let stamp = self.timestamp_nanos(); + let stamp = naive.timestamp_nanos(); if span > stamp.abs() { return Err(RoundingError::DurationExceedsTimestamp); } @@ -395,6 +399,28 @@ mod tests { dt.duration_round(Duration::days(1)).unwrap().to_string(), "2012-12-13 00:00:00 UTC" ); + + // timezone east + let dt = FixedOffset::east(1 * 3600).ymd(2020, 10, 27).and_hms(15, 0, 0); + assert_eq!( + dt.duration_round(Duration::days(1)).unwrap().to_string(), + "2020-10-28 00:00:00 +01:00" + ); + assert_eq!( + dt.duration_round(Duration::weeks(1)).unwrap().to_string(), + "2020-10-29 00:00:00 +01:00" + ); + + // timezone west + let dt = FixedOffset::west(1 * 3600).ymd(2020, 10, 27).and_hms(15, 0, 0); + assert_eq!( + dt.duration_round(Duration::days(1)).unwrap().to_string(), + "2020-10-28 00:00:00 -01:00" + ); + assert_eq!( + dt.duration_round(Duration::weeks(1)).unwrap().to_string(), + "2020-10-29 00:00:00 -01:00" + ); } #[test] @@ -443,6 +469,28 @@ mod tests { dt.duration_trunc(Duration::days(1)).unwrap().to_string(), "2012-12-12 00:00:00 UTC" ); + + // timezone east + let dt = FixedOffset::east(1 * 3600).ymd(2020, 10, 27).and_hms(15, 0, 0); + assert_eq!( + dt.duration_trunc(Duration::days(1)).unwrap().to_string(), + "2020-10-27 00:00:00 +01:00" + ); + assert_eq!( + dt.duration_trunc(Duration::weeks(1)).unwrap().to_string(), + "2020-10-22 00:00:00 +01:00" + ); + + // timezone west + let dt = FixedOffset::west(1 * 3600).ymd(2020, 10, 27).and_hms(15, 0, 0); + assert_eq!( + dt.duration_trunc(Duration::days(1)).unwrap().to_string(), + "2020-10-27 00:00:00 -01:00" + ); + assert_eq!( + dt.duration_trunc(Duration::weeks(1)).unwrap().to_string(), + "2020-10-22 00:00:00 -01:00" + ); } #[test]