diff --git a/bench/benches/chrono.rs b/bench/benches/chrono.rs index 38f8513d41..ab6a324453 100644 --- a/bench/benches/chrono.rs +++ b/bench/benches/chrono.rs @@ -6,7 +6,7 @@ use chrono::format::StrftimeItems; use chrono::prelude::*; #[cfg(feature = "unstable-locales")] use chrono::Locale; -use chrono::{DateTime, Duration, FixedOffset, Local, Utc, __BenchYearFlags}; +use chrono::{DateTime, FixedOffset, Local, TimeDelta, Utc, __BenchYearFlags}; fn bench_datetime_parse_from_rfc2822(c: &mut Criterion) { c.bench_function("bench_datetime_parse_from_rfc2822", |b| { @@ -198,7 +198,7 @@ fn bench_format_manual(c: &mut Criterion) { fn bench_naivedate_add_signed(c: &mut Criterion) { let date = NaiveDate::from_ymd_opt(2023, 7, 29).unwrap(); - let extra = Duration::days(25); + let extra = TimeDelta::days(25); c.bench_function("bench_naivedate_add_signed", |b| { b.iter(|| black_box(date).checked_add_signed(extra).unwrap()) }); diff --git a/src/date.rs b/src/date.rs index be2f05c559..a66882cecc 100644 --- a/src/date.rs +++ b/src/date.rs @@ -13,15 +13,13 @@ use core::{fmt, hash}; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; -use crate::duration::Duration as OldDuration; #[cfg(all(feature = "unstable-locales", feature = "alloc"))] use crate::format::Locale; #[cfg(feature = "alloc")] use crate::format::{DelayedFormat, Item, StrftimeItems}; use crate::naive::{IsoWeek, NaiveDate, NaiveTime}; use crate::offset::{TimeZone, Utc}; -use crate::DateTime; -use crate::{Datelike, Weekday}; +use crate::{DateTime, Datelike, TimeDelta, Weekday}; /// ISO 8601 calendar date with time zone. /// @@ -53,7 +51,7 @@ use crate::{Datelike, Weekday}; /// /// - The date is timezone-agnostic up to one day (i.e. practically always), /// so the local date and UTC date should be equal for most cases -/// even though the raw calculation between `NaiveDate` and `Duration` may not. +/// even though the raw calculation between `NaiveDate` and `TimeDelta` may not. #[deprecated(since = "0.4.23", note = "Use `NaiveDate` or `DateTime` instead")] #[derive(Clone)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -259,34 +257,34 @@ impl Date { tz.from_utc_date(&self.date) } - /// Adds given `Duration` to the current date. + /// Adds given `TimeDelta` to the current date. /// /// Returns `None` when it will result in overflow. #[inline] #[must_use] - pub fn checked_add_signed(self, rhs: OldDuration) -> Option> { + pub fn checked_add_signed(self, rhs: TimeDelta) -> Option> { let date = self.date.checked_add_signed(rhs)?; Some(Date { date, offset: self.offset }) } - /// Subtracts given `Duration` from the current date. + /// Subtracts given `TimeDelta` from the current date. /// /// Returns `None` when it will result in overflow. #[inline] #[must_use] - pub fn checked_sub_signed(self, rhs: OldDuration) -> Option> { + pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option> { let date = self.date.checked_sub_signed(rhs)?; Some(Date { date, offset: self.offset }) } /// Subtracts another `Date` from the current date. - /// Returns a `Duration` of integral numbers. + /// Returns a `TimeDelta` of integral numbers. /// /// This does not overflow or underflow at all, - /// as all possible output fits in the range of `Duration`. + /// as all possible output fits in the range of `TimeDelta`. #[inline] #[must_use] - pub fn signed_duration_since(self, rhs: Date) -> OldDuration { + pub fn signed_duration_since(self, rhs: Date) -> TimeDelta { self.date.signed_duration_since(rhs.date) } @@ -495,43 +493,43 @@ impl hash::Hash for Date { } } -impl Add for Date { +impl Add for Date { type Output = Date; #[inline] - fn add(self, rhs: OldDuration) -> Date { - self.checked_add_signed(rhs).expect("`Date + Duration` overflowed") + fn add(self, rhs: TimeDelta) -> Date { + self.checked_add_signed(rhs).expect("`Date + TimeDelta` overflowed") } } -impl AddAssign for Date { +impl AddAssign for Date { #[inline] - fn add_assign(&mut self, rhs: OldDuration) { - self.date = self.date.checked_add_signed(rhs).expect("`Date + Duration` overflowed"); + fn add_assign(&mut self, rhs: TimeDelta) { + self.date = self.date.checked_add_signed(rhs).expect("`Date + TimeDelta` overflowed"); } } -impl Sub for Date { +impl Sub for Date { type Output = Date; #[inline] - fn sub(self, rhs: OldDuration) -> Date { - self.checked_sub_signed(rhs).expect("`Date - Duration` overflowed") + fn sub(self, rhs: TimeDelta) -> Date { + self.checked_sub_signed(rhs).expect("`Date - TimeDelta` overflowed") } } -impl SubAssign for Date { +impl SubAssign for Date { #[inline] - fn sub_assign(&mut self, rhs: OldDuration) { - self.date = self.date.checked_sub_signed(rhs).expect("`Date - Duration` overflowed"); + fn sub_assign(&mut self, rhs: TimeDelta) { + self.date = self.date.checked_sub_signed(rhs).expect("`Date - TimeDelta` overflowed"); } } impl Sub> for Date { - type Output = OldDuration; + type Output = TimeDelta; #[inline] - fn sub(self, rhs: Date) -> OldDuration { + fn sub(self, rhs: Date) -> TimeDelta { self.signed_duration_since(rhs) } } @@ -572,8 +570,7 @@ where mod tests { use super::Date; - use crate::duration::Duration; - use crate::{FixedOffset, NaiveDate, Utc}; + use crate::{FixedOffset, NaiveDate, TimeDelta, Utc}; #[cfg(feature = "clock")] use crate::offset::{Local, TimeZone}; @@ -584,15 +581,15 @@ mod tests { const WEEKS_PER_YEAR: f32 = 52.1775; // This is always at least one year because 1 year = 52.1775 weeks. - let one_year_ago = Utc::today() - Duration::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); + let one_year_ago = Utc::today() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); // A bit more than 2 years. - let two_year_ago = Utc::today() - Duration::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); + let two_year_ago = Utc::today() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); assert_eq!(Utc::today().years_since(one_year_ago), Some(1)); assert_eq!(Utc::today().years_since(two_year_ago), Some(2)); // If the given DateTime is later than now, the function will always return 0. - let future = Utc::today() + Duration::weeks(12); + let future = Utc::today() + TimeDelta::weeks(12); assert_eq!(Utc::today().years_since(future), None); } @@ -602,20 +599,20 @@ mod tests { let date = Date::::from_utc(naivedate, Utc); let mut date_add = date; - date_add += Duration::days(5); - assert_eq!(date_add, date + Duration::days(5)); + date_add += TimeDelta::days(5); + assert_eq!(date_add, date + TimeDelta::days(5)); let timezone = FixedOffset::east_opt(60 * 60).unwrap(); let date = date.with_timezone(&timezone); let date_add = date_add.with_timezone(&timezone); - assert_eq!(date_add, date + Duration::days(5)); + assert_eq!(date_add, date + TimeDelta::days(5)); let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap(); let date = date.with_timezone(&timezone); let date_add = date_add.with_timezone(&timezone); - assert_eq!(date_add, date + Duration::days(5)); + assert_eq!(date_add, date + TimeDelta::days(5)); } #[test] @@ -626,8 +623,8 @@ mod tests { let date = Local.from_utc_date(&naivedate); let mut date_add = date; - date_add += Duration::days(5); - assert_eq!(date_add, date + Duration::days(5)); + date_add += TimeDelta::days(5); + assert_eq!(date_add, date + TimeDelta::days(5)); } #[test] @@ -636,20 +633,20 @@ mod tests { let date = Date::::from_utc(naivedate, Utc); let mut date_sub = date; - date_sub -= Duration::days(5); - assert_eq!(date_sub, date - Duration::days(5)); + date_sub -= TimeDelta::days(5); + assert_eq!(date_sub, date - TimeDelta::days(5)); let timezone = FixedOffset::east_opt(60 * 60).unwrap(); let date = date.with_timezone(&timezone); let date_sub = date_sub.with_timezone(&timezone); - assert_eq!(date_sub, date - Duration::days(5)); + assert_eq!(date_sub, date - TimeDelta::days(5)); let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap(); let date = date.with_timezone(&timezone); let date_sub = date_sub.with_timezone(&timezone); - assert_eq!(date_sub, date - Duration::days(5)); + assert_eq!(date_sub, date - TimeDelta::days(5)); } #[test] @@ -660,7 +657,7 @@ mod tests { let date = Local.from_utc_date(&naivedate); let mut date_sub = date; - date_sub -= Duration::days(5); - assert_eq!(date_sub, date - Duration::days(5)); + date_sub -= TimeDelta::days(5); + assert_eq!(date_sub, date - TimeDelta::days(5)); } } diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 6d79239582..e4e460b280 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -14,7 +14,6 @@ use core::{fmt, hash, str}; #[cfg(feature = "std")] use std::time::{SystemTime, UNIX_EPOCH}; -use crate::duration::Duration as OldDuration; #[cfg(all(feature = "unstable-locales", feature = "alloc"))] use crate::format::Locale; use crate::format::{ @@ -30,7 +29,7 @@ use crate::offset::{FixedOffset, Offset, TimeZone, Utc}; use crate::try_opt; #[allow(deprecated)] use crate::Date; -use crate::{Datelike, Months, Timelike, Weekday}; +use crate::{Datelike, Months, TimeDelta, Timelike, Weekday}; #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))] use rkyv::{Archive, Deserialize, Serialize}; @@ -364,14 +363,14 @@ impl DateTime { DateTime { datetime: self.datetime, offset: Utc } } - /// Adds given `Duration` to the current date and time. + /// Adds given `TimeDelta` to the current date and time. /// /// # Errors /// /// Returns `None` if the resulting date would be out of range. #[inline] #[must_use] - pub fn checked_add_signed(self, rhs: OldDuration) -> Option> { + pub fn checked_add_signed(self, rhs: TimeDelta) -> Option> { let datetime = self.datetime.checked_add_signed(rhs)?; let tz = self.timezone(); Some(tz.from_utc_datetime(&datetime)) @@ -397,14 +396,14 @@ impl DateTime { .single() } - /// Subtracts given `Duration` from the current date and time. + /// Subtracts given `TimeDelta` from the current date and time. /// /// # Errors /// /// Returns `None` if the resulting date would be out of range. #[inline] #[must_use] - pub fn checked_sub_signed(self, rhs: OldDuration) -> Option> { + pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option> { let datetime = self.datetime.checked_sub_signed(rhs)?; let tz = self.timezone(); Some(tz.from_utc_datetime(&datetime)) @@ -469,7 +468,7 @@ impl DateTime { pub fn signed_duration_since( self, rhs: impl Borrow>, - ) -> OldDuration { + ) -> TimeDelta { self.datetime.signed_duration_since(rhs.borrow().datetime) } @@ -1239,7 +1238,7 @@ impl hash::Hash for DateTime { } } -/// Add `chrono::Duration` to `DateTime`. +/// Add `TimeDelta` to `DateTime`. /// /// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap /// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case @@ -1249,12 +1248,12 @@ impl hash::Hash for DateTime { /// /// Panics if the resulting date would be out of range. /// Consider using [`DateTime::checked_add_signed`] to get an `Option` instead. -impl Add for DateTime { +impl Add for DateTime { type Output = DateTime; #[inline] - fn add(self, rhs: OldDuration) -> DateTime { - self.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed") + fn add(self, rhs: TimeDelta) -> DateTime { + self.checked_add_signed(rhs).expect("`DateTime + TimeDelta` overflowed") } } @@ -1273,9 +1272,9 @@ impl Add for DateTime { #[inline] fn add(self, rhs: Duration) -> DateTime { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); - self.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed") + let rhs = TimeDelta::from_std(rhs) + .expect("overflow converting from core::time::Duration to TimeDelta"); + self.checked_add_signed(rhs).expect("`DateTime + TimeDelta` overflowed") } } @@ -1289,11 +1288,11 @@ impl Add for DateTime { /// /// Panics if the resulting date would be out of range. /// Consider using [`DateTime::checked_add_signed`] to get an `Option` instead. -impl AddAssign for DateTime { +impl AddAssign for DateTime { #[inline] - fn add_assign(&mut self, rhs: OldDuration) { + fn add_assign(&mut self, rhs: TimeDelta) { let datetime = - self.datetime.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed"); + self.datetime.checked_add_signed(rhs).expect("`DateTime + TimeDelta` overflowed"); let tz = self.timezone(); *self = tz.from_utc_datetime(&datetime); } @@ -1312,8 +1311,8 @@ impl AddAssign for DateTime { impl AddAssign for DateTime { #[inline] fn add_assign(&mut self, rhs: Duration) { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); + let rhs = TimeDelta::from_std(rhs) + .expect("overflow converting from core::time::Duration to TimeDelta"); *self += rhs; } } @@ -1355,9 +1354,9 @@ impl Add for DateTime { } } -/// Subtract `chrono::Duration` from `DateTime`. +/// Subtract `TimeDelta` from `DateTime`. /// -/// This is the same as the addition with a negated `Duration`. +/// This is the same as the addition with a negated `TimeDelta`. /// /// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap /// second ever**, except when the `DateTime` itself represents a leap second in which case @@ -1367,12 +1366,12 @@ impl Add for DateTime { /// /// Panics if the resulting date would be out of range. /// Consider using [`DateTime::checked_sub_signed`] to get an `Option` instead. -impl Sub for DateTime { +impl Sub for DateTime { type Output = DateTime; #[inline] - fn sub(self, rhs: OldDuration) -> DateTime { - self.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed") + fn sub(self, rhs: TimeDelta) -> DateTime { + self.checked_sub_signed(rhs).expect("`DateTime - TimeDelta` overflowed") } } @@ -1391,15 +1390,15 @@ impl Sub for DateTime { #[inline] fn sub(self, rhs: Duration) -> DateTime { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); - self.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed") + let rhs = TimeDelta::from_std(rhs) + .expect("overflow converting from core::time::Duration to TimeDelta"); + self.checked_sub_signed(rhs).expect("`DateTime - TimeDelta` overflowed") } } -/// Subtract-assign `chrono::Duration` from `DateTime`. +/// Subtract-assign `TimeDelta` from `DateTime`. /// -/// This is the same as the addition with a negated `Duration`. +/// This is the same as the addition with a negated `TimeDelta`. /// /// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap /// second ever**, except when the `DateTime` itself represents a leap second in which case @@ -1409,11 +1408,11 @@ impl Sub for DateTime { /// /// Panics if the resulting date would be out of range. /// Consider using [`DateTime::checked_sub_signed`] to get an `Option` instead. -impl SubAssign for DateTime { +impl SubAssign for DateTime { #[inline] - fn sub_assign(&mut self, rhs: OldDuration) { + fn sub_assign(&mut self, rhs: TimeDelta) { let datetime = - self.datetime.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed"); + self.datetime.checked_sub_signed(rhs).expect("`DateTime - TimeDelta` overflowed"); let tz = self.timezone(); *self = tz.from_utc_datetime(&datetime) } @@ -1432,8 +1431,8 @@ impl SubAssign for DateTime { impl SubAssign for DateTime { #[inline] fn sub_assign(&mut self, rhs: Duration) { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); + let rhs = TimeDelta::from_std(rhs) + .expect("overflow converting from core::time::Duration to TimeDelta"); *self -= rhs; } } @@ -1476,19 +1475,19 @@ impl Sub for DateTime { } impl Sub> for DateTime { - type Output = OldDuration; + type Output = TimeDelta; #[inline] - fn sub(self, rhs: DateTime) -> OldDuration { + fn sub(self, rhs: DateTime) -> TimeDelta { self.signed_duration_since(rhs) } } impl Sub<&DateTime> for DateTime { - type Output = OldDuration; + type Output = TimeDelta; #[inline] - fn sub(self, rhs: &DateTime) -> OldDuration { + fn sub(self, rhs: &DateTime) -> TimeDelta { self.signed_duration_since(rhs) } } diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 3e96e227fa..88fcd80dec 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1,10 +1,9 @@ use super::DateTime; -use crate::duration::Duration as OldDuration; use crate::naive::{NaiveDate, NaiveTime}; use crate::offset::{FixedOffset, TimeZone, Utc}; #[cfg(feature = "clock")] use crate::offset::{Local, Offset}; -use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime, Timelike, Weekday}; +use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime, TimeDelta, Timelike, Weekday}; #[derive(Clone)] struct DstTester; @@ -54,7 +53,7 @@ impl TimeZone for DstTester { DstTester::TO_WINTER_MONTH_DAY.1, ) .unwrap() - .and_time(DstTester::transition_start_local() - OldDuration::hours(1)); + .and_time(DstTester::transition_start_local() - TimeDelta::hours(1)); let local_to_summer_transition_start = NaiveDate::from_ymd_opt( local.year(), @@ -70,7 +69,7 @@ impl TimeZone for DstTester { DstTester::TO_SUMMER_MONTH_DAY.1, ) .unwrap() - .and_time(DstTester::transition_start_local() + OldDuration::hours(1)); + .and_time(DstTester::transition_start_local() + TimeDelta::hours(1)); if *local < local_to_winter_transition_end || *local >= local_to_summer_transition_end { LocalResult::Single(DstTester::summer_offset()) @@ -393,12 +392,12 @@ fn test_datetime_offset() { let dt = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap(); assert_eq!(dt, edt.with_ymd_and_hms(2014, 5, 6, 3, 8, 9).unwrap()); assert_eq!( - dt + OldDuration::seconds(3600 + 60 + 1), + dt + TimeDelta::seconds(3600 + 60 + 1), Utc.with_ymd_and_hms(2014, 5, 6, 8, 9, 10).unwrap() ); assert_eq!( dt.signed_duration_since(edt.with_ymd_and_hms(2014, 5, 6, 10, 11, 12).unwrap()), - OldDuration::seconds(-7 * 3600 - 3 * 60 - 3) + TimeDelta::seconds(-7 * 3600 - 3 * 60 - 3) ); assert_eq!(*Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset(), Utc); @@ -1272,16 +1271,16 @@ fn test_years_elapsed() { // This is always at least one year because 1 year = 52.1775 weeks. let one_year_ago = - Utc::now().date_naive() - OldDuration::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); + Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); // A bit more than 2 years. let two_year_ago = - Utc::now().date_naive() - OldDuration::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); + Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); assert_eq!(Utc::now().date_naive().years_since(one_year_ago), Some(1)); assert_eq!(Utc::now().date_naive().years_since(two_year_ago), Some(2)); // If the given DateTime is later than now, the function will always return 0. - let future = Utc::now().date_naive() + OldDuration::weeks(12); + let future = Utc::now().date_naive() + TimeDelta::weeks(12); assert_eq!(Utc::now().date_naive().years_since(future), None); } @@ -1291,20 +1290,20 @@ fn test_datetime_add_assign() { let datetime = naivedatetime.and_utc(); let mut datetime_add = datetime; - datetime_add += OldDuration::seconds(60); - assert_eq!(datetime_add, datetime + OldDuration::seconds(60)); + datetime_add += TimeDelta::seconds(60); + assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); let timezone = FixedOffset::east_opt(60 * 60).unwrap(); let datetime = datetime.with_timezone(&timezone); let datetime_add = datetime_add.with_timezone(&timezone); - assert_eq!(datetime_add, datetime + OldDuration::seconds(60)); + assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap(); let datetime = datetime.with_timezone(&timezone); let datetime_add = datetime_add.with_timezone(&timezone); - assert_eq!(datetime_add, datetime + OldDuration::seconds(60)); + assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); } #[test] @@ -1317,8 +1316,8 @@ fn test_datetime_add_assign_local() { // ensure we cross a DST transition for i in 1..=365 { - datetime_add += OldDuration::days(1); - assert_eq!(datetime_add, datetime + OldDuration::days(i)) + datetime_add += TimeDelta::days(1); + assert_eq!(datetime_add, datetime + TimeDelta::days(i)) } } @@ -1328,20 +1327,20 @@ fn test_datetime_sub_assign() { let datetime = naivedatetime.and_utc(); let mut datetime_sub = datetime; - datetime_sub -= OldDuration::minutes(90); - assert_eq!(datetime_sub, datetime - OldDuration::minutes(90)); + datetime_sub -= TimeDelta::minutes(90); + assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); let timezone = FixedOffset::east_opt(60 * 60).unwrap(); let datetime = datetime.with_timezone(&timezone); let datetime_sub = datetime_sub.with_timezone(&timezone); - assert_eq!(datetime_sub, datetime - OldDuration::minutes(90)); + assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap(); let datetime = datetime.with_timezone(&timezone); let datetime_sub = datetime_sub.with_timezone(&timezone); - assert_eq!(datetime_sub, datetime - OldDuration::minutes(90)); + assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); } #[test] @@ -1423,7 +1422,7 @@ fn test_min_max_setters() { assert_eq!(beyond_min.with_ordinal0(beyond_min.ordinal0()), Some(beyond_min)); assert_eq!(beyond_min.with_ordinal0(200), None); assert_eq!(beyond_min.with_hour(beyond_min.hour()), Some(beyond_min)); - assert_eq!(beyond_min.with_hour(23), beyond_min.checked_add_signed(OldDuration::hours(1))); + assert_eq!(beyond_min.with_hour(23), beyond_min.checked_add_signed(TimeDelta::hours(1))); assert_eq!(beyond_min.with_hour(5), None); assert_eq!(beyond_min.with_minute(0), Some(beyond_min)); assert_eq!(beyond_min.with_second(0), Some(beyond_min)); @@ -1443,7 +1442,7 @@ fn test_min_max_setters() { assert_eq!(beyond_max.with_ordinal0(beyond_max.ordinal0()), Some(beyond_max)); assert_eq!(beyond_max.with_ordinal0(200), None); assert_eq!(beyond_max.with_hour(beyond_max.hour()), Some(beyond_max)); - assert_eq!(beyond_max.with_hour(0), beyond_max.checked_sub_signed(OldDuration::hours(1))); + assert_eq!(beyond_max.with_hour(0), beyond_max.checked_sub_signed(TimeDelta::hours(1))); assert_eq!(beyond_max.with_hour(5), None); assert_eq!(beyond_max.with_minute(beyond_max.minute()), Some(beyond_max)); assert_eq!(beyond_max.with_second(beyond_max.second()), Some(beyond_max)); @@ -1474,8 +1473,8 @@ fn test_datetime_sub_assign_local() { // ensure we cross a DST transition for i in 1..=365 { - datetime_sub -= OldDuration::days(1); - assert_eq!(datetime_sub, datetime - OldDuration::days(i)) + datetime_sub -= TimeDelta::days(1); + assert_eq!(datetime_sub, datetime - TimeDelta::days(i)) } } diff --git a/src/duration.rs b/src/duration.rs deleted file mode 100644 index c7d6ee9b9a..0000000000 --- a/src/duration.rs +++ /dev/null @@ -1,1196 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Temporal quantification - -use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}; -use core::time::Duration as StdDuration; -use core::{fmt, i64}; -#[cfg(feature = "std")] -use std::error::Error; - -use crate::{expect, try_opt}; - -#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))] -use rkyv::{Archive, Deserialize, Serialize}; - -/// The number of nanoseconds in a microsecond. -const NANOS_PER_MICRO: i32 = 1000; -/// The number of nanoseconds in a millisecond. -const NANOS_PER_MILLI: i32 = 1_000_000; -/// The number of nanoseconds in seconds. -pub(crate) const NANOS_PER_SEC: i32 = 1_000_000_000; -/// The number of microseconds per second. -const MICROS_PER_SEC: i64 = 1_000_000; -/// The number of milliseconds per second. -const MILLIS_PER_SEC: i64 = 1000; -/// The number of seconds in a minute. -const SECS_PER_MINUTE: i64 = 60; -/// The number of seconds in an hour. -const SECS_PER_HOUR: i64 = 3600; -/// The number of (non-leap) seconds in days. -const SECS_PER_DAY: i64 = 86_400; -/// The number of (non-leap) seconds in a week. -const SECS_PER_WEEK: i64 = 604_800; - -/// ISO 8601 time duration with nanosecond precision. -/// -/// This also allows for negative durations; see individual methods for details. -/// -/// A `Duration` is represented internally as a complement of seconds and -/// nanoseconds. The range is restricted to that of `i64` milliseconds, with the -/// minimum value notably being set to `-i64::MAX` rather than allowing the full -/// range of `i64::MIN`. This is to allow easy flipping of sign, so that for -/// instance `abs()` can be called without any checks. -#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -#[cfg_attr( - any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"), - derive(Archive, Deserialize, Serialize), - archive(compare(PartialEq, PartialOrd)), - archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)) -)] -#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))] -pub struct Duration { - secs: i64, - nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC -} - -/// The minimum possible `Duration`: `-i64::MAX` milliseconds. -pub(crate) const MIN: Duration = Duration { - secs: -i64::MAX / MILLIS_PER_SEC - 1, - nanos: NANOS_PER_SEC + (-i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI, -}; - -/// The maximum possible `Duration`: `i64::MAX` milliseconds. -pub(crate) const MAX: Duration = Duration { - secs: i64::MAX / MILLIS_PER_SEC, - nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI, -}; - -impl Duration { - /// Makes a new `Duration` with given number of seconds and nanoseconds. - /// - /// # Errors - /// - /// Returns `None` when the duration is out of bounds, or if `nanos` ≥ 1,000,000,000. - pub const fn new(secs: i64, nanos: u32) -> Option { - if secs < MIN.secs - || secs > MAX.secs - || nanos >= 1_000_000_000 - || (secs == MAX.secs && nanos > MAX.nanos as u32) - || (secs == MIN.secs && nanos < MIN.nanos as u32) - { - return None; - } - Some(Duration { secs, nanos: nanos as i32 }) - } - - /// Makes a new `Duration` with the given number of weeks. - /// - /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with - /// overflow checks. - /// - /// # Panics - /// - /// Panics when the duration is out of bounds. - #[inline] - #[must_use] - pub const fn weeks(weeks: i64) -> Duration { - expect!(Duration::try_weeks(weeks), "Duration::weeks out of bounds") - } - - /// Makes a new `Duration` with the given number of weeks. - /// - /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with - /// overflow checks. - /// - /// # Errors - /// - /// Returns `None` when the duration is out of bounds. - #[inline] - pub const fn try_weeks(weeks: i64) -> Option { - Duration::try_seconds(try_opt!(weeks.checked_mul(SECS_PER_WEEK))) - } - - /// Makes a new `Duration` with the given number of days. - /// - /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow - /// checks. - /// - /// # Panics - /// - /// Panics when the duration is out of bounds. - #[inline] - #[must_use] - pub const fn days(days: i64) -> Duration { - expect!(Duration::try_days(days), "Duration::days out of bounds") - } - - /// Makes a new `Duration` with the given number of days. - /// - /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow - /// checks. - /// - /// # Errors - /// - /// Returns `None` when the duration is out of bounds. - #[inline] - pub const fn try_days(days: i64) -> Option { - Duration::try_seconds(try_opt!(days.checked_mul(SECS_PER_DAY))) - } - - /// Makes a new `Duration` with the given number of hours. - /// - /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. - /// - /// # Panics - /// - /// Panics when the duration is out of bounds. - #[inline] - #[must_use] - pub const fn hours(hours: i64) -> Duration { - expect!(Duration::try_hours(hours), "Duration::hours out of bounds") - } - - /// Makes a new `Duration` with the given number of hours. - /// - /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. - /// - /// # Errors - /// - /// Returns `None` when the duration is out of bounds. - #[inline] - pub const fn try_hours(hours: i64) -> Option { - Duration::try_seconds(try_opt!(hours.checked_mul(SECS_PER_HOUR))) - } - - /// Makes a new `Duration` with the given number of minutes. - /// - /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. - /// - /// # Panics - /// - /// Panics when the duration is out of bounds. - #[inline] - #[must_use] - pub const fn minutes(minutes: i64) -> Duration { - expect!(Duration::try_minutes(minutes), "Duration::minutes out of bounds") - } - - /// Makes a new `Duration` with the given number of minutes. - /// - /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. - /// - /// # Errors - /// - /// Returns `None` when the duration is out of bounds. - #[inline] - pub const fn try_minutes(minutes: i64) -> Option { - Duration::try_seconds(try_opt!(minutes.checked_mul(SECS_PER_MINUTE))) - } - - /// Makes a new `Duration` with the given number of seconds. - /// - /// # Panics - /// - /// Panics when the duration is out of bounds, i.e. when the value is more - /// than `i64::MAX / 1_000` seconds or less than `-i64::MAX / 1_000` seconds - /// (in this context, this is the same as `i64::MIN / 1_000` due to - /// rounding). - #[inline] - #[must_use] - pub const fn seconds(seconds: i64) -> Duration { - expect!(Duration::try_seconds(seconds), "Duration::seconds out of bounds") - } - - /// Makes a new `Duration` with the given number of seconds. - /// - /// # Errors - /// - /// Returns `None` when the duration is more than `i64::MAX / 1_000` seconds - /// or less than `-i64::MAX / 1_000` seconds (in this context, this is the - /// same as `i64::MIN / 1_000` due to rounding). - #[inline] - pub const fn try_seconds(seconds: i64) -> Option { - Duration::new(seconds, 0) - } - - /// Makes a new `Duration` with the given number of milliseconds. - /// - /// # Panics - /// - /// Panics when the duration is out of bounds, i.e. when the duration is - /// more than `i64::MAX` milliseconds or less than `-i64::MAX` milliseconds. - /// Notably, this is not the same as `i64::MIN`. - #[inline] - pub const fn milliseconds(milliseconds: i64) -> Duration { - expect!(Duration::try_milliseconds(milliseconds), "Duration::milliseconds out of bounds") - } - - /// Makes a new `Duration` with the given number of milliseconds. - /// - /// # Errors - /// - /// Returns `None` when the duration is more than `i64::MAX` milliseconds or - /// less than `-i64::MAX` milliseconds. Notably, this is not the same as - /// `i64::MIN`. - #[inline] - pub const fn try_milliseconds(milliseconds: i64) -> Option { - // We don't need to compare against MAX, as this function accepts an - // i64, and MAX is aligned to i64::MAX milliseconds. - if milliseconds < -i64::MAX { - return None; - } - let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC); - let d = Duration { secs, nanos: millis as i32 * NANOS_PER_MILLI }; - Some(d) - } - - /// Makes a new `Duration` with the given number of microseconds. - /// - /// The number of microseconds acceptable by this constructor is less than - /// the total number that can actually be stored in a `Duration`, so it is - /// not possible to specify a value that would be out of bounds. This - /// function is therefore infallible. - #[inline] - pub const fn microseconds(microseconds: i64) -> Duration { - let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - let nanos = micros as i32 * NANOS_PER_MICRO; - Duration { secs, nanos } - } - - /// Makes a new `Duration` with the given number of nanoseconds. - /// - /// The number of nanoseconds acceptable by this constructor is less than - /// the total number that can actually be stored in a `Duration`, so it is - /// not possible to specify a value that would be out of bounds. This - /// function is therefore infallible. - #[inline] - pub const fn nanoseconds(nanos: i64) -> Duration { - let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64); - Duration { secs, nanos: nanos as i32 } - } - - /// Returns the total number of whole weeks in the `Duration`. - #[inline] - pub const fn num_weeks(&self) -> i64 { - self.num_days() / 7 - } - - /// Returns the total number of whole days in the `Duration`. - pub const fn num_days(&self) -> i64 { - self.num_seconds() / SECS_PER_DAY - } - - /// Returns the total number of whole hours in the `Duration`. - #[inline] - pub const fn num_hours(&self) -> i64 { - self.num_seconds() / SECS_PER_HOUR - } - - /// Returns the total number of whole minutes in the `Duration`. - #[inline] - pub const fn num_minutes(&self) -> i64 { - self.num_seconds() / SECS_PER_MINUTE - } - - /// Returns the total number of whole seconds in the `Duration`. - pub const fn num_seconds(&self) -> i64 { - // If secs is negative, nanos should be subtracted from the duration. - if self.secs < 0 && self.nanos > 0 { - self.secs + 1 - } else { - self.secs - } - } - - /// Returns the number of nanoseconds such that - /// `subsec_nanos() + num_seconds() * NANOS_PER_SEC` is the total number of - /// nanoseconds in the `Duration`. - pub const fn subsec_nanos(&self) -> i32 { - if self.secs < 0 && self.nanos > 0 { - self.nanos - NANOS_PER_SEC - } else { - self.nanos - } - } - - /// Returns the total number of whole milliseconds in the `Duration`. - pub const fn num_milliseconds(&self) -> i64 { - // A proper Duration will not overflow, because MIN and MAX are defined such - // that the range is within the bounds of an i64, from -i64::MAX through to - // +i64::MAX inclusive. Notably, i64::MIN is excluded from this range. - let secs_part = self.num_seconds() * MILLIS_PER_SEC; - let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI; - secs_part + nanos_part as i64 - } - - /// Returns the total number of whole microseconds in the `Duration`, - /// or `None` on overflow (exceeding 2^63 microseconds in either direction). - pub const fn num_microseconds(&self) -> Option { - let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC)); - let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO; - secs_part.checked_add(nanos_part as i64) - } - - /// Returns the total number of whole nanoseconds in the `Duration`, - /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction). - pub const fn num_nanoseconds(&self) -> Option { - let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64)); - let nanos_part = self.subsec_nanos(); - secs_part.checked_add(nanos_part as i64) - } - - /// Add two `Duration`s, returning `None` if overflow occurred. - #[must_use] - pub const fn checked_add(&self, rhs: &Duration) -> Option { - // No overflow checks here because we stay comfortably within the range of an `i64`. - // Range checks happen in `Duration::new`. - let mut secs = self.secs + rhs.secs; - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs += 1; - } - Duration::new(secs, nanos as u32) - } - - /// Subtract two `Duration`s, returning `None` if overflow occurred. - #[must_use] - pub const fn checked_sub(&self, rhs: &Duration) -> Option { - // No overflow checks here because we stay comfortably within the range of an `i64`. - // Range checks happen in `Duration::new`. - let mut secs = self.secs - rhs.secs; - let mut nanos = self.nanos - rhs.nanos; - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs -= 1; - } - Duration::new(secs, nanos as u32) - } - - /// Returns the `Duration` as an absolute (non-negative) value. - #[inline] - pub const fn abs(&self) -> Duration { - if self.secs < 0 && self.nanos != 0 { - Duration { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos } - } else { - Duration { secs: self.secs.abs(), nanos: self.nanos } - } - } - - /// The minimum possible `Duration`: `-i64::MAX` milliseconds. - #[inline] - pub const fn min_value() -> Duration { - MIN - } - - /// The maximum possible `Duration`: `i64::MAX` milliseconds. - #[inline] - pub const fn max_value() -> Duration { - MAX - } - - /// A `Duration` where the stored seconds and nanoseconds are equal to zero. - #[inline] - pub const fn zero() -> Duration { - Duration { secs: 0, nanos: 0 } - } - - /// Returns `true` if the `Duration` equals `Duration::zero()`. - #[inline] - pub const fn is_zero(&self) -> bool { - self.secs == 0 && self.nanos == 0 - } - - /// Creates a `time::Duration` object from `std::time::Duration` - /// - /// This function errors when original duration is larger than the maximum - /// value supported for this type. - pub const fn from_std(duration: StdDuration) -> Result { - // We need to check secs as u64 before coercing to i64 - if duration.as_secs() > MAX.secs as u64 { - return Err(OutOfRangeError(())); - } - match Duration::new(duration.as_secs() as i64, duration.subsec_nanos()) { - Some(d) => Ok(d), - None => Err(OutOfRangeError(())), - } - } - - /// Creates a `std::time::Duration` object from `time::Duration` - /// - /// This function errors when duration is less than zero. As standard - /// library implementation is limited to non-negative values. - pub const fn to_std(&self) -> Result { - if self.secs < 0 { - return Err(OutOfRangeError(())); - } - Ok(StdDuration::new(self.secs as u64, self.nanos as u32)) - } - - /// This duplicates `Neg::neg` because trait methods can't be const yet. - pub(crate) const fn neg(self) -> Duration { - let (secs_diff, nanos) = match self.nanos { - 0 => (0, 0), - nanos => (1, NANOS_PER_SEC - nanos), - }; - Duration { secs: -self.secs - secs_diff, nanos } - } -} - -impl Neg for Duration { - type Output = Duration; - - #[inline] - fn neg(self) -> Duration { - let (secs_diff, nanos) = match self.nanos { - 0 => (0, 0), - nanos => (1, NANOS_PER_SEC - nanos), - }; - Duration { secs: -self.secs - secs_diff, nanos } - } -} - -impl Add for Duration { - type Output = Duration; - - fn add(self, rhs: Duration) -> Duration { - self.checked_add(&rhs).expect("`Duration + Duration` overflowed") - } -} - -impl Sub for Duration { - type Output = Duration; - - fn sub(self, rhs: Duration) -> Duration { - self.checked_sub(&rhs).expect("`Duration - Duration` overflowed") - } -} - -impl AddAssign for Duration { - fn add_assign(&mut self, rhs: Duration) { - let new = self.checked_add(&rhs).expect("`Duration + Duration` overflowed"); - *self = new; - } -} - -impl SubAssign for Duration { - fn sub_assign(&mut self, rhs: Duration) { - let new = self.checked_sub(&rhs).expect("`Duration - Duration` overflowed"); - *self = new; - } -} - -impl Mul for Duration { - type Output = Duration; - - fn mul(self, rhs: i32) -> Duration { - // Multiply nanoseconds as i64, because it cannot overflow that way. - let total_nanos = self.nanos as i64 * rhs as i64; - let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64); - let secs = self.secs * rhs as i64 + extra_secs; - Duration { secs, nanos: nanos as i32 } - } -} - -impl Div for Duration { - type Output = Duration; - - fn div(self, rhs: i32) -> Duration { - let mut secs = self.secs / rhs as i64; - let carry = self.secs - secs * rhs as i64; - let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64; - let mut nanos = self.nanos / rhs + extra_nanos as i32; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs += 1; - } - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs -= 1; - } - Duration { secs, nanos } - } -} - -impl<'a> core::iter::Sum<&'a Duration> for Duration { - fn sum>(iter: I) -> Duration { - iter.fold(Duration::zero(), |acc, x| acc + *x) - } -} - -impl core::iter::Sum for Duration { - fn sum>(iter: I) -> Duration { - iter.fold(Duration::zero(), |acc, x| acc + x) - } -} - -impl fmt::Display for Duration { - /// Format a duration using the [ISO 8601] format - /// - /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601#Durations - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // technically speaking, negative duration is not valid ISO 8601, - // but we need to print it anyway. - let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") }; - - let days = abs.secs / SECS_PER_DAY; - let secs = abs.secs - days * SECS_PER_DAY; - let hasdate = days != 0; - let hastime = (secs != 0 || abs.nanos != 0) || !hasdate; - - write!(f, "{}P", sign)?; - - if hasdate { - write!(f, "{}D", days)?; - } - if hastime { - if abs.nanos == 0 { - write!(f, "T{}S", secs)?; - } else if abs.nanos % NANOS_PER_MILLI == 0 { - write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI)?; - } else if abs.nanos % NANOS_PER_MICRO == 0 { - write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO)?; - } else { - write!(f, "T{}.{:09}S", secs, abs.nanos)?; - } - } - Ok(()) - } -} - -/// Represents error when converting `Duration` to/from a standard library -/// implementation -/// -/// The `std::time::Duration` supports a range from zero to `u64::MAX` -/// *seconds*, while this module supports signed range of up to -/// `i64::MAX` of *milliseconds*. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct OutOfRangeError(()); - -impl fmt::Display for OutOfRangeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Source duration value is out of range for the target type") - } -} - -#[cfg(feature = "std")] -impl Error for OutOfRangeError { - #[allow(deprecated)] - fn description(&self) -> &str { - "out of range error" - } -} - -#[inline] -const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { - (this.div_euclid(other), this.rem_euclid(other)) -} - -#[cfg(all(feature = "arbitrary", feature = "std"))] -impl arbitrary::Arbitrary<'_> for Duration { - fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result { - const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1; - const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC; - - let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?; - let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?; - let duration = Duration { secs, nanos }; - - if duration < MIN || duration > MAX { - Err(arbitrary::Error::IncorrectFormat) - } else { - Ok(duration) - } - } -} - -#[cfg(test)] -mod tests { - use super::OutOfRangeError; - use super::{Duration, MAX, MIN}; - use core::time::Duration as StdDuration; - - #[test] - fn test_duration() { - assert!(Duration::seconds(1) != Duration::zero()); - assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3)); - assert_eq!( - Duration::seconds(86_399) + Duration::seconds(4), - Duration::days(1) + Duration::seconds(3) - ); - assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863_000)); - assert_eq!(Duration::days(10) - Duration::seconds(1_000_000), Duration::seconds(-136_000)); - assert_eq!( - Duration::days(2) + Duration::seconds(86_399) + Duration::nanoseconds(1_234_567_890), - Duration::days(3) + Duration::nanoseconds(234_567_890) - ); - assert_eq!(-Duration::days(3), Duration::days(-3)); - assert_eq!( - -(Duration::days(3) + Duration::seconds(70)), - Duration::days(-4) + Duration::seconds(86_400 - 70) - ); - - let mut d = Duration::default(); - d += Duration::minutes(1); - d -= Duration::seconds(30); - assert_eq!(d, Duration::seconds(30)); - } - - #[test] - fn test_duration_num_days() { - assert_eq!(Duration::zero().num_days(), 0); - assert_eq!(Duration::days(1).num_days(), 1); - assert_eq!(Duration::days(-1).num_days(), -1); - assert_eq!(Duration::seconds(86_399).num_days(), 0); - assert_eq!(Duration::seconds(86_401).num_days(), 1); - assert_eq!(Duration::seconds(-86_399).num_days(), 0); - assert_eq!(Duration::seconds(-86_401).num_days(), -1); - assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64); - assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64); - } - - #[test] - fn test_duration_num_seconds() { - assert_eq!(Duration::zero().num_seconds(), 0); - assert_eq!(Duration::seconds(1).num_seconds(), 1); - assert_eq!(Duration::seconds(-1).num_seconds(), -1); - assert_eq!(Duration::milliseconds(999).num_seconds(), 0); - assert_eq!(Duration::milliseconds(1001).num_seconds(), 1); - assert_eq!(Duration::milliseconds(-999).num_seconds(), 0); - assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1); - } - #[test] - fn test_duration_seconds_max_allowed() { - let duration = Duration::seconds(i64::MAX / 1_000); - assert_eq!(duration.num_seconds(), i64::MAX / 1_000); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MAX as i128 / 1_000 * 1_000_000_000 - ); - } - #[test] - fn test_duration_seconds_max_overflow() { - assert!(Duration::try_seconds(i64::MAX / 1_000 + 1).is_none()); - } - #[test] - #[should_panic(expected = "Duration::seconds out of bounds")] - fn test_duration_seconds_max_overflow_panic() { - let _ = Duration::seconds(i64::MAX / 1_000 + 1); - } - #[test] - fn test_duration_seconds_min_allowed() { - let duration = Duration::seconds(i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding - assert_eq!(duration.num_seconds(), i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - -i64::MAX as i128 / 1_000 * 1_000_000_000 - ); - } - #[test] - fn test_duration_seconds_min_underflow() { - assert!(Duration::try_seconds(-i64::MAX / 1_000 - 1).is_none()); - } - #[test] - #[should_panic(expected = "Duration::seconds out of bounds")] - fn test_duration_seconds_min_underflow_panic() { - let _ = Duration::seconds(-i64::MAX / 1_000 - 1); - } - - #[test] - fn test_duration_num_milliseconds() { - assert_eq!(Duration::zero().num_milliseconds(), 0); - assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1); - assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1); - assert_eq!(Duration::microseconds(999).num_milliseconds(), 0); - assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1); - assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0); - assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1); - } - #[test] - fn test_duration_milliseconds_max_allowed() { - // The maximum number of milliseconds acceptable through the constructor is - // equal to the number that can be stored in a Duration. - let duration = Duration::milliseconds(i64::MAX); - assert_eq!(duration.num_milliseconds(), i64::MAX); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MAX as i128 * 1_000_000 - ); - } - #[test] - fn test_duration_milliseconds_max_overflow() { - // Here we ensure that trying to add one millisecond to the maximum storable - // value will fail. - assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::milliseconds(1)).is_none()); - } - #[test] - fn test_duration_milliseconds_min_allowed() { - // The minimum number of milliseconds acceptable through the constructor is - // not equal to the number that can be stored in a Duration - there is a - // difference of one (i64::MIN vs -i64::MAX). - let duration = Duration::milliseconds(-i64::MAX); - assert_eq!(duration.num_milliseconds(), -i64::MAX); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - -i64::MAX as i128 * 1_000_000 - ); - } - #[test] - fn test_duration_milliseconds_min_underflow() { - // Here we ensure that trying to subtract one millisecond from the minimum - // storable value will fail. - assert!(Duration::milliseconds(-i64::MAX) - .checked_sub(&Duration::milliseconds(1)) - .is_none()); - } - #[test] - #[should_panic(expected = "Duration::milliseconds out of bounds")] - fn test_duration_milliseconds_min_underflow_panic() { - // Here we ensure that trying to create a value one millisecond below the - // minimum storable value will fail. This test is necessary because the - // storable range is -i64::MAX, but the constructor type of i64 will allow - // i64::MIN, which is one value below. - let _ = Duration::milliseconds(i64::MIN); // Same as -i64::MAX - 1 - } - - #[test] - fn test_duration_num_microseconds() { - assert_eq!(Duration::zero().num_microseconds(), Some(0)); - assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1)); - assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1)); - assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0)); - assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1)); - assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0)); - assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1)); - - // overflow checks - const MICROS_PER_DAY: i64 = 86_400_000_000; - assert_eq!( - Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(), - Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY) - ); - assert_eq!( - Duration::days(-i64::MAX / MICROS_PER_DAY).num_microseconds(), - Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY) - ); - assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None); - assert_eq!(Duration::days(-i64::MAX / MICROS_PER_DAY - 1).num_microseconds(), None); - } - #[test] - fn test_duration_microseconds_max_allowed() { - // The number of microseconds acceptable through the constructor is far - // fewer than the number that can actually be stored in a Duration, so this - // is not a particular insightful test. - let duration = Duration::microseconds(i64::MAX); - assert_eq!(duration.num_microseconds(), Some(i64::MAX)); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MAX as i128 * 1_000 - ); - // Here we create a Duration with the maximum possible number of - // microseconds by creating a Duration with the maximum number of - // milliseconds and then checking that the number of microseconds matches - // the storage limit. - let duration = Duration::milliseconds(i64::MAX); - assert!(duration.num_microseconds().is_none()); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MAX as i128 * 1_000_000 - ); - } - #[test] - fn test_duration_microseconds_max_overflow() { - // This test establishes that a Duration can store more microseconds than - // are representable through the return of duration.num_microseconds(). - let duration = Duration::microseconds(i64::MAX) + Duration::microseconds(1); - assert!(duration.num_microseconds().is_none()); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - (i64::MAX as i128 + 1) * 1_000 - ); - // Here we ensure that trying to add one microsecond to the maximum storable - // value will fail. - assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1)).is_none()); - } - #[test] - fn test_duration_microseconds_min_allowed() { - // The number of microseconds acceptable through the constructor is far - // fewer than the number that can actually be stored in a Duration, so this - // is not a particular insightful test. - let duration = Duration::microseconds(i64::MIN); - assert_eq!(duration.num_microseconds(), Some(i64::MIN)); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MIN as i128 * 1_000 - ); - // Here we create a Duration with the minimum possible number of - // microseconds by creating a Duration with the minimum number of - // milliseconds and then checking that the number of microseconds matches - // the storage limit. - let duration = Duration::milliseconds(-i64::MAX); - assert!(duration.num_microseconds().is_none()); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - -i64::MAX as i128 * 1_000_000 - ); - } - #[test] - fn test_duration_microseconds_min_underflow() { - // This test establishes that a Duration can store more microseconds than - // are representable through the return of duration.num_microseconds(). - let duration = Duration::microseconds(i64::MIN) - Duration::microseconds(1); - assert!(duration.num_microseconds().is_none()); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - (i64::MIN as i128 - 1) * 1_000 - ); - // Here we ensure that trying to subtract one microsecond from the minimum - // storable value will fail. - assert!(Duration::milliseconds(-i64::MAX) - .checked_sub(&Duration::microseconds(1)) - .is_none()); - } - - #[test] - fn test_duration_num_nanoseconds() { - assert_eq!(Duration::zero().num_nanoseconds(), Some(0)); - assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1)); - assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1)); - - // overflow checks - const NANOS_PER_DAY: i64 = 86_400_000_000_000; - assert_eq!( - Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(), - Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY) - ); - assert_eq!( - Duration::days(-i64::MAX / NANOS_PER_DAY).num_nanoseconds(), - Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY) - ); - assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None); - assert_eq!(Duration::days(-i64::MAX / NANOS_PER_DAY - 1).num_nanoseconds(), None); - } - #[test] - fn test_duration_nanoseconds_max_allowed() { - // The number of nanoseconds acceptable through the constructor is far fewer - // than the number that can actually be stored in a Duration, so this is not - // a particular insightful test. - let duration = Duration::nanoseconds(i64::MAX); - assert_eq!(duration.num_nanoseconds(), Some(i64::MAX)); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MAX as i128 - ); - // Here we create a Duration with the maximum possible number of nanoseconds - // by creating a Duration with the maximum number of milliseconds and then - // checking that the number of nanoseconds matches the storage limit. - let duration = Duration::milliseconds(i64::MAX); - assert!(duration.num_nanoseconds().is_none()); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MAX as i128 * 1_000_000 - ); - } - #[test] - fn test_duration_nanoseconds_max_overflow() { - // This test establishes that a Duration can store more nanoseconds than are - // representable through the return of duration.num_nanoseconds(). - let duration = Duration::nanoseconds(i64::MAX) + Duration::nanoseconds(1); - assert!(duration.num_nanoseconds().is_none()); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MAX as i128 + 1 - ); - // Here we ensure that trying to add one nanosecond to the maximum storable - // value will fail. - assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::nanoseconds(1)).is_none()); - } - #[test] - fn test_duration_nanoseconds_min_allowed() { - // The number of nanoseconds acceptable through the constructor is far fewer - // than the number that can actually be stored in a Duration, so this is not - // a particular insightful test. - let duration = Duration::nanoseconds(i64::MIN); - assert_eq!(duration.num_nanoseconds(), Some(i64::MIN)); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MIN as i128 - ); - // Here we create a Duration with the minimum possible number of nanoseconds - // by creating a Duration with the minimum number of milliseconds and then - // checking that the number of nanoseconds matches the storage limit. - let duration = Duration::milliseconds(-i64::MAX); - assert!(duration.num_nanoseconds().is_none()); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - -i64::MAX as i128 * 1_000_000 - ); - } - #[test] - fn test_duration_nanoseconds_min_underflow() { - // This test establishes that a Duration can store more nanoseconds than are - // representable through the return of duration.num_nanoseconds(). - let duration = Duration::nanoseconds(i64::MIN) - Duration::nanoseconds(1); - assert!(duration.num_nanoseconds().is_none()); - assert_eq!( - duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, - i64::MIN as i128 - 1 - ); - // Here we ensure that trying to subtract one nanosecond from the minimum - // storable value will fail. - assert!(Duration::milliseconds(-i64::MAX).checked_sub(&Duration::nanoseconds(1)).is_none()); - } - - #[test] - fn test_max() { - assert_eq!( - MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128, - i64::MAX as i128 * 1_000_000 - ); - assert_eq!(MAX, Duration::milliseconds(i64::MAX)); - assert_eq!(MAX.num_milliseconds(), i64::MAX); - assert_eq!(MAX.num_microseconds(), None); - assert_eq!(MAX.num_nanoseconds(), None); - } - #[test] - fn test_min() { - assert_eq!( - MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128, - -i64::MAX as i128 * 1_000_000 - ); - assert_eq!(MIN, Duration::milliseconds(-i64::MAX)); - assert_eq!(MIN.num_milliseconds(), -i64::MAX); - assert_eq!(MIN.num_microseconds(), None); - assert_eq!(MIN.num_nanoseconds(), None); - } - - #[test] - fn test_duration_ord() { - assert!(Duration::milliseconds(1) < Duration::milliseconds(2)); - assert!(Duration::milliseconds(2) > Duration::milliseconds(1)); - assert!(Duration::milliseconds(-1) > Duration::milliseconds(-2)); - assert!(Duration::milliseconds(-2) < Duration::milliseconds(-1)); - assert!(Duration::milliseconds(-1) < Duration::milliseconds(1)); - assert!(Duration::milliseconds(1) > Duration::milliseconds(-1)); - assert!(Duration::milliseconds(0) < Duration::milliseconds(1)); - assert!(Duration::milliseconds(0) > Duration::milliseconds(-1)); - assert!(Duration::milliseconds(1_001) < Duration::milliseconds(1_002)); - assert!(Duration::milliseconds(-1_001) > Duration::milliseconds(-1_002)); - assert!(Duration::nanoseconds(1_234_567_890) < Duration::nanoseconds(1_234_567_891)); - assert!(Duration::nanoseconds(-1_234_567_890) > Duration::nanoseconds(-1_234_567_891)); - assert!(Duration::milliseconds(i64::MAX) > Duration::milliseconds(i64::MAX - 1)); - assert!(Duration::milliseconds(-i64::MAX) < Duration::milliseconds(-i64::MAX + 1)); - } - - #[test] - fn test_duration_checked_ops() { - assert_eq!( - Duration::milliseconds(i64::MAX).checked_add(&Duration::milliseconds(0)), - Some(Duration::milliseconds(i64::MAX)) - ); - assert_eq!( - Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)), - Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999)) - ); - assert!(Duration::milliseconds(i64::MAX) - .checked_add(&Duration::microseconds(1000)) - .is_none()); - assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::nanoseconds(1)).is_none()); - - assert_eq!( - Duration::milliseconds(-i64::MAX).checked_sub(&Duration::milliseconds(0)), - Some(Duration::milliseconds(-i64::MAX)) - ); - assert_eq!( - Duration::milliseconds(-i64::MAX + 1).checked_sub(&Duration::microseconds(999)), - Some(Duration::milliseconds(-i64::MAX + 2) - Duration::microseconds(1999)) - ); - assert!(Duration::milliseconds(-i64::MAX) - .checked_sub(&Duration::milliseconds(1)) - .is_none()); - assert!(Duration::milliseconds(-i64::MAX).checked_sub(&Duration::nanoseconds(1)).is_none()); - } - - #[test] - fn test_duration_abs() { - assert_eq!(Duration::milliseconds(1300).abs(), Duration::milliseconds(1300)); - assert_eq!(Duration::milliseconds(1000).abs(), Duration::milliseconds(1000)); - assert_eq!(Duration::milliseconds(300).abs(), Duration::milliseconds(300)); - assert_eq!(Duration::milliseconds(0).abs(), Duration::milliseconds(0)); - assert_eq!(Duration::milliseconds(-300).abs(), Duration::milliseconds(300)); - assert_eq!(Duration::milliseconds(-700).abs(), Duration::milliseconds(700)); - assert_eq!(Duration::milliseconds(-1000).abs(), Duration::milliseconds(1000)); - assert_eq!(Duration::milliseconds(-1300).abs(), Duration::milliseconds(1300)); - assert_eq!(Duration::milliseconds(-1700).abs(), Duration::milliseconds(1700)); - assert_eq!(Duration::milliseconds(-i64::MAX).abs(), Duration::milliseconds(i64::MAX)); - } - - #[test] - #[allow(clippy::erasing_op)] - fn test_duration_mul() { - assert_eq!(Duration::zero() * i32::MAX, Duration::zero()); - assert_eq!(Duration::zero() * i32::MIN, Duration::zero()); - assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero()); - assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1)); - assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1)); - assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1)); - assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1)); - assert_eq!( - Duration::nanoseconds(30) * 333_333_333, - Duration::seconds(10) - Duration::nanoseconds(10) - ); - assert_eq!( - (Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3, - Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3) - ); - assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3)); - assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3)); - } - - #[test] - fn test_duration_div() { - assert_eq!(Duration::zero() / i32::MAX, Duration::zero()); - assert_eq!(Duration::zero() / i32::MIN, Duration::zero()); - assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789)); - assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789)); - assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789)); - assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789)); - assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333)); - assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333)); - assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500)); - assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500)); - assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500)); - assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333)); - assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333)); - } - - #[test] - fn test_duration_sum() { - let duration_list_1 = [Duration::zero(), Duration::seconds(1)]; - let sum_1: Duration = duration_list_1.iter().sum(); - assert_eq!(sum_1, Duration::seconds(1)); - - let duration_list_2 = - [Duration::zero(), Duration::seconds(1), Duration::seconds(6), Duration::seconds(10)]; - let sum_2: Duration = duration_list_2.iter().sum(); - assert_eq!(sum_2, Duration::seconds(17)); - - let duration_arr = - [Duration::zero(), Duration::seconds(1), Duration::seconds(6), Duration::seconds(10)]; - let sum_3: Duration = duration_arr.into_iter().sum(); - assert_eq!(sum_3, Duration::seconds(17)); - } - - #[test] - fn test_duration_fmt() { - assert_eq!(Duration::zero().to_string(), "PT0S"); - assert_eq!(Duration::days(42).to_string(), "P42D"); - assert_eq!(Duration::days(-42).to_string(), "-P42D"); - assert_eq!(Duration::seconds(42).to_string(), "PT42S"); - assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S"); - assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S"); - assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S"); - assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(), "P7DT6.543S"); - assert_eq!(Duration::seconds(-86_401).to_string(), "-P1DT1S"); - assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S"); - - // the format specifier should have no effect on `Duration` - assert_eq!( - format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)), - "P1DT2.345S" - ); - } - - #[test] - fn test_to_std() { - assert_eq!(Duration::seconds(1).to_std(), Ok(StdDuration::new(1, 0))); - assert_eq!(Duration::seconds(86_401).to_std(), Ok(StdDuration::new(86_401, 0))); - assert_eq!(Duration::milliseconds(123).to_std(), Ok(StdDuration::new(0, 123_000_000))); - assert_eq!( - Duration::milliseconds(123_765).to_std(), - Ok(StdDuration::new(123, 765_000_000)) - ); - assert_eq!(Duration::nanoseconds(777).to_std(), Ok(StdDuration::new(0, 777))); - assert_eq!(MAX.to_std(), Ok(StdDuration::new(9_223_372_036_854_775, 807_000_000))); - assert_eq!(Duration::seconds(-1).to_std(), Err(OutOfRangeError(()))); - assert_eq!(Duration::milliseconds(-1).to_std(), Err(OutOfRangeError(()))); - } - - #[test] - fn test_from_std() { - assert_eq!(Ok(Duration::seconds(1)), Duration::from_std(StdDuration::new(1, 0))); - assert_eq!(Ok(Duration::seconds(86_401)), Duration::from_std(StdDuration::new(86_401, 0))); - assert_eq!( - Ok(Duration::milliseconds(123)), - Duration::from_std(StdDuration::new(0, 123_000_000)) - ); - assert_eq!( - Ok(Duration::milliseconds(123_765)), - Duration::from_std(StdDuration::new(123, 765_000_000)) - ); - assert_eq!(Ok(Duration::nanoseconds(777)), Duration::from_std(StdDuration::new(0, 777))); - assert_eq!( - Ok(MAX), - Duration::from_std(StdDuration::new(9_223_372_036_854_775, 807_000_000)) - ); - assert_eq!( - Duration::from_std(StdDuration::new(9_223_372_036_854_776, 0)), - Err(OutOfRangeError(())) - ); - assert_eq!( - Duration::from_std(StdDuration::new(9_223_372_036_854_775, 807_000_001)), - Err(OutOfRangeError(())) - ); - } - - #[test] - fn test_duration_const() { - const ONE_WEEK: Duration = Duration::weeks(1); - const ONE_DAY: Duration = Duration::days(1); - const ONE_HOUR: Duration = Duration::hours(1); - const ONE_MINUTE: Duration = Duration::minutes(1); - const ONE_SECOND: Duration = Duration::seconds(1); - const ONE_MILLI: Duration = Duration::milliseconds(1); - const ONE_MICRO: Duration = Duration::microseconds(1); - const ONE_NANO: Duration = Duration::nanoseconds(1); - let combo: Duration = ONE_WEEK - + ONE_DAY - + ONE_HOUR - + ONE_MINUTE - + ONE_SECOND - + ONE_MILLI - + ONE_MICRO - + ONE_NANO; - - assert!(ONE_WEEK != Duration::zero()); - assert!(ONE_DAY != Duration::zero()); - assert!(ONE_HOUR != Duration::zero()); - assert!(ONE_MINUTE != Duration::zero()); - assert!(ONE_SECOND != Duration::zero()); - assert!(ONE_MILLI != Duration::zero()); - assert!(ONE_MICRO != Duration::zero()); - assert!(ONE_NANO != Duration::zero()); - assert_eq!( - combo, - Duration::seconds(86400 * 7 + 86400 + 3600 + 60 + 1) - + Duration::nanoseconds(1 + 1_000 + 1_000_000) - ); - } - - #[test] - #[cfg(feature = "rkyv-validation")] - fn test_rkyv_validation() { - let duration = Duration::seconds(1); - let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap(); - assert_eq!(rkyv::from_bytes::(&bytes).unwrap(), duration); - } -} diff --git a/src/format/parsed.rs b/src/format/parsed.rs index fb9d113442..19f7f81615 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -5,10 +5,9 @@ //! They can be constructed incrementally while being checked for consistency. use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE}; -use crate::duration::Duration as OldDuration; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone}; -use crate::{DateTime, Datelike, Timelike, Weekday}; +use crate::{DateTime, Datelike, TimeDelta, Timelike, Weekday}; /// Parsed parts of date and time. There are two classes of methods: /// @@ -430,7 +429,7 @@ impl Parsed { + (week_from_sun as i32 - 1) * 7 + weekday.num_days_from_sunday() as i32; let date = newyear - .checked_add_signed(OldDuration::days(i64::from(ndays))) + .checked_add_signed(TimeDelta::days(i64::from(ndays))) .ok_or(OUT_OF_RANGE)?; if date.year() != year { return Err(OUT_OF_RANGE); @@ -464,7 +463,7 @@ impl Parsed { + (week_from_mon as i32 - 1) * 7 + weekday.num_days_from_monday() as i32; let date = newyear - .checked_add_signed(OldDuration::days(i64::from(ndays))) + .checked_add_signed(TimeDelta::days(i64::from(ndays))) .ok_or(OUT_OF_RANGE)?; if date.year() != year { return Err(OUT_OF_RANGE); @@ -587,7 +586,7 @@ impl Parsed { 59 => {} // `datetime` is known to be off by one second. 0 => { - datetime -= OldDuration::seconds(1); + datetime -= TimeDelta::seconds(1); } // otherwise it is impossible. _ => return Err(IMPOSSIBLE), diff --git a/src/lib.rs b/src/lib.rs index 795aa1596f..18d1faac73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,23 +52,18 @@ //! //! ## Overview //! -//! ### Duration -//! -//! Chrono currently uses its own [`Duration`] type to represent the magnitude -//! of a time span. Since this has the same name as the newer, standard type for -//! duration, the reference will refer this type as `OldDuration`. -//! -//! Note that this is an "accurate" duration represented as seconds and -//! nanoseconds and does not represent "nominal" components such as days or -//! months. -//! -//! Chrono does not yet natively support -//! the standard [`Duration`](https://doc.rust-lang.org/std/time/struct.Duration.html) type, -//! but it will be supported in the future. -//! Meanwhile you can convert between two types with -//! [`Duration::from_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.from_std) -//! and -//! [`Duration::to_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.to_std) +//! ### Time delta / Duration +//! +//! Chrono has a [`TimeDelta`] type to represent the magnitude of a time span. This is an +//! "accurate" duration represented as seconds and nanoseconds, and does not represent "nominal" +//! components such as days or months. +//! +//! The [`TimeDelta`] type was previously named `Duration` (and is still available as a type alias +//! with that name). A notable difference with the similar [`core::time::Duration`] is that it is a +//! signed value instead of unsigned. +//! +//! Chrono currently only supports a small number of operations with [`core::time::Duration`] . +//! You can convert between both types with the [`TimeDelta::from_std`] and [`TimeDelta::to_std`] //! methods. //! //! ### Date and Time @@ -174,7 +169,7 @@ //! //! ```rust //! use chrono::prelude::*; -//! use chrono::Duration; +//! use chrono::TimeDelta; //! //! // assume this returned `2014-11-28T21:45:59.324310806+09:00`: //! let dt = FixedOffset::east_opt(9*3600).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(21, 45, 59, 324310806).unwrap()).unwrap(); @@ -201,11 +196,11 @@ //! // arithmetic operations //! let dt1 = Utc.with_ymd_and_hms(2014, 11, 14, 8, 9, 10).unwrap(); //! let dt2 = Utc.with_ymd_and_hms(2014, 11, 14, 10, 9, 8).unwrap(); -//! assert_eq!(dt1.signed_duration_since(dt2), Duration::seconds(-2 * 3600 + 2)); -//! assert_eq!(dt2.signed_duration_since(dt1), Duration::seconds(2 * 3600 - 2)); -//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() + Duration::seconds(1_000_000_000), +//! assert_eq!(dt1.signed_duration_since(dt2), TimeDelta::seconds(-2 * 3600 + 2)); +//! assert_eq!(dt2.signed_duration_since(dt1), TimeDelta::seconds(2 * 3600 - 2)); +//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() + TimeDelta::seconds(1_000_000_000), //! Utc.with_ymd_and_hms(2001, 9, 9, 1, 46, 40).unwrap()); -//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() - Duration::seconds(1_000_000_000), +//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() - TimeDelta::seconds(1_000_000_000), //! Utc.with_ymd_and_hms(1938, 4, 24, 22, 13, 20).unwrap()); //! ``` //! @@ -465,11 +460,14 @@ #[cfg(feature = "alloc")] extern crate alloc; -mod duration; -pub use duration::Duration; +mod time_delta; #[cfg(feature = "std")] #[doc(no_inline)] -pub use duration::OutOfRangeError; +pub use time_delta::OutOfRangeError; +pub use time_delta::TimeDelta; + +/// Alias of [`TimeDelta`]. +pub type Duration = TimeDelta; use core::fmt; @@ -563,7 +561,6 @@ pub mod serde { #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))] pub mod rkyv { pub use crate::datetime::ArchivedDateTime; - pub use crate::duration::ArchivedDuration; pub use crate::month::ArchivedMonth; pub use crate::naive::date::ArchivedNaiveDate; pub use crate::naive::datetime::ArchivedNaiveDateTime; @@ -573,7 +570,11 @@ pub mod rkyv { #[cfg(feature = "clock")] pub use crate::offset::local::ArchivedLocal; pub use crate::offset::utc::ArchivedUtc; + pub use crate::time_delta::ArchivedTimeDelta; pub use crate::weekday::ArchivedWeekday; + + /// Alias of [`ArchivedTimeDelta`] + pub type ArchivedDuration = ArchivedTimeDelta; } /// Out of range error type used in various converting APIs diff --git a/src/naive/date.rs b/src/naive/date.rs index c4fe5209d1..190a6bac60 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -16,7 +16,6 @@ use rkyv::{Archive, Deserialize, Serialize}; #[cfg(all(feature = "unstable-locales", feature = "alloc"))] use pure_rust_locales::Locale; -use crate::duration::Duration as OldDuration; #[cfg(feature = "alloc")] use crate::format::DelayedFormat; use crate::format::{ @@ -26,7 +25,7 @@ use crate::format::{ use crate::month::Months; use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime}; use crate::{expect, try_opt}; -use crate::{Datelike, Weekday}; +use crate::{Datelike, TimeDelta, Weekday}; use super::internals::{self, DateImpl, Mdf, Of, YearFlags}; use super::isoweek; @@ -126,10 +125,10 @@ impl NaiveWeek { /// A duration in calendar days. /// -/// This is useful because when using `Duration` it is possible -/// that adding `Duration::days(1)` doesn't increment the day value as expected due to it being a -/// fixed number of seconds. This difference applies only when dealing with `DateTime` data types -/// and in other cases `Duration::days(n)` and `Days::new(n)` are equivalent. +/// This is useful because when using `TimeDelta` it is possible that adding `TimeDelta::days(1)` +/// doesn't increment the day value as expected due to it being a fixed number of seconds. This +/// difference applies only when dealing with `DateTime` data types and in other cases +/// `TimeDelta::days(n)` and `Days::new(n)` are equivalent. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] pub struct Days(pub(crate) u64); @@ -1134,7 +1133,7 @@ impl NaiveDate { } } - /// Adds the number of whole days in the given `Duration` to the current date. + /// Adds the number of whole days in the given `TimeDelta` to the current date. /// /// # Errors /// @@ -1143,19 +1142,19 @@ impl NaiveDate { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); - /// assert_eq!(d.checked_add_signed(Duration::days(40)), + /// assert_eq!(d.checked_add_signed(TimeDelta::days(40)), /// Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap())); - /// assert_eq!(d.checked_add_signed(Duration::days(-40)), + /// assert_eq!(d.checked_add_signed(TimeDelta::days(-40)), /// Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap())); - /// assert_eq!(d.checked_add_signed(Duration::days(1_000_000_000)), None); - /// assert_eq!(d.checked_add_signed(Duration::days(-1_000_000_000)), None); - /// assert_eq!(NaiveDate::MAX.checked_add_signed(Duration::days(1)), None); + /// assert_eq!(d.checked_add_signed(TimeDelta::days(1_000_000_000)), None); + /// assert_eq!(d.checked_add_signed(TimeDelta::days(-1_000_000_000)), None); + /// assert_eq!(NaiveDate::MAX.checked_add_signed(TimeDelta::days(1)), None); /// ``` #[must_use] - pub const fn checked_add_signed(self, rhs: OldDuration) -> Option { + pub const fn checked_add_signed(self, rhs: TimeDelta) -> Option { let days = rhs.num_days(); if days < i32::MIN as i64 || days > i32::MAX as i64 { return None; @@ -1163,7 +1162,7 @@ impl NaiveDate { self.add_days(days as i32) } - /// Subtracts the number of whole days in the given `Duration` from the current date. + /// Subtracts the number of whole days in the given `TimeDelta` from the current date. /// /// # Errors /// @@ -1172,19 +1171,19 @@ impl NaiveDate { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); - /// assert_eq!(d.checked_sub_signed(Duration::days(40)), + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(40)), /// Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap())); - /// assert_eq!(d.checked_sub_signed(Duration::days(-40)), + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-40)), /// Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap())); - /// assert_eq!(d.checked_sub_signed(Duration::days(1_000_000_000)), None); - /// assert_eq!(d.checked_sub_signed(Duration::days(-1_000_000_000)), None); - /// assert_eq!(NaiveDate::MIN.checked_sub_signed(Duration::days(1)), None); + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(1_000_000_000)), None); + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-1_000_000_000)), None); + /// assert_eq!(NaiveDate::MIN.checked_sub_signed(TimeDelta::days(1)), None); /// ``` #[must_use] - pub const fn checked_sub_signed(self, rhs: OldDuration) -> Option { + pub const fn checked_sub_signed(self, rhs: TimeDelta) -> Option { let days = -rhs.num_days(); if days < i32::MIN as i64 || days > i32::MAX as i64 { return None; @@ -1193,38 +1192,36 @@ impl NaiveDate { } /// Subtracts another `NaiveDate` from the current date. - /// Returns a `Duration` of integral numbers. + /// Returns a `TimeDelta` of integral numbers. /// /// This does not overflow or underflow at all, - /// as all possible output fits in the range of `Duration`. + /// as all possible output fits in the range of `TimeDelta`. /// /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// let since = NaiveDate::signed_duration_since; /// - /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 1)), Duration::zero()); - /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 12, 31)), Duration::days(1)); - /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 2)), Duration::days(-1)); - /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 9, 23)), Duration::days(100)); - /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 1, 1)), Duration::days(365)); - /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), Duration::days(365*4 + 1)); - /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), Duration::days(365*400 + 97)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 1)), TimeDelta::zero()); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 12, 31)), TimeDelta::days(1)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 2)), TimeDelta::days(-1)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 9, 23)), TimeDelta::days(100)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 1, 1)), TimeDelta::days(365)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), TimeDelta::days(365*4 + 1)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), TimeDelta::days(365*400 + 97)); /// ``` #[must_use] - pub const fn signed_duration_since(self, rhs: NaiveDate) -> OldDuration { + pub const fn signed_duration_since(self, rhs: NaiveDate) -> TimeDelta { let year1 = self.year(); let year2 = rhs.year(); let (year1_div_400, year1_mod_400) = div_mod_floor(year1, 400); let (year2_div_400, year2_mod_400) = div_mod_floor(year2, 400); let cycle1 = internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal()) as i64; let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal()) as i64; - OldDuration::days( - (year1_div_400 as i64 - year2_div_400 as i64) * 146_097 + (cycle1 - cycle2), - ) + TimeDelta::days((year1_div_400 as i64 - year2_div_400 as i64) * 146_097 + (cycle1 - cycle2)) } /// Returns the number of whole years from the given `base` until `self`. @@ -1862,10 +1859,10 @@ impl Datelike for NaiveDate { } } -/// Add `chrono::Duration` to `NaiveDate`. +/// Add `TimeDelta` to `NaiveDate`. /// -/// This discards the fractional days in `Duration`, rounding to the closest integral number of days -/// towards `Duration::zero()`. +/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of +/// days towards `TimeDelta::zero()`. /// /// # Panics /// @@ -1875,42 +1872,42 @@ impl Datelike for NaiveDate { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// -/// assert_eq!(from_ymd(2014, 1, 1) + Duration::zero(), from_ymd(2014, 1, 1)); -/// assert_eq!(from_ymd(2014, 1, 1) + Duration::seconds(86399), from_ymd(2014, 1, 1)); -/// assert_eq!(from_ymd(2014, 1, 1) + Duration::seconds(-86399), from_ymd(2014, 1, 1)); -/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(1), from_ymd(2014, 1, 2)); -/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(-1), from_ymd(2013, 12, 31)); -/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(364), from_ymd(2014, 12, 31)); -/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*4 + 1), from_ymd(2018, 1, 1)); -/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*400 + 97), from_ymd(2414, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::zero(), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::seconds(86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::seconds(-86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(1), from_ymd(2014, 1, 2)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(-1), from_ymd(2013, 12, 31)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(364), from_ymd(2014, 12, 31)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(365*4 + 1), from_ymd(2018, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(365*400 + 97), from_ymd(2414, 1, 1)); /// ``` /// /// [`NaiveDate::checked_add_signed`]: crate::NaiveDate::checked_add_signed -impl Add for NaiveDate { +impl Add for NaiveDate { type Output = NaiveDate; #[inline] - fn add(self, rhs: OldDuration) -> NaiveDate { - self.checked_add_signed(rhs).expect("`NaiveDate + Duration` overflowed") + fn add(self, rhs: TimeDelta) -> NaiveDate { + self.checked_add_signed(rhs).expect("`NaiveDate + TimeDelta` overflowed") } } -/// Add-assign of `chrono::Duration` to `NaiveDate`. +/// Add-assign of `TimeDelta` to `NaiveDate`. /// -/// This discards the fractional days in `Duration`, rounding to the closest integral number of days -/// towards `Duration::zero()`. +/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of days +/// towards `TimeDelta::zero()`. /// /// # Panics /// /// Panics if the resulting date would be out of range. /// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead. -impl AddAssign for NaiveDate { +impl AddAssign for NaiveDate { #[inline] - fn add_assign(&mut self, rhs: OldDuration) { + fn add_assign(&mut self, rhs: TimeDelta) { *self = self.add(rhs); } } @@ -2004,11 +2001,11 @@ impl Sub for NaiveDate { } } -/// Subtract `chrono::Duration` from `NaiveDate`. +/// Subtract `TimeDelta` from `NaiveDate`. /// -/// This discards the fractional days in `Duration`, rounding to the closest integral number of days -/// towards `Duration::zero()`. -/// It is the same as the addition with a negated `Duration`. +/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of +/// days towards `TimeDelta::zero()`. +/// It is the same as the addition with a negated `TimeDelta`. /// /// # Panics /// @@ -2018,52 +2015,52 @@ impl Sub for NaiveDate { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// -/// assert_eq!(from_ymd(2014, 1, 1) - Duration::zero(), from_ymd(2014, 1, 1)); -/// assert_eq!(from_ymd(2014, 1, 1) - Duration::seconds(86399), from_ymd(2014, 1, 1)); -/// assert_eq!(from_ymd(2014, 1, 1) - Duration::seconds(-86399), from_ymd(2014, 1, 1)); -/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(1), from_ymd(2013, 12, 31)); -/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(-1), from_ymd(2014, 1, 2)); -/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(364), from_ymd(2013, 1, 2)); -/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*4 + 1), from_ymd(2010, 1, 1)); -/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*400 + 97), from_ymd(1614, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::zero(), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::seconds(86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::seconds(-86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(1), from_ymd(2013, 12, 31)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(-1), from_ymd(2014, 1, 2)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(364), from_ymd(2013, 1, 2)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(365*4 + 1), from_ymd(2010, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(365*400 + 97), from_ymd(1614, 1, 1)); /// ``` /// /// [`NaiveDate::checked_sub_signed`]: crate::NaiveDate::checked_sub_signed -impl Sub for NaiveDate { +impl Sub for NaiveDate { type Output = NaiveDate; #[inline] - fn sub(self, rhs: OldDuration) -> NaiveDate { - self.checked_sub_signed(rhs).expect("`NaiveDate - Duration` overflowed") + fn sub(self, rhs: TimeDelta) -> NaiveDate { + self.checked_sub_signed(rhs).expect("`NaiveDate - TimeDelta` overflowed") } } -/// Subtract-assign `chrono::Duration` from `NaiveDate`. +/// Subtract-assign `TimeDelta` from `NaiveDate`. /// -/// This discards the fractional days in `Duration`, rounding to the closest integral number of days -/// towards `Duration::zero()`. -/// It is the same as the addition with a negated `Duration`. +/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of +/// days towards `TimeDelta::zero()`. +/// It is the same as the addition with a negated `TimeDelta`. /// /// # Panics /// /// Panics if the resulting date would be out of range. /// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead. -impl SubAssign for NaiveDate { +impl SubAssign for NaiveDate { #[inline] - fn sub_assign(&mut self, rhs: OldDuration) { + fn sub_assign(&mut self, rhs: TimeDelta) { *self = self.sub(rhs); } } /// Subtracts another `NaiveDate` from the current date. -/// Returns a `Duration` of integral numbers. +/// Returns a `TimeDelta` of integral numbers. /// /// This does not overflow or underflow at all, -/// as all possible output fits in the range of `Duration`. +/// as all possible output fits in the range of `TimeDelta`. /// /// The implementation is a wrapper around /// [`NaiveDate::signed_duration_since`](#method.signed_duration_since). @@ -2071,23 +2068,23 @@ impl SubAssign for NaiveDate { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// -/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 1), Duration::zero()); -/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 12, 31), Duration::days(1)); -/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 2), Duration::days(-1)); -/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 9, 23), Duration::days(100)); -/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 1, 1), Duration::days(365)); -/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2010, 1, 1), Duration::days(365*4 + 1)); -/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(1614, 1, 1), Duration::days(365*400 + 97)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 1), TimeDelta::zero()); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 12, 31), TimeDelta::days(1)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 2), TimeDelta::days(-1)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 9, 23), TimeDelta::days(100)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 1, 1), TimeDelta::days(365)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2010, 1, 1), TimeDelta::days(365*4 + 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(1614, 1, 1), TimeDelta::days(365*400 + 97)); /// ``` impl Sub for NaiveDate { - type Output = OldDuration; + type Output = TimeDelta; #[inline] - fn sub(self, rhs: NaiveDate) -> OldDuration { + fn sub(self, rhs: NaiveDate) -> TimeDelta { self.signed_duration_since(rhs) } } @@ -2145,7 +2142,7 @@ impl Iterator for NaiveDateWeeksIterator { fn next(&mut self) -> Option { let current = self.value; - self.value = current.checked_add_signed(OldDuration::weeks(1))?; + self.value = current.checked_add_signed(TimeDelta::weeks(1))?; Some(current) } @@ -2160,7 +2157,7 @@ impl ExactSizeIterator for NaiveDateWeeksIterator {} impl DoubleEndedIterator for NaiveDateWeeksIterator { fn next_back(&mut self) -> Option { let current = self.value; - self.value = current.checked_sub_signed(OldDuration::weeks(1))?; + self.value = current.checked_sub_signed(TimeDelta::weeks(1))?; Some(current) } } @@ -2479,9 +2476,8 @@ mod serde { #[cfg(test)] mod tests { use super::{Days, Months, NaiveDate, MAX_YEAR, MIN_YEAR}; - use crate::duration::Duration; use crate::naive::internals::YearFlags; - use crate::{Datelike, Weekday}; + use crate::{Datelike, TimeDelta, Weekday}; // as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`, // we use a separate run-time test. @@ -2502,7 +2498,7 @@ mod tests { ); // let's also check that the entire range do not exceed 2^44 seconds - // (sometimes used for bounding `Duration` against overflow) + // (sometimes used for bounding `TimeDelta` against overflow) let maxsecs = NaiveDate::MAX.signed_duration_since(NaiveDate::MIN).num_seconds(); let maxsecs = maxsecs + 86401; // also take care of DateTime assert!( @@ -2965,52 +2961,52 @@ mod tests { #[test] fn test_date_add() { - fn check((y1, m1, d1): (i32, u32, u32), rhs: Duration, ymd: Option<(i32, u32, u32)>) { + fn check((y1, m1, d1): (i32, u32, u32), rhs: TimeDelta, ymd: Option<(i32, u32, u32)>) { let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap(); let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd_opt(y, m, d).unwrap()); assert_eq!(lhs.checked_add_signed(rhs), sum); assert_eq!(lhs.checked_sub_signed(-rhs), sum); } - check((2014, 1, 1), Duration::zero(), Some((2014, 1, 1))); - check((2014, 1, 1), Duration::seconds(86399), Some((2014, 1, 1))); + check((2014, 1, 1), TimeDelta::zero(), Some((2014, 1, 1))); + check((2014, 1, 1), TimeDelta::seconds(86399), Some((2014, 1, 1))); // always round towards zero - check((2014, 1, 1), Duration::seconds(-86399), Some((2014, 1, 1))); - check((2014, 1, 1), Duration::days(1), Some((2014, 1, 2))); - check((2014, 1, 1), Duration::days(-1), Some((2013, 12, 31))); - check((2014, 1, 1), Duration::days(364), Some((2014, 12, 31))); - check((2014, 1, 1), Duration::days(365 * 4 + 1), Some((2018, 1, 1))); - check((2014, 1, 1), Duration::days(365 * 400 + 97), Some((2414, 1, 1))); + check((2014, 1, 1), TimeDelta::seconds(-86399), Some((2014, 1, 1))); + check((2014, 1, 1), TimeDelta::days(1), Some((2014, 1, 2))); + check((2014, 1, 1), TimeDelta::days(-1), Some((2013, 12, 31))); + check((2014, 1, 1), TimeDelta::days(364), Some((2014, 12, 31))); + check((2014, 1, 1), TimeDelta::days(365 * 4 + 1), Some((2018, 1, 1))); + check((2014, 1, 1), TimeDelta::days(365 * 400 + 97), Some((2414, 1, 1))); - check((-7, 1, 1), Duration::days(365 * 12 + 3), Some((5, 1, 1))); + check((-7, 1, 1), TimeDelta::days(365 * 12 + 3), Some((5, 1, 1))); // overflow check - check((0, 1, 1), Duration::days(MAX_DAYS_FROM_YEAR_0 as i64), Some((MAX_YEAR, 12, 31))); - check((0, 1, 1), Duration::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1), None); - check((0, 1, 1), Duration::max_value(), None); - check((0, 1, 1), Duration::days(MIN_DAYS_FROM_YEAR_0 as i64), Some((MIN_YEAR, 1, 1))); - check((0, 1, 1), Duration::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1), None); - check((0, 1, 1), Duration::min_value(), None); + check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64), Some((MAX_YEAR, 12, 31))); + check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1), None); + check((0, 1, 1), TimeDelta::max_value(), None); + check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64), Some((MIN_YEAR, 1, 1))); + check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1), None); + check((0, 1, 1), TimeDelta::min_value(), None); } #[test] fn test_date_sub() { - fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: Duration) { + fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: TimeDelta) { let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap(); let rhs = NaiveDate::from_ymd_opt(y2, m2, d2).unwrap(); assert_eq!(lhs.signed_duration_since(rhs), diff); assert_eq!(rhs.signed_duration_since(lhs), -diff); } - check((2014, 1, 1), (2014, 1, 1), Duration::zero()); - check((2014, 1, 2), (2014, 1, 1), Duration::days(1)); - check((2014, 12, 31), (2014, 1, 1), Duration::days(364)); - check((2015, 1, 3), (2014, 1, 1), Duration::days(365 + 2)); - check((2018, 1, 1), (2014, 1, 1), Duration::days(365 * 4 + 1)); - check((2414, 1, 1), (2014, 1, 1), Duration::days(365 * 400 + 97)); + check((2014, 1, 1), (2014, 1, 1), TimeDelta::zero()); + check((2014, 1, 2), (2014, 1, 1), TimeDelta::days(1)); + check((2014, 12, 31), (2014, 1, 1), TimeDelta::days(364)); + check((2015, 1, 3), (2014, 1, 1), TimeDelta::days(365 + 2)); + check((2018, 1, 1), (2014, 1, 1), TimeDelta::days(365 * 4 + 1)); + check((2414, 1, 1), (2014, 1, 1), TimeDelta::days(365 * 400 + 97)); - check((MAX_YEAR, 12, 31), (0, 1, 1), Duration::days(MAX_DAYS_FROM_YEAR_0 as i64)); - check((MIN_YEAR, 1, 1), (0, 1, 1), Duration::days(MIN_DAYS_FROM_YEAR_0 as i64)); + check((MAX_YEAR, 12, 31), (0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64)); + check((MIN_YEAR, 1, 1), (0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64)); } #[test] @@ -3062,9 +3058,9 @@ mod tests { fn test_date_addassignment() { let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); let mut date = ymd(2016, 10, 1); - date += Duration::days(10); + date += TimeDelta::days(10); assert_eq!(date, ymd(2016, 10, 11)); - date += Duration::days(30); + date += TimeDelta::days(30); assert_eq!(date, ymd(2016, 11, 10)); } @@ -3072,9 +3068,9 @@ mod tests { fn test_date_subassignment() { let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); let mut date = ymd(2016, 10, 11); - date -= Duration::days(10); + date -= TimeDelta::days(10); assert_eq!(date, ymd(2016, 10, 1)); - date -= Duration::days(2); + date -= TimeDelta::days(2); assert_eq!(date, ymd(2016, 9, 29)); } diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 69fa52a824..c5c8953c16 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -13,16 +13,16 @@ use core::{fmt, str}; #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))] use rkyv::{Archive, Deserialize, Serialize}; -use crate::duration::{Duration as OldDuration, NANOS_PER_SEC}; #[cfg(feature = "alloc")] use crate::format::DelayedFormat; use crate::format::{parse, parse_and_remainder, ParseError, ParseResult, Parsed, StrftimeItems}; use crate::format::{Fixed, Item, Numeric, Pad}; use crate::naive::{Days, IsoWeek, NaiveDate, NaiveTime}; use crate::offset::Utc; +use crate::time_delta::NANOS_PER_SEC; use crate::{ - expect, try_opt, DateTime, Datelike, FixedOffset, LocalResult, Months, TimeZone, Timelike, - Weekday, + expect, try_opt, DateTime, Datelike, FixedOffset, LocalResult, Months, TimeDelta, TimeZone, + Timelike, Weekday, }; #[cfg(feature = "rustc-serialize")] pub(super) mod rustc_serialize; @@ -34,10 +34,10 @@ pub(crate) mod serde; #[cfg(test)] mod tests; -/// The tight upper bound guarantees that a duration with `|Duration| >= 2^MAX_SECS_BITS` +/// The tight upper bound guarantees that a time delta with `|TimeDelta| >= 2^MAX_SECS_BITS` /// will always overflow the addition with any date and time type. /// -/// So why is this needed? `Duration::seconds(rhs)` may overflow, and we don't have +/// So why is this needed? `TimeDelta::seconds(rhs)` may overflow, and we don't have /// an alternative returning `Option` or `Result`. Thus we need some early bound to avoid /// touching that call when we are already sure that it WILL overflow... const MAX_SECS_BITS: usize = 44; @@ -633,7 +633,7 @@ impl NaiveDateTime { self.time.nanosecond() } - /// Adds given `Duration` to the current date and time. + /// Adds given `TimeDelta` to the current date and time. /// /// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), /// the addition assumes that **there is no leap second ever**, @@ -647,69 +647,69 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); - /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::zero()), + /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::zero()), /// Some(hms(3, 5, 7))); - /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(1)), + /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::seconds(1)), /// Some(hms(3, 5, 8))); - /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(-1)), + /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::seconds(-1)), /// Some(hms(3, 5, 6))); - /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(3600 + 60)), + /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::seconds(3600 + 60)), /// Some(hms(4, 6, 7))); - /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(86_400)), + /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::seconds(86_400)), /// Some(from_ymd(2016, 7, 9).and_hms_opt(3, 5, 7).unwrap())); /// /// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap(); - /// assert_eq!(hmsm(3, 5, 7, 980).checked_add_signed(Duration::milliseconds(450)), + /// assert_eq!(hmsm(3, 5, 7, 980).checked_add_signed(TimeDelta::milliseconds(450)), /// Some(hmsm(3, 5, 8, 430))); /// ``` /// /// Overflow returns `None`. /// /// ``` - /// # use chrono::{Duration, NaiveDate}; + /// # use chrono::{TimeDelta, NaiveDate}; /// # let hms = |h, m, s| NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(h, m, s).unwrap(); - /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::days(1_000_000_000)), None); + /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::days(1_000_000_000)), None); /// ``` /// /// Leap seconds are handled, /// but the addition assumes that it is the only leap second happened. /// /// ``` - /// # use chrono::{Duration, NaiveDate}; + /// # use chrono::{TimeDelta, NaiveDate}; /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap(); /// let leap = hmsm(3, 5, 59, 1_300); - /// assert_eq!(leap.checked_add_signed(Duration::zero()), + /// assert_eq!(leap.checked_add_signed(TimeDelta::zero()), /// Some(hmsm(3, 5, 59, 1_300))); - /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(-500)), + /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(-500)), /// Some(hmsm(3, 5, 59, 800))); - /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(500)), + /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(500)), /// Some(hmsm(3, 5, 59, 1_800))); - /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(800)), + /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(800)), /// Some(hmsm(3, 6, 0, 100))); - /// assert_eq!(leap.checked_add_signed(Duration::seconds(10)), + /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(10)), /// Some(hmsm(3, 6, 9, 300))); - /// assert_eq!(leap.checked_add_signed(Duration::seconds(-10)), + /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(-10)), /// Some(hmsm(3, 5, 50, 300))); - /// assert_eq!(leap.checked_add_signed(Duration::days(1)), + /// assert_eq!(leap.checked_add_signed(TimeDelta::days(1)), /// Some(from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap())); /// ``` #[must_use] - pub const fn checked_add_signed(self, rhs: OldDuration) -> Option { + pub const fn checked_add_signed(self, rhs: TimeDelta) -> Option { let (time, rhs) = self.time.overflowing_add_signed(rhs); - // early checking to avoid overflow in OldDuration::seconds + // early checking to avoid overflow in TimeDelta::seconds if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) { return None; } - let date = try_opt!(self.date.checked_add_signed(OldDuration::seconds(rhs))); + let date = try_opt!(self.date.checked_add_signed(TimeDelta::seconds(rhs))); Some(NaiveDateTime { date, time }) } @@ -790,7 +790,7 @@ impl NaiveDateTime { NaiveDateTime { date, time } } - /// Subtracts given `Duration` from the current date and time. + /// Subtracts given `TimeDelta` from the current date and time. /// /// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), /// the subtraction assumes that **there is no leap second ever**, @@ -804,65 +804,65 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); - /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::zero()), + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::zero()), /// Some(hms(3, 5, 7))); - /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(1)), + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::seconds(1)), /// Some(hms(3, 5, 6))); - /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(-1)), + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::seconds(-1)), /// Some(hms(3, 5, 8))); - /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(3600 + 60)), + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::seconds(3600 + 60)), /// Some(hms(2, 4, 7))); - /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(86_400)), + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::seconds(86_400)), /// Some(from_ymd(2016, 7, 7).and_hms_opt(3, 5, 7).unwrap())); /// /// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap(); - /// assert_eq!(hmsm(3, 5, 7, 450).checked_sub_signed(Duration::milliseconds(670)), + /// assert_eq!(hmsm(3, 5, 7, 450).checked_sub_signed(TimeDelta::milliseconds(670)), /// Some(hmsm(3, 5, 6, 780))); /// ``` /// /// Overflow returns `None`. /// /// ``` - /// # use chrono::{Duration, NaiveDate}; + /// # use chrono::{TimeDelta, NaiveDate}; /// # let hms = |h, m, s| NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(h, m, s).unwrap(); - /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::days(1_000_000_000)), None); + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::days(1_000_000_000)), None); /// ``` /// /// Leap seconds are handled, /// but the subtraction assumes that it is the only leap second happened. /// /// ``` - /// # use chrono::{Duration, NaiveDate}; + /// # use chrono::{TimeDelta, NaiveDate}; /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap(); /// let leap = hmsm(3, 5, 59, 1_300); - /// assert_eq!(leap.checked_sub_signed(Duration::zero()), + /// assert_eq!(leap.checked_sub_signed(TimeDelta::zero()), /// Some(hmsm(3, 5, 59, 1_300))); - /// assert_eq!(leap.checked_sub_signed(Duration::milliseconds(200)), + /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(200)), /// Some(hmsm(3, 5, 59, 1_100))); - /// assert_eq!(leap.checked_sub_signed(Duration::milliseconds(500)), + /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(500)), /// Some(hmsm(3, 5, 59, 800))); - /// assert_eq!(leap.checked_sub_signed(Duration::seconds(60)), + /// assert_eq!(leap.checked_sub_signed(TimeDelta::seconds(60)), /// Some(hmsm(3, 5, 0, 300))); - /// assert_eq!(leap.checked_sub_signed(Duration::days(1)), + /// assert_eq!(leap.checked_sub_signed(TimeDelta::days(1)), /// Some(from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap())); /// ``` #[must_use] - pub const fn checked_sub_signed(self, rhs: OldDuration) -> Option { + pub const fn checked_sub_signed(self, rhs: TimeDelta) -> Option { let (time, rhs) = self.time.overflowing_sub_signed(rhs); - // early checking to avoid overflow in OldDuration::seconds + // early checking to avoid overflow in TimeDelta::seconds if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) { return None; } - let date = try_opt!(self.date.checked_sub_signed(OldDuration::seconds(rhs))); + let date = try_opt!(self.date.checked_sub_signed(TimeDelta::seconds(rhs))); Some(NaiveDateTime { date, time }) } @@ -924,34 +924,34 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// assert_eq!(d.and_hms_opt(3, 5, 7).unwrap().signed_duration_since(d.and_hms_opt(2, 4, 6).unwrap()), - /// Duration::seconds(3600 + 60 + 1)); + /// TimeDelta::seconds(3600 + 60 + 1)); /// /// // July 8 is 190th day in the year 2016 /// let d0 = from_ymd(2016, 1, 1); /// assert_eq!(d.and_hms_milli_opt(0, 7, 6, 500).unwrap().signed_duration_since(d0.and_hms_opt(0, 0, 0).unwrap()), - /// Duration::seconds(189 * 86_400 + 7 * 60 + 6) + Duration::milliseconds(500)); + /// TimeDelta::seconds(189 * 86_400 + 7 * 60 + 6) + TimeDelta::milliseconds(500)); /// ``` /// /// Leap seconds are handled, but the subtraction assumes that /// there were no other leap seconds happened. /// /// ``` - /// # use chrono::{Duration, NaiveDate}; + /// # use chrono::{TimeDelta, NaiveDate}; /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// let leap = from_ymd(2015, 6, 30).and_hms_milli_opt(23, 59, 59, 1_500).unwrap(); /// assert_eq!(leap.signed_duration_since(from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap()), - /// Duration::seconds(3600) + Duration::milliseconds(500)); + /// TimeDelta::seconds(3600) + TimeDelta::milliseconds(500)); /// assert_eq!(from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap().signed_duration_since(leap), - /// Duration::seconds(3600) - Duration::milliseconds(500)); + /// TimeDelta::seconds(3600) - TimeDelta::milliseconds(500)); /// ``` #[must_use] - pub const fn signed_duration_since(self, rhs: NaiveDateTime) -> OldDuration { + pub const fn signed_duration_since(self, rhs: NaiveDateTime) -> TimeDelta { expect!( self.date .signed_duration_since(rhs.date) @@ -1606,7 +1606,7 @@ impl Timelike for NaiveDateTime { } } -/// Add `chrono::Duration` to `NaiveDateTime`. +/// Add `TimeDelta` to `NaiveDateTime`. /// /// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap /// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case @@ -1620,50 +1620,50 @@ impl Timelike for NaiveDateTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); -/// assert_eq!(hms(3, 5, 7) + Duration::zero(), hms(3, 5, 7)); -/// assert_eq!(hms(3, 5, 7) + Duration::seconds(1), hms(3, 5, 8)); -/// assert_eq!(hms(3, 5, 7) + Duration::seconds(-1), hms(3, 5, 6)); -/// assert_eq!(hms(3, 5, 7) + Duration::seconds(3600 + 60), hms(4, 6, 7)); -/// assert_eq!(hms(3, 5, 7) + Duration::seconds(86_400), +/// assert_eq!(hms(3, 5, 7) + TimeDelta::zero(), hms(3, 5, 7)); +/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(1), hms(3, 5, 8)); +/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(-1), hms(3, 5, 6)); +/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(3600 + 60), hms(4, 6, 7)); +/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(86_400), /// from_ymd(2016, 7, 9).and_hms_opt(3, 5, 7).unwrap()); -/// assert_eq!(hms(3, 5, 7) + Duration::days(365), +/// assert_eq!(hms(3, 5, 7) + TimeDelta::days(365), /// from_ymd(2017, 7, 8).and_hms_opt(3, 5, 7).unwrap()); /// /// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap(); -/// assert_eq!(hmsm(3, 5, 7, 980) + Duration::milliseconds(450), hmsm(3, 5, 8, 430)); +/// assert_eq!(hmsm(3, 5, 7, 980) + TimeDelta::milliseconds(450), hmsm(3, 5, 8, 430)); /// ``` /// /// Leap seconds are handled, /// but the addition assumes that it is the only leap second happened. /// /// ``` -/// # use chrono::{Duration, NaiveDate}; +/// # use chrono::{TimeDelta, NaiveDate}; /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap(); /// let leap = hmsm(3, 5, 59, 1_300); -/// assert_eq!(leap + Duration::zero(), hmsm(3, 5, 59, 1_300)); -/// assert_eq!(leap + Duration::milliseconds(-500), hmsm(3, 5, 59, 800)); -/// assert_eq!(leap + Duration::milliseconds(500), hmsm(3, 5, 59, 1_800)); -/// assert_eq!(leap + Duration::milliseconds(800), hmsm(3, 6, 0, 100)); -/// assert_eq!(leap + Duration::seconds(10), hmsm(3, 6, 9, 300)); -/// assert_eq!(leap + Duration::seconds(-10), hmsm(3, 5, 50, 300)); -/// assert_eq!(leap + Duration::days(1), +/// assert_eq!(leap + TimeDelta::zero(), hmsm(3, 5, 59, 1_300)); +/// assert_eq!(leap + TimeDelta::milliseconds(-500), hmsm(3, 5, 59, 800)); +/// assert_eq!(leap + TimeDelta::milliseconds(500), hmsm(3, 5, 59, 1_800)); +/// assert_eq!(leap + TimeDelta::milliseconds(800), hmsm(3, 6, 0, 100)); +/// assert_eq!(leap + TimeDelta::seconds(10), hmsm(3, 6, 9, 300)); +/// assert_eq!(leap + TimeDelta::seconds(-10), hmsm(3, 5, 50, 300)); +/// assert_eq!(leap + TimeDelta::days(1), /// from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap()); /// ``` /// /// [leap second handling]: crate::NaiveTime#leap-second-handling -impl Add for NaiveDateTime { +impl Add for NaiveDateTime { type Output = NaiveDateTime; #[inline] - fn add(self, rhs: OldDuration) -> NaiveDateTime { - self.checked_add_signed(rhs).expect("`NaiveDateTime + Duration` overflowed") + fn add(self, rhs: TimeDelta) -> NaiveDateTime { + self.checked_add_signed(rhs).expect("`NaiveDateTime + TimeDelta` overflowed") } } @@ -1682,13 +1682,13 @@ impl Add for NaiveDateTime { #[inline] fn add(self, rhs: Duration) -> NaiveDateTime { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); - self.checked_add_signed(rhs).expect("`NaiveDateTime + Duration` overflowed") + let rhs = TimeDelta::from_std(rhs) + .expect("overflow converting from core::time::Duration to TimeDelta"); + self.checked_add_signed(rhs).expect("`NaiveDateTime + TimeDelta` overflowed") } } -/// Add-assign `chrono::Duration` to `NaiveDateTime`. +/// Add-assign `TimeDelta` to `NaiveDateTime`. /// /// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap /// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case @@ -1698,9 +1698,9 @@ impl Add for NaiveDateTime { /// /// Panics if the resulting date would be out of range. /// Consider using [`NaiveDateTime::checked_add_signed`] to get an `Option` instead. -impl AddAssign for NaiveDateTime { +impl AddAssign for NaiveDateTime { #[inline] - fn add_assign(&mut self, rhs: OldDuration) { + fn add_assign(&mut self, rhs: TimeDelta) { *self = self.add(rhs); } } @@ -1785,9 +1785,9 @@ impl Add for NaiveDateTime { } } -/// Subtract `chrono::Duration` from `NaiveDateTime`. +/// Subtract `TimeDelta` from `NaiveDateTime`. /// -/// This is the same as the addition with a negated `Duration`. +/// This is the same as the addition with a negated `TimeDelta`. /// /// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap /// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case @@ -1801,48 +1801,48 @@ impl Add for NaiveDateTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); -/// assert_eq!(hms(3, 5, 7) - Duration::zero(), hms(3, 5, 7)); -/// assert_eq!(hms(3, 5, 7) - Duration::seconds(1), hms(3, 5, 6)); -/// assert_eq!(hms(3, 5, 7) - Duration::seconds(-1), hms(3, 5, 8)); -/// assert_eq!(hms(3, 5, 7) - Duration::seconds(3600 + 60), hms(2, 4, 7)); -/// assert_eq!(hms(3, 5, 7) - Duration::seconds(86_400), +/// assert_eq!(hms(3, 5, 7) - TimeDelta::zero(), hms(3, 5, 7)); +/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(1), hms(3, 5, 6)); +/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(-1), hms(3, 5, 8)); +/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(3600 + 60), hms(2, 4, 7)); +/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(86_400), /// from_ymd(2016, 7, 7).and_hms_opt(3, 5, 7).unwrap()); -/// assert_eq!(hms(3, 5, 7) - Duration::days(365), +/// assert_eq!(hms(3, 5, 7) - TimeDelta::days(365), /// from_ymd(2015, 7, 9).and_hms_opt(3, 5, 7).unwrap()); /// /// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap(); -/// assert_eq!(hmsm(3, 5, 7, 450) - Duration::milliseconds(670), hmsm(3, 5, 6, 780)); +/// assert_eq!(hmsm(3, 5, 7, 450) - TimeDelta::milliseconds(670), hmsm(3, 5, 6, 780)); /// ``` /// /// Leap seconds are handled, /// but the subtraction assumes that it is the only leap second happened. /// /// ``` -/// # use chrono::{Duration, NaiveDate}; +/// # use chrono::{TimeDelta, NaiveDate}; /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap(); /// let leap = hmsm(3, 5, 59, 1_300); -/// assert_eq!(leap - Duration::zero(), hmsm(3, 5, 59, 1_300)); -/// assert_eq!(leap - Duration::milliseconds(200), hmsm(3, 5, 59, 1_100)); -/// assert_eq!(leap - Duration::milliseconds(500), hmsm(3, 5, 59, 800)); -/// assert_eq!(leap - Duration::seconds(60), hmsm(3, 5, 0, 300)); -/// assert_eq!(leap - Duration::days(1), +/// assert_eq!(leap - TimeDelta::zero(), hmsm(3, 5, 59, 1_300)); +/// assert_eq!(leap - TimeDelta::milliseconds(200), hmsm(3, 5, 59, 1_100)); +/// assert_eq!(leap - TimeDelta::milliseconds(500), hmsm(3, 5, 59, 800)); +/// assert_eq!(leap - TimeDelta::seconds(60), hmsm(3, 5, 0, 300)); +/// assert_eq!(leap - TimeDelta::days(1), /// from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap()); /// ``` /// /// [leap second handling]: crate::NaiveTime#leap-second-handling -impl Sub for NaiveDateTime { +impl Sub for NaiveDateTime { type Output = NaiveDateTime; #[inline] - fn sub(self, rhs: OldDuration) -> NaiveDateTime { - self.checked_sub_signed(rhs).expect("`NaiveDateTime - Duration` overflowed") + fn sub(self, rhs: TimeDelta) -> NaiveDateTime { + self.checked_sub_signed(rhs).expect("`NaiveDateTime - TimeDelta` overflowed") } } @@ -1861,15 +1861,15 @@ impl Sub for NaiveDateTime { #[inline] fn sub(self, rhs: Duration) -> NaiveDateTime { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); - self.checked_sub_signed(rhs).expect("`NaiveDateTime - Duration` overflowed") + let rhs = TimeDelta::from_std(rhs) + .expect("overflow converting from core::time::Duration to TimeDelta"); + self.checked_sub_signed(rhs).expect("`NaiveDateTime - TimeDelta` overflowed") } } -/// Subtract-assign `chrono::Duration` from `NaiveDateTime`. +/// Subtract-assign `TimeDelta` from `NaiveDateTime`. /// -/// This is the same as the addition with a negated `Duration`. +/// This is the same as the addition with a negated `TimeDelta`. /// /// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap /// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case @@ -1879,9 +1879,9 @@ impl Sub for NaiveDateTime { /// /// Panics if the resulting date would be out of range. /// Consider using [`NaiveDateTime::checked_sub_signed`] to get an `Option` instead. -impl SubAssign for NaiveDateTime { +impl SubAssign for NaiveDateTime { #[inline] - fn sub_assign(&mut self, rhs: OldDuration) { + fn sub_assign(&mut self, rhs: TimeDelta) { *self = self.sub(rhs); } } @@ -1968,36 +1968,36 @@ impl Sub for NaiveDateTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); -/// assert_eq!(d.and_hms_opt(3, 5, 7).unwrap() - d.and_hms_opt(2, 4, 6).unwrap(), Duration::seconds(3600 + 60 + 1)); +/// assert_eq!(d.and_hms_opt(3, 5, 7).unwrap() - d.and_hms_opt(2, 4, 6).unwrap(), TimeDelta::seconds(3600 + 60 + 1)); /// /// // July 8 is 190th day in the year 2016 /// let d0 = from_ymd(2016, 1, 1); /// assert_eq!(d.and_hms_milli_opt(0, 7, 6, 500).unwrap() - d0.and_hms_opt(0, 0, 0).unwrap(), -/// Duration::seconds(189 * 86_400 + 7 * 60 + 6) + Duration::milliseconds(500)); +/// TimeDelta::seconds(189 * 86_400 + 7 * 60 + 6) + TimeDelta::milliseconds(500)); /// ``` /// /// Leap seconds are handled, but the subtraction assumes that no other leap /// seconds happened. /// /// ``` -/// # use chrono::{Duration, NaiveDate}; +/// # use chrono::{TimeDelta, NaiveDate}; /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// let leap = from_ymd(2015, 6, 30).and_hms_milli_opt(23, 59, 59, 1_500).unwrap(); /// assert_eq!(leap - from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap(), -/// Duration::seconds(3600) + Duration::milliseconds(500)); +/// TimeDelta::seconds(3600) + TimeDelta::milliseconds(500)); /// assert_eq!(from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap() - leap, -/// Duration::seconds(3600) - Duration::milliseconds(500)); +/// TimeDelta::seconds(3600) - TimeDelta::milliseconds(500)); /// ``` impl Sub for NaiveDateTime { - type Output = OldDuration; + type Output = TimeDelta; #[inline] - fn sub(self, rhs: NaiveDateTime) -> OldDuration { + fn sub(self, rhs: NaiveDateTime) -> TimeDelta { self.signed_duration_since(rhs) } } diff --git a/src/naive/datetime/tests.rs b/src/naive/datetime/tests.rs index 6375a9d351..4d36208c39 100644 --- a/src/naive/datetime/tests.rs +++ b/src/naive/datetime/tests.rs @@ -1,6 +1,5 @@ use super::NaiveDateTime; -use crate::duration::Duration as OldDuration; -use crate::{Datelike, FixedOffset, LocalResult, NaiveDate, Utc}; +use crate::{Datelike, FixedOffset, LocalResult, NaiveDate, TimeDelta, Utc}; #[test] fn test_datetime_from_timestamp_millis() { @@ -147,7 +146,7 @@ fn test_datetime_from_timestamp() { fn test_datetime_add() { fn check( (y, m, d, h, n, s): (i32, u32, u32, u32, u32, u32), - rhs: OldDuration, + rhs: TimeDelta, result: Option<(i32, u32, u32, u32, u32, u32)>, ) { let lhs = NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); @@ -158,16 +157,12 @@ fn test_datetime_add() { assert_eq!(lhs.checked_sub_signed(-rhs), sum); } - check((2014, 5, 6, 7, 8, 9), OldDuration::seconds(3600 + 60 + 1), Some((2014, 5, 6, 8, 9, 10))); - check( - (2014, 5, 6, 7, 8, 9), - OldDuration::seconds(-(3600 + 60 + 1)), - Some((2014, 5, 6, 6, 7, 8)), - ); - check((2014, 5, 6, 7, 8, 9), OldDuration::seconds(86399), Some((2014, 5, 7, 7, 8, 8))); - check((2014, 5, 6, 7, 8, 9), OldDuration::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9))); - check((2014, 5, 6, 7, 8, 9), OldDuration::seconds(-86_400 * 10), Some((2014, 4, 26, 7, 8, 9))); - check((2014, 5, 6, 7, 8, 9), OldDuration::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9))); + check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(3600 + 60 + 1), Some((2014, 5, 6, 8, 9, 10))); + check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(-(3600 + 60 + 1)), Some((2014, 5, 6, 6, 7, 8))); + check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(86399), Some((2014, 5, 7, 7, 8, 8))); + check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9))); + check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(-86_400 * 10), Some((2014, 4, 26, 7, 8, 9))); + check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9))); // overflow check // assumes that we have correct values for MAX/MIN_DAYS_FROM_YEAR_0 from `naive::date`. @@ -177,17 +172,17 @@ fn test_datetime_add() { check((0, 1, 1, 0, 0, 0), max_days_from_year_0, Some((NaiveDate::MAX.year(), 12, 31, 0, 0, 0))); check( (0, 1, 1, 0, 0, 0), - max_days_from_year_0 + OldDuration::seconds(86399), + max_days_from_year_0 + TimeDelta::seconds(86399), Some((NaiveDate::MAX.year(), 12, 31, 23, 59, 59)), ); - check((0, 1, 1, 0, 0, 0), max_days_from_year_0 + OldDuration::seconds(86_400), None); - check((0, 1, 1, 0, 0, 0), OldDuration::max_value(), None); + check((0, 1, 1, 0, 0, 0), max_days_from_year_0 + TimeDelta::seconds(86_400), None); + check((0, 1, 1, 0, 0, 0), TimeDelta::max_value(), None); let min_days_from_year_0 = NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd_opt(0, 1, 1).unwrap()); check((0, 1, 1, 0, 0, 0), min_days_from_year_0, Some((NaiveDate::MIN.year(), 1, 1, 0, 0, 0))); - check((0, 1, 1, 0, 0, 0), min_days_from_year_0 - OldDuration::seconds(1), None); - check((0, 1, 1, 0, 0, 0), OldDuration::min_value(), None); + check((0, 1, 1, 0, 0, 0), min_days_from_year_0 - TimeDelta::seconds(1), None); + check((0, 1, 1, 0, 0, 0), TimeDelta::min_value(), None); } #[test] @@ -195,25 +190,22 @@ fn test_datetime_sub() { let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); let since = NaiveDateTime::signed_duration_since; - assert_eq!( - since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 9)), - OldDuration::zero() - ); + assert_eq!(since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 9)), TimeDelta::zero()); assert_eq!( since(ymdhms(2014, 5, 6, 7, 8, 10), ymdhms(2014, 5, 6, 7, 8, 9)), - OldDuration::seconds(1) + TimeDelta::seconds(1) ); assert_eq!( since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)), - OldDuration::seconds(-1) + TimeDelta::seconds(-1) ); assert_eq!( since(ymdhms(2014, 5, 7, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)), - OldDuration::seconds(86399) + TimeDelta::seconds(86399) ); assert_eq!( since(ymdhms(2001, 9, 9, 1, 46, 39), ymdhms(1970, 1, 1, 0, 0, 0)), - OldDuration::seconds(999_999_999) + TimeDelta::seconds(999_999_999) ); } @@ -222,9 +214,9 @@ fn test_datetime_addassignment() { let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); let mut date = ymdhms(2016, 10, 1, 10, 10, 10); - date += OldDuration::minutes(10_000_000); + date += TimeDelta::minutes(10_000_000); assert_eq!(date, ymdhms(2035, 10, 6, 20, 50, 10)); - date += OldDuration::days(10); + date += TimeDelta::days(10); assert_eq!(date, ymdhms(2035, 10, 16, 20, 50, 10)); } @@ -233,9 +225,9 @@ fn test_datetime_subassignment() { let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); let mut date = ymdhms(2016, 10, 1, 10, 10, 10); - date -= OldDuration::minutes(10_000_000); + date -= TimeDelta::minutes(10_000_000); assert_eq!(date, ymdhms(1997, 9, 26, 23, 30, 10)); - date -= OldDuration::days(10); + date -= TimeDelta::days(10); assert_eq!(date, ymdhms(1997, 9, 16, 23, 30, 10)); } @@ -427,7 +419,7 @@ fn test_datetime_add_sub_invariant() { // issue #37 let base = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); let t = -946684799990000; - let time = base + OldDuration::microseconds(t); + let time = base + TimeDelta::microseconds(t); assert_eq!(t, time.signed_duration_since(base).num_microseconds().unwrap()); } @@ -453,13 +445,13 @@ fn test_nanosecond_range() { // Just beyond range let maximum = "2262-04-11T23:47:16.854775804"; let parsed: NaiveDateTime = maximum.parse().unwrap(); - let beyond_max = parsed + OldDuration::milliseconds(300); + let beyond_max = parsed + TimeDelta::milliseconds(300); assert!(beyond_max.timestamp_nanos_opt().is_none()); // Far beyond range let maximum = "2262-04-11T23:47:16.854775804"; let parsed: NaiveDateTime = maximum.parse().unwrap(); - let beyond_max = parsed + OldDuration::days(365); + let beyond_max = parsed + TimeDelta::days(365); assert!(beyond_max.timestamp_nanos_opt().is_none()); } diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index b47639ce0d..0bdb76522c 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -12,7 +12,6 @@ use core::{fmt, str}; #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))] use rkyv::{Archive, Deserialize, Serialize}; -use crate::duration::Duration as OldDuration; #[cfg(feature = "alloc")] use crate::format::DelayedFormat; use crate::format::{ @@ -20,7 +19,7 @@ use crate::format::{ Parsed, StrftimeItems, }; use crate::{expect, try_opt}; -use crate::{FixedOffset, Timelike}; +use crate::{FixedOffset, TimeDelta, Timelike}; #[cfg(feature = "rustc-serialize")] mod rustc_serialize; @@ -98,7 +97,7 @@ mod tests; /// In reality, of course, leap seconds are separated by at least 6 months. /// We will also use some intuitive concise notations for the explanation. /// -/// `Time + Duration` +/// `Time + TimeDelta` /// (short for [`NaiveTime::overflowing_add_signed`](#method.overflowing_add_signed)): /// /// - `03:00:00 + 1s = 03:00:01`. @@ -111,7 +110,7 @@ mod tests; /// - `03:00:60 + 61s = 03:02:00`. /// - `03:00:60.1 + 0.8s = 03:00:60.9`. /// -/// `Time - Duration` +/// `Time - TimeDelta` /// (short for [`NaiveTime::overflowing_sub_signed`](#method.overflowing_sub_signed)): /// /// - `03:00:00 - 1s = 02:59:59`. @@ -140,21 +139,21 @@ mod tests; /// /// In general, /// -/// - `Time + Duration` unconditionally equals to `Duration + Time`. +/// - `Time + TimeDelta` unconditionally equals to `TimeDelta + Time`. /// -/// - `Time - Duration` unconditionally equals to `Time + (-Duration)`. +/// - `Time - TimeDelta` unconditionally equals to `Time + (-TimeDelta)`. /// /// - `Time1 - Time2` unconditionally equals to `-(Time2 - Time1)`. /// /// - Associativity does not generally hold, because -/// `(Time + Duration1) - Duration2` no longer equals to `Time + (Duration1 - Duration2)` +/// `(Time + TimeDelta1) - TimeDelta2` no longer equals to `Time + (TimeDelta1 - TimeDelta2)` /// for two positive durations. /// -/// - As a special case, `(Time + Duration) - Duration` also does not equal to `Time`. +/// - As a special case, `(Time + TimeDelta) - TimeDelta` also does not equal to `Time`. /// /// - If you can assume that all durations have the same sign, however, /// then the associativity holds: -/// `(Time + Duration1) + Duration2` equals to `Time + (Duration1 + Duration2)` +/// `(Time + TimeDelta1) + TimeDelta2` equals to `Time + (TimeDelta1 + TimeDelta2)` /// for two positive durations. /// /// ## Reading And Writing Leap Seconds @@ -564,25 +563,25 @@ impl NaiveTime { parsed.to_naive_time().map(|t| (t, remainder)) } - /// Adds given `Duration` to the current time, and also returns the number of *seconds* + /// Adds given `TimeDelta` to the current time, and also returns the number of *seconds* /// in the integral number of days ignored from the addition. /// /// # Example /// /// ``` - /// use chrono::{Duration, NaiveTime}; + /// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hms = |h, m, s| { NaiveTime::from_hms_opt(h, m, s).unwrap() }; /// - /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(Duration::hours(11)), + /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::hours(11)), /// (from_hms(14, 4, 5), 0)); - /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(Duration::hours(23)), + /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::hours(23)), /// (from_hms(2, 4, 5), 86_400)); - /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(Duration::hours(-7)), + /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::hours(-7)), /// (from_hms(20, 4, 5), -86_400)); /// ``` #[must_use] - pub const fn overflowing_add_signed(&self, rhs: OldDuration) -> (NaiveTime, i64) { + pub const fn overflowing_add_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) { let mut secs = self.secs as i64; let mut frac = self.frac as i32; let secs_to_add = rhs.num_seconds(); @@ -620,32 +619,32 @@ impl NaiveTime { (NaiveTime { secs: secs_in_day as u32, frac: frac as u32 }, remaining) } - /// Subtracts given `Duration` from the current time, and also returns the number of *seconds* + /// Subtracts given `TimeDelta` from the current time, and also returns the number of *seconds* /// in the integral number of days ignored from the subtraction. /// /// # Example /// /// ``` - /// use chrono::{Duration, NaiveTime}; + /// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hms = |h, m, s| { NaiveTime::from_hms_opt(h, m, s).unwrap() }; /// - /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(Duration::hours(2)), + /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::hours(2)), /// (from_hms(1, 4, 5), 0)); - /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(Duration::hours(17)), + /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::hours(17)), /// (from_hms(10, 4, 5), 86_400)); - /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(Duration::hours(-22)), + /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::hours(-22)), /// (from_hms(1, 4, 5), -86_400)); /// ``` #[inline] #[must_use] - pub const fn overflowing_sub_signed(&self, rhs: OldDuration) -> (NaiveTime, i64) { + pub const fn overflowing_sub_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) { let (time, rhs) = self.overflowing_add_signed(rhs.neg()); (time, -rhs) // safe to negate, rhs is within +/- (2^63 / 1000) } /// Subtracts another `NaiveTime` from the current time. - /// Returns a `Duration` within +/- 1 day. + /// Returns a `TimeDelta` within +/- 1 day. /// This does not overflow or underflow at all. /// /// As a part of Chrono's [leap second handling](#leap-second-handling), @@ -657,49 +656,49 @@ impl NaiveTime { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveTime}; + /// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// let since = NaiveTime::signed_duration_since; /// /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 900)), - /// Duration::zero()); + /// TimeDelta::zero()); /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 875)), - /// Duration::milliseconds(25)); + /// TimeDelta::milliseconds(25)); /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 6, 925)), - /// Duration::milliseconds(975)); + /// TimeDelta::milliseconds(975)); /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 0, 900)), - /// Duration::seconds(7)); + /// TimeDelta::seconds(7)); /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 0, 7, 900)), - /// Duration::seconds(5 * 60)); + /// TimeDelta::seconds(5 * 60)); /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(0, 5, 7, 900)), - /// Duration::seconds(3 * 3600)); + /// TimeDelta::seconds(3 * 3600)); /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(4, 5, 7, 900)), - /// Duration::seconds(-3600)); + /// TimeDelta::seconds(-3600)); /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(2, 4, 6, 800)), - /// Duration::seconds(3600 + 60 + 1) + Duration::milliseconds(100)); + /// TimeDelta::seconds(3600 + 60 + 1) + TimeDelta::milliseconds(100)); /// ``` /// /// Leap seconds are handled, but the subtraction assumes that /// there were no other leap seconds happened. /// /// ``` - /// # use chrono::{Duration, NaiveTime}; + /// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// # let since = NaiveTime::signed_duration_since; /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(3, 0, 59, 0)), - /// Duration::seconds(1)); + /// TimeDelta::seconds(1)); /// assert_eq!(since(from_hmsm(3, 0, 59, 1_500), from_hmsm(3, 0, 59, 0)), - /// Duration::milliseconds(1500)); + /// TimeDelta::milliseconds(1500)); /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(3, 0, 0, 0)), - /// Duration::seconds(60)); + /// TimeDelta::seconds(60)); /// assert_eq!(since(from_hmsm(3, 0, 0, 0), from_hmsm(2, 59, 59, 1_000)), - /// Duration::seconds(1)); + /// TimeDelta::seconds(1)); /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(2, 59, 59, 1_000)), - /// Duration::seconds(61)); + /// TimeDelta::seconds(61)); /// ``` #[must_use] - pub const fn signed_duration_since(self, rhs: NaiveTime) -> OldDuration { + pub const fn signed_duration_since(self, rhs: NaiveTime) -> TimeDelta { // | | :leap| | | | | | | :leap| | // | | : | | | | | | | : | | // ----+----+-----*---+----+----+----+----+----+----+-------*-+----+---- @@ -723,7 +722,7 @@ impl NaiveTime { let secs_from_frac = frac.div_euclid(1_000_000_000); let frac = frac.rem_euclid(1_000_000_000) as u32; - expect!(OldDuration::new(secs + secs_from_frac, frac), "must be in range") + expect!(TimeDelta::new(secs + secs_from_frac, frac), "must be in range") } /// Adds given `FixedOffset` to the current time, and returns the number of days that should be @@ -1081,7 +1080,7 @@ impl Timelike for NaiveTime { } } -/// Add `chrono::Duration` to `NaiveTime`. +/// Add `TimeDelta` to `NaiveTime`. /// /// This wraps around and never overflows or underflows. /// In particular the addition ignores integral number of days. @@ -1093,62 +1092,62 @@ impl Timelike for NaiveTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveTime}; +/// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// -/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::zero(), from_hmsm(3, 5, 7, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(1), from_hmsm(3, 5, 8, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(-1), from_hmsm(3, 5, 6, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(60 + 4), from_hmsm(3, 6, 11, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(7*60*60 - 6*60), from_hmsm(9, 59, 7, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::milliseconds(80), from_hmsm(3, 5, 7, 80)); -/// assert_eq!(from_hmsm(3, 5, 7, 950) + Duration::milliseconds(280), from_hmsm(3, 5, 8, 230)); -/// assert_eq!(from_hmsm(3, 5, 7, 950) + Duration::milliseconds(-980), from_hmsm(3, 5, 6, 970)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::zero(), from_hmsm(3, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(1), from_hmsm(3, 5, 8, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(-1), from_hmsm(3, 5, 6, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(60 + 4), from_hmsm(3, 6, 11, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(7*60*60 - 6*60), from_hmsm(9, 59, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::milliseconds(80), from_hmsm(3, 5, 7, 80)); +/// assert_eq!(from_hmsm(3, 5, 7, 950) + TimeDelta::milliseconds(280), from_hmsm(3, 5, 8, 230)); +/// assert_eq!(from_hmsm(3, 5, 7, 950) + TimeDelta::milliseconds(-980), from_hmsm(3, 5, 6, 970)); /// ``` /// /// The addition wraps around. /// /// ``` -/// # use chrono::{Duration, NaiveTime}; +/// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; -/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(22*60*60), from_hmsm(1, 5, 7, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(-8*60*60), from_hmsm(19, 5, 7, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::days(800), from_hmsm(3, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(22*60*60), from_hmsm(1, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(-8*60*60), from_hmsm(19, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::days(800), from_hmsm(3, 5, 7, 0)); /// ``` /// /// Leap seconds are handled, but the addition assumes that it is the only leap second happened. /// /// ``` -/// # use chrono::{Duration, NaiveTime}; +/// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// let leap = from_hmsm(3, 5, 59, 1_300); -/// assert_eq!(leap + Duration::zero(), from_hmsm(3, 5, 59, 1_300)); -/// assert_eq!(leap + Duration::milliseconds(-500), from_hmsm(3, 5, 59, 800)); -/// assert_eq!(leap + Duration::milliseconds(500), from_hmsm(3, 5, 59, 1_800)); -/// assert_eq!(leap + Duration::milliseconds(800), from_hmsm(3, 6, 0, 100)); -/// assert_eq!(leap + Duration::seconds(10), from_hmsm(3, 6, 9, 300)); -/// assert_eq!(leap + Duration::seconds(-10), from_hmsm(3, 5, 50, 300)); -/// assert_eq!(leap + Duration::days(1), from_hmsm(3, 5, 59, 300)); +/// assert_eq!(leap + TimeDelta::zero(), from_hmsm(3, 5, 59, 1_300)); +/// assert_eq!(leap + TimeDelta::milliseconds(-500), from_hmsm(3, 5, 59, 800)); +/// assert_eq!(leap + TimeDelta::milliseconds(500), from_hmsm(3, 5, 59, 1_800)); +/// assert_eq!(leap + TimeDelta::milliseconds(800), from_hmsm(3, 6, 0, 100)); +/// assert_eq!(leap + TimeDelta::seconds(10), from_hmsm(3, 6, 9, 300)); +/// assert_eq!(leap + TimeDelta::seconds(-10), from_hmsm(3, 5, 50, 300)); +/// assert_eq!(leap + TimeDelta::days(1), from_hmsm(3, 5, 59, 300)); /// ``` /// /// [leap second handling]: crate::NaiveTime#leap-second-handling -impl Add for NaiveTime { +impl Add for NaiveTime { type Output = NaiveTime; #[inline] - fn add(self, rhs: OldDuration) -> NaiveTime { + fn add(self, rhs: TimeDelta) -> NaiveTime { self.overflowing_add_signed(rhs).0 } } -/// Add-assign `chrono::Duration` to `NaiveTime`. +/// Add-assign `TimeDelta` to `NaiveTime`. /// /// This wraps around and never overflows or underflows. /// In particular the addition ignores integral number of days. -impl AddAssign for NaiveTime { +impl AddAssign for NaiveTime { #[inline] - fn add_assign(&mut self, rhs: OldDuration) { + fn add_assign(&mut self, rhs: TimeDelta) { *self = self.add(rhs); } } @@ -1163,10 +1162,10 @@ impl Add for NaiveTime { #[inline] fn add(self, rhs: Duration) -> NaiveTime { // We don't care about values beyond `24 * 60 * 60`, so we can take a modulus and avoid - // overflow during the conversion to `chrono::Duration`. + // overflow during the conversion to `TimeDelta`. // But we limit to double that just in case `self` is a leap-second. let secs = rhs.as_secs() % (2 * 24 * 60 * 60); - let d = OldDuration::new(secs as i64, rhs.subsec_nanos()).unwrap(); + let d = TimeDelta::new(secs as i64, rhs.subsec_nanos()).unwrap(); self.overflowing_add_signed(d).0 } } @@ -1195,11 +1194,11 @@ impl Add for NaiveTime { } } -/// Subtract `chrono::Duration` from `NaiveTime`. +/// Subtract `TimeDelta` from `NaiveTime`. /// /// This wraps around and never overflows or underflows. /// In particular the subtraction ignores integral number of days. -/// This is the same as addition with a negated `Duration`. +/// This is the same as addition with a negated `TimeDelta`. /// /// As a part of Chrono's [leap second handling], the subtraction assumes that **there is no leap /// second ever**, except when the `NaiveTime` itself represents a leap second in which case the @@ -1208,57 +1207,57 @@ impl Add for NaiveTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveTime}; +/// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// -/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::zero(), from_hmsm(3, 5, 7, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(1), from_hmsm(3, 5, 6, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(60 + 5), from_hmsm(3, 4, 2, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(2*60*60 + 6*60), from_hmsm(0, 59, 7, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::milliseconds(80), from_hmsm(3, 5, 6, 920)); -/// assert_eq!(from_hmsm(3, 5, 7, 950) - Duration::milliseconds(280), from_hmsm(3, 5, 7, 670)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::zero(), from_hmsm(3, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::seconds(1), from_hmsm(3, 5, 6, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::seconds(60 + 5), from_hmsm(3, 4, 2, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::seconds(2*60*60 + 6*60), from_hmsm(0, 59, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::milliseconds(80), from_hmsm(3, 5, 6, 920)); +/// assert_eq!(from_hmsm(3, 5, 7, 950) - TimeDelta::milliseconds(280), from_hmsm(3, 5, 7, 670)); /// ``` /// /// The subtraction wraps around. /// /// ``` -/// # use chrono::{Duration, NaiveTime}; +/// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; -/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(8*60*60), from_hmsm(19, 5, 7, 0)); -/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::days(800), from_hmsm(3, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::seconds(8*60*60), from_hmsm(19, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::days(800), from_hmsm(3, 5, 7, 0)); /// ``` /// /// Leap seconds are handled, but the subtraction assumes that it is the only leap second happened. /// /// ``` -/// # use chrono::{Duration, NaiveTime}; +/// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// let leap = from_hmsm(3, 5, 59, 1_300); -/// assert_eq!(leap - Duration::zero(), from_hmsm(3, 5, 59, 1_300)); -/// assert_eq!(leap - Duration::milliseconds(200), from_hmsm(3, 5, 59, 1_100)); -/// assert_eq!(leap - Duration::milliseconds(500), from_hmsm(3, 5, 59, 800)); -/// assert_eq!(leap - Duration::seconds(60), from_hmsm(3, 5, 0, 300)); -/// assert_eq!(leap - Duration::days(1), from_hmsm(3, 6, 0, 300)); +/// assert_eq!(leap - TimeDelta::zero(), from_hmsm(3, 5, 59, 1_300)); +/// assert_eq!(leap - TimeDelta::milliseconds(200), from_hmsm(3, 5, 59, 1_100)); +/// assert_eq!(leap - TimeDelta::milliseconds(500), from_hmsm(3, 5, 59, 800)); +/// assert_eq!(leap - TimeDelta::seconds(60), from_hmsm(3, 5, 0, 300)); +/// assert_eq!(leap - TimeDelta::days(1), from_hmsm(3, 6, 0, 300)); /// ``` /// /// [leap second handling]: crate::NaiveTime#leap-second-handling -impl Sub for NaiveTime { +impl Sub for NaiveTime { type Output = NaiveTime; #[inline] - fn sub(self, rhs: OldDuration) -> NaiveTime { + fn sub(self, rhs: TimeDelta) -> NaiveTime { self.overflowing_sub_signed(rhs).0 } } -/// Subtract-assign `chrono::Duration` from `NaiveTime`. +/// Subtract-assign `TimeDelta` from `NaiveTime`. /// /// This wraps around and never overflows or underflows. /// In particular the subtraction ignores integral number of days. -impl SubAssign for NaiveTime { +impl SubAssign for NaiveTime { #[inline] - fn sub_assign(&mut self, rhs: OldDuration) { + fn sub_assign(&mut self, rhs: TimeDelta) { *self = self.sub(rhs); } } @@ -1273,10 +1272,10 @@ impl Sub for NaiveTime { #[inline] fn sub(self, rhs: Duration) -> NaiveTime { // We don't care about values beyond `24 * 60 * 60`, so we can take a modulus and avoid - // overflow during the conversion to `chrono::Duration`. + // overflow during the conversion to `TimeDelta`. // But we limit to double that just in case `self` is a leap-second. let secs = rhs.as_secs() % (2 * 24 * 60 * 60); - let d = OldDuration::new(secs as i64, rhs.subsec_nanos()).unwrap(); + let d = TimeDelta::new(secs as i64, rhs.subsec_nanos()).unwrap(); self.overflowing_sub_signed(d).0 } } @@ -1306,7 +1305,7 @@ impl Sub for NaiveTime { } /// Subtracts another `NaiveTime` from the current time. -/// Returns a `Duration` within +/- 1 day. +/// Returns a `TimeDelta` within +/- 1 day. /// This does not overflow or underflow at all. /// /// As a part of Chrono's [leap second handling](#leap-second-handling), @@ -1321,40 +1320,40 @@ impl Sub for NaiveTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveTime}; +/// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// -/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 900), Duration::zero()); -/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 875), Duration::milliseconds(25)); -/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 6, 925), Duration::milliseconds(975)); -/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 0, 900), Duration::seconds(7)); -/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 0, 7, 900), Duration::seconds(5 * 60)); -/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(0, 5, 7, 900), Duration::seconds(3 * 3600)); -/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(4, 5, 7, 900), Duration::seconds(-3600)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 900), TimeDelta::zero()); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 875), TimeDelta::milliseconds(25)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 6, 925), TimeDelta::milliseconds(975)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 0, 900), TimeDelta::seconds(7)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 0, 7, 900), TimeDelta::seconds(5 * 60)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(0, 5, 7, 900), TimeDelta::seconds(3 * 3600)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(4, 5, 7, 900), TimeDelta::seconds(-3600)); /// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(2, 4, 6, 800), -/// Duration::seconds(3600 + 60 + 1) + Duration::milliseconds(100)); +/// TimeDelta::seconds(3600 + 60 + 1) + TimeDelta::milliseconds(100)); /// ``` /// /// Leap seconds are handled, but the subtraction assumes that /// there were no other leap seconds happened. /// /// ``` -/// # use chrono::{Duration, NaiveTime}; +/// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; -/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 59, 0), Duration::seconds(1)); +/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 59, 0), TimeDelta::seconds(1)); /// assert_eq!(from_hmsm(3, 0, 59, 1_500) - from_hmsm(3, 0, 59, 0), -/// Duration::milliseconds(1500)); -/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 0, 0), Duration::seconds(60)); -/// assert_eq!(from_hmsm(3, 0, 0, 0) - from_hmsm(2, 59, 59, 1_000), Duration::seconds(1)); +/// TimeDelta::milliseconds(1500)); +/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 0, 0), TimeDelta::seconds(60)); +/// assert_eq!(from_hmsm(3, 0, 0, 0) - from_hmsm(2, 59, 59, 1_000), TimeDelta::seconds(1)); /// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(2, 59, 59, 1_000), -/// Duration::seconds(61)); +/// TimeDelta::seconds(61)); /// ``` impl Sub for NaiveTime { - type Output = OldDuration; + type Output = TimeDelta; #[inline] - fn sub(self, rhs: NaiveTime) -> OldDuration { + fn sub(self, rhs: NaiveTime) -> TimeDelta { self.signed_duration_since(rhs) } } diff --git a/src/naive/time/tests.rs b/src/naive/time/tests.rs index 784a8390b8..a991117a7f 100644 --- a/src/naive/time/tests.rs +++ b/src/naive/time/tests.rs @@ -1,6 +1,5 @@ use super::NaiveTime; -use crate::duration::Duration as OldDuration; -use crate::{FixedOffset, Timelike}; +use crate::{FixedOffset, TimeDelta, Timelike}; #[test] fn test_time_from_hms_milli() { @@ -94,23 +93,23 @@ fn test_time_add() { let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap(); - check!(hmsm(3, 5, 59, 900), OldDuration::zero(), hmsm(3, 5, 59, 900)); - check!(hmsm(3, 5, 59, 900), OldDuration::milliseconds(100), hmsm(3, 6, 0, 0)); - check!(hmsm(3, 5, 59, 1_300), OldDuration::milliseconds(-1800), hmsm(3, 5, 58, 500)); - check!(hmsm(3, 5, 59, 1_300), OldDuration::milliseconds(-800), hmsm(3, 5, 59, 500)); - check!(hmsm(3, 5, 59, 1_300), OldDuration::milliseconds(-100), hmsm(3, 5, 59, 1_200)); - check!(hmsm(3, 5, 59, 1_300), OldDuration::milliseconds(100), hmsm(3, 5, 59, 1_400)); - check!(hmsm(3, 5, 59, 1_300), OldDuration::milliseconds(800), hmsm(3, 6, 0, 100)); - check!(hmsm(3, 5, 59, 1_300), OldDuration::milliseconds(1800), hmsm(3, 6, 1, 100)); - check!(hmsm(3, 5, 59, 900), OldDuration::seconds(86399), hmsm(3, 5, 58, 900)); // overwrap - check!(hmsm(3, 5, 59, 900), OldDuration::seconds(-86399), hmsm(3, 6, 0, 900)); - check!(hmsm(3, 5, 59, 900), OldDuration::days(12345), hmsm(3, 5, 59, 900)); - check!(hmsm(3, 5, 59, 1_300), OldDuration::days(1), hmsm(3, 5, 59, 300)); - check!(hmsm(3, 5, 59, 1_300), OldDuration::days(-1), hmsm(3, 6, 0, 300)); + check!(hmsm(3, 5, 59, 900), TimeDelta::zero(), hmsm(3, 5, 59, 900)); + check!(hmsm(3, 5, 59, 900), TimeDelta::milliseconds(100), hmsm(3, 6, 0, 0)); + check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(-1800), hmsm(3, 5, 58, 500)); + check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(-800), hmsm(3, 5, 59, 500)); + check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(-100), hmsm(3, 5, 59, 1_200)); + check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(100), hmsm(3, 5, 59, 1_400)); + check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(800), hmsm(3, 6, 0, 100)); + check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(1800), hmsm(3, 6, 1, 100)); + check!(hmsm(3, 5, 59, 900), TimeDelta::seconds(86399), hmsm(3, 5, 58, 900)); // overwrap + check!(hmsm(3, 5, 59, 900), TimeDelta::seconds(-86399), hmsm(3, 6, 0, 900)); + check!(hmsm(3, 5, 59, 900), TimeDelta::days(12345), hmsm(3, 5, 59, 900)); + check!(hmsm(3, 5, 59, 1_300), TimeDelta::days(1), hmsm(3, 5, 59, 300)); + check!(hmsm(3, 5, 59, 1_300), TimeDelta::days(-1), hmsm(3, 6, 0, 300)); // regression tests for #37 - check!(hmsm(0, 0, 0, 0), OldDuration::milliseconds(-990), hmsm(23, 59, 59, 10)); - check!(hmsm(0, 0, 0, 0), OldDuration::milliseconds(-9990), hmsm(23, 59, 50, 10)); + check!(hmsm(0, 0, 0, 0), TimeDelta::milliseconds(-990), hmsm(23, 59, 59, 10)); + check!(hmsm(0, 0, 0, 0), TimeDelta::milliseconds(-9990), hmsm(23, 59, 50, 10)); } #[test] @@ -118,25 +117,25 @@ fn test_time_overflowing_add() { let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap(); assert_eq!( - hmsm(3, 4, 5, 678).overflowing_add_signed(OldDuration::hours(11)), + hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(11)), (hmsm(14, 4, 5, 678), 0) ); assert_eq!( - hmsm(3, 4, 5, 678).overflowing_add_signed(OldDuration::hours(23)), + hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(23)), (hmsm(2, 4, 5, 678), 86_400) ); assert_eq!( - hmsm(3, 4, 5, 678).overflowing_add_signed(OldDuration::hours(-7)), + hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(-7)), (hmsm(20, 4, 5, 678), -86_400) ); // overflowing_add_signed with leap seconds may be counter-intuitive assert_eq!( - hmsm(3, 4, 59, 1_678).overflowing_add_signed(OldDuration::days(1)), + hmsm(3, 4, 59, 1_678).overflowing_add_signed(TimeDelta::days(1)), (hmsm(3, 4, 59, 678), 86_400) ); assert_eq!( - hmsm(3, 4, 59, 1_678).overflowing_add_signed(OldDuration::days(-1)), + hmsm(3, 4, 59, 1_678).overflowing_add_signed(TimeDelta::days(-1)), (hmsm(3, 5, 0, 678), -86_400) ); } @@ -145,9 +144,9 @@ fn test_time_overflowing_add() { fn test_time_addassignment() { let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap(); let mut time = hms(12, 12, 12); - time += OldDuration::hours(10); + time += TimeDelta::hours(10); assert_eq!(time, hms(22, 12, 12)); - time += OldDuration::hours(10); + time += TimeDelta::hours(10); assert_eq!(time, hms(8, 12, 12)); } @@ -155,9 +154,9 @@ fn test_time_addassignment() { fn test_time_subassignment() { let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap(); let mut time = hms(12, 12, 12); - time -= OldDuration::hours(10); + time -= TimeDelta::hours(10); assert_eq!(time, hms(2, 12, 12)); - time -= OldDuration::hours(10); + time -= TimeDelta::hours(10); assert_eq!(time, hms(16, 12, 12)); } @@ -173,25 +172,25 @@ fn test_time_sub() { let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap(); - check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), OldDuration::zero()); - check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), OldDuration::milliseconds(300)); - check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), OldDuration::seconds(3600 + 60 + 1)); + check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), TimeDelta::zero()); + check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), TimeDelta::milliseconds(300)); + check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), TimeDelta::seconds(3600 + 60 + 1)); check!( hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 300), - OldDuration::seconds(3600 + 60) + OldDuration::milliseconds(900) + TimeDelta::seconds(3600 + 60) + TimeDelta::milliseconds(900) ); // treats the leap second as if it coincides with the prior non-leap second, // as required by `time1 - time2 = duration` and `time2 - time1 = -duration` equivalence. - check!(hmsm(3, 6, 0, 200), hmsm(3, 5, 59, 1_800), OldDuration::milliseconds(400)); - //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), OldDuration::milliseconds(1400)); - //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), OldDuration::milliseconds(1400)); + check!(hmsm(3, 6, 0, 200), hmsm(3, 5, 59, 1_800), TimeDelta::milliseconds(400)); + //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), TimeDelta::milliseconds(1400)); + //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), TimeDelta::milliseconds(1400)); // additional equality: `time1 + duration = time2` is equivalent to // `time2 - time1 = duration` IF AND ONLY IF `time2` represents a non-leap second. - assert_eq!(hmsm(3, 5, 6, 800) + OldDuration::milliseconds(400), hmsm(3, 5, 7, 200)); - //assert_eq!(hmsm(3, 5, 6, 1_800) + OldDuration::milliseconds(400), hmsm(3, 5, 7, 200)); + assert_eq!(hmsm(3, 5, 6, 800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200)); + //assert_eq!(hmsm(3, 5, 6, 1_800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200)); } #[test] diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 1767763738..724f3597ad 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -187,7 +187,7 @@ impl TimeZone for Local { mod tests { use super::Local; use crate::offset::TimeZone; - use crate::{Datelike, Duration, Utc}; + use crate::{Datelike, TimeDelta, Utc}; #[test] fn verify_correct_offsets() { @@ -204,8 +204,8 @@ mod tests { #[test] fn verify_correct_offsets_distant_past() { - // let distant_past = Local::now() - Duration::days(365 * 100); - let distant_past = Local::now() - Duration::days(250 * 31); + // let distant_past = Local::now() - TimeDelta::days(365 * 100); + let distant_past = Local::now() - TimeDelta::days(250 * 31); let from_local = Local.from_local_datetime(&distant_past.naive_local()).unwrap(); let from_utc = Local.from_utc_datetime(&distant_past.naive_utc()); @@ -218,7 +218,7 @@ mod tests { #[test] fn verify_correct_offsets_distant_future() { - let distant_future = Local::now() + Duration::days(250 * 31); + let distant_future = Local::now() + TimeDelta::days(250 * 31); let from_local = Local.from_local_datetime(&distant_future.naive_local()).unwrap(); let from_utc = Local.from_utc_datetime(&distant_future.naive_utc()); diff --git a/src/round.rs b/src/round.rs index ab16fbb89a..281816330e 100644 --- a/src/round.rs +++ b/src/round.rs @@ -1,13 +1,9 @@ // This is a part of Chrono. // See README.md and LICENSE.txt for details. -//! Functionality for rounding or truncating a `DateTime` by a `Duration`. +//! Functionality for rounding or truncating a `DateTime` by a `TimeDelta`. -use crate::datetime::DateTime; -use crate::duration::Duration; -use crate::NaiveDateTime; -use crate::TimeZone; -use crate::Timelike; +use crate::{DateTime, NaiveDateTime, TimeDelta, TimeZone, Timelike}; use core::cmp::Ordering; use core::fmt; use core::marker::Sized; @@ -48,7 +44,7 @@ pub trait SubsecRound { impl SubsecRound for T where - T: Timelike + Add + Sub, + T: Timelike + Add + Sub, { fn round_subsecs(self, digits: u16) -> T { let span = span_for_digits(digits); @@ -56,9 +52,9 @@ where if delta_down > 0 { let delta_up = span - delta_down; if delta_up <= delta_down { - self + Duration::nanoseconds(delta_up.into()) + self + TimeDelta::nanoseconds(delta_up.into()) } else { - self - Duration::nanoseconds(delta_down.into()) + self - TimeDelta::nanoseconds(delta_down.into()) } } else { self // unchanged @@ -69,7 +65,7 @@ where let span = span_for_digits(digits); let delta_down = self.nanosecond() % span; if delta_down > 0 { - self - Duration::nanoseconds(delta_down.into()) + self - TimeDelta::nanoseconds(delta_down.into()) } else { self // unchanged } @@ -93,13 +89,13 @@ const fn span_for_digits(digits: u16) -> u32 { } } -/// Extension trait for rounding or truncating a DateTime by a Duration. +/// Extension trait for rounding or truncating a DateTime by a TimeDelta. /// /// # Limitations -/// Both rounding and truncating are done via [`Duration::num_nanoseconds`] and +/// Both rounding and truncating are done via [`TimeDelta::num_nanoseconds`] and /// [`DateTime::timestamp_nanos_opt`]. This means that they will fail if either the -/// `Duration` or the `DateTime` are too big to represented as nanoseconds. They -/// will also fail if the `Duration` is bigger than the timestamp. +/// `TimeDelta` or the `DateTime` are too big to represented as nanoseconds. They +/// will also fail if the `TimeDelta` is bigger than the timestamp. pub trait DurationRound: Sized { /// Error that can occur in rounding or truncating #[cfg(feature = "std")] @@ -109,49 +105,49 @@ pub trait DurationRound: Sized { #[cfg(not(feature = "std"))] type Err: fmt::Debug + fmt::Display; - /// Return a copy rounded by Duration. + /// Return a copy rounded by TimeDelta. /// /// # Example /// ``` rust - /// # use chrono::{DurationRound, Duration, Utc, NaiveDate}; + /// # use chrono::{DurationRound, TimeDelta, 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(), + /// dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(), /// "2018-01-11 12:00:00.150 UTC" /// ); /// assert_eq!( - /// dt.duration_round(Duration::days(1)).unwrap().to_string(), + /// dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), /// "2018-01-12 00:00:00 UTC" /// ); /// ``` - fn duration_round(self, duration: Duration) -> Result; + fn duration_round(self, duration: TimeDelta) -> Result; - /// Return a copy truncated by Duration. + /// Return a copy truncated by TimeDelta. /// /// # Example /// ``` rust - /// # use chrono::{DurationRound, Duration, Utc, NaiveDate}; + /// # use chrono::{DurationRound, TimeDelta, 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(), + /// dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), /// "2018-01-11 12:00:00.150 UTC" /// ); /// assert_eq!( - /// dt.duration_trunc(Duration::days(1)).unwrap().to_string(), + /// dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), /// "2018-01-11 00:00:00 UTC" /// ); /// ``` - fn duration_trunc(self, duration: Duration) -> Result; + fn duration_trunc(self, duration: TimeDelta) -> Result; } impl DurationRound for DateTime { type Err = RoundingError; - fn duration_round(self, duration: Duration) -> Result { + fn duration_round(self, duration: TimeDelta) -> Result { duration_round(self.naive_local(), self, duration) } - fn duration_trunc(self, duration: Duration) -> Result { + fn duration_trunc(self, duration: TimeDelta) -> Result { duration_trunc(self.naive_local(), self, duration) } } @@ -159,11 +155,11 @@ impl DurationRound for DateTime { impl DurationRound for NaiveDateTime { type Err = RoundingError; - fn duration_round(self, duration: Duration) -> Result { + fn duration_round(self, duration: TimeDelta) -> Result { duration_round(self, self, duration) } - fn duration_trunc(self, duration: Duration) -> Result { + fn duration_trunc(self, duration: TimeDelta) -> Result { duration_trunc(self, self, duration) } } @@ -171,10 +167,10 @@ impl DurationRound for NaiveDateTime { fn duration_round( naive: NaiveDateTime, original: T, - duration: Duration, + duration: TimeDelta, ) -> Result where - T: Timelike + Add + Sub, + T: Timelike + Add + Sub, { if let Some(span) = duration.num_nanoseconds() { if span < 0 { @@ -197,9 +193,9 @@ where (span - delta_down, delta_down) }; if delta_up <= delta_down { - Ok(original + Duration::nanoseconds(delta_up)) + Ok(original + TimeDelta::nanoseconds(delta_up)) } else { - Ok(original - Duration::nanoseconds(delta_down)) + Ok(original - TimeDelta::nanoseconds(delta_down)) } } } else { @@ -210,10 +206,10 @@ where fn duration_trunc( naive: NaiveDateTime, original: T, - duration: Duration, + duration: TimeDelta, ) -> Result where - T: Timelike + Add + Sub, + T: Timelike + Add + Sub, { if let Some(span) = duration.num_nanoseconds() { if span < 0 { @@ -226,40 +222,40 @@ where 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())), + Ordering::Greater => Ok(original - TimeDelta::nanoseconds(delta_down)), + Ordering::Less => Ok(original - TimeDelta::nanoseconds(span - delta_down.abs())), } } else { Err(RoundingError::DurationExceedsLimit) } } -/// An error from rounding by `Duration` +/// An error from rounding by `TimeDelta` /// /// See: [`DurationRound`] #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum RoundingError { - /// Error when the Duration exceeds the Duration from or until the Unix epoch. + /// Error when the TimeDelta exceeds the TimeDelta from or until the Unix epoch. /// /// ``` rust - /// # use chrono::{DurationRound, Duration, RoundingError, TimeZone, Utc}; + /// # use chrono::{DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; /// let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0).unwrap(); /// /// assert_eq!( - /// dt.duration_round(Duration::days(365)), + /// dt.duration_round(TimeDelta::days(365)), /// Err(RoundingError::DurationExceedsTimestamp), /// ); /// ``` DurationExceedsTimestamp, - /// Error when `Duration.num_nanoseconds` exceeds the limit. + /// Error when `TimeDelta.num_nanoseconds` exceeds the limit. /// /// ``` rust - /// # use chrono::{DurationRound, Duration, RoundingError, Utc, NaiveDate}; + /// # use chrono::{DurationRound, TimeDelta, RoundingError, 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)), + /// dt.duration_round(TimeDelta::days(300 * 365)), /// Err(RoundingError::DurationExceedsLimit) /// ); /// ``` @@ -268,10 +264,10 @@ pub enum RoundingError { /// Error when `DateTime.timestamp_nanos` exceeds the limit. /// /// ``` rust - /// # use chrono::{DurationRound, Duration, RoundingError, TimeZone, Utc}; + /// # use chrono::{DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; /// 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),); + /// assert_eq!(dt.duration_round(TimeDelta::days(1)), Err(RoundingError::TimestampExceedsLimit),); /// ``` TimestampExceedsLimit, } @@ -302,7 +298,7 @@ impl std::error::Error for RoundingError { #[cfg(test)] mod tests { - use super::{Duration, DurationRound, RoundingError, SubsecRound}; + use super::{DurationRound, RoundingError, SubsecRound, TimeDelta}; use crate::offset::{FixedOffset, TimeZone, Utc}; use crate::Timelike; use crate::{NaiveDate, NaiveDateTime}; @@ -447,12 +443,12 @@ mod tests { .unwrap(); assert_eq!( - dt.duration_round(Duration::zero()).unwrap().to_string(), + dt.duration_round(TimeDelta::zero()).unwrap().to_string(), "2016-12-31 23:59:59.175500 UTC" ); assert_eq!( - dt.duration_round(Duration::milliseconds(10)).unwrap().to_string(), + dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(), "2016-12-31 23:59:59.180 UTC" ); @@ -466,7 +462,7 @@ mod tests { ) .unwrap(); assert_eq!( - dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:25:00 UTC" ); // round down @@ -479,24 +475,24 @@ mod tests { ) .unwrap(); assert_eq!( - dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" ); assert_eq!( - dt.duration_round(Duration::minutes(10)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" ); assert_eq!( - dt.duration_round(Duration::minutes(30)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(30)).unwrap().to_string(), "2012-12-12 18:30:00 UTC" ); assert_eq!( - dt.duration_round(Duration::hours(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::hours(1)).unwrap().to_string(), "2012-12-12 18:00:00 UTC" ); assert_eq!( - dt.duration_round(Duration::days(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), "2012-12-13 00:00:00 UTC" ); @@ -504,11 +500,11 @@ mod tests { 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(), + dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), "2020-10-28 00:00:00 +01:00" ); assert_eq!( - dt.duration_round(Duration::weeks(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::weeks(1)).unwrap().to_string(), "2020-10-29 00:00:00 +01:00" ); @@ -516,11 +512,11 @@ mod tests { 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(), + dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), "2020-10-28 00:00:00 -01:00" ); assert_eq!( - dt.duration_round(Duration::weeks(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::weeks(1)).unwrap().to_string(), "2020-10-29 00:00:00 -01:00" ); } @@ -538,12 +534,12 @@ mod tests { .naive_utc(); assert_eq!( - dt.duration_round(Duration::zero()).unwrap().to_string(), + dt.duration_round(TimeDelta::zero()).unwrap().to_string(), "2016-12-31 23:59:59.175500" ); assert_eq!( - dt.duration_round(Duration::milliseconds(10)).unwrap().to_string(), + dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(), "2016-12-31 23:59:59.180" ); @@ -558,7 +554,7 @@ mod tests { .unwrap() .naive_utc(); assert_eq!( - dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:25:00" ); // round down @@ -572,24 +568,24 @@ mod tests { .unwrap() .naive_utc(); assert_eq!( - dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00" ); assert_eq!( - dt.duration_round(Duration::minutes(10)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(), "2012-12-12 18:20:00" ); assert_eq!( - dt.duration_round(Duration::minutes(30)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(30)).unwrap().to_string(), "2012-12-12 18:30:00" ); assert_eq!( - dt.duration_round(Duration::hours(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::hours(1)).unwrap().to_string(), "2012-12-12 18:00:00" ); assert_eq!( - dt.duration_round(Duration::days(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), "2012-12-13 00:00:00" ); } @@ -598,7 +594,7 @@ mod tests { fn test_duration_round_pre_epoch() { 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(), + dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(), "1969-12-12 12:10:00 UTC" ); } @@ -615,7 +611,7 @@ mod tests { .unwrap(); assert_eq!( - dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), "2016-12-31 23:59:59.170 UTC" ); @@ -629,7 +625,7 @@ mod tests { ) .unwrap(); assert_eq!( - dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" ); // would round down @@ -642,23 +638,23 @@ mod tests { ) .unwrap(); assert_eq!( - dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" ); assert_eq!( - dt.duration_trunc(Duration::minutes(10)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" ); assert_eq!( - dt.duration_trunc(Duration::minutes(30)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(30)).unwrap().to_string(), "2012-12-12 18:00:00 UTC" ); assert_eq!( - dt.duration_trunc(Duration::hours(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::hours(1)).unwrap().to_string(), "2012-12-12 18:00:00 UTC" ); assert_eq!( - dt.duration_trunc(Duration::days(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), "2012-12-12 00:00:00 UTC" ); @@ -666,11 +662,11 @@ mod tests { 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(), + dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), "2020-10-27 00:00:00 +01:00" ); assert_eq!( - dt.duration_trunc(Duration::weeks(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::weeks(1)).unwrap().to_string(), "2020-10-22 00:00:00 +01:00" ); @@ -678,11 +674,11 @@ mod tests { 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(), + dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), "2020-10-27 00:00:00 -01:00" ); assert_eq!( - dt.duration_trunc(Duration::weeks(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::weeks(1)).unwrap().to_string(), "2020-10-22 00:00:00 -01:00" ); } @@ -700,7 +696,7 @@ mod tests { .naive_utc(); assert_eq!( - dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), "2016-12-31 23:59:59.170" ); @@ -715,7 +711,7 @@ mod tests { .unwrap() .naive_utc(); assert_eq!( - dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00" ); // would round down @@ -729,23 +725,23 @@ mod tests { .unwrap() .naive_utc(); assert_eq!( - dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00" ); assert_eq!( - dt.duration_trunc(Duration::minutes(10)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(), "2012-12-12 18:20:00" ); assert_eq!( - dt.duration_trunc(Duration::minutes(30)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(30)).unwrap().to_string(), "2012-12-12 18:00:00" ); assert_eq!( - dt.duration_trunc(Duration::hours(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::hours(1)).unwrap().to_string(), "2012-12-12 18:00:00" ); assert_eq!( - dt.duration_trunc(Duration::days(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), "2012-12-12 00:00:00" ); } @@ -754,7 +750,7 @@ mod tests { fn test_duration_trunc_pre_epoch() { 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(), + dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(), "1969-12-12 12:10:00 UTC" ); } @@ -762,15 +758,15 @@ mod tests { #[test] fn issue1010() { let dt = NaiveDateTime::from_timestamp_opt(-4_227_854_320, 678_774_288).unwrap(); - let span = Duration::microseconds(-7_019_067_213_869_040); + let span = TimeDelta::microseconds(-7_019_067_213_869_040); assert_eq!(dt.duration_trunc(span), Err(RoundingError::DurationExceedsLimit)); let dt = NaiveDateTime::from_timestamp_opt(320_041_586, 920_103_021).unwrap(); - let span = Duration::nanoseconds(-8_923_838_508_697_114_584); + let span = TimeDelta::nanoseconds(-8_923_838_508_697_114_584); assert_eq!(dt.duration_round(span), Err(RoundingError::DurationExceedsLimit)); let dt = NaiveDateTime::from_timestamp_opt(-2_621_440, 0).unwrap(); - let span = Duration::nanoseconds(-9_223_372_036_854_771_421); + let span = TimeDelta::nanoseconds(-9_223_372_036_854_771_421); assert_eq!(dt.duration_round(span), Err(RoundingError::DurationExceedsLimit)); } } diff --git a/src/time_delta.rs b/src/time_delta.rs new file mode 100644 index 0000000000..a2c737969e --- /dev/null +++ b/src/time_delta.rs @@ -0,0 +1,1209 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Temporal quantification + +use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}; +use core::time::Duration; +use core::{fmt, i64}; +#[cfg(feature = "std")] +use std::error::Error; + +use crate::{expect, try_opt}; + +#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))] +use rkyv::{Archive, Deserialize, Serialize}; + +/// The number of nanoseconds in a microsecond. +const NANOS_PER_MICRO: i32 = 1000; +/// The number of nanoseconds in a millisecond. +const NANOS_PER_MILLI: i32 = 1_000_000; +/// The number of nanoseconds in seconds. +pub(crate) const NANOS_PER_SEC: i32 = 1_000_000_000; +/// The number of microseconds per second. +const MICROS_PER_SEC: i64 = 1_000_000; +/// The number of milliseconds per second. +const MILLIS_PER_SEC: i64 = 1000; +/// The number of seconds in a minute. +const SECS_PER_MINUTE: i64 = 60; +/// The number of seconds in an hour. +const SECS_PER_HOUR: i64 = 3600; +/// The number of (non-leap) seconds in days. +const SECS_PER_DAY: i64 = 86_400; +/// The number of (non-leap) seconds in a week. +const SECS_PER_WEEK: i64 = 604_800; + +/// Time duration with nanosecond precision. +/// +/// This also allows for negative durations; see individual methods for details. +/// +/// A `TimeDelta` is represented internally as a complement of seconds and +/// nanoseconds. The range is restricted to that of `i64` milliseconds, with the +/// minimum value notably being set to `-i64::MAX` rather than allowing the full +/// range of `i64::MIN`. This is to allow easy flipping of sign, so that for +/// instance `abs()` can be called without any checks. +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +#[cfg_attr( + any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"), + derive(Archive, Deserialize, Serialize), + archive(compare(PartialEq, PartialOrd)), + archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)) +)] +#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))] +pub struct TimeDelta { + secs: i64, + nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC +} + +/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds. +pub(crate) const MIN: TimeDelta = TimeDelta { + secs: -i64::MAX / MILLIS_PER_SEC - 1, + nanos: NANOS_PER_SEC + (-i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI, +}; + +/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds. +pub(crate) const MAX: TimeDelta = TimeDelta { + secs: i64::MAX / MILLIS_PER_SEC, + nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI, +}; + +impl TimeDelta { + /// Makes a new `TimeDelta` with given number of seconds and nanoseconds. + /// + /// # Errors + /// + /// Returns `None` when the duration is out of bounds, or if `nanos` ≥ 1,000,000,000. + pub const fn new(secs: i64, nanos: u32) -> Option { + if secs < MIN.secs + || secs > MAX.secs + || nanos >= 1_000_000_000 + || (secs == MAX.secs && nanos > MAX.nanos as u32) + || (secs == MIN.secs && nanos < MIN.nanos as u32) + { + return None; + } + Some(TimeDelta { secs, nanos: nanos as i32 }) + } + + /// Makes a new `TimeDelta` with the given number of weeks. + /// + /// Equivalent to `TimeDelta::seconds(weeks * 7 * 24 * 60 * 60)` with + /// overflow checks. + /// + /// # Panics + /// + /// Panics when the duration is out of bounds. + #[inline] + #[must_use] + pub const fn weeks(weeks: i64) -> TimeDelta { + expect!(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds") + } + + /// Makes a new `TimeDelta` with the given number of weeks. + /// + /// Equivalent to `TimeDelta::seconds(weeks * 7 * 24 * 60 * 60)` with + /// overflow checks. + /// + /// # Errors + /// + /// Returns `None` when the `TimeDelta` would be out of bounds. + #[inline] + pub const fn try_weeks(weeks: i64) -> Option { + TimeDelta::try_seconds(try_opt!(weeks.checked_mul(SECS_PER_WEEK))) + } + + /// Makes a new `TimeDelta` with the given number of days. + /// + /// Equivalent to `TimeDelta::seconds(days * 24 * 60 * 60)` with overflow + /// checks. + /// + /// # Panics + /// + /// Panics when the `TimeDelta` would be out of bounds. + #[inline] + #[must_use] + pub const fn days(days: i64) -> TimeDelta { + expect!(TimeDelta::try_days(days), "TimeDelta::days out of bounds") + } + + /// Makes a new `TimeDelta` with the given number of days. + /// + /// Equivalent to `TimeDelta::seconds(days * 24 * 60 * 60)` with overflow + /// checks. + /// + /// # Errors + /// + /// Returns `None` when the `TimeDelta` would be out of bounds. + #[inline] + pub const fn try_days(days: i64) -> Option { + TimeDelta::try_seconds(try_opt!(days.checked_mul(SECS_PER_DAY))) + } + + /// Makes a new `TimeDelta` with the given number of hours. + /// + /// Equivalent to `TimeDelta::seconds(hours * 60 * 60)` with overflow checks. + /// + /// # Panics + /// + /// Panics when the `TimeDelta` would be out of bounds. + #[inline] + #[must_use] + pub const fn hours(hours: i64) -> TimeDelta { + expect!(TimeDelta::try_hours(hours), "TimeDelta::hours out of bounds") + } + + /// Makes a new `TimeDelta` with the given number of hours. + /// + /// Equivalent to `TimeDelta::seconds(hours * 60 * 60)` with overflow checks. + /// + /// # Errors + /// + /// Returns `None` when the `TimeDelta` would be out of bounds. + #[inline] + pub const fn try_hours(hours: i64) -> Option { + TimeDelta::try_seconds(try_opt!(hours.checked_mul(SECS_PER_HOUR))) + } + + /// Makes a new `TimeDelta` with the given number of minutes. + /// + /// Equivalent to `TimeDelta::seconds(minutes * 60)` with overflow checks. + /// + /// # Panics + /// + /// Panics when the `TimeDelta` would be out of bounds. + #[inline] + #[must_use] + pub const fn minutes(minutes: i64) -> TimeDelta { + expect!(TimeDelta::try_minutes(minutes), "TimeDelta::minutes out of bounds") + } + + /// Makes a new `TimeDelta` with the given number of minutes. + /// + /// Equivalent to `TimeDelta::seconds(minutes * 60)` with overflow checks. + /// + /// # Errors + /// + /// Returns `None` when the `TimeDelta` would be out of bounds. + #[inline] + pub const fn try_minutes(minutes: i64) -> Option { + TimeDelta::try_seconds(try_opt!(minutes.checked_mul(SECS_PER_MINUTE))) + } + + /// Makes a new `TimeDelta` with the given number of seconds. + /// + /// # Panics + /// + /// Panics when `seconds` is more than `i64::MAX / 1_000` or less than `-i64::MAX / 1_000` + /// (in this context, this is the same as `i64::MIN / 1_000` due to rounding). + #[inline] + #[must_use] + pub const fn seconds(seconds: i64) -> TimeDelta { + expect!(TimeDelta::try_seconds(seconds), "TimeDelta::seconds out of bounds") + } + + /// Makes a new `TimeDelta` with the given number of seconds. + /// + /// # Errors + /// + /// Returns `None` when `seconds` is more than `i64::MAX / 1_000` or less than + /// `-i64::MAX / 1_000` (in this context, this is the same as `i64::MIN / 1_000` due to + /// rounding). + #[inline] + pub const fn try_seconds(seconds: i64) -> Option { + TimeDelta::new(seconds, 0) + } + + /// Makes a new `TimeDelta` with the given number of milliseconds. + /// + /// # Panics + /// + /// Panics when the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more than + /// `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`. + #[inline] + pub const fn milliseconds(milliseconds: i64) -> TimeDelta { + expect!(TimeDelta::try_milliseconds(milliseconds), "TimeDelta::milliseconds out of bounds") + } + + /// Makes a new `TimeDelta` with the given number of milliseconds. + /// + /// # Errors + /// + /// Returns `None` the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more + /// than `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`. + #[inline] + pub const fn try_milliseconds(milliseconds: i64) -> Option { + // We don't need to compare against MAX, as this function accepts an + // i64, and MAX is aligned to i64::MAX milliseconds. + if milliseconds < -i64::MAX { + return None; + } + let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC); + let d = TimeDelta { secs, nanos: millis as i32 * NANOS_PER_MILLI }; + Some(d) + } + + /// Makes a new `TimeDelta` with the given number of microseconds. + /// + /// The number of microseconds acceptable by this constructor is less than + /// the total number that can actually be stored in a `TimeDelta`, so it is + /// not possible to specify a value that would be out of bounds. This + /// function is therefore infallible. + #[inline] + pub const fn microseconds(microseconds: i64) -> TimeDelta { + let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); + let nanos = micros as i32 * NANOS_PER_MICRO; + TimeDelta { secs, nanos } + } + + /// Makes a new `TimeDelta` with the given number of nanoseconds. + /// + /// The number of nanoseconds acceptable by this constructor is less than + /// the total number that can actually be stored in a `TimeDelta`, so it is + /// not possible to specify a value that would be out of bounds. This + /// function is therefore infallible. + #[inline] + pub const fn nanoseconds(nanos: i64) -> TimeDelta { + let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64); + TimeDelta { secs, nanos: nanos as i32 } + } + + /// Returns the total number of whole weeks in the `TimeDelta`. + #[inline] + pub const fn num_weeks(&self) -> i64 { + self.num_days() / 7 + } + + /// Returns the total number of whole days in the `TimeDelta`. + pub const fn num_days(&self) -> i64 { + self.num_seconds() / SECS_PER_DAY + } + + /// Returns the total number of whole hours in the `TimeDelta`. + #[inline] + pub const fn num_hours(&self) -> i64 { + self.num_seconds() / SECS_PER_HOUR + } + + /// Returns the total number of whole minutes in the `TimeDelta`. + #[inline] + pub const fn num_minutes(&self) -> i64 { + self.num_seconds() / SECS_PER_MINUTE + } + + /// Returns the total number of whole seconds in the `TimeDelta`. + pub const fn num_seconds(&self) -> i64 { + // If secs is negative, nanos should be subtracted from the duration. + if self.secs < 0 && self.nanos > 0 { + self.secs + 1 + } else { + self.secs + } + } + + /// Returns the number of nanoseconds such that + /// `subsec_nanos() + num_seconds() * NANOS_PER_SEC` is the total number of + /// nanoseconds in the `TimeDelta`. + pub const fn subsec_nanos(&self) -> i32 { + if self.secs < 0 && self.nanos > 0 { + self.nanos - NANOS_PER_SEC + } else { + self.nanos + } + } + + /// Returns the total number of whole milliseconds in the `TimeDelta`. + pub const fn num_milliseconds(&self) -> i64 { + // A proper TimeDelta will not overflow, because MIN and MAX are defined such + // that the range is within the bounds of an i64, from -i64::MAX through to + // +i64::MAX inclusive. Notably, i64::MIN is excluded from this range. + let secs_part = self.num_seconds() * MILLIS_PER_SEC; + let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI; + secs_part + nanos_part as i64 + } + + /// Returns the total number of whole microseconds in the `TimeDelta`, + /// or `None` on overflow (exceeding 2^63 microseconds in either direction). + pub const fn num_microseconds(&self) -> Option { + let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC)); + let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO; + secs_part.checked_add(nanos_part as i64) + } + + /// Returns the total number of whole nanoseconds in the `TimeDelta`, + /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction). + pub const fn num_nanoseconds(&self) -> Option { + let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64)); + let nanos_part = self.subsec_nanos(); + secs_part.checked_add(nanos_part as i64) + } + + /// Add two `TimeDelta`s, returning `None` if overflow occurred. + #[must_use] + pub const fn checked_add(&self, rhs: &TimeDelta) -> Option { + // No overflow checks here because we stay comfortably within the range of an `i64`. + // Range checks happen in `TimeDelta::new`. + let mut secs = self.secs + rhs.secs; + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + TimeDelta::new(secs, nanos as u32) + } + + /// Subtract two `TimeDelta`s, returning `None` if overflow occurred. + #[must_use] + pub const fn checked_sub(&self, rhs: &TimeDelta) -> Option { + // No overflow checks here because we stay comfortably within the range of an `i64`. + // Range checks happen in `TimeDelta::new`. + let mut secs = self.secs - rhs.secs; + let mut nanos = self.nanos - rhs.nanos; + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + TimeDelta::new(secs, nanos as u32) + } + + /// Returns the `TimeDelta` as an absolute (non-negative) value. + #[inline] + pub const fn abs(&self) -> TimeDelta { + if self.secs < 0 && self.nanos != 0 { + TimeDelta { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos } + } else { + TimeDelta { secs: self.secs.abs(), nanos: self.nanos } + } + } + + /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds. + #[inline] + pub const fn min_value() -> TimeDelta { + MIN + } + + /// The maximum possible `TimeDelta`: `i64::MAX` milliseconds. + #[inline] + pub const fn max_value() -> TimeDelta { + MAX + } + + /// A `TimeDelta` where the stored seconds and nanoseconds are equal to zero. + #[inline] + pub const fn zero() -> TimeDelta { + TimeDelta { secs: 0, nanos: 0 } + } + + /// Returns `true` if the `TimeDelta` equals `TimeDelta::zero()`. + #[inline] + pub const fn is_zero(&self) -> bool { + self.secs == 0 && self.nanos == 0 + } + + /// Creates a `TimeDelta` object from `std::time::Duration` + /// + /// This function errors when original duration is larger than the maximum + /// value supported for this type. + pub const fn from_std(duration: Duration) -> Result { + // We need to check secs as u64 before coercing to i64 + if duration.as_secs() > MAX.secs as u64 { + return Err(OutOfRangeError(())); + } + match TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos()) { + Some(d) => Ok(d), + None => Err(OutOfRangeError(())), + } + } + + /// Creates a `std::time::Duration` object from a `TimeDelta`. + /// + /// This function errors when duration is less than zero. As standard + /// library implementation is limited to non-negative values. + pub const fn to_std(&self) -> Result { + if self.secs < 0 { + return Err(OutOfRangeError(())); + } + Ok(Duration::new(self.secs as u64, self.nanos as u32)) + } + + /// This duplicates `Neg::neg` because trait methods can't be const yet. + pub(crate) const fn neg(self) -> TimeDelta { + let (secs_diff, nanos) = match self.nanos { + 0 => (0, 0), + nanos => (1, NANOS_PER_SEC - nanos), + }; + TimeDelta { secs: -self.secs - secs_diff, nanos } + } +} + +impl Neg for TimeDelta { + type Output = TimeDelta; + + #[inline] + fn neg(self) -> TimeDelta { + let (secs_diff, nanos) = match self.nanos { + 0 => (0, 0), + nanos => (1, NANOS_PER_SEC - nanos), + }; + TimeDelta { secs: -self.secs - secs_diff, nanos } + } +} + +impl Add for TimeDelta { + type Output = TimeDelta; + + fn add(self, rhs: TimeDelta) -> TimeDelta { + self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed") + } +} + +impl Sub for TimeDelta { + type Output = TimeDelta; + + fn sub(self, rhs: TimeDelta) -> TimeDelta { + self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed") + } +} + +impl AddAssign for TimeDelta { + fn add_assign(&mut self, rhs: TimeDelta) { + let new = self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed"); + *self = new; + } +} + +impl SubAssign for TimeDelta { + fn sub_assign(&mut self, rhs: TimeDelta) { + let new = self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed"); + *self = new; + } +} + +impl Mul for TimeDelta { + type Output = TimeDelta; + + fn mul(self, rhs: i32) -> TimeDelta { + // Multiply nanoseconds as i64, because it cannot overflow that way. + let total_nanos = self.nanos as i64 * rhs as i64; + let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64); + let secs = self.secs * rhs as i64 + extra_secs; + TimeDelta { secs, nanos: nanos as i32 } + } +} + +impl Div for TimeDelta { + type Output = TimeDelta; + + fn div(self, rhs: i32) -> TimeDelta { + let mut secs = self.secs / rhs as i64; + let carry = self.secs - secs * rhs as i64; + let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64; + let mut nanos = self.nanos / rhs + extra_nanos as i32; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + TimeDelta { secs, nanos } + } +} + +impl<'a> core::iter::Sum<&'a TimeDelta> for TimeDelta { + fn sum>(iter: I) -> TimeDelta { + iter.fold(TimeDelta::zero(), |acc, x| acc + *x) + } +} + +impl core::iter::Sum for TimeDelta { + fn sum>(iter: I) -> TimeDelta { + iter.fold(TimeDelta::zero(), |acc, x| acc + x) + } +} + +impl fmt::Display for TimeDelta { + /// Format a `TimeDelta` using the [ISO 8601] format + /// + /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601#Durations + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // technically speaking, negative duration is not valid ISO 8601, + // but we need to print it anyway. + let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") }; + + let days = abs.secs / SECS_PER_DAY; + let secs = abs.secs - days * SECS_PER_DAY; + let hasdate = days != 0; + let hastime = (secs != 0 || abs.nanos != 0) || !hasdate; + + write!(f, "{}P", sign)?; + + if hasdate { + write!(f, "{}D", days)?; + } + if hastime { + if abs.nanos == 0 { + write!(f, "T{}S", secs)?; + } else if abs.nanos % NANOS_PER_MILLI == 0 { + write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI)?; + } else if abs.nanos % NANOS_PER_MICRO == 0 { + write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO)?; + } else { + write!(f, "T{}.{:09}S", secs, abs.nanos)?; + } + } + Ok(()) + } +} + +/// Represents error when converting `TimeDelta` to/from a standard library +/// implementation +/// +/// The `std::time::Duration` supports a range from zero to `u64::MAX` +/// *seconds*, while this module supports signed range of up to +/// `i64::MAX` of *milliseconds*. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OutOfRangeError(()); + +impl fmt::Display for OutOfRangeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Source duration value is out of range for the target type") + } +} + +#[cfg(feature = "std")] +impl Error for OutOfRangeError { + #[allow(deprecated)] + fn description(&self) -> &str { + "out of range error" + } +} + +#[inline] +const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { + (this.div_euclid(other), this.rem_euclid(other)) +} + +#[cfg(all(feature = "arbitrary", feature = "std"))] +impl arbitrary::Arbitrary<'_> for TimeDelta { + fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result { + const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1; + const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC; + + let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?; + let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?; + let duration = TimeDelta { secs, nanos }; + + if duration < MIN || duration > MAX { + Err(arbitrary::Error::IncorrectFormat) + } else { + Ok(duration) + } + } +} + +#[cfg(test)] +mod tests { + use super::OutOfRangeError; + use super::{TimeDelta, MAX, MIN}; + use core::time::Duration; + + #[test] + fn test_duration() { + assert!(TimeDelta::seconds(1) != TimeDelta::zero()); + assert_eq!(TimeDelta::seconds(1) + TimeDelta::seconds(2), TimeDelta::seconds(3)); + assert_eq!( + TimeDelta::seconds(86_399) + TimeDelta::seconds(4), + TimeDelta::days(1) + TimeDelta::seconds(3) + ); + assert_eq!(TimeDelta::days(10) - TimeDelta::seconds(1000), TimeDelta::seconds(863_000)); + assert_eq!( + TimeDelta::days(10) - TimeDelta::seconds(1_000_000), + TimeDelta::seconds(-136_000) + ); + assert_eq!( + TimeDelta::days(2) + TimeDelta::seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890), + TimeDelta::days(3) + TimeDelta::nanoseconds(234_567_890) + ); + assert_eq!(-TimeDelta::days(3), TimeDelta::days(-3)); + assert_eq!( + -(TimeDelta::days(3) + TimeDelta::seconds(70)), + TimeDelta::days(-4) + TimeDelta::seconds(86_400 - 70) + ); + + let mut d = TimeDelta::default(); + d += TimeDelta::minutes(1); + d -= TimeDelta::seconds(30); + assert_eq!(d, TimeDelta::seconds(30)); + } + + #[test] + fn test_duration_num_days() { + assert_eq!(TimeDelta::zero().num_days(), 0); + assert_eq!(TimeDelta::days(1).num_days(), 1); + assert_eq!(TimeDelta::days(-1).num_days(), -1); + assert_eq!(TimeDelta::seconds(86_399).num_days(), 0); + assert_eq!(TimeDelta::seconds(86_401).num_days(), 1); + assert_eq!(TimeDelta::seconds(-86_399).num_days(), 0); + assert_eq!(TimeDelta::seconds(-86_401).num_days(), -1); + assert_eq!(TimeDelta::days(i32::MAX as i64).num_days(), i32::MAX as i64); + assert_eq!(TimeDelta::days(i32::MIN as i64).num_days(), i32::MIN as i64); + } + + #[test] + fn test_duration_num_seconds() { + assert_eq!(TimeDelta::zero().num_seconds(), 0); + assert_eq!(TimeDelta::seconds(1).num_seconds(), 1); + assert_eq!(TimeDelta::seconds(-1).num_seconds(), -1); + assert_eq!(TimeDelta::milliseconds(999).num_seconds(), 0); + assert_eq!(TimeDelta::milliseconds(1001).num_seconds(), 1); + assert_eq!(TimeDelta::milliseconds(-999).num_seconds(), 0); + assert_eq!(TimeDelta::milliseconds(-1001).num_seconds(), -1); + } + #[test] + fn test_duration_seconds_max_allowed() { + let duration = TimeDelta::seconds(i64::MAX / 1_000); + assert_eq!(duration.num_seconds(), i64::MAX / 1_000); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MAX as i128 / 1_000 * 1_000_000_000 + ); + } + #[test] + fn test_duration_seconds_max_overflow() { + assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none()); + } + #[test] + #[should_panic(expected = "TimeDelta::seconds out of bounds")] + fn test_duration_seconds_max_overflow_panic() { + let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1); + } + #[test] + fn test_duration_seconds_min_allowed() { + let duration = TimeDelta::seconds(i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding + assert_eq!(duration.num_seconds(), i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + -i64::MAX as i128 / 1_000 * 1_000_000_000 + ); + } + #[test] + fn test_duration_seconds_min_underflow() { + assert!(TimeDelta::try_seconds(-i64::MAX / 1_000 - 1).is_none()); + } + #[test] + #[should_panic(expected = "TimeDelta::seconds out of bounds")] + fn test_duration_seconds_min_underflow_panic() { + let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1); + } + + #[test] + fn test_duration_num_milliseconds() { + assert_eq!(TimeDelta::zero().num_milliseconds(), 0); + assert_eq!(TimeDelta::milliseconds(1).num_milliseconds(), 1); + assert_eq!(TimeDelta::milliseconds(-1).num_milliseconds(), -1); + assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0); + assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1); + assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0); + assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1); + } + #[test] + fn test_duration_milliseconds_max_allowed() { + // The maximum number of milliseconds acceptable through the constructor is + // equal to the number that can be stored in a TimeDelta. + let duration = TimeDelta::milliseconds(i64::MAX); + assert_eq!(duration.num_milliseconds(), i64::MAX); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MAX as i128 * 1_000_000 + ); + } + #[test] + fn test_duration_milliseconds_max_overflow() { + // Here we ensure that trying to add one millisecond to the maximum storable + // value will fail. + assert!(TimeDelta::milliseconds(i64::MAX) + .checked_add(&TimeDelta::milliseconds(1)) + .is_none()); + } + #[test] + fn test_duration_milliseconds_min_allowed() { + // The minimum number of milliseconds acceptable through the constructor is + // not equal to the number that can be stored in a TimeDelta - there is a + // difference of one (i64::MIN vs -i64::MAX). + let duration = TimeDelta::milliseconds(-i64::MAX); + assert_eq!(duration.num_milliseconds(), -i64::MAX); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + -i64::MAX as i128 * 1_000_000 + ); + } + #[test] + fn test_duration_milliseconds_min_underflow() { + // Here we ensure that trying to subtract one millisecond from the minimum + // storable value will fail. + assert!(TimeDelta::milliseconds(-i64::MAX) + .checked_sub(&TimeDelta::milliseconds(1)) + .is_none()); + } + #[test] + #[should_panic(expected = "TimeDelta::milliseconds out of bounds")] + fn test_duration_milliseconds_min_underflow_panic() { + // Here we ensure that trying to create a value one millisecond below the + // minimum storable value will fail. This test is necessary because the + // storable range is -i64::MAX, but the constructor type of i64 will allow + // i64::MIN, which is one value below. + let _ = TimeDelta::milliseconds(i64::MIN); // Same as -i64::MAX - 1 + } + + #[test] + fn test_duration_num_microseconds() { + assert_eq!(TimeDelta::zero().num_microseconds(), Some(0)); + assert_eq!(TimeDelta::microseconds(1).num_microseconds(), Some(1)); + assert_eq!(TimeDelta::microseconds(-1).num_microseconds(), Some(-1)); + assert_eq!(TimeDelta::nanoseconds(999).num_microseconds(), Some(0)); + assert_eq!(TimeDelta::nanoseconds(1001).num_microseconds(), Some(1)); + assert_eq!(TimeDelta::nanoseconds(-999).num_microseconds(), Some(0)); + assert_eq!(TimeDelta::nanoseconds(-1001).num_microseconds(), Some(-1)); + + // overflow checks + const MICROS_PER_DAY: i64 = 86_400_000_000; + assert_eq!( + TimeDelta::days(i64::MAX / MICROS_PER_DAY).num_microseconds(), + Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY) + ); + assert_eq!( + TimeDelta::days(-i64::MAX / MICROS_PER_DAY).num_microseconds(), + Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY) + ); + assert_eq!(TimeDelta::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None); + assert_eq!(TimeDelta::days(-i64::MAX / MICROS_PER_DAY - 1).num_microseconds(), None); + } + #[test] + fn test_duration_microseconds_max_allowed() { + // The number of microseconds acceptable through the constructor is far + // fewer than the number that can actually be stored in a TimeDelta, so this + // is not a particular insightful test. + let duration = TimeDelta::microseconds(i64::MAX); + assert_eq!(duration.num_microseconds(), Some(i64::MAX)); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MAX as i128 * 1_000 + ); + // Here we create a TimeDelta with the maximum possible number of + // microseconds by creating a TimeDelta with the maximum number of + // milliseconds and then checking that the number of microseconds matches + // the storage limit. + let duration = TimeDelta::milliseconds(i64::MAX); + assert!(duration.num_microseconds().is_none()); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MAX as i128 * 1_000_000 + ); + } + #[test] + fn test_duration_microseconds_max_overflow() { + // This test establishes that a TimeDelta can store more microseconds than + // are representable through the return of duration.num_microseconds(). + let duration = TimeDelta::microseconds(i64::MAX) + TimeDelta::microseconds(1); + assert!(duration.num_microseconds().is_none()); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + (i64::MAX as i128 + 1) * 1_000 + ); + // Here we ensure that trying to add one microsecond to the maximum storable + // value will fail. + assert!(TimeDelta::milliseconds(i64::MAX) + .checked_add(&TimeDelta::microseconds(1)) + .is_none()); + } + #[test] + fn test_duration_microseconds_min_allowed() { + // The number of microseconds acceptable through the constructor is far + // fewer than the number that can actually be stored in a TimeDelta, so this + // is not a particular insightful test. + let duration = TimeDelta::microseconds(i64::MIN); + assert_eq!(duration.num_microseconds(), Some(i64::MIN)); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MIN as i128 * 1_000 + ); + // Here we create a TimeDelta with the minimum possible number of + // microseconds by creating a TimeDelta with the minimum number of + // milliseconds and then checking that the number of microseconds matches + // the storage limit. + let duration = TimeDelta::milliseconds(-i64::MAX); + assert!(duration.num_microseconds().is_none()); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + -i64::MAX as i128 * 1_000_000 + ); + } + #[test] + fn test_duration_microseconds_min_underflow() { + // This test establishes that a TimeDelta can store more microseconds than + // are representable through the return of duration.num_microseconds(). + let duration = TimeDelta::microseconds(i64::MIN) - TimeDelta::microseconds(1); + assert!(duration.num_microseconds().is_none()); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + (i64::MIN as i128 - 1) * 1_000 + ); + // Here we ensure that trying to subtract one microsecond from the minimum + // storable value will fail. + assert!(TimeDelta::milliseconds(-i64::MAX) + .checked_sub(&TimeDelta::microseconds(1)) + .is_none()); + } + + #[test] + fn test_duration_num_nanoseconds() { + assert_eq!(TimeDelta::zero().num_nanoseconds(), Some(0)); + assert_eq!(TimeDelta::nanoseconds(1).num_nanoseconds(), Some(1)); + assert_eq!(TimeDelta::nanoseconds(-1).num_nanoseconds(), Some(-1)); + + // overflow checks + const NANOS_PER_DAY: i64 = 86_400_000_000_000; + assert_eq!( + TimeDelta::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(), + Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY) + ); + assert_eq!( + TimeDelta::days(-i64::MAX / NANOS_PER_DAY).num_nanoseconds(), + Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY) + ); + assert_eq!(TimeDelta::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None); + assert_eq!(TimeDelta::days(-i64::MAX / NANOS_PER_DAY - 1).num_nanoseconds(), None); + } + #[test] + fn test_duration_nanoseconds_max_allowed() { + // The number of nanoseconds acceptable through the constructor is far fewer + // than the number that can actually be stored in a TimeDelta, so this is not + // a particular insightful test. + let duration = TimeDelta::nanoseconds(i64::MAX); + assert_eq!(duration.num_nanoseconds(), Some(i64::MAX)); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MAX as i128 + ); + // Here we create a TimeDelta with the maximum possible number of nanoseconds + // by creating a TimeDelta with the maximum number of milliseconds and then + // checking that the number of nanoseconds matches the storage limit. + let duration = TimeDelta::milliseconds(i64::MAX); + assert!(duration.num_nanoseconds().is_none()); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MAX as i128 * 1_000_000 + ); + } + #[test] + fn test_duration_nanoseconds_max_overflow() { + // This test establishes that a TimeDelta can store more nanoseconds than are + // representable through the return of duration.num_nanoseconds(). + let duration = TimeDelta::nanoseconds(i64::MAX) + TimeDelta::nanoseconds(1); + assert!(duration.num_nanoseconds().is_none()); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MAX as i128 + 1 + ); + // Here we ensure that trying to add one nanosecond to the maximum storable + // value will fail. + assert!(TimeDelta::milliseconds(i64::MAX) + .checked_add(&TimeDelta::nanoseconds(1)) + .is_none()); + } + #[test] + fn test_duration_nanoseconds_min_allowed() { + // The number of nanoseconds acceptable through the constructor is far fewer + // than the number that can actually be stored in a TimeDelta, so this is not + // a particular insightful test. + let duration = TimeDelta::nanoseconds(i64::MIN); + assert_eq!(duration.num_nanoseconds(), Some(i64::MIN)); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MIN as i128 + ); + // Here we create a TimeDelta with the minimum possible number of nanoseconds + // by creating a TimeDelta with the minimum number of milliseconds and then + // checking that the number of nanoseconds matches the storage limit. + let duration = TimeDelta::milliseconds(-i64::MAX); + assert!(duration.num_nanoseconds().is_none()); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + -i64::MAX as i128 * 1_000_000 + ); + } + #[test] + fn test_duration_nanoseconds_min_underflow() { + // This test establishes that a TimeDelta can store more nanoseconds than are + // representable through the return of duration.num_nanoseconds(). + let duration = TimeDelta::nanoseconds(i64::MIN) - TimeDelta::nanoseconds(1); + assert!(duration.num_nanoseconds().is_none()); + assert_eq!( + duration.secs as i128 * 1_000_000_000 + duration.nanos as i128, + i64::MIN as i128 - 1 + ); + // Here we ensure that trying to subtract one nanosecond from the minimum + // storable value will fail. + assert!(TimeDelta::milliseconds(-i64::MAX) + .checked_sub(&TimeDelta::nanoseconds(1)) + .is_none()); + } + + #[test] + fn test_max() { + assert_eq!( + MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128, + i64::MAX as i128 * 1_000_000 + ); + assert_eq!(MAX, TimeDelta::milliseconds(i64::MAX)); + assert_eq!(MAX.num_milliseconds(), i64::MAX); + assert_eq!(MAX.num_microseconds(), None); + assert_eq!(MAX.num_nanoseconds(), None); + } + #[test] + fn test_min() { + assert_eq!( + MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128, + -i64::MAX as i128 * 1_000_000 + ); + assert_eq!(MIN, TimeDelta::milliseconds(-i64::MAX)); + assert_eq!(MIN.num_milliseconds(), -i64::MAX); + assert_eq!(MIN.num_microseconds(), None); + assert_eq!(MIN.num_nanoseconds(), None); + } + + #[test] + fn test_duration_ord() { + assert!(TimeDelta::milliseconds(1) < TimeDelta::milliseconds(2)); + assert!(TimeDelta::milliseconds(2) > TimeDelta::milliseconds(1)); + assert!(TimeDelta::milliseconds(-1) > TimeDelta::milliseconds(-2)); + assert!(TimeDelta::milliseconds(-2) < TimeDelta::milliseconds(-1)); + assert!(TimeDelta::milliseconds(-1) < TimeDelta::milliseconds(1)); + assert!(TimeDelta::milliseconds(1) > TimeDelta::milliseconds(-1)); + assert!(TimeDelta::milliseconds(0) < TimeDelta::milliseconds(1)); + assert!(TimeDelta::milliseconds(0) > TimeDelta::milliseconds(-1)); + assert!(TimeDelta::milliseconds(1_001) < TimeDelta::milliseconds(1_002)); + assert!(TimeDelta::milliseconds(-1_001) > TimeDelta::milliseconds(-1_002)); + assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891)); + assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891)); + assert!(TimeDelta::milliseconds(i64::MAX) > TimeDelta::milliseconds(i64::MAX - 1)); + assert!(TimeDelta::milliseconds(-i64::MAX) < TimeDelta::milliseconds(-i64::MAX + 1)); + } + + #[test] + fn test_duration_checked_ops() { + assert_eq!( + TimeDelta::milliseconds(i64::MAX).checked_add(&TimeDelta::milliseconds(0)), + Some(TimeDelta::milliseconds(i64::MAX)) + ); + assert_eq!( + TimeDelta::milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)), + Some(TimeDelta::milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999)) + ); + assert!(TimeDelta::milliseconds(i64::MAX) + .checked_add(&TimeDelta::microseconds(1000)) + .is_none()); + assert!(TimeDelta::milliseconds(i64::MAX) + .checked_add(&TimeDelta::nanoseconds(1)) + .is_none()); + + assert_eq!( + TimeDelta::milliseconds(-i64::MAX).checked_sub(&TimeDelta::milliseconds(0)), + Some(TimeDelta::milliseconds(-i64::MAX)) + ); + assert_eq!( + TimeDelta::milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)), + Some(TimeDelta::milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999)) + ); + assert!(TimeDelta::milliseconds(-i64::MAX) + .checked_sub(&TimeDelta::milliseconds(1)) + .is_none()); + assert!(TimeDelta::milliseconds(-i64::MAX) + .checked_sub(&TimeDelta::nanoseconds(1)) + .is_none()); + } + + #[test] + fn test_duration_abs() { + assert_eq!(TimeDelta::milliseconds(1300).abs(), TimeDelta::milliseconds(1300)); + assert_eq!(TimeDelta::milliseconds(1000).abs(), TimeDelta::milliseconds(1000)); + assert_eq!(TimeDelta::milliseconds(300).abs(), TimeDelta::milliseconds(300)); + assert_eq!(TimeDelta::milliseconds(0).abs(), TimeDelta::milliseconds(0)); + assert_eq!(TimeDelta::milliseconds(-300).abs(), TimeDelta::milliseconds(300)); + assert_eq!(TimeDelta::milliseconds(-700).abs(), TimeDelta::milliseconds(700)); + assert_eq!(TimeDelta::milliseconds(-1000).abs(), TimeDelta::milliseconds(1000)); + assert_eq!(TimeDelta::milliseconds(-1300).abs(), TimeDelta::milliseconds(1300)); + assert_eq!(TimeDelta::milliseconds(-1700).abs(), TimeDelta::milliseconds(1700)); + assert_eq!(TimeDelta::milliseconds(-i64::MAX).abs(), TimeDelta::milliseconds(i64::MAX)); + } + + #[test] + #[allow(clippy::erasing_op)] + fn test_duration_mul() { + assert_eq!(TimeDelta::zero() * i32::MAX, TimeDelta::zero()); + assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero()); + assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero()); + assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1)); + assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::seconds(1)); + assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::seconds(1)); + assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::seconds(1)); + assert_eq!( + TimeDelta::nanoseconds(30) * 333_333_333, + TimeDelta::seconds(10) - TimeDelta::nanoseconds(10) + ); + assert_eq!( + (TimeDelta::nanoseconds(1) + TimeDelta::seconds(1) + TimeDelta::days(1)) * 3, + TimeDelta::nanoseconds(3) + TimeDelta::seconds(3) + TimeDelta::days(3) + ); + assert_eq!(TimeDelta::milliseconds(1500) * -2, TimeDelta::seconds(-3)); + assert_eq!(TimeDelta::milliseconds(-1500) * 2, TimeDelta::seconds(-3)); + } + + #[test] + fn test_duration_div() { + assert_eq!(TimeDelta::zero() / i32::MAX, TimeDelta::zero()); + assert_eq!(TimeDelta::zero() / i32::MIN, TimeDelta::zero()); + assert_eq!(TimeDelta::nanoseconds(123_456_789) / 1, TimeDelta::nanoseconds(123_456_789)); + assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789)); + assert_eq!(-TimeDelta::nanoseconds(123_456_789) / -1, TimeDelta::nanoseconds(123_456_789)); + assert_eq!(-TimeDelta::nanoseconds(123_456_789) / 1, -TimeDelta::nanoseconds(123_456_789)); + assert_eq!(TimeDelta::seconds(1) / 3, TimeDelta::nanoseconds(333_333_333)); + assert_eq!(TimeDelta::seconds(4) / 3, TimeDelta::nanoseconds(1_333_333_333)); + assert_eq!(TimeDelta::seconds(-1) / 2, TimeDelta::milliseconds(-500)); + assert_eq!(TimeDelta::seconds(1) / -2, TimeDelta::milliseconds(-500)); + assert_eq!(TimeDelta::seconds(-1) / -2, TimeDelta::milliseconds(500)); + assert_eq!(TimeDelta::seconds(-4) / 3, TimeDelta::nanoseconds(-1_333_333_333)); + assert_eq!(TimeDelta::seconds(-4) / -3, TimeDelta::nanoseconds(1_333_333_333)); + } + + #[test] + fn test_duration_sum() { + let duration_list_1 = [TimeDelta::zero(), TimeDelta::seconds(1)]; + let sum_1: TimeDelta = duration_list_1.iter().sum(); + assert_eq!(sum_1, TimeDelta::seconds(1)); + + let duration_list_2 = [ + TimeDelta::zero(), + TimeDelta::seconds(1), + TimeDelta::seconds(6), + TimeDelta::seconds(10), + ]; + let sum_2: TimeDelta = duration_list_2.iter().sum(); + assert_eq!(sum_2, TimeDelta::seconds(17)); + + let duration_arr = [ + TimeDelta::zero(), + TimeDelta::seconds(1), + TimeDelta::seconds(6), + TimeDelta::seconds(10), + ]; + let sum_3: TimeDelta = duration_arr.into_iter().sum(); + assert_eq!(sum_3, TimeDelta::seconds(17)); + } + + #[test] + fn test_duration_fmt() { + assert_eq!(TimeDelta::zero().to_string(), "PT0S"); + assert_eq!(TimeDelta::days(42).to_string(), "P42D"); + assert_eq!(TimeDelta::days(-42).to_string(), "-P42D"); + assert_eq!(TimeDelta::seconds(42).to_string(), "PT42S"); + assert_eq!(TimeDelta::milliseconds(42).to_string(), "PT0.042S"); + assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S"); + assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S"); + assert_eq!((TimeDelta::days(7) + TimeDelta::milliseconds(6543)).to_string(), "P7DT6.543S"); + assert_eq!(TimeDelta::seconds(-86_401).to_string(), "-P1DT1S"); + assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S"); + + // the format specifier should have no effect on `TimeDelta` + assert_eq!( + format!("{:30}", TimeDelta::days(1) + TimeDelta::milliseconds(2345)), + "P1DT2.345S" + ); + } + + #[test] + fn test_to_std() { + assert_eq!(TimeDelta::seconds(1).to_std(), Ok(Duration::new(1, 0))); + assert_eq!(TimeDelta::seconds(86_401).to_std(), Ok(Duration::new(86_401, 0))); + assert_eq!(TimeDelta::milliseconds(123).to_std(), Ok(Duration::new(0, 123_000_000))); + assert_eq!(TimeDelta::milliseconds(123_765).to_std(), Ok(Duration::new(123, 765_000_000))); + assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777))); + assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000))); + assert_eq!(TimeDelta::seconds(-1).to_std(), Err(OutOfRangeError(()))); + assert_eq!(TimeDelta::milliseconds(-1).to_std(), Err(OutOfRangeError(()))); + } + + #[test] + fn test_from_std() { + assert_eq!(Ok(TimeDelta::seconds(1)), TimeDelta::from_std(Duration::new(1, 0))); + assert_eq!(Ok(TimeDelta::seconds(86_401)), TimeDelta::from_std(Duration::new(86_401, 0))); + assert_eq!( + Ok(TimeDelta::milliseconds(123)), + TimeDelta::from_std(Duration::new(0, 123_000_000)) + ); + assert_eq!( + Ok(TimeDelta::milliseconds(123_765)), + TimeDelta::from_std(Duration::new(123, 765_000_000)) + ); + assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777))); + assert_eq!(Ok(MAX), TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_000))); + assert_eq!( + TimeDelta::from_std(Duration::new(9_223_372_036_854_776, 0)), + Err(OutOfRangeError(())) + ); + assert_eq!( + TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_001)), + Err(OutOfRangeError(())) + ); + } + + #[test] + fn test_duration_const() { + const ONE_WEEK: TimeDelta = TimeDelta::weeks(1); + const ONE_DAY: TimeDelta = TimeDelta::days(1); + const ONE_HOUR: TimeDelta = TimeDelta::hours(1); + const ONE_MINUTE: TimeDelta = TimeDelta::minutes(1); + const ONE_SECOND: TimeDelta = TimeDelta::seconds(1); + const ONE_MILLI: TimeDelta = TimeDelta::milliseconds(1); + const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1); + const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1); + let combo: TimeDelta = ONE_WEEK + + ONE_DAY + + ONE_HOUR + + ONE_MINUTE + + ONE_SECOND + + ONE_MILLI + + ONE_MICRO + + ONE_NANO; + + assert!(ONE_WEEK != TimeDelta::zero()); + assert!(ONE_DAY != TimeDelta::zero()); + assert!(ONE_HOUR != TimeDelta::zero()); + assert!(ONE_MINUTE != TimeDelta::zero()); + assert!(ONE_SECOND != TimeDelta::zero()); + assert!(ONE_MILLI != TimeDelta::zero()); + assert!(ONE_MICRO != TimeDelta::zero()); + assert!(ONE_NANO != TimeDelta::zero()); + assert_eq!( + combo, + TimeDelta::seconds(86400 * 7 + 86400 + 3600 + 60 + 1) + + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000) + ); + } + + #[test] + #[cfg(feature = "rkyv-validation")] + fn test_rkyv_validation() { + let duration = TimeDelta::seconds(1); + let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap(); + assert_eq!(rkyv::from_bytes::(&bytes).unwrap(), duration); + } +} diff --git a/src/traits.rs b/src/traits.rs index 1094bd822b..0018a7d9bd 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -330,7 +330,7 @@ pub trait Timelike: Sized { #[cfg(test)] mod tests { use super::Datelike; - use crate::{Duration, NaiveDate}; + use crate::{NaiveDate, TimeDelta}; /// Tests `Datelike::num_days_from_ce` against an alternative implementation. /// @@ -377,7 +377,7 @@ mod tests { "on {:?}", jan1_year ); - let mid_year = jan1_year + Duration::days(133); + let mid_year = jan1_year + TimeDelta::days(133); assert_eq!( mid_year.num_days_from_ce(), num_days_from_ce(&mid_year), diff --git a/tests/dateutils.rs b/tests/dateutils.rs index 8d3ce9c102..cf3d908a4b 100644 --- a/tests/dateutils.rs +++ b/tests/dateutils.rs @@ -94,7 +94,7 @@ fn try_verify_against_date_command() { let end = NaiveDate::from_ymd_opt(*year + 1, 1, 1).unwrap().and_time(NaiveTime::MIN); while date <= end { verify_against_date_command_local(DATE_PATH, date); - date += chrono::Duration::hours(1); + date += chrono::TimeDelta::hours(1); } })); } @@ -157,6 +157,6 @@ fn try_verify_against_date_command_format() { let mut date = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_opt(12, 11, 13).unwrap(); while date.year() < 2008 { verify_against_date_command_format_local(DATE_PATH, date); - date += chrono::Duration::days(55); + date += chrono::TimeDelta::days(55); } } diff --git a/tests/wasm.rs b/tests/wasm.rs index 28eaacd0d5..6937da9f71 100644 --- a/tests/wasm.rs +++ b/tests/wasm.rs @@ -25,7 +25,7 @@ fn now() { let actual = NaiveDateTime::parse_from_str(&now, "%s").unwrap().and_utc(); let diff = utc - actual; assert!( - diff < chrono::Duration::minutes(5), + diff < chrono::TimeDelta::minutes(5), "expected {} - {} == {} < 5m (env var: {})", utc, actual,