diff options
Diffstat (limited to 'vendor/chrono/src/round.rs')
-rw-r--r-- | vendor/chrono/src/round.rs | 487 |
1 files changed, 397 insertions, 90 deletions
diff --git a/vendor/chrono/src/round.rs b/vendor/chrono/src/round.rs index 92d7c3a50..b95f24570 100644 --- a/vendor/chrono/src/round.rs +++ b/vendor/chrono/src/round.rs @@ -1,16 +1,15 @@ // This is a part of Chrono. // See README.md and LICENSE.txt for details. +use crate::datetime::DateTime; +use crate::oldtime::Duration; +use crate::NaiveDateTime; +use crate::TimeZone; +use crate::Timelike; use core::cmp::Ordering; use core::fmt; use core::marker::Sized; use core::ops::{Add, Sub}; -use datetime::DateTime; -use oldtime::Duration; -#[cfg(any(feature = "std", test))] -use std; -use TimeZone; -use Timelike; /// Extension trait for subsecond rounding or truncation to a maximum number /// of digits. Rounding can be used to decrease the error variance when @@ -25,8 +24,8 @@ pub trait SubsecRound { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000); /// ``` @@ -37,8 +36,8 @@ pub trait SubsecRound { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000); /// ``` @@ -112,8 +111,8 @@ pub trait DurationRound: Sized { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!( /// dt.duration_round(Duration::milliseconds(10)).unwrap().to_string(), /// "2018-01-11 12:00:00.150 UTC" @@ -129,8 +128,8 @@ pub trait DurationRound: Sized { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!( /// dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(), /// "2018-01-11 12:00:00.150 UTC" @@ -150,52 +149,89 @@ impl<Tz: TimeZone> DurationRound for DateTime<Tz> { type Err = RoundingError; fn duration_round(self, duration: Duration) -> Result<Self, Self::Err> { - if let Some(span) = duration.num_nanoseconds() { - if self.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { - return Err(RoundingError::TimestampExceedsLimit); - } - let stamp = self.timestamp_nanos(); - if span > stamp.abs() { - return Err(RoundingError::DurationExceedsTimestamp); - } - let delta_down = stamp % span; - if delta_down == 0 { - Ok(self) + duration_round(self.naive_local(), self, duration) + } + + fn duration_trunc(self, duration: Duration) -> Result<Self, Self::Err> { + duration_trunc(self.naive_local(), self, duration) + } +} + +impl DurationRound for NaiveDateTime { + type Err = RoundingError; + + fn duration_round(self, duration: Duration) -> Result<Self, Self::Err> { + duration_round(self, self, duration) + } + + fn duration_trunc(self, duration: Duration) -> Result<Self, Self::Err> { + duration_trunc(self, self, duration) + } +} + +fn duration_round<T>( + naive: NaiveDateTime, + original: T, + duration: Duration, +) -> Result<T, RoundingError> +where + T: Timelike + Add<Duration, Output = T> + Sub<Duration, Output = T>, +{ + if let Some(span) = duration.num_nanoseconds() { + if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { + return Err(RoundingError::TimestampExceedsLimit); + } + let stamp = naive.timestamp_nanos(); + if span > stamp.abs() { + return Err(RoundingError::DurationExceedsTimestamp); + } + if span == 0 { + return Ok(original); + } + let delta_down = stamp % span; + if delta_down == 0 { + Ok(original) + } else { + let (delta_up, delta_down) = if delta_down < 0 { + (delta_down.abs(), span - delta_down.abs()) + } else { + (span - delta_down, delta_down) + }; + if delta_up <= delta_down { + Ok(original + Duration::nanoseconds(delta_up)) } else { - let (delta_up, delta_down) = if delta_down < 0 { - (delta_down.abs(), span - delta_down.abs()) - } else { - (span - delta_down, delta_down) - }; - if delta_up <= delta_down { - Ok(self + Duration::nanoseconds(delta_up)) - } else { - Ok(self - Duration::nanoseconds(delta_down)) - } + Ok(original - Duration::nanoseconds(delta_down)) } - } else { - Err(RoundingError::DurationExceedsLimit) } + } else { + Err(RoundingError::DurationExceedsLimit) } +} - fn duration_trunc(self, duration: Duration) -> Result<Self, Self::Err> { - if let Some(span) = duration.num_nanoseconds() { - if self.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { - return Err(RoundingError::TimestampExceedsLimit); - } - let stamp = self.timestamp_nanos(); - if span > stamp.abs() { - return Err(RoundingError::DurationExceedsTimestamp); - } - let delta_down = stamp % span; - match delta_down.cmp(&0) { - Ordering::Equal => Ok(self), - Ordering::Greater => Ok(self - Duration::nanoseconds(delta_down)), - Ordering::Less => Ok(self - Duration::nanoseconds(span - delta_down.abs())), - } - } else { - Err(RoundingError::DurationExceedsLimit) +fn duration_trunc<T>( + naive: NaiveDateTime, + original: T, + duration: Duration, +) -> Result<T, RoundingError> +where + T: Timelike + Add<Duration, Output = T> + Sub<Duration, Output = T>, +{ + if let Some(span) = duration.num_nanoseconds() { + if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { + return Err(RoundingError::TimestampExceedsLimit); + } + let stamp = naive.timestamp_nanos(); + if span > stamp.abs() { + return Err(RoundingError::DurationExceedsTimestamp); } + let delta_down = stamp % span; + match delta_down.cmp(&0) { + Ordering::Equal => Ok(original), + Ordering::Greater => Ok(original - Duration::nanoseconds(delta_down)), + Ordering::Less => Ok(original - Duration::nanoseconds(span - delta_down.abs())), + } + } else { + Err(RoundingError::DurationExceedsLimit) } } @@ -208,7 +244,7 @@ pub enum RoundingError { /// /// ``` rust /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc}; - /// let dt = Utc.ymd(1970, 12, 12).and_hms(0, 0, 0); + /// let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0).unwrap(); /// /// assert_eq!( /// dt.duration_round(Duration::days(365)), @@ -220,8 +256,8 @@ pub enum RoundingError { /// Error when `Duration.num_nanoseconds` exceeds the limit. /// /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc}; - /// let dt = Utc.ymd(2260, 12, 31).and_hms_nano(23, 59, 59, 1_75_500_000); + /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd_opt(2260, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 1_75_500_000).unwrap().and_local_timezone(Utc).unwrap(); /// /// assert_eq!( /// dt.duration_round(Duration::days(300 * 365)), @@ -234,7 +270,7 @@ pub enum RoundingError { /// /// ``` rust /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc}; - /// let dt = Utc.ymd(2300, 12, 12).and_hms(0, 0, 0); + /// let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0).unwrap(); /// /// assert_eq!(dt.duration_round(Duration::days(1)), Err(RoundingError::TimestampExceedsLimit),); /// ``` @@ -258,6 +294,7 @@ impl fmt::Display for RoundingError { } #[cfg(any(feature = "std", test))] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::error::Error for RoundingError { #[allow(deprecated)] fn description(&self) -> &str { @@ -268,29 +305,44 @@ impl std::error::Error for RoundingError { #[cfg(test)] mod tests { use super::{Duration, DurationRound, SubsecRound}; - use offset::{FixedOffset, TimeZone, Utc}; - use Timelike; + use crate::offset::{FixedOffset, TimeZone, Utc}; + use crate::NaiveDate; + use crate::Timelike; #[test] fn test_round_subsecs() { - let pst = FixedOffset::east(8 * 60 * 60); - let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684); + let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap(); + let dt = pst + .from_local_datetime( + &NaiveDate::from_ymd_opt(2018, 1, 11) + .unwrap() + .and_hms_nano_opt(10, 5, 13, 84_660_684) + .unwrap(), + ) + .unwrap(); assert_eq!(dt.round_subsecs(10), dt); assert_eq!(dt.round_subsecs(9), dt); - assert_eq!(dt.round_subsecs(8).nanosecond(), 084_660_680); - assert_eq!(dt.round_subsecs(7).nanosecond(), 084_660_700); - assert_eq!(dt.round_subsecs(6).nanosecond(), 084_661_000); - assert_eq!(dt.round_subsecs(5).nanosecond(), 084_660_000); - assert_eq!(dt.round_subsecs(4).nanosecond(), 084_700_000); - assert_eq!(dt.round_subsecs(3).nanosecond(), 085_000_000); - assert_eq!(dt.round_subsecs(2).nanosecond(), 080_000_000); + assert_eq!(dt.round_subsecs(8).nanosecond(), 84_660_680); + assert_eq!(dt.round_subsecs(7).nanosecond(), 84_660_700); + assert_eq!(dt.round_subsecs(6).nanosecond(), 84_661_000); + assert_eq!(dt.round_subsecs(5).nanosecond(), 84_660_000); + assert_eq!(dt.round_subsecs(4).nanosecond(), 84_700_000); + assert_eq!(dt.round_subsecs(3).nanosecond(), 85_000_000); + assert_eq!(dt.round_subsecs(2).nanosecond(), 80_000_000); assert_eq!(dt.round_subsecs(1).nanosecond(), 100_000_000); assert_eq!(dt.round_subsecs(0).nanosecond(), 0); assert_eq!(dt.round_subsecs(0).second(), 13); - let dt = Utc.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2018, 1, 11) + .unwrap() + .and_hms_nano_opt(10, 5, 27, 750_500_000) + .unwrap(), + ) + .unwrap(); assert_eq!(dt.round_subsecs(9), dt); assert_eq!(dt.round_subsecs(4), dt); assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000); @@ -303,7 +355,14 @@ mod tests { #[test] fn test_round_leap_nanos() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2016, 12, 31) + .unwrap() + .and_hms_nano_opt(23, 59, 59, 1_750_500_000) + .unwrap(), + ) + .unwrap(); assert_eq!(dt.round_subsecs(9), dt); assert_eq!(dt.round_subsecs(4), dt); assert_eq!(dt.round_subsecs(2).nanosecond(), 1_750_000_000); @@ -316,24 +375,38 @@ mod tests { #[test] fn test_trunc_subsecs() { - let pst = FixedOffset::east(8 * 60 * 60); - let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684); + let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap(); + let dt = pst + .from_local_datetime( + &NaiveDate::from_ymd_opt(2018, 1, 11) + .unwrap() + .and_hms_nano_opt(10, 5, 13, 84_660_684) + .unwrap(), + ) + .unwrap(); assert_eq!(dt.trunc_subsecs(10), dt); assert_eq!(dt.trunc_subsecs(9), dt); - assert_eq!(dt.trunc_subsecs(8).nanosecond(), 084_660_680); - assert_eq!(dt.trunc_subsecs(7).nanosecond(), 084_660_600); - assert_eq!(dt.trunc_subsecs(6).nanosecond(), 084_660_000); - assert_eq!(dt.trunc_subsecs(5).nanosecond(), 084_660_000); - assert_eq!(dt.trunc_subsecs(4).nanosecond(), 084_600_000); - assert_eq!(dt.trunc_subsecs(3).nanosecond(), 084_000_000); - assert_eq!(dt.trunc_subsecs(2).nanosecond(), 080_000_000); + assert_eq!(dt.trunc_subsecs(8).nanosecond(), 84_660_680); + assert_eq!(dt.trunc_subsecs(7).nanosecond(), 84_660_600); + assert_eq!(dt.trunc_subsecs(6).nanosecond(), 84_660_000); + assert_eq!(dt.trunc_subsecs(5).nanosecond(), 84_660_000); + assert_eq!(dt.trunc_subsecs(4).nanosecond(), 84_600_000); + assert_eq!(dt.trunc_subsecs(3).nanosecond(), 84_000_000); + assert_eq!(dt.trunc_subsecs(2).nanosecond(), 80_000_000); assert_eq!(dt.trunc_subsecs(1).nanosecond(), 0); assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0); assert_eq!(dt.trunc_subsecs(0).second(), 13); - let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000); + let dt = pst + .from_local_datetime( + &NaiveDate::from_ymd_opt(2018, 1, 11) + .unwrap() + .and_hms_nano_opt(10, 5, 27, 750_500_000) + .unwrap(), + ) + .unwrap(); assert_eq!(dt.trunc_subsecs(9), dt); assert_eq!(dt.trunc_subsecs(4), dt); assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000); @@ -346,7 +419,14 @@ mod tests { #[test] fn test_trunc_leap_nanos() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2016, 12, 31) + .unwrap() + .and_hms_nano_opt(23, 59, 59, 1_750_500_000) + .unwrap(), + ) + .unwrap(); assert_eq!(dt.trunc_subsecs(9), dt); assert_eq!(dt.trunc_subsecs(4), dt); assert_eq!(dt.trunc_subsecs(2).nanosecond(), 1_750_000_000); @@ -359,7 +439,19 @@ mod tests { #[test] fn test_duration_round() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2016, 12, 31) + .unwrap() + .and_hms_nano_opt(23, 59, 59, 175_500_000) + .unwrap(), + ) + .unwrap(); + + assert_eq!( + dt.duration_round(Duration::zero()).unwrap().to_string(), + "2016-12-31 23:59:59.175500 UTC" + ); assert_eq!( dt.duration_round(Duration::milliseconds(10)).unwrap().to_string(), @@ -367,13 +459,27 @@ mod tests { ); // round up - let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2012, 12, 12) + .unwrap() + .and_hms_milli_opt(18, 22, 30, 0) + .unwrap(), + ) + .unwrap(); assert_eq!( dt.duration_round(Duration::minutes(5)).unwrap().to_string(), "2012-12-12 18:25:00 UTC" ); // round down - let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 29, 999); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2012, 12, 12) + .unwrap() + .and_hms_milli_opt(18, 22, 29, 999) + .unwrap(), + ) + .unwrap(); assert_eq!( dt.duration_round(Duration::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" @@ -395,11 +501,104 @@ mod tests { dt.duration_round(Duration::days(1)).unwrap().to_string(), "2012-12-13 00:00:00 UTC" ); + + // timezone east + let dt = + FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap(); + 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_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap(); + 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] + fn test_duration_round_naive() { + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2016, 12, 31) + .unwrap() + .and_hms_nano_opt(23, 59, 59, 175_500_000) + .unwrap(), + ) + .unwrap() + .naive_utc(); + + assert_eq!( + dt.duration_round(Duration::zero()).unwrap().to_string(), + "2016-12-31 23:59:59.175500" + ); + + assert_eq!( + dt.duration_round(Duration::milliseconds(10)).unwrap().to_string(), + "2016-12-31 23:59:59.180" + ); + + // round up + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2012, 12, 12) + .unwrap() + .and_hms_milli_opt(18, 22, 30, 0) + .unwrap(), + ) + .unwrap() + .naive_utc(); + assert_eq!( + dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + "2012-12-12 18:25:00" + ); + // round down + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2012, 12, 12) + .unwrap() + .and_hms_milli_opt(18, 22, 29, 999) + .unwrap(), + ) + .unwrap() + .naive_utc(); + assert_eq!( + dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + "2012-12-12 18:20:00" + ); + + assert_eq!( + dt.duration_round(Duration::minutes(10)).unwrap().to_string(), + "2012-12-12 18:20:00" + ); + assert_eq!( + dt.duration_round(Duration::minutes(30)).unwrap().to_string(), + "2012-12-12 18:30:00" + ); + assert_eq!( + dt.duration_round(Duration::hours(1)).unwrap().to_string(), + "2012-12-12 18:00:00" + ); + assert_eq!( + dt.duration_round(Duration::days(1)).unwrap().to_string(), + "2012-12-13 00:00:00" + ); } #[test] fn test_duration_round_pre_epoch() { - let dt = Utc.ymd(1969, 12, 12).and_hms(12, 12, 12); + let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap(); assert_eq!( dt.duration_round(Duration::minutes(10)).unwrap().to_string(), "1969-12-12 12:10:00 UTC" @@ -408,7 +607,14 @@ mod tests { #[test] fn test_duration_trunc() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_75_500_000); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2016, 12, 31) + .unwrap() + .and_hms_nano_opt(23, 59, 59, 175_500_000) + .unwrap(), + ) + .unwrap(); assert_eq!( dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(), @@ -416,13 +622,27 @@ mod tests { ); // would round up - let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2012, 12, 12) + .unwrap() + .and_hms_milli_opt(18, 22, 30, 0) + .unwrap(), + ) + .unwrap(); assert_eq!( dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" ); // would round down - let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 29, 999); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2012, 12, 12) + .unwrap() + .and_hms_milli_opt(18, 22, 29, 999) + .unwrap(), + ) + .unwrap(); assert_eq!( dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" @@ -443,11 +663,98 @@ mod tests { dt.duration_trunc(Duration::days(1)).unwrap().to_string(), "2012-12-12 00:00:00 UTC" ); + + // timezone east + let dt = + FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap(); + 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_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap(); + 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] + fn test_duration_trunc_naive() { + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2016, 12, 31) + .unwrap() + .and_hms_nano_opt(23, 59, 59, 175_500_000) + .unwrap(), + ) + .unwrap() + .naive_utc(); + + assert_eq!( + dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(), + "2016-12-31 23:59:59.170" + ); + + // would round up + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2012, 12, 12) + .unwrap() + .and_hms_milli_opt(18, 22, 30, 0) + .unwrap(), + ) + .unwrap() + .naive_utc(); + assert_eq!( + dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + "2012-12-12 18:20:00" + ); + // would round down + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd_opt(2012, 12, 12) + .unwrap() + .and_hms_milli_opt(18, 22, 29, 999) + .unwrap(), + ) + .unwrap() + .naive_utc(); + assert_eq!( + dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + "2012-12-12 18:20:00" + ); + assert_eq!( + dt.duration_trunc(Duration::minutes(10)).unwrap().to_string(), + "2012-12-12 18:20:00" + ); + assert_eq!( + dt.duration_trunc(Duration::minutes(30)).unwrap().to_string(), + "2012-12-12 18:00:00" + ); + assert_eq!( + dt.duration_trunc(Duration::hours(1)).unwrap().to_string(), + "2012-12-12 18:00:00" + ); + assert_eq!( + dt.duration_trunc(Duration::days(1)).unwrap().to_string(), + "2012-12-12 00:00:00" + ); } #[test] fn test_duration_trunc_pre_epoch() { - let dt = Utc.ymd(1969, 12, 12).and_hms(12, 12, 12); + let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap(); assert_eq!( dt.duration_trunc(Duration::minutes(10)).unwrap().to_string(), "1969-12-12 12:10:00 UTC" |