From 05c808fcc4ee5e68e5f742276143bd0991e96ebf Mon Sep 17 00:00:00 2001 From: Eric Sheppard Date: Sat, 13 Aug 2022 21:27:06 +1000 Subject: [PATCH] add `TimeDelta` type which implements infallible conversion with `core::time::Duration` readme updates fix broken function name remove wayward install-cross fix broken function name - v2 --- Cargo.toml | 4 +- README.md | 45 +-- ci/github.sh | 8 +- src/date.rs | 116 ++++-- src/datetime/mod.rs | 91 +++-- src/datetime/tests.rs | 48 ++- src/duration.rs | 724 +++++++++++++++++++++++++++++++++++ src/format/parsed.rs | 11 +- src/lib.rs | 61 ++- src/naive/date.rs | 257 +++++++------ src/naive/datetime/mod.rs | 237 +++++++----- src/naive/datetime/tests.rs | 46 +-- src/naive/time/mod.rs | 304 +++++++++------ src/naive/time/tests.rs | 98 +++-- src/offset/fixed.rs | 6 +- src/offset/local/mod.rs | 12 +- src/oldtime.rs | 744 ------------------------------------ src/round.rs | 225 +++++------ src/traits.rs | 4 +- 19 files changed, 1605 insertions(+), 1436 deletions(-) create mode 100644 src/duration.rs delete mode 100644 src/oldtime.rs diff --git a/Cargo.toml b/Cargo.toml index 59abf99af3..2771009be5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,19 +20,17 @@ appveyor = { repository = "chronotope/chrono" } name = "chrono" [features] -default = ["clock", "std", "oldtime", "wasmbind"] +default = ["clock", "std", "wasmbind"] alloc = [] libc = [] std = [] clock = ["std", "winapi", "iana-time-zone"] -oldtime = ["time"] wasmbind = ["wasm-bindgen", "js-sys"] unstable-locales = ["pure-rust-locales", "alloc"] __internal_bench = ["criterion"] __doctest = [] [dependencies] -time = { version = "0.1.43", optional = true } num-integer = { version = "0.1.36", default-features = false } num-traits = { version = "0.2", default-features = false } rustc-serialize = { version = "0.3.20", optional = true } diff --git a/README.md b/README.md index fa7e289de5..f40865f325 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,6 @@ [gitter-image]: https://badges.gitter.im/chrono-rs/chrono.svg [gitter]: https://gitter.im/chrono-rs/chrono -It aims to be a feature-complete superset of -the [time](https://github.com/rust-lang-deprecated/time) library. -In particular, - * Chrono strictly adheres to ISO 8601. * Chrono is timezone-aware by default, with separate timezone-naive types. * Chrono is space-optimal and (while not being the primary goal) reasonably efficient. @@ -74,32 +70,17 @@ See the [cargo docs][] for examples of specifying features. ## Overview -### Duration +### TimeDelta -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`. +Chrono currently uses its own [`TimeDelta`] type to represent the magnitude +of a time span. This is seperate from the [`Duration`] type in the `std`/`core` library as it +supports negative and positive durations. This type can be converted losslessly from [`Duration`] +but when converting into a [`Duration`] you must take the absolute value. -Note that this is an "accurate" duration represented as seconds and +Note that this is an "accurate" TimeDelta represented as seconds and nanoseconds and does not represent "nominal" components such as days or -months. - -When the `oldtime` feature is enabled, [`Duration`] is an alias for the -[`time::Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) -type from v0.1 of the time crate. time v0.1 is deprecated, so new code -should disable the `oldtime` feature and use the `chrono::Duration` type -instead. The `oldtime` feature is enabled by default for backwards -compatibility, but future versions of Chrono are likely to remove the -feature entirely. - -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) -methods. +months. These are supported via the [`NaiveDate::succ`] and [`NaiveDate::pred`] functions +as well as the [`Months`] data type. ### Date and Time @@ -184,7 +165,7 @@ The following illustrates most supported operations to the date and time: ```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(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 324310806); @@ -211,11 +192,11 @@ assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November // arithmetic operations let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10); let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8); -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.ymd(1970, 1, 1).and_hms(0, 0, 0) + 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.ymd(1970, 1, 1).and_hms(0, 0, 0) + TimeDelta::seconds(1_000_000_000), Utc.ymd(2001, 9, 9).and_hms(1, 46, 40)); -assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000), +assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - TimeDelta::seconds(1_000_000_000), Utc.ymd(1938, 4, 24).and_hms(22, 13, 20)); ``` diff --git a/ci/github.sh b/ci/github.sh index 3c9ffb17a6..6287b812a6 100755 --- a/ci/github.sh +++ b/ci/github.sh @@ -8,7 +8,7 @@ source "${BASH_SOURCE[0]%/*}/_shlib.sh" TEST_TZS=(ACST-9:30 EST4 UTC0 Asia/Katmandu) FEATURES=(std serde clock "alloc serde" unstable-locales) CHECK_FEATURES=(alloc "std unstable-locales" "serde clock" "clock unstable-locales") -RUST_132_FEATURES=(rustc-serialize serde) +RUST_136_FEATURES=(rustc-serialize serde) main() { if [[ "$*" =~ "-h" ]]; then @@ -52,7 +52,7 @@ meaningful in the github actions feature matrix UI. test_regular UTC0 fi elif [[ ${RUST_VERSION:-} == 1.38.0 ]]; then - test_132 + test_138 else echo "ERROR: didn't run any tests" exit 1 @@ -82,9 +82,9 @@ check_combinatoric() { done } -test_132() { +test_138() { runv cargo build --color=always - for feature in "${RUST_132_FEATURES[@]}"; do + for feature in "${RUST_136_FEATURES[@]}"; do runt cargo build --features "$feature" --color=always done } diff --git a/src/date.rs b/src/date.rs index ef409ef7cd..dfec58f9be 100644 --- a/src/date.rs +++ b/src/date.rs @@ -7,6 +7,7 @@ use core::borrow::Borrow; use core::cmp::Ordering; use core::ops::{Add, AddAssign, Sub, SubAssign}; +use core::time::Duration; use core::{fmt, hash}; #[cfg(feature = "rkyv")] @@ -18,8 +19,8 @@ use crate::format::Locale; use crate::format::{DelayedFormat, Item, StrftimeItems}; use crate::naive::{IsoWeek, NaiveDate, NaiveTime}; use crate::offset::{TimeZone, Utc}; -use crate::oldtime::Duration as OldDuration; use crate::DateTime; +use crate::TimeDelta; use crate::{Datelike, Weekday}; /// ISO 8601 calendar date with time zone. @@ -52,7 +53,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. #[derive(Clone)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] pub struct Date { @@ -236,31 +237,31 @@ 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] - 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] - 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] - 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) } @@ -479,43 +480,80 @@ 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 Add for Date { + type Output = Date; + + #[inline] + fn add(self, rhs: Duration) -> Date { + self.checked_add_signed(rhs.into()).expect("`Date + core::time::Duration` 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 AddAssign for Date { + #[inline] + fn add_assign(&mut self, rhs: Duration) { + self.date = self + .date + .checked_add_signed(rhs.into()) + .expect("`Date + core::time::Duration` overflowed"); + } +} + +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 Sub for Date { + type Output = Date; + + #[inline] + fn sub(self, rhs: Duration) -> Date { + self.checked_sub_signed(rhs.into()).expect("`Date - core::time::Duration` overflowed") + } +} + +impl SubAssign for Date { + #[inline] + fn sub_assign(&mut self, rhs: TimeDelta) { + self.date = self.date.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: Duration) { + self.date = self + .date + .checked_sub_signed(rhs.into()) + .expect("`Date - core::time::Duration` 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) } } @@ -539,7 +577,7 @@ where mod tests { use super::Date; - use crate::oldtime::Duration; + use crate::TimeDelta; use crate::{FixedOffset, NaiveDate, Utc}; #[cfg(feature = "clock")] @@ -551,15 +589,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); } @@ -569,20 +607,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(60 * 60); 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(2 * 60 * 60); 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] @@ -593,8 +631,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] @@ -603,20 +641,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(60 * 60); 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(2 * 60 * 60); 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] @@ -627,7 +665,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 0907b2a6c0..c95aa49092 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -12,6 +12,7 @@ use alloc::string::{String, ToString}; use core::borrow::Borrow; use core::cmp::Ordering; use core::ops::{Add, AddAssign, Sub, SubAssign}; +use core::time::Duration; use core::{fmt, hash, str}; #[cfg(feature = "std")] use std::string::ToString; @@ -28,8 +29,8 @@ use crate::naive::{IsoWeek, NaiveDate, NaiveDateTime, NaiveTime}; #[cfg(feature = "clock")] use crate::offset::Local; use crate::offset::{FixedOffset, Offset, TimeZone, Utc}; -use crate::oldtime::Duration as OldDuration; use crate::Date; +use crate::TimeDelta; use crate::{Datelike, Timelike, Weekday}; #[cfg(feature = "rkyv")] @@ -319,21 +320,22 @@ impl DateTime { tz.from_utc_datetime(&self.datetime) } - /// Adds given `Duration` to the current date and time. + /// Adds given `TimeDelta` to the current date and time. /// /// Returns `None` when it will result in overflow. #[inline] - 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)) } - /// Subtracts given `Duration` from the current date and time. + /// Subtracts given `TimeDelta` from the current date and time. /// /// Returns `None` when it will result in overflow. #[inline] - 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)) @@ -342,7 +344,7 @@ impl DateTime { /// Subtracts another `DateTime` from the current date and time. /// This does not overflow or underflow at all. #[inline] - pub fn signed_duration_since(self, rhs: DateTime) -> OldDuration { + pub fn signed_duration_since(self, rhs: DateTime) -> TimeDelta { self.datetime.signed_duration_since(rhs.datetime) } @@ -850,49 +852,91 @@ impl hash::Hash for DateTime { } } -impl Add for DateTime { +impl Add for DateTime { + type Output = DateTime; + + #[inline] + fn add(self, rhs: TimeDelta) -> DateTime { + self.checked_add_signed(rhs).expect("`DateTime + TimeDelta` overflowed") + } +} + +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: Duration) -> DateTime { + self.checked_add_signed(rhs.into()).expect("`DateTime + core::timeDuration` overflowed") } } -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); + } +} + +impl AddAssign for DateTime { + #[inline] + fn add_assign(&mut self, rhs: Duration) { + let datetime = self + .datetime + .checked_add_signed(rhs.into()) + .expect("`DateTime + core::timeDuration` overflowed"); let tz = self.timezone(); *self = tz.from_utc_datetime(&datetime); } } -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") } } -impl SubAssign for DateTime { +impl Sub for DateTime { + type Output = DateTime; + + #[inline] + fn sub(self, rhs: Duration) -> DateTime { + self.checked_sub_signed(rhs.into()).expect("`DateTime - core::timeDuration` overflowed") + } +} + +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) + } +} + +impl SubAssign for DateTime { + #[inline] + fn sub_assign(&mut self, rhs: Duration) { + let datetime = self + .datetime + .checked_sub_signed(rhs.into()) + .expect("`DateTime - core::timeDuration` overflowed"); let tz = self.timezone(); *self = tz.from_utc_datetime(&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) } } @@ -981,15 +1025,16 @@ impl From for DateTime { #[cfg(any(feature = "std", test))] impl From> for SystemTime { fn from(dt: DateTime) -> SystemTime { - use std::time::Duration; + use std::convert::TryFrom; let sec = dt.timestamp(); let nsec = dt.timestamp_subsec_nanos(); if sec < 0 { // unlikely but should be handled - UNIX_EPOCH - Duration::new(-sec as u64, 0) + Duration::new(0, nsec) + UNIX_EPOCH - core::time::Duration::new(u64::try_from(i128::from(sec).abs()).unwrap(), 0) + + core::time::Duration::new(0, nsec) } else { - UNIX_EPOCH + Duration::new(sec as u64, nsec) + UNIX_EPOCH + core::time::Duration::new(u64::try_from(sec).unwrap(), nsec) } } } diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index d9b11757c8..8734511da2 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -5,9 +5,9 @@ use crate::naive::{NaiveDate, NaiveTime}; #[cfg(feature = "clock")] use crate::offset::Local; use crate::offset::{FixedOffset, TimeZone, Utc}; -use crate::oldtime::Duration; #[cfg(feature = "clock")] use crate::Datelike; +use crate::TimeDelta; #[test] fn test_datetime_offset() { @@ -38,10 +38,10 @@ fn test_datetime_offset() { let dt = Utc.ymd(2014, 5, 6).and_hms(7, 8, 9); assert_eq!(dt, edt.ymd(2014, 5, 6).and_hms(3, 8, 9)); - assert_eq!(dt + Duration::seconds(3600 + 60 + 1), Utc.ymd(2014, 5, 6).and_hms(8, 9, 10)); + assert_eq!(dt + TimeDelta::seconds(3600 + 60 + 1), Utc.ymd(2014, 5, 6).and_hms(8, 9, 10)); assert_eq!( dt.signed_duration_since(edt.ymd(2014, 5, 6).and_hms(10, 11, 12)), - Duration::seconds(-7 * 3600 - 3 * 60 - 3) + TimeDelta::seconds(-7 * 3600 - 3 * 60 - 3) ); assert_eq!(*Utc.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Utc); @@ -283,19 +283,17 @@ fn test_subsecond_part() { #[test] #[cfg(not(target_os = "windows"))] fn test_from_system_time() { - use std::time::Duration; - let epoch = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0); let nanos = 999_999_999; // SystemTime -> DateTime assert_eq!(DateTime::::from(UNIX_EPOCH), epoch); assert_eq!( - DateTime::::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)), + DateTime::::from(UNIX_EPOCH + core::time::Duration::new(999_999_999, nanos)), Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos) ); assert_eq!( - DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), + DateTime::::from(UNIX_EPOCH - core::time::Duration::new(999_999_999, nanos)), Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1) ); @@ -303,11 +301,11 @@ fn test_from_system_time() { assert_eq!(SystemTime::from(epoch), UNIX_EPOCH); assert_eq!( SystemTime::from(Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos)), - UNIX_EPOCH + Duration::new(999_999_999, nanos) + UNIX_EPOCH + core::time::Duration::new(999_999_999, nanos) ); assert_eq!( SystemTime::from(Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1)), - UNIX_EPOCH - Duration::new(999_999_999, 999_999_999) + UNIX_EPOCH - core::time::Duration::new(999_999_999, 999_999_999) ); // DateTime -> SystemTime (via `with_timezone`) @@ -322,7 +320,7 @@ fn test_from_system_time() { #[test] #[cfg(target_os = "windows")] fn test_from_system_time() { - use std::time::Duration; + use core::time::Duration; let nanos = 999_999_000; @@ -415,15 +413,15 @@ fn test_years_elapsed() { 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); } @@ -433,20 +431,20 @@ fn test_datetime_add_assign() { let datetime = DateTime::::from_utc(naivedatetime, Utc); let mut datetime_add = datetime; - datetime_add += Duration::seconds(60); - assert_eq!(datetime_add, datetime + Duration::seconds(60)); + datetime_add += TimeDelta::seconds(60); + assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); let timezone = FixedOffset::east(60 * 60); let datetime = datetime.with_timezone(&timezone); let datetime_add = datetime_add.with_timezone(&timezone); - assert_eq!(datetime_add, datetime + Duration::seconds(60)); + assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); let timezone = FixedOffset::west(2 * 60 * 60); let datetime = datetime.with_timezone(&timezone); let datetime_add = datetime_add.with_timezone(&timezone); - assert_eq!(datetime_add, datetime + Duration::seconds(60)); + assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); } #[test] @@ -459,8 +457,8 @@ fn test_datetime_add_assign_local() { // ensure we cross a DST transition for i in 1..=365 { - datetime_add += Duration::days(1); - assert_eq!(datetime_add, datetime + Duration::days(i)) + datetime_add += TimeDelta::days(1); + assert_eq!(datetime_add, datetime + TimeDelta::days(i)) } } @@ -470,20 +468,20 @@ fn test_datetime_sub_assign() { let datetime = DateTime::::from_utc(naivedatetime, Utc); let mut datetime_sub = datetime; - datetime_sub -= Duration::minutes(90); - assert_eq!(datetime_sub, datetime - Duration::minutes(90)); + datetime_sub -= TimeDelta::minutes(90); + assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); let timezone = FixedOffset::east(60 * 60); let datetime = datetime.with_timezone(&timezone); let datetime_sub = datetime_sub.with_timezone(&timezone); - assert_eq!(datetime_sub, datetime - Duration::minutes(90)); + assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); let timezone = FixedOffset::west(2 * 60 * 60); let datetime = datetime.with_timezone(&timezone); let datetime_sub = datetime_sub.with_timezone(&timezone); - assert_eq!(datetime_sub, datetime - Duration::minutes(90)); + assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); } #[test] @@ -496,7 +494,7 @@ fn test_datetime_sub_assign_local() { // ensure we cross a DST transition for i in 1..=365 { - datetime_sub -= Duration::days(1); - assert_eq!(datetime_sub, datetime - Duration::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 new file mode 100644 index 0000000000..349bf2eaa2 --- /dev/null +++ b/src/duration.rs @@ -0,0 +1,724 @@ +// 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::cmp::Ordering; +use core::convert::TryFrom; +use core::ops::{Add, Div, Mul, Neg, Sub}; +use core::time::Duration; +use core::{fmt, i64}; + +#[cfg(feature = "rkyv")] +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 seconds in a minute. +const SECS_PER_MINUTE: i64 = 60; +/// The number of seconds in an hour. +const SECS_PER_HOUR: i64 = 3_600; +/// The number of (non-leap) seconds in days. +const SECS_PER_DAY: i64 = 8_6400; +/// The number of (non-leap) seconds in a week. +const SECS_PER_WEEK: i64 = 604_800; + +const MAX_NANOS_NON_LEAP: u32 = 999_999_999; + +/// ISO 8601 time duration with nanosecond precision. +/// +/// This also allows for the negative duration; see individual methods for details. +#[derive(Clone, Copy, PartialOrd, Ord, Debug)] +#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] +pub enum TimeDelta { + /// A duration heading in forwards in time + Forwards(Duration), + /// A duration heading in backwards in time + Backwards(Duration), +} + +// const MAX_CORE_DURATION: Duration = MAX_SECONDS_DURATION + Duration::from_nanos(999_999_999); + +impl TimeDelta { + // has to be a function as Duration::new is only const on rust >= 1.53 + /// The minimum possible `Duration` (Equivalent to the max but heading backwards) + pub fn min() -> TimeDelta { + TimeDelta::Backwards(Duration::new( + #[allow(deprecated)] + core::u64::MAX, + MAX_NANOS_NON_LEAP, + )) + } + + /// A duration of zero length. + pub const ZERO: TimeDelta = TimeDelta::Forwards(Duration::from_nanos(0)); + + // has to be a function as Duration::new is only const on rust >= 1.53 + /// The maximum possible `Duration` + pub fn max() -> TimeDelta { + TimeDelta::Forwards(Duration::new( + #[allow(deprecated)] + core::u64::MAX, + MAX_NANOS_NON_LEAP, + )) + } +} + +impl PartialEq for TimeDelta { + fn eq(&self, other: &TimeDelta) -> bool { + match (self, other) { + (TimeDelta::Forwards(f1), TimeDelta::Forwards(f2)) => f1 == f2, + (TimeDelta::Backwards(b1), TimeDelta::Backwards(b2)) => b1 == b2, + (TimeDelta::Forwards(lhs), TimeDelta::Backwards(rhs)) + | (TimeDelta::Backwards(lhs), TimeDelta::Forwards(rhs)) => { + *lhs == Duration::from_nanos(0) && *rhs == Duration::from_nanos(0) + } + } + } +} + +impl Eq for TimeDelta {} + +impl From for TimeDelta { + fn from(s: Duration) -> Self { + TimeDelta::Forwards(s) + } +} + +impl TimeDelta { + /// Makes a new `Duration` with given number of weeks. + /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn weeks(weeks: i64) -> TimeDelta { + let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds"); + TimeDelta::seconds(secs) + } + + /// Makes a new `Duration` with given number of days. + /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn days(days: i64) -> TimeDelta { + let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds"); + TimeDelta::seconds(secs) + } + + /// Makes a new `Duration` with given number of hours. + /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn hours(hours: i64) -> TimeDelta { + let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); + TimeDelta::seconds(secs) + } + + /// Makes a new `Duration` with given number of minutes. + /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn minutes(minutes: i64) -> TimeDelta { + let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); + TimeDelta::seconds(secs) + } + + /// Makes a new `Duration` with given number of seconds. + /// Panics when the duration is more than `i64::MAX` seconds + /// or less than `i64::MIN` seconds. + #[inline] + pub fn seconds(seconds: i64) -> TimeDelta { + match seconds.cmp(&0) { + Ordering::Greater => { + TimeDelta::Forwards(Duration::from_secs(u64::try_from(seconds).unwrap())) + } + Ordering::Less => TimeDelta::Backwards(Duration::from_secs( + u64::try_from(i128::from(seconds).abs()).unwrap(), + )), + Ordering::Equal => TimeDelta::ZERO, + } + } + + /// Makes a new `Duration` with given number of milliseconds. + #[inline] + pub fn milliseconds(milliseconds: i64) -> TimeDelta { + match milliseconds.cmp(&0) { + Ordering::Greater => { + TimeDelta::Forwards(Duration::from_millis(u64::try_from(milliseconds).unwrap())) + } + Ordering::Less => TimeDelta::Backwards(Duration::from_millis( + u64::try_from(i128::from(milliseconds).abs()).unwrap(), + )), + Ordering::Equal => TimeDelta::ZERO, + } + } + + /// Makes a new `Duration` with given number of microseconds. + #[inline] + pub fn microseconds(microseconds: i64) -> TimeDelta { + match microseconds.cmp(&0) { + Ordering::Greater => { + TimeDelta::Forwards(Duration::from_micros(u64::try_from(microseconds).unwrap())) + } + Ordering::Less => TimeDelta::Backwards(Duration::from_micros( + u64::try_from(i128::from(microseconds).abs()).unwrap(), + )), + Ordering::Equal => TimeDelta::ZERO, + } + } + + /// Makes a new `Duration` with given number of nanoseconds. + #[inline] + pub fn nanoseconds(nanos: i64) -> TimeDelta { + match nanos.cmp(&0) { + Ordering::Greater => { + TimeDelta::Forwards(Duration::from_nanos(u64::try_from(nanos).unwrap())) + } + Ordering::Less => TimeDelta::Backwards(Duration::from_nanos( + u64::try_from(i128::from(nanos).abs()).unwrap(), + )), + Ordering::Equal => TimeDelta::ZERO, + } + } + + /// Returns the total number of whole weeks in the duration. + #[inline] + pub fn num_weeks(&self) -> i64 { + self.num_days() / 7 + } + + /// Returns the total number of whole days in the duration. + pub fn num_days(&self) -> i64 { + self.num_seconds() / SECS_PER_DAY + } + + /// Returns the total number of whole hours in the duration. + #[inline] + pub fn num_hours(&self) -> i64 { + self.num_seconds() / SECS_PER_HOUR + } + + /// Returns the total number of whole minutes in the duration. + #[inline] + pub fn num_minutes(&self) -> i64 { + self.num_seconds() / SECS_PER_MINUTE + } + + /// Returns the total number of whole seconds in the duration. + pub fn num_seconds(&self) -> i64 { + match self { + TimeDelta::Forwards(d) => i64::try_from(d.as_secs()).expect(""), + TimeDelta::Backwards(d) => -i64::try_from(d.as_secs()).expect(""), + } + } + + // /// Returns the number of nanoseconds such that + // /// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of + // /// nanoseconds in the duration. + // fn nanos_mod_sec(&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 fn num_milliseconds(&self) -> i64 { + match self { + TimeDelta::Forwards(d) => i64::try_from(d.as_millis()).expect(""), + TimeDelta::Backwards(d) => { + -i64::try_from(i128::try_from(d.as_millis()).expect("")).expect("") + } + } + } + + /// Returns the total number of whole microseconds in the duration, + /// or `None` on overflow (exceeding 2^63 microseconds in either direction). + pub fn num_microseconds(&self) -> Option { + match self { + TimeDelta::Forwards(d) => i64::try_from(d.as_micros()).ok(), + TimeDelta::Backwards(d) => { + i128::try_from(d.as_micros()).ok().map(Neg::neg).and_then(|n| i64::try_from(n).ok()) + } + } + } + + /// Returns the total number of whole nanoseconds in the duration, + /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction). + pub fn num_nanoseconds(&self) -> Option { + match self { + TimeDelta::Forwards(d) => i64::try_from(d.as_nanos()).ok(), + TimeDelta::Backwards(d) => { + i128::try_from(d.as_nanos()).ok().map(Neg::neg).and_then(|n| i64::try_from(n).ok()) + } + } + } + + /// Add two durations, returning `None` if overflow occurred. + pub fn checked_add(&self, rhs: &TimeDelta) -> Option { + match (self, rhs) { + (TimeDelta::Forwards(d), TimeDelta::Forwards(r)) => { + d.checked_add(*r).map(TimeDelta::Forwards) + } + (TimeDelta::Backwards(d), TimeDelta::Backwards(r)) => { + d.checked_add(*r).map(TimeDelta::Backwards) + } + (TimeDelta::Forwards(d), TimeDelta::Backwards(r)) if d > r => { + d.checked_sub(*r).map(TimeDelta::Forwards) + } + (TimeDelta::Forwards(d), TimeDelta::Backwards(r)) if d < r => { + r.checked_sub(*d).map(TimeDelta::Backwards) + } + (TimeDelta::Forwards(_), TimeDelta::Backwards(_)) => Some(TimeDelta::ZERO), + (TimeDelta::Backwards(d), TimeDelta::Forwards(r)) if d < r => { + r.checked_sub(*d).map(TimeDelta::Forwards) + } + (TimeDelta::Backwards(d), TimeDelta::Forwards(r)) if d > r => { + d.checked_sub(*r).map(TimeDelta::Backwards) + } + (TimeDelta::Backwards(_), TimeDelta::Forwards(_)) => Some(TimeDelta::ZERO), + } + } + + /// Subtract two durations, returning `None` if overflow occurred. + pub fn checked_sub(&self, rhs: &TimeDelta) -> Option { + self.checked_add(&Neg::neg(*rhs)) + } + + // /// The minimum possible `Duration`: `i64::MIN` milliseconds. + // #[inline] + // pub fn min_value() -> TimeDelta { + // TimeDelta::min() + // } + + // /// The maximum possible `Duration`: `i64::MAX` milliseconds. + // #[inline] + // pub fn max_value() -> TimeDelta { + // TimeDelta::max() + // } + + // /// A duration where the stored seconds and nanoseconds are equal to zero. + // #[inline] + // pub fn ZERO -> TimeDelta { + // TimeDelta::ZERO + // } + + /// Returns `true` if the duration equals `Duration::ZERO`. + #[inline] + pub fn is_zero(&self) -> bool { + match self { + TimeDelta::Forwards(d) => d.as_nanos() == 0, + TimeDelta::Backwards(d) => d.as_nanos() == 0, + } + } + + /// 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. + #[inline] + pub fn abs(&self) -> Duration { + match self { + TimeDelta::Forwards(d) => *d, + TimeDelta::Backwards(d) => *d, + } + } +} + +impl Neg for TimeDelta { + type Output = TimeDelta; + + #[inline] + fn neg(self) -> TimeDelta { + match self { + TimeDelta::Forwards(d) => TimeDelta::Backwards(d), + TimeDelta::Backwards(d) => TimeDelta::Forwards(d), + } + } +} + +impl Add for TimeDelta +where + T: Into, +{ + type Output = TimeDelta; + + fn add(self, rhs: T) -> TimeDelta { + self.checked_add(&rhs.into()).expect("") + } +} + +impl Sub for TimeDelta +where + T: Into, +{ + type Output = TimeDelta; + + fn sub(self, rhs: T) -> TimeDelta { + self.checked_sub(&rhs.into()).expect("") + } +} + +impl Mul for TimeDelta { + type Output = TimeDelta; + + fn mul(self, rhs: i32) -> TimeDelta { + match rhs.cmp(&0) { + Ordering::Equal => TimeDelta::ZERO, + Ordering::Greater => match self { + TimeDelta::Forwards(d) => TimeDelta::Forwards(d * u32::try_from(rhs).unwrap()), + TimeDelta::Backwards(d) => TimeDelta::Backwards(d * u32::try_from(rhs).unwrap()), + }, + Ordering::Less => match self { + TimeDelta::Forwards(d) => { + TimeDelta::Backwards(d * u32::try_from(i64::from(rhs).abs()).unwrap()) + } + TimeDelta::Backwards(d) => { + TimeDelta::Forwards(d * u32::try_from(i64::from(rhs).abs()).unwrap()) + } + }, + } + } +} + +impl Div for TimeDelta { + type Output = TimeDelta; + + fn div(self, rhs: i32) -> TimeDelta { + let quot = u32::try_from(i64::from(rhs).abs()).expect("u32(abs(i32)) will always succeed"); + match (self, rhs.cmp(&0)) { + (_, Ordering::Equal) => panic!("Divide by zero"), + (TimeDelta::Forwards(d), Ordering::Less) => TimeDelta::Backwards(d / quot), + (TimeDelta::Forwards(d), Ordering::Greater) => TimeDelta::Forwards(d / quot), + (TimeDelta::Backwards(d), Ordering::Less) => TimeDelta::Forwards(d / quot), + (TimeDelta::Backwards(d), Ordering::Greater) => TimeDelta::Backwards(d / quot), + } + } +} + +#[cfg(any(feature = "std", test))] +impl<'a> std::iter::Sum<&'a TimeDelta> for TimeDelta { + fn sum>(iter: I) -> TimeDelta { + iter.fold(TimeDelta::ZERO, |acc, x| acc + *x) + } +} + +#[cfg(any(feature = "std", test))] +impl std::iter::Sum for TimeDelta { + fn sum>(iter: I) -> TimeDelta { + iter.fold(TimeDelta::ZERO, |acc, x| acc + x) + } +} + +impl fmt::Display for TimeDelta { + /// 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 { + let dur = self.abs(); + + let days = dur.as_secs() / u64::try_from(SECS_PER_DAY).unwrap(); + let remaining_seconds = dur.as_secs() - days * u64::try_from(SECS_PER_DAY).unwrap(); + let hasdate = days != 0; + let hastime = (remaining_seconds != 0 || dur.subsec_nanos() != 0) || !hasdate; + + if let TimeDelta::Forwards(_) = self { + write!(f, "P")?; + } else { + // technically speaking, negative duration is not valid ISO 8601, + // so should we instead just base this on the abs value of the duration + // and remove this branch?? + write!(f, "-P")?; + } + + if hasdate { + write!(f, "{}D", days)?; + } + + if hastime { + if dur.subsec_nanos() == 0 { + write!(f, "T{}S", remaining_seconds)?; + } else if dur.subsec_nanos() % u32::try_from(NANOS_PER_MILLI).unwrap() == 0 { + write!( + f, + "T{}.{:03}S", + remaining_seconds, + dur.subsec_nanos() / u32::try_from(NANOS_PER_MILLI).unwrap() + )?; + } else if dur.subsec_nanos() % u32::try_from(NANOS_PER_MICRO).unwrap() == 0 { + write!( + f, + "T{}.{:06}S", + remaining_seconds, + dur.subsec_nanos() / u32::try_from(NANOS_PER_MICRO).unwrap() + )?; + } else { + write!(f, "T{}.{:09}S", remaining_seconds, dur.subsec_nanos())?; + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::{TimeDelta, MAX_NANOS_NON_LEAP}; + use std::time::Duration; + use std::{i32, i64}; + + #[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(86399) + TimeDelta::seconds(4), + TimeDelta::days(1) + TimeDelta::seconds(3) + ); + assert_eq!(TimeDelta::days(10) - TimeDelta::seconds(1000), TimeDelta::seconds(863000)); + assert_eq!(TimeDelta::days(10) - TimeDelta::seconds(1000000), TimeDelta::seconds(-136000)); + assert_eq!( + TimeDelta::days(2) + TimeDelta::seconds(86399) + TimeDelta::nanoseconds(1234567890), + TimeDelta::days(3) + TimeDelta::nanoseconds(234567890) + ); + assert_eq!(-TimeDelta::days(3), TimeDelta::days(-3)); + assert_eq!( + -(TimeDelta::days(3) + TimeDelta::seconds(70)), + TimeDelta::days(-4) + TimeDelta::seconds(86400 - 70) + ); + } + + #[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(86399).num_days(), 0); + assert_eq!(TimeDelta::seconds(86401).num_days(), 1); + assert_eq!(TimeDelta::seconds(-86399).num_days(), 0); + assert_eq!(TimeDelta::seconds(-86401).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_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); + assert_eq!(TimeDelta::milliseconds(i64::MAX).num_milliseconds(), i64::MAX); + assert_eq!(TimeDelta::milliseconds(i64::MIN + 1).num_milliseconds(), i64::MIN + 1); + // assert_eq!(MAX.num_milliseconds(), i64::MAX); + // assert_eq!(MIN.num_milliseconds(), i64::MIN); + } + + #[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)); + assert_eq!(TimeDelta::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX)); + assert_eq!(TimeDelta::microseconds(i64::MIN + 1).num_microseconds(), Some(i64::MIN + 1)); + assert_eq!(TimeDelta::max().num_microseconds(), None); + assert_eq!(TimeDelta::min().num_microseconds(), None); + + // 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::MIN / MICROS_PER_DAY).num_microseconds(), + Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY) + ); + assert_eq!(TimeDelta::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None); + assert_eq!(TimeDelta::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), 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)); + assert_eq!(TimeDelta::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX)); + assert_eq!(TimeDelta::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN)); + assert_eq!(TimeDelta::max().num_nanoseconds(), None); + assert_eq!(TimeDelta::min().num_nanoseconds(), None); + + // 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::MIN / NANOS_PER_DAY).num_nanoseconds(), + Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY) + ); + assert_eq!(TimeDelta::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None); + assert_eq!(TimeDelta::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None); + } + + #[test] + fn test_duration_checked_ops() { + assert_eq!( + TimeDelta::milliseconds(i64::MAX).checked_add(&TimeDelta::microseconds(999)), + Some(TimeDelta::milliseconds(i64::MAX - 1) + TimeDelta::microseconds(1999)) + ); + assert!(TimeDelta::max().checked_add(&TimeDelta::milliseconds(1)).is_none()); + + assert_eq!( + TimeDelta::milliseconds(i64::MIN + 1).checked_sub(&TimeDelta::milliseconds(1)), + Some(TimeDelta::milliseconds(i64::MIN)) + ); + // assert!(TimeDelta::milliseconds(i64::MIN).checked_sub(&TimeDelta::milliseconds(i64::MAX)).is_none()); + } + + #[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_vec = vec![ + TimeDelta::ZERO, + TimeDelta::seconds(1), + TimeDelta::seconds(6), + TimeDelta::seconds(10), + ]; + let sum_3: TimeDelta = duration_vec.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(-86401).to_string(), "-P1DT1S"); + assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S"); + + // the format specifier should have no effect on `Duration` + assert_eq!( + format!("{:30}", TimeDelta::days(1) + TimeDelta::milliseconds(2345)), + "P1DT2.345S" + ); + } + + #[test] + fn test_to_std() { + assert_eq!(TimeDelta::seconds(1).abs(), Duration::new(1, 0)); + assert_eq!(TimeDelta::seconds(86401).abs(), Duration::new(86401, 0)); + assert_eq!(TimeDelta::milliseconds(123).abs(), Duration::new(0, 123000000)); + assert_eq!(TimeDelta::milliseconds(123765).abs(), Duration::new(123, 765000000)); + assert_eq!(TimeDelta::nanoseconds(777).abs(), Duration::new(0, 777)); + assert_eq!( + TimeDelta::max().abs(), + Duration::new( + #[allow(deprecated)] + core::u64::MAX, + MAX_NANOS_NON_LEAP + ) + ); + assert_eq!(TimeDelta::seconds(-1).abs(), Duration::from_secs(1)); + assert_eq!(TimeDelta::milliseconds(-1).abs(), Duration::from_millis(1)); + } + + #[test] + fn test_from_std() { + assert_eq!((TimeDelta::seconds(1)), TimeDelta::from(Duration::new(1, 0))); + assert_eq!((TimeDelta::seconds(86401)), TimeDelta::from(Duration::new(86401, 0))); + assert_eq!((TimeDelta::milliseconds(123)), TimeDelta::from(Duration::new(0, 123000000))); + assert_eq!( + (TimeDelta::milliseconds(123765)), + TimeDelta::from(Duration::new(123, 765000000)) + ); + assert_eq!((TimeDelta::nanoseconds(777)), TimeDelta::from(Duration::new(0, 777))); + assert_eq!( + TimeDelta::max(), + TimeDelta::from(Duration::new( + #[allow(deprecated)] + core::u64::MAX, + MAX_NANOS_NON_LEAP + )) + ); + } +} diff --git a/src/format/parsed.rs b/src/format/parsed.rs index 32c6c7afbf..dd63e43337 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -10,8 +10,8 @@ use num_traits::ToPrimitive; use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone}; -use crate::oldtime::Duration as OldDuration; use crate::DateTime; +use crate::TimeDelta; use crate::Weekday; use crate::{Datelike, Timelike}; @@ -428,7 +428,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); @@ -462,7 +462,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); @@ -585,7 +585,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), @@ -629,7 +629,7 @@ impl Parsed { // this is used to prevent an overflow when calling FixedOffset::from_local_datetime datetime - .checked_sub_signed(OldDuration::seconds(i64::from(offset.local_minus_utc()))) + .checked_sub_signed(TimeDelta::seconds(i64::from(offset.local_minus_utc()))) .ok_or(OUT_OF_RANGE)?; match offset.from_local_datetime(&datetime) { @@ -1086,6 +1086,7 @@ mod tests { NaiveDate::from_ymd(0, 1, 1).signed_duration_since(NaiveDate::from_ymd(1970, 1, 1)); let min_days_from_year_1970 = NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd(1970, 1, 1)); + assert_eq!( parse!(timestamp: min_days_from_year_1970.num_seconds()), ymdhms(NaiveDate::MIN.year(), 1, 1, 0, 0, 0) diff --git a/src/lib.rs b/src/lib.rs index eed9b259ac..ba81244e96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,10 +3,6 @@ //! # Chrono: Date and Time for Rust //! -//! It aims to be a feature-complete superset of -//! the [time](https://github.com/rust-lang-deprecated/time) library. -//! In particular, -//! //! * Chrono strictly adheres to ISO 8601. //! * Chrono is timezone-aware by default, with separate timezone-naive types. //! * Chrono is space-optimal and (while not being the primary goal) reasonably efficient. @@ -61,32 +57,17 @@ //! //! ## Overview //! -//! ### Duration +//! ### TimeDelta //! -//! 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`. +//! Chrono currently uses its own [`TimeDelta`] type to represent the magnitude +//! of a time span. This is seperate from the [`Duration`] type in the `std`/`core` library as it +//! supports negative and positive durations. This type can be converted losslessly from [`Duration`] +//! but when converting into a [`Duration`] you must take the absolute value. //! -//! Note that this is an "accurate" duration represented as seconds and +//! Note that this is an "accurate" TimeDelta represented as seconds and //! nanoseconds and does not represent "nominal" components such as days or -//! months. -//! -//! When the `oldtime` feature is enabled, [`Duration`] is an alias for the -//! [`time::Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) -//! type from v0.1 of the time crate. time v0.1 is deprecated, so new code -//! should disable the `oldtime` feature and use the `chrono::Duration` type -//! instead. The `oldtime` feature is enabled by default for backwards -//! compatibility, but future versions of Chrono are likely to remove the -//! feature entirely. -//! -//! 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) -//! methods. +//! months. These are supported via the [`NaiveDate::succ`] and [`NaiveDate::pred`] functions +//! as well as the [`Months`] data type. //! //! ### Date and Time //! @@ -173,7 +154,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(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 324310806); @@ -200,11 +181,11 @@ //! // arithmetic operations //! let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10); //! let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8); -//! 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.ymd(1970, 1, 1).and_hms(0, 0, 0) + 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.ymd(1970, 1, 1).and_hms(0, 0, 0) + TimeDelta::seconds(1_000_000_000), //! Utc.ymd(2001, 9, 9).and_hms(1, 46, 40)); -//! assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000), +//! assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - TimeDelta::seconds(1_000_000_000), //! Utc.ymd(1938, 4, 24).and_hms(22, 13, 20)); //! ``` //! @@ -424,12 +405,8 @@ // keeps clippy happy in the meantime #![cfg_attr(feature = "rustc-serialize", allow(deprecated))] -#[cfg(feature = "oldtime")] -extern crate time as oldtime; -#[cfg(not(feature = "oldtime"))] -mod oldtime; -// this reexport is to aid the transition and should not be in the prelude! -pub use oldtime::Duration; +mod duration; +pub use duration::TimeDelta; #[cfg(feature = "__doctest")] #[cfg_attr(feature = "__doctest", cfg(doctest))] @@ -491,7 +468,7 @@ pub use offset::Local; pub use offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc}; mod round; -pub use round::{DurationRound, RoundingError, SubsecRound}; +pub use round::{RoundingError, SubsecRound, TimeDeltaRound}; mod weekday; pub use weekday::{ParseWeekdayError, Weekday}; @@ -520,6 +497,12 @@ pub mod serde { pub use super::datetime::serde::*; } +#[deprecated(since = "0.5.0", note = "Please use chrono::TimeDelta instead")] +/// This is a convenience alias for the `TimeDelta` type +/// of which previous versions were called `Duration`. +/// This will be removed in a future version. +pub type Duration = TimeDelta; + /// MSRV 1.42 #[cfg(test)] #[macro_export] diff --git a/src/naive/date.rs b/src/naive/date.rs index 0c17a79b4e..9e681852df 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -6,6 +6,7 @@ #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign}; +use core::time::Duration; use core::{fmt, str}; use num_integer::div_mod_floor; @@ -19,8 +20,8 @@ use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems}; use crate::format::{Item, Numeric, Pad}; use crate::month::Months; use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime}; -use crate::oldtime::Duration as OldDuration; -use crate::{Datelike, Duration, Weekday}; +use crate::TimeDelta; +use crate::{Datelike, Weekday}; use super::internals::{self, DateImpl, Mdf, Of, YearFlags}; use super::isoweek; @@ -76,7 +77,7 @@ impl NaiveWeek { let start = self.start.num_days_from_monday(); let end = self.date.weekday().num_days_from_monday(); let days = if start > end { 7 - start + end } else { end - start }; - self.date - Duration::days(days.into()) + self.date - TimeDelta::days(days.into()) } /// Returns a date representing the last day of the week. @@ -92,7 +93,7 @@ impl NaiveWeek { /// ``` #[inline] pub fn last_day(&self) -> NaiveDate { - self.first_day() + Duration::days(6) + self.first_day() + TimeDelta::days(6) } /// Returns a [`RangeInclusive`] representing the whole week bounded by @@ -194,7 +195,7 @@ fn test_date_bounds() { ); // 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!( @@ -1031,25 +1032,25 @@ impl NaiveDate { self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31)) } - /// Adds the `days` part of given `Duration` to the current date. + /// Adds the `days` part of given `TimeDelta` to the current date. /// /// Returns `None` when it will result in overflow. /// /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let d = NaiveDate::from_ymd(2015, 9, 5); - /// assert_eq!(d.checked_add_signed(Duration::days(40)), + /// assert_eq!(d.checked_add_signed(TimeDelta::days(40)), /// Some(NaiveDate::from_ymd(2015, 10, 15))); - /// assert_eq!(d.checked_add_signed(Duration::days(-40)), + /// assert_eq!(d.checked_add_signed(TimeDelta::days(-40)), /// Some(NaiveDate::from_ymd(2015, 7, 27))); - /// 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); /// ``` - pub fn checked_add_signed(self, rhs: OldDuration) -> Option { + pub fn checked_add_signed(self, rhs: TimeDelta) -> Option { let year = self.year(); let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); @@ -1062,25 +1063,25 @@ impl NaiveDate { NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)) } - /// Subtracts the `days` part of given `Duration` from the current date. + /// Subtracts the `days` part of given `TimeDelta` from the current date. /// /// Returns `None` when it will result in overflow. /// /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let d = NaiveDate::from_ymd(2015, 9, 5); - /// assert_eq!(d.checked_sub_signed(Duration::days(40)), + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(40)), /// Some(NaiveDate::from_ymd(2015, 7, 27))); - /// assert_eq!(d.checked_sub_signed(Duration::days(-40)), + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-40)), /// Some(NaiveDate::from_ymd(2015, 10, 15))); - /// 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); /// ``` - pub fn checked_sub_signed(self, rhs: OldDuration) -> Option { + pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option { let year = self.year(); let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); @@ -1094,35 +1095,35 @@ 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 = NaiveDate::from_ymd; /// 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)); /// ``` - pub fn signed_duration_since(self, rhs: NaiveDate) -> OldDuration { + pub 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 = i64::from(internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal())); let cycle2 = i64::from(internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal())); - OldDuration::days( + TimeDelta::days( (i64::from(year1_div_400) - i64::from(year2_div_400)) * 146_097 + (cycle1 - cycle2), ) } @@ -1619,8 +1620,8 @@ impl Datelike for NaiveDate { } } -/// An addition of `Duration` to `NaiveDate` discards the fractional days, -/// rounding to the closest integral number of days towards `Duration::zero()`. +/// An addition of `TimeDelta` to `NaiveDate` discards the fractional days, +/// rounding to the closest integral number of days towards `TimeDelta::ZERO`. /// /// Panics on underflow or overflow. /// Use [`NaiveDate::checked_add_signed`](#method.checked_add_signed) to detect that. @@ -1628,31 +1629,47 @@ impl Datelike for NaiveDate { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// -/// 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)); /// ``` -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") } } -impl AddAssign for NaiveDate { +impl Add for NaiveDate { + type Output = NaiveDate; + + #[inline] + fn add(self, rhs: Duration) -> NaiveDate { + self.checked_add_signed(rhs.into()).expect("`NaiveDate + core::time::Duration` overflowed") + } +} + +impl AddAssign for NaiveDate { + #[inline] + fn add_assign(&mut self, rhs: TimeDelta) { + *self = self.add(rhs); + } +} + +impl AddAssign for NaiveDate { #[inline] - fn add_assign(&mut self, rhs: OldDuration) { + fn add_assign(&mut self, rhs: Duration) { *self = self.add(rhs); } } @@ -1710,9 +1727,9 @@ impl Sub for NaiveDate { } } -/// A subtraction of `Duration` from `NaiveDate` discards the fractional days, -/// rounding to the closest integral number of days towards `Duration::zero()`. -/// It is the same as the addition with a negated `Duration`. +/// A subtraction of `TimeDelta` from `NaiveDate` discards the fractional days, +/// rounding to the closest integral number of days towards `TimeDelta::ZERO`. +/// It is the same as the addition with a negated `TimeDelta`. /// /// Panics on underflow or overflow. /// Use [`NaiveDate::checked_sub_signed`](#method.checked_sub_signed) to detect that. @@ -1720,40 +1737,56 @@ impl Sub for NaiveDate { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// -/// 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)); /// ``` -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") + } +} + +impl Sub for NaiveDate { + type Output = NaiveDate; + + #[inline] + fn sub(self, rhs: Duration) -> NaiveDate { + self.checked_sub_signed(rhs.into()).expect("`NaiveDate - core::time::Duration` overflowed") + } +} + +impl SubAssign for NaiveDate { + #[inline] + fn sub_assign(&mut self, rhs: TimeDelta) { + *self = self.sub(rhs); } } -impl SubAssign for NaiveDate { +impl SubAssign for NaiveDate { #[inline] - fn sub_assign(&mut self, rhs: OldDuration) { + fn sub_assign(&mut self, rhs: Duration) { *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). @@ -1761,23 +1794,23 @@ impl SubAssign for NaiveDate { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// -/// 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) } } @@ -1830,11 +1863,11 @@ impl Iterator for NaiveDateWeeksIterator { type Item = NaiveDate; fn next(&mut self) -> Option { - if NaiveDate::MAX - self.value < OldDuration::weeks(1) { + if NaiveDate::MAX - self.value < TimeDelta::weeks(1) { return None; } let current = self.value; - self.value = current + OldDuration::weeks(1); + self.value = current + TimeDelta::weeks(1); Some(current) } @@ -1848,11 +1881,11 @@ impl ExactSizeIterator for NaiveDateWeeksIterator {} impl DoubleEndedIterator for NaiveDateWeeksIterator { fn next_back(&mut self) -> Option { - if self.value - NaiveDate::MIN < OldDuration::weeks(1) { + if self.value - NaiveDate::MIN < TimeDelta::weeks(1) { return None; } let current = self.value; - self.value = current - OldDuration::weeks(1); + self.value = current - TimeDelta::weeks(1); Some(current) } } @@ -2148,7 +2181,7 @@ mod tests { use super::{ Months, NaiveDate, MAX_DAYS_FROM_YEAR_0, MAX_YEAR, MIN_DAYS_FROM_YEAR_0, MIN_YEAR, }; - use crate::oldtime::Duration; + use crate::TimeDelta; use crate::{Datelike, Weekday}; use std::{i32, u32}; @@ -2545,61 +2578,61 @@ 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(y1, m1, d1); let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd(y, m, d)); 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::days(i32::MAX.into()), 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::days(i32::MIN.into()), 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(y1, m1, d1); let rhs = NaiveDate::from_ymd(y2, m2, d2); 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] fn test_date_addassignment() { let ymd = NaiveDate::from_ymd; 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)); } @@ -2607,9 +2640,9 @@ mod tests { fn test_date_subassignment() { let ymd = NaiveDate::from_ymd; 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 7c60c41e30..b00914febf 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -6,6 +6,7 @@ #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::ops::{Add, AddAssign, Sub, SubAssign}; +use core::time::Duration; use core::{fmt, str}; use num_integer::div_mod_floor; @@ -18,7 +19,7 @@ use crate::format::DelayedFormat; use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems}; use crate::format::{Fixed, Item, Numeric, Pad}; use crate::naive::{IsoWeek, NaiveDate, NaiveTime}; -use crate::oldtime::Duration as OldDuration; +use crate::TimeDelta; use crate::{DateTime, Datelike, LocalResult, TimeZone, Timelike, Weekday}; #[cfg(feature = "rustc-serialize")] @@ -31,10 +32,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 TimeDelta 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; @@ -456,7 +457,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**, @@ -468,72 +469,72 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms(h, m, s); - /// 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(3, 5, 7))); /// /// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli); - /// 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(2016, 7, 8).and_hms(h, m, s); - /// 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 = NaiveDate::from_ymd; /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); /// 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(3, 5, 59, 300))); /// ``` - pub fn checked_add_signed(self, rhs: OldDuration) -> Option { + pub 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 = self.date.checked_add_signed(OldDuration::seconds(rhs))?; + let date = self.date.checked_add_signed(TimeDelta::seconds(rhs))?; Some(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**, @@ -545,64 +546,64 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms(h, m, s); - /// 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(3, 5, 7))); /// /// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli); - /// 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(2016, 7, 8).and_hms(h, m, s); - /// 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 = NaiveDate::from_ymd; /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); /// 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(3, 6, 0, 300))); /// ``` - pub fn checked_sub_signed(self, rhs: OldDuration) -> Option { + pub 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 = self.date.checked_sub_signed(OldDuration::seconds(rhs))?; + let date = self.date.checked_sub_signed(TimeDelta::seconds(rhs))?; Some(NaiveDateTime { date, time }) } @@ -618,33 +619,33 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate}; + /// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// /// let d = from_ymd(2016, 7, 8); /// assert_eq!(d.and_hms(3, 5, 7).signed_duration_since(d.and_hms(2, 4, 6)), - /// 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(0, 7, 6, 500).signed_duration_since(d0.and_hms(0, 0, 0)), - /// 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 = NaiveDate::from_ymd; /// let leap = from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); /// assert_eq!(leap.signed_duration_since(from_ymd(2015, 6, 30).and_hms(23, 0, 0)), - /// Duration::seconds(3600) + Duration::milliseconds(500)); + /// TimeDelta::seconds(3600) + TimeDelta::milliseconds(500)); /// assert_eq!(from_ymd(2015, 7, 1).and_hms(1, 0, 0).signed_duration_since(leap), - /// Duration::seconds(3600) - Duration::milliseconds(500)); + /// TimeDelta::seconds(3600) - TimeDelta::milliseconds(500)); /// ``` - pub fn signed_duration_since(self, rhs: NaiveDateTime) -> OldDuration { + pub fn signed_duration_since(self, rhs: NaiveDateTime) -> TimeDelta { self.date.signed_duration_since(rhs.date) + self.time.signed_duration_since(rhs.time) } @@ -1224,7 +1225,7 @@ impl Timelike for NaiveDateTime { } } -/// An addition of `Duration` to `NaiveDateTime` yields another `NaiveDateTime`. +/// An addition of `TimeDelta` to `NaiveDateTime` yields another `NaiveDateTime`. /// /// 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**, @@ -1237,60 +1238,77 @@ impl Timelike for NaiveDateTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms(h, m, s); -/// 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(3, 5, 7)); -/// 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(3, 5, 7)); /// /// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli); -/// 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 = NaiveDate::from_ymd; /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); /// 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(3, 5, 59, 300)); /// ``` -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") } } -impl AddAssign for NaiveDateTime { +impl Add for NaiveDateTime { + type Output = NaiveDateTime; + + #[inline] + fn add(self, rhs: Duration) -> NaiveDateTime { + self.checked_add_signed(rhs.into()) + .expect("`NaiveDateTime + core::time::Duration` overflowed") + } +} + +impl AddAssign for NaiveDateTime { + #[inline] + fn add_assign(&mut self, rhs: TimeDelta) { + *self = self.add(rhs); + } +} + +impl AddAssign for NaiveDateTime { #[inline] - fn add_assign(&mut self, rhs: OldDuration) { + fn add_assign(&mut self, rhs: Duration) { *self = self.add(rhs); } } -/// A subtraction of `Duration` from `NaiveDateTime` yields another `NaiveDateTime`. -/// It is the same as the addition with a negated `Duration`. +/// A subtraction of `TimeDelta` from `NaiveDateTime` yields another `NaiveDateTime`. +/// It is the same as the addition with a negated `TimeDelta`. /// /// 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**, @@ -1303,52 +1321,69 @@ impl AddAssign for NaiveDateTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms(h, m, s); -/// 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(3, 5, 7)); -/// 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(3, 5, 7)); /// /// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli); -/// 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 = NaiveDate::from_ymd; /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); /// 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(3, 6, 0, 300)); /// ``` -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") + } +} + +impl Sub for NaiveDateTime { + type Output = NaiveDateTime; + + #[inline] + fn sub(self, rhs: Duration) -> NaiveDateTime { + self.checked_sub_signed(rhs.into()) + .expect("`NaiveDateTime - core::time::Duration` overflowed") + } +} + +impl SubAssign for NaiveDateTime { + #[inline] + fn sub_assign(&mut self, rhs: TimeDelta) { + *self = self.sub(rhs); } } -impl SubAssign for NaiveDateTime { +impl SubAssign for NaiveDateTime { #[inline] - fn sub_assign(&mut self, rhs: OldDuration) { + fn sub_assign(&mut self, rhs: Duration) { *self = self.sub(rhs); } } @@ -1367,36 +1402,36 @@ impl SubAssign for NaiveDateTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDate}; +/// use chrono::{TimeDelta, NaiveDate}; /// /// let from_ymd = NaiveDate::from_ymd; /// /// let d = from_ymd(2016, 7, 8); -/// assert_eq!(d.and_hms(3, 5, 7) - d.and_hms(2, 4, 6), Duration::seconds(3600 + 60 + 1)); +/// assert_eq!(d.and_hms(3, 5, 7) - d.and_hms(2, 4, 6), 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(0, 7, 6, 500) - d0.and_hms(0, 0, 0), -/// 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 = NaiveDate::from_ymd; /// let leap = from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); /// assert_eq!(leap - from_ymd(2015, 6, 30).and_hms(23, 0, 0), -/// Duration::seconds(3600) + Duration::milliseconds(500)); +/// TimeDelta::seconds(3600) + TimeDelta::milliseconds(500)); /// assert_eq!(from_ymd(2015, 7, 1).and_hms(1, 0, 0) - 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 8efc46b19b..73c00c0578 100644 --- a/src/naive/datetime/tests.rs +++ b/src/naive/datetime/tests.rs @@ -1,6 +1,6 @@ use super::NaiveDateTime; use crate::naive::NaiveDate; -use crate::oldtime::Duration; +use crate::TimeDelta; use crate::{Datelike, FixedOffset, Utc}; use std::i64; @@ -21,7 +21,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: Duration, + rhs: TimeDelta, result: Option<(i32, u32, u32, u32, u32, u32)>, ) { let lhs = NaiveDate::from_ymd(y, m, d).and_hms(h, n, s); @@ -30,12 +30,12 @@ fn test_datetime_add() { assert_eq!(lhs.checked_sub_signed(-rhs), sum); } - check((2014, 5, 6, 7, 8, 9), Duration::seconds(3600 + 60 + 1), Some((2014, 5, 6, 8, 9, 10))); - check((2014, 5, 6, 7, 8, 9), Duration::seconds(-(3600 + 60 + 1)), Some((2014, 5, 6, 6, 7, 8))); - check((2014, 5, 6, 7, 8, 9), Duration::seconds(86399), Some((2014, 5, 7, 7, 8, 8))); - check((2014, 5, 6, 7, 8, 9), Duration::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9))); - check((2014, 5, 6, 7, 8, 9), Duration::seconds(-86_400 * 10), Some((2014, 4, 26, 7, 8, 9))); - check((2014, 5, 6, 7, 8, 9), Duration::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`. @@ -44,38 +44,38 @@ 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 + Duration::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 + Duration::seconds(86_400), None); - check((0, 1, 1, 0, 0, 0), Duration::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::days(i32::MAX.into()), None); let min_days_from_year_0 = NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd(0, 1, 1)); 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 - Duration::seconds(1), None); - check((0, 1, 1, 0, 0, 0), Duration::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(), None); } #[test] fn test_datetime_sub() { let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s); let since = NaiveDateTime::signed_duration_since; - assert_eq!(since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 9)), Duration::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)), - Duration::seconds(1) + TimeDelta::seconds(1) ); assert_eq!( since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)), - Duration::seconds(-1) + TimeDelta::seconds(-1) ); assert_eq!( since(ymdhms(2014, 5, 7, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)), - Duration::seconds(86399) + TimeDelta::seconds(86399) ); assert_eq!( since(ymdhms(2001, 9, 9, 1, 46, 39), ymdhms(1970, 1, 1, 0, 0, 0)), - Duration::seconds(999_999_999) + TimeDelta::seconds(999_999_999) ); } @@ -83,9 +83,9 @@ fn test_datetime_sub() { fn test_datetime_addassignment() { let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s); let mut date = ymdhms(2016, 10, 1, 10, 10, 10); - date += Duration::minutes(10_000_000); + date += TimeDelta::minutes(10_000_000); assert_eq!(date, ymdhms(2035, 10, 6, 20, 50, 10)); - date += Duration::days(10); + date += TimeDelta::days(10); assert_eq!(date, ymdhms(2035, 10, 16, 20, 50, 10)); } @@ -93,9 +93,9 @@ fn test_datetime_addassignment() { fn test_datetime_subassignment() { let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s); let mut date = ymdhms(2016, 10, 1, 10, 10, 10); - date -= Duration::minutes(10_000_000); + date -= TimeDelta::minutes(10_000_000); assert_eq!(date, ymdhms(1997, 9, 26, 23, 30, 10)); - date -= Duration::days(10); + date -= TimeDelta::days(10); assert_eq!(date, ymdhms(1997, 9, 16, 23, 30, 10)); } @@ -217,7 +217,7 @@ fn test_datetime_add_sub_invariant() { // issue #37 let base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0); let t = -946684799990000; - let time = base + Duration::microseconds(t); + let time = base + TimeDelta::microseconds(t); assert_eq!(t, time.signed_duration_since(base).num_microseconds().unwrap()); } diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index f882ccd454..1920bf86dc 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -5,7 +5,9 @@ #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; +use core::convert::TryFrom; use core::ops::{Add, AddAssign, Sub, SubAssign}; +use core::time::Duration; use core::{fmt, str}; use num_integer::div_mod_floor; @@ -16,7 +18,7 @@ use rkyv::{Archive, Deserialize, Serialize}; use crate::format::DelayedFormat; use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems}; use crate::format::{Fixed, Item, Numeric, Pad}; -use crate::oldtime::Duration as OldDuration; +use crate::TimeDelta; use crate::Timelike; #[cfg(feature = "rustc-serialize")] @@ -28,6 +30,8 @@ mod serde; #[cfg(test)] mod tests; +const SECOND_AS_NANOS: u128 = 1_000_000_000; + /// ISO 8601 time without timezone. /// Allows for the nanosecond precision and optional leap second representation. /// @@ -95,7 +99,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`. @@ -107,7 +111,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`. @@ -136,22 +140,22 @@ 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)` -/// for two positive durations. +/// `(Time + TimeDelta1) - TimeDelta2` no longer equals to `Time + (TimeDelta1 - TimeDelta2)` +/// for two positive TimeDeltas. /// -/// - 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, +/// - If you can assume that all TimeDeltas have the same sign, however, /// then the associativity holds: -/// `(Time + Duration1) + Duration2` equals to `Time + (Duration1 + Duration2)` -/// for two positive durations. +/// `(Time + TimeDelta1) + TimeDelta2` equals to `Time + (TimeDelta1 + TimeDelta2)` +/// for two positive TimeDeltas. /// /// ## Reading And Writing Leap Seconds /// @@ -517,53 +521,73 @@ impl NaiveTime { parsed.to_naive_time() } - /// Adds given `Duration` to the current time, + /// Adds given `TimeDelta` to the current time, /// and also returns the number of *seconds* /// in the integral number of days ignored from the addition. - /// (We cannot return `Duration` because it is subject to overflow or underflow.) + /// (We cannot return `TimeDelta` because it is subject to overflow or underflow.) /// /// # Example /// /// ``` - /// use chrono::{Duration, NaiveTime}; + /// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hms = NaiveTime::from_hms; /// - /// 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)); /// ``` - pub fn overflowing_add_signed(&self, mut rhs: OldDuration) -> (NaiveTime, i64) { + pub fn overflowing_add_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) { let mut secs = self.secs; let mut frac = self.frac; + // todo!("FIX THIS"); // check if `self` is a leap second and adding `rhs` would escape that leap second. // if it's the case, update `self` and `rhs` to involve no leap second; // otherwise the addition immediately finishes. - if frac >= 1_000_000_000 { - let rfrac = 2_000_000_000 - frac; - if rhs >= OldDuration::nanoseconds(i64::from(rfrac)) { - rhs = rhs - OldDuration::nanoseconds(i64::from(rfrac)); - secs += 1; - frac = 0; - } else if rhs < OldDuration::nanoseconds(-i64::from(frac)) { - rhs = rhs + OldDuration::nanoseconds(i64::from(frac)); - frac = 0; - } else { - frac = (i64::from(frac) + rhs.num_nanoseconds().unwrap()) as u32; - debug_assert!(frac < 2_000_000_000); - return (NaiveTime { secs, frac }, 0); + if u128::from(frac) >= SECOND_AS_NANOS { + match rhs { + // stays within the leap second + TimeDelta::Forwards(d) if d.as_nanos() + u128::from(frac) < 2 * SECOND_AS_NANOS => { + frac += u32::try_from(rhs.num_nanoseconds().unwrap()).unwrap(); + debug_assert!(frac < 2_000_000_000); + return (NaiveTime { secs, frac }, 0); + } + // stays within the leap second + // shouldn't overflow as frac is >= 1_000_000_000 + TimeDelta::Backwards(d) if d.as_nanos() <= u128::from(frac) - SECOND_AS_NANOS => { + frac -= u32::try_from(rhs.num_nanoseconds().unwrap().abs()).unwrap(); + debug_assert!(frac < 2_000_000_000); + return (NaiveTime { secs, frac }, 0); + } + + // leaves the leap second + // so normalise the NaiveTime to not be in a leap second + // but we also loose a whole second + // as the leap second consumes it + TimeDelta::Forwards(_) => { + frac -= u32::try_from(SECOND_AS_NANOS).unwrap(); + } + // leaves the leap second + // so normalise the NaiveTime to not be in a leap second + // here we have to increment the second by one so that once we subtract we + // end up in the right place. + TimeDelta::Backwards(_) => { + secs += 1; + frac -= u32::try_from(SECOND_AS_NANOS).unwrap(); + } } } debug_assert!(secs <= 86_400); debug_assert!(frac < 1_000_000_000); let rhssecs = rhs.num_seconds(); - let rhsfrac = (rhs - OldDuration::seconds(rhssecs)).num_nanoseconds().unwrap(); - debug_assert_eq!(OldDuration::seconds(rhssecs) + OldDuration::nanoseconds(rhsfrac), rhs); + + let rhsfrac = (rhs - TimeDelta::seconds(rhssecs)).num_nanoseconds().unwrap(); + debug_assert_eq!(TimeDelta::seconds(rhssecs) + TimeDelta::nanoseconds(rhsfrac), rhs); let rhssecsinday = rhssecs % 86_400; let mut morerhssecs = rhssecs - rhssecsinday; let rhssecs = rhssecsinday as i32; @@ -599,33 +623,33 @@ impl NaiveTime { (NaiveTime { secs: secs as u32, frac: frac as u32 }, morerhssecs) } - /// Subtracts given `Duration` from the current time, + /// Subtracts given `TimeDelta` from the current time, /// and also returns the number of *seconds* /// in the integral number of days ignored from the subtraction. - /// (We cannot return `Duration` because it is subject to overflow or underflow.) + /// (We cannot return `TimeDelta` because it is subject to overflow or underflow.) /// /// # Example /// /// ``` - /// use chrono::{Duration, NaiveTime}; + /// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hms = NaiveTime::from_hms; /// - /// 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] - pub fn overflowing_sub_signed(&self, rhs: OldDuration) -> (NaiveTime, i64) { + pub fn overflowing_sub_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) { let (time, rhs) = self.overflowing_add_signed(-rhs); (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), @@ -637,48 +661,48 @@ impl NaiveTime { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveTime}; + /// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hmsm = NaiveTime::from_hms_milli; /// 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 = NaiveTime::from_hms_milli; /// # 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)); /// ``` - pub fn signed_duration_since(self, rhs: NaiveTime) -> OldDuration { + pub fn signed_duration_since(self, rhs: NaiveTime) -> TimeDelta { // | | :leap| | | | | | | :leap| | // | | : | | | | | | | : | | // ----+----+-----*---+----+----+----+----+----+----+-------*-+----+---- @@ -713,7 +737,7 @@ impl NaiveTime { } }; - OldDuration::seconds(secs + adjust) + OldDuration::nanoseconds(frac) + TimeDelta::seconds(secs + adjust) + TimeDelta::nanoseconds(frac) } /// Formats the time with the specified formatting items. @@ -1013,7 +1037,7 @@ impl Timelike for NaiveTime { } } -/// An addition of `Duration` to `NaiveTime` wraps around and never overflows or underflows. +/// An addition of `TimeDelta` to `NaiveTime` wraps around and never overflows or underflows. /// In particular the addition ignores integral number of days. /// /// As a part of Chrono's [leap second handling](#leap-second-handling), @@ -1024,63 +1048,79 @@ impl Timelike for NaiveTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveTime}; +/// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hmsm = NaiveTime::from_hms_milli; /// -/// 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 = NaiveTime::from_hms_milli; -/// 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 = NaiveTime::from_hms_milli; /// 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)); /// ``` -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 } } -impl AddAssign for NaiveTime { +impl Add for NaiveTime { + type Output = NaiveTime; + #[inline] - fn add_assign(&mut self, rhs: OldDuration) { + fn add(self, rhs: Duration) -> NaiveTime { + self.overflowing_add_signed(rhs.into()).0 + } +} + +impl AddAssign for NaiveTime { + #[inline] + fn add_assign(&mut self, rhs: TimeDelta) { *self = self.add(rhs); } } -/// A subtraction of `Duration` from `NaiveTime` wraps around and never overflows or underflows. +impl AddAssign for NaiveTime { + #[inline] + fn add_assign(&mut self, rhs: Duration) { + *self = self.add(rhs); + } +} + +/// A subtraction of `TimeDelta` from `NaiveTime` wraps around and never overflows or underflows. /// In particular the addition ignores integral number of days. -/// It is the same as the addition with a negated `Duration`. +/// It is the same as the addition with a negated `TimeDelta`. /// /// As a part of Chrono's [leap second handling](#leap-second-handling), /// the addition assumes that **there is no leap second ever**, @@ -1090,57 +1130,73 @@ impl AddAssign for NaiveTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveTime}; +/// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hmsm = NaiveTime::from_hms_milli; /// -/// 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 = NaiveTime::from_hms_milli; -/// 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 = NaiveTime::from_hms_milli; /// 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)); /// ``` -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 } } -impl SubAssign for NaiveTime { +impl Sub for NaiveTime { + type Output = NaiveTime; + + #[inline] + fn sub(self, rhs: Duration) -> NaiveTime { + self.overflowing_sub_signed(rhs.into()).0 + } +} + +impl SubAssign for NaiveTime { + #[inline] + fn sub_assign(&mut self, rhs: TimeDelta) { + *self = self.sub(rhs); + } +} + +impl SubAssign for NaiveTime { #[inline] - fn sub_assign(&mut self, rhs: OldDuration) { + fn sub_assign(&mut self, rhs: Duration) { *self = self.sub(rhs); } } /// 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), @@ -1155,40 +1211,40 @@ impl SubAssign for NaiveTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveTime}; +/// use chrono::{TimeDelta, NaiveTime}; /// /// let from_hmsm = NaiveTime::from_hms_milli; /// -/// 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 = NaiveTime::from_hms_milli; -/// 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 b853c9f22d..246fada388 100644 --- a/src/naive/time/tests.rs +++ b/src/naive/time/tests.rs @@ -1,5 +1,5 @@ use super::NaiveTime; -use crate::oldtime::Duration; +use crate::TimeDelta; use crate::Timelike; use std::u32; @@ -71,29 +71,49 @@ fn test_time_add() { macro_rules! check { ($lhs:expr, $rhs:expr, $sum:expr) => {{ assert_eq!($lhs + $rhs, $sum); - //assert_eq!($rhs + $lhs, $sum); + // assert_eq!($rhs + $lhs, $sum); }}; } let hmsm = NaiveTime::from_hms_milli; - check!(hmsm(3, 5, 7, 900), Duration::zero(), hmsm(3, 5, 7, 900)); - check!(hmsm(3, 5, 7, 900), Duration::milliseconds(100), hmsm(3, 5, 8, 0)); - check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-1800), hmsm(3, 5, 6, 500)); - check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-800), hmsm(3, 5, 7, 500)); - check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-100), hmsm(3, 5, 7, 1_200)); - check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(100), hmsm(3, 5, 7, 1_400)); - check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(800), hmsm(3, 5, 8, 100)); - check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(1800), hmsm(3, 5, 9, 100)); - check!(hmsm(3, 5, 7, 900), Duration::seconds(86399), hmsm(3, 5, 6, 900)); // overwrap - check!(hmsm(3, 5, 7, 900), Duration::seconds(-86399), hmsm(3, 5, 8, 900)); - check!(hmsm(3, 5, 7, 900), Duration::days(12345), hmsm(3, 5, 7, 900)); - check!(hmsm(3, 5, 7, 1_300), Duration::days(1), hmsm(3, 5, 7, 300)); - check!(hmsm(3, 5, 7, 1_300), Duration::days(-1), hmsm(3, 5, 8, 300)); + check!(hmsm(3, 5, 7, 900), TimeDelta::ZERO, hmsm(3, 5, 7, 900)); + check!(hmsm(3, 5, 7, 900), TimeDelta::milliseconds(100), hmsm(3, 5, 8, 0)); + check!(hmsm(3, 5, 7, 1_300), TimeDelta::milliseconds(-1800), hmsm(3, 5, 6, 500)); + check!(hmsm(3, 5, 7, 1_300), TimeDelta::milliseconds(-800), hmsm(3, 5, 7, 500)); + check!(hmsm(3, 5, 7, 1_300), TimeDelta::milliseconds(-100), hmsm(3, 5, 7, 1_200)); + check!(hmsm(3, 5, 7, 1_300), TimeDelta::milliseconds(100), hmsm(3, 5, 7, 1_400)); + check!(hmsm(3, 5, 7, 1_300), TimeDelta::milliseconds(800), hmsm(3, 5, 8, 100)); + check!(hmsm(3, 5, 7, 1_300), TimeDelta::milliseconds(1800), hmsm(3, 5, 9, 100)); + check!(hmsm(3, 5, 7, 900), TimeDelta::seconds(86399), hmsm(3, 5, 6, 900)); // overwrap + check!(hmsm(3, 5, 7, 900), TimeDelta::seconds(-86399), hmsm(3, 5, 8, 900)); + check!(hmsm(3, 5, 7, 900), TimeDelta::days(12345), hmsm(3, 5, 7, 900)); + check!(hmsm(3, 5, 7, 1_300), TimeDelta::days(1), hmsm(3, 5, 7, 300)); + check!(hmsm(3, 5, 7, 1_300), TimeDelta::days(-1), hmsm(3, 5, 8, 300)); + check!(hmsm(3, 5, 7, 1_900), TimeDelta::milliseconds(200), hmsm(3, 5, 8, 100)); + check!(hmsm(3, 5, 7, 1_900), TimeDelta::hours(1), hmsm(4, 5, 7, 900)); + check!(hmsm(3, 5, 7, 900), TimeDelta::hours(1), hmsm(4, 5, 7, 900)); + check!(hmsm(3, 5, 7, 1_000), TimeDelta::milliseconds(1), hmsm(3, 5, 7, 1_001)); + check!(hmsm(3, 5, 7, 999), TimeDelta::milliseconds(1), hmsm(3, 5, 8, 0)); + + check!( + NaiveTime::from_hms_nano(3, 5, 7, 1_000_000_000), + TimeDelta::nanoseconds(1), + NaiveTime::from_hms_nano(3, 5, 7, 1_000_000_001) + ); + check!( + NaiveTime::from_hms_nano(3, 5, 7, 999_999_999), + TimeDelta::nanoseconds(1), + NaiveTime::from_hms_nano(3, 5, 8, 0) + ); + + check!(hmsm(3, 5, 7, 1_100), TimeDelta::milliseconds(-200), hmsm(3, 5, 7, 900)); + check!(hmsm(3, 5, 7, 1_000), TimeDelta::milliseconds(-1), hmsm(3, 5, 7, 999)); + check!(hmsm(3, 5, 7, 999), TimeDelta::milliseconds(-1), hmsm(3, 5, 7, 998)); // regression tests for #37 - check!(hmsm(0, 0, 0, 0), Duration::milliseconds(-990), hmsm(23, 59, 59, 10)); - check!(hmsm(0, 0, 0, 0), Duration::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] @@ -101,25 +121,25 @@ fn test_time_overflowing_add() { let hmsm = NaiveTime::from_hms_milli; assert_eq!( - hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::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(Duration::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(Duration::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, 5, 1_678).overflowing_add_signed(Duration::days(1)), + hmsm(3, 4, 5, 1_678).overflowing_add_signed(TimeDelta::days(1)), (hmsm(3, 4, 5, 678), 86_400) ); assert_eq!( - hmsm(3, 4, 5, 1_678).overflowing_add_signed(Duration::days(-1)), + hmsm(3, 4, 5, 1_678).overflowing_add_signed(TimeDelta::days(-1)), (hmsm(3, 4, 6, 678), -86_400) ); } @@ -128,9 +148,9 @@ fn test_time_overflowing_add() { fn test_time_addassignment() { let hms = NaiveTime::from_hms; let mut time = hms(12, 12, 12); - time += Duration::hours(10); + time += TimeDelta::hours(10); assert_eq!(time, hms(22, 12, 12)); - time += Duration::hours(10); + time += TimeDelta::hours(10); assert_eq!(time, hms(8, 12, 12)); } @@ -138,9 +158,9 @@ fn test_time_addassignment() { fn test_time_subassignment() { let hms = NaiveTime::from_hms; let mut time = hms(12, 12, 12); - time -= Duration::hours(10); + time -= TimeDelta::hours(10); assert_eq!(time, hms(2, 12, 12)); - time -= Duration::hours(10); + time -= TimeDelta::hours(10); assert_eq!(time, hms(16, 12, 12)); } @@ -148,7 +168,7 @@ fn test_time_subassignment() { fn test_time_sub() { macro_rules! check { ($lhs:expr, $rhs:expr, $diff:expr) => {{ - // `time1 - time2 = duration` is equivalent to `time2 - time1 = -duration` + // `time1 - time2 = TimeDelta` is equivalent to `time2 - time1 = -TimeDelta` assert_eq!($lhs.signed_duration_since($rhs), $diff); assert_eq!($rhs.signed_duration_since($lhs), -$diff); }}; @@ -156,25 +176,25 @@ fn test_time_sub() { let hmsm = NaiveTime::from_hms_milli; - check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), Duration::zero()); - check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), Duration::milliseconds(300)); - check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), Duration::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), - Duration::seconds(3600 + 60) + Duration::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, 5, 7, 200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(400)); - check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(1400)); - check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), Duration::milliseconds(1400)); + // as required by `time1 - time2 = TimeDelta` and `time2 - time1 = -TimeDelta` equivalence. + check!(hmsm(3, 5, 7, 200), hmsm(3, 5, 6, 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) + Duration::milliseconds(400), hmsm(3, 5, 7, 200)); - assert_eq!(hmsm(3, 5, 6, 1_800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200)); + // additional equality: `time1 + TimeDelta = time2` is equivalent to + // `time2 - time1 = TimeDelta` IF AND ONLY IF `time2` represents a non-leap second. + 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/fixed.rs b/src/offset/fixed.rs index df1a990bac..e31da455f8 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -12,8 +12,8 @@ use rkyv::{Archive, Deserialize, Serialize}; use super::{LocalResult, Offset, TimeZone}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; -use crate::oldtime::Duration as OldDuration; use crate::DateTime; +use crate::TimeDelta; use crate::Timelike; /// The time zone with fixed offset, from UTC-23:59:59 to UTC+23:59:59. @@ -157,12 +157,12 @@ impl fmt::Display for FixedOffset { fn add_with_leapsecond(lhs: &T, rhs: i32) -> T where - T: Timelike + Add, + T: Timelike + Add, { // extract and temporarily remove the fractional part and later recover it let nanos = lhs.nanosecond(); let lhs = lhs.with_nanosecond(0).unwrap(); - (lhs + OldDuration::seconds(i64::from(rhs))).with_nanosecond(nanos).unwrap() + (lhs + TimeDelta::seconds(i64::from(rhs))).with_nanosecond(nanos).unwrap() } impl Add for NaiveTime { diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 5a546de99e..cd31505039 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -128,7 +128,7 @@ impl TimeZone for Local { let mut local = local.clone(); // Get the offset from the js runtime let offset = FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60); - local -= crate::Duration::seconds(offset.local_minus_utc() as i64); + local -= crate::TimeDelta::seconds(offset.local_minus_utc() as i64); LocalResult::Single(DateTime::from_utc(local, offset)) } @@ -173,7 +173,7 @@ impl TimeZone for Local { mod tests { use super::Local; use crate::offset::TimeZone; - use crate::{Datelike, Duration, NaiveDate, NaiveDateTime, Timelike}; + use crate::{Datelike, NaiveDate, NaiveDateTime, TimeDelta, Timelike}; use std::{path, process}; @@ -247,7 +247,7 @@ mod tests { verify_against_date_command_local(date_path, date); } - date += crate::Duration::hours(1); + date += crate::TimeDelta::hours(1); } } @@ -266,8 +266,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()); @@ -280,7 +280,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/oldtime.rs b/src/oldtime.rs deleted file mode 100644 index d348b1d228..0000000000 --- a/src/oldtime.rs +++ /dev/null @@ -1,744 +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, Div, Mul, Neg, Sub}; -use core::time::Duration as StdDuration; -use core::{fmt, i64}; -#[cfg(any(feature = "std", test))] -use std::error::Error; - -#[cfg(feature = "rkyv")] -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 = 1000_000; -/// The number of nanoseconds in seconds. -const NANOS_PER_SEC: i32 = 1_000_000_000; -/// The number of microseconds per second. -const MICROS_PER_SEC: i64 = 1000_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 = 86400; -/// The number of (non-leap) seconds in a week. -const SECS_PER_WEEK: i64 = 604800; - -macro_rules! try_opt { - ($e:expr) => { - match $e { - Some(v) => v, - None => return None, - } - }; -} - -/// ISO 8601 time duration with nanosecond precision. -/// -/// This also allows for the negative duration; see individual methods for details. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] -#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] -pub struct Duration { - secs: i64, - nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC -} - -/// The minimum possible `Duration`: `i64::MIN` milliseconds. -pub(crate) const MIN: Duration = Duration { - secs: i64::MIN / MILLIS_PER_SEC - 1, - nanos: NANOS_PER_SEC + (i64::MIN % 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 weeks. - /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - pub fn weeks(weeks: i64) -> Duration { - let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of days. - /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - pub fn days(days: i64) -> Duration { - let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of hours. - /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - pub fn hours(hours: i64) -> Duration { - let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of minutes. - /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - pub fn minutes(minutes: i64) -> Duration { - let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of seconds. - /// Panics when the duration is more than `i64::MAX` seconds - /// or less than `i64::MIN` seconds. - #[inline] - pub fn seconds(seconds: i64) -> Duration { - let d = Duration { secs: seconds, nanos: 0 }; - if d < MIN || d > MAX { - panic!("Duration::seconds out of bounds"); - } - d - } - - /// Makes a new `Duration` with given number of milliseconds. - #[inline] - pub fn milliseconds(milliseconds: i64) -> Duration { - let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC); - let nanos = millis as i32 * NANOS_PER_MILLI; - Duration { secs: secs, nanos: nanos } - } - - /// Makes a new `Duration` with given number of microseconds. - #[inline] - pub 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: secs, nanos: nanos } - } - - /// Makes a new `Duration` with given number of nanoseconds. - #[inline] - pub fn nanoseconds(nanos: i64) -> Duration { - let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64); - Duration { secs: secs, nanos: nanos as i32 } - } - - /// Returns the total number of whole weeks in the duration. - #[inline] - pub fn num_weeks(&self) -> i64 { - self.num_days() / 7 - } - - /// Returns the total number of whole days in the duration. - pub fn num_days(&self) -> i64 { - self.num_seconds() / SECS_PER_DAY - } - - /// Returns the total number of whole hours in the duration. - #[inline] - pub fn num_hours(&self) -> i64 { - self.num_seconds() / SECS_PER_HOUR - } - - /// Returns the total number of whole minutes in the duration. - #[inline] - pub fn num_minutes(&self) -> i64 { - self.num_seconds() / SECS_PER_MINUTE - } - - /// Returns the total number of whole seconds in the duration. - pub 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 - /// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of - /// nanoseconds in the duration. - fn nanos_mod_sec(&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 fn num_milliseconds(&self) -> i64 { - // A proper Duration will not overflow, because MIN and MAX are defined - // such that the range is exactly i64 milliseconds. - let secs_part = self.num_seconds() * MILLIS_PER_SEC; - let nanos_part = self.nanos_mod_sec() / 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 fn num_microseconds(&self) -> Option { - let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC)); - let nanos_part = self.nanos_mod_sec() / 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 fn num_nanoseconds(&self) -> Option { - let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64)); - let nanos_part = self.nanos_mod_sec(); - secs_part.checked_add(nanos_part as i64) - } - - /// Add two durations, returning `None` if overflow occurred. - pub fn checked_add(&self, rhs: &Duration) -> Option { - let mut secs = try_opt!(self.secs.checked_add(rhs.secs)); - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs = try_opt!(secs.checked_add(1)); - } - let d = Duration { secs: secs, nanos: nanos }; - // Even if d is within the bounds of i64 seconds, - // it might still overflow i64 milliseconds. - if d < MIN || d > MAX { - None - } else { - Some(d) - } - } - - /// Subtract two durations, returning `None` if overflow occurred. - pub fn checked_sub(&self, rhs: &Duration) -> Option { - let mut secs = try_opt!(self.secs.checked_sub(rhs.secs)); - let mut nanos = self.nanos - rhs.nanos; - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs = try_opt!(secs.checked_sub(1)); - } - let d = Duration { secs: secs, nanos: nanos }; - // Even if d is within the bounds of i64 seconds, - // it might still overflow i64 milliseconds. - if d < MIN || d > MAX { - None - } else { - Some(d) - } - } - - /// Returns the duration as an absolute (non-negative) value. - #[inline] - pub 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::MIN` milliseconds. - #[inline] - pub fn min_value() -> Duration { - MIN - } - - /// The maximum possible `Duration`: `i64::MAX` milliseconds. - #[inline] - pub fn max_value() -> Duration { - MAX - } - - /// A duration where the stored seconds and nanoseconds are equal to zero. - #[inline] - pub fn zero() -> Duration { - Duration { secs: 0, nanos: 0 } - } - - /// Returns `true` if the duration equals `Duration::zero()`. - #[inline] - pub 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 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(())); - } - let d = Duration { secs: duration.as_secs() as i64, nanos: duration.subsec_nanos() as i32 }; - if d > MAX { - return Err(OutOfRangeError(())); - } - Ok(d) - } - - /// 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 fn to_std(&self) -> Result { - if self.secs < 0 { - return Err(OutOfRangeError(())); - } - Ok(StdDuration::new(self.secs as u64, self.nanos as u32)) - } -} - -impl Neg for Duration { - type Output = Duration; - - #[inline] - fn neg(self) -> Duration { - if self.nanos == 0 { - Duration { secs: -self.secs, nanos: 0 } - } else { - Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos } - } - } -} - -impl Add for Duration { - type Output = Duration; - - fn add(self, rhs: Duration) -> Duration { - 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 { secs: secs, nanos: nanos } - } -} - -impl Sub for Duration { - type Output = Duration; - - fn sub(self, rhs: Duration) -> Duration { - let mut secs = self.secs - rhs.secs; - let mut nanos = self.nanos - rhs.nanos; - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs -= 1; - } - Duration { secs: secs, nanos: nanos } - } -} - -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: 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: secs, nanos: nanos } - } -} - -#[cfg(any(feature = "std", test))] -impl<'a> std::iter::Sum<&'a Duration> for Duration { - fn sum>(iter: I) -> Duration { - iter.fold(Duration::zero(), |acc, x| acc + *x) - } -} - -#[cfg(any(feature = "std", test))] -impl std::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(any(feature = "std", test))] -impl Error for OutOfRangeError { - #[allow(deprecated)] - fn description(&self) -> &str { - "out of range error" - } -} - -// Copied from libnum -#[inline] -fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { - (div_floor_64(this, other), mod_floor_64(this, other)) -} - -#[inline] -fn div_floor_64(this: i64, other: i64) -> i64 { - match div_rem_64(this, other) { - (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1, - (d, _) => d, - } -} - -#[inline] -fn mod_floor_64(this: i64, other: i64) -> i64 { - match this % other { - r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other, - r => r, - } -} - -#[inline] -fn div_rem_64(this: i64, other: i64) -> (i64, i64) { - (this / other, this % other) -} - -#[cfg(test)] -mod tests { - use super::{Duration, OutOfRangeError, MAX, MIN}; - use std::time::Duration as StdDuration; - use std::{i32, i64}; - - #[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(86399) + Duration::seconds(4), - Duration::days(1) + Duration::seconds(3) - ); - assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000)); - assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000)); - assert_eq!( - Duration::days(2) + Duration::seconds(86399) + Duration::nanoseconds(1234567890), - Duration::days(3) + Duration::nanoseconds(234567890) - ); - assert_eq!(-Duration::days(3), Duration::days(-3)); - assert_eq!( - -(Duration::days(3) + Duration::seconds(70)), - Duration::days(-4) + Duration::seconds(86400 - 70) - ); - } - - #[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(86399).num_days(), 0); - assert_eq!(Duration::seconds(86401).num_days(), 1); - assert_eq!(Duration::seconds(-86399).num_days(), 0); - assert_eq!(Duration::seconds(-86401).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_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); - assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX); - assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN); - assert_eq!(MAX.num_milliseconds(), i64::MAX); - assert_eq!(MIN.num_milliseconds(), i64::MIN); - } - - #[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)); - assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX)); - assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN)); - assert_eq!(MAX.num_microseconds(), None); - assert_eq!(MIN.num_microseconds(), None); - - // overflow checks - const MICROS_PER_DAY: i64 = 86400_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::MIN / MICROS_PER_DAY).num_microseconds(), - Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY) - ); - assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None); - assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), 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)); - assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX)); - assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN)); - assert_eq!(MAX.num_nanoseconds(), None); - assert_eq!(MIN.num_nanoseconds(), None); - - // overflow checks - const NANOS_PER_DAY: i64 = 86400_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::MIN / NANOS_PER_DAY).num_nanoseconds(), - Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY) - ); - assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None); - assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None); - } - - #[test] - fn test_duration_checked_ops() { - 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_eq!( - Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)), - Some(Duration::milliseconds(i64::MIN)) - ); - assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(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)); - } - - #[test] - 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_vec = vec![ - Duration::zero(), - Duration::seconds(1), - Duration::seconds(6), - Duration::seconds(10), - ]; - let sum_3: Duration = duration_vec.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(-86401).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(86401).to_std(), Ok(StdDuration::new(86401, 0))); - assert_eq!(Duration::milliseconds(123).to_std(), Ok(StdDuration::new(0, 123000000))); - assert_eq!(Duration::milliseconds(123765).to_std(), Ok(StdDuration::new(123, 765000000))); - assert_eq!(Duration::nanoseconds(777).to_std(), Ok(StdDuration::new(0, 777))); - assert_eq!(MAX.to_std(), Ok(StdDuration::new(9223372036854775, 807000000))); - 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(86401)), Duration::from_std(StdDuration::new(86401, 0))); - assert_eq!( - Ok(Duration::milliseconds(123)), - Duration::from_std(StdDuration::new(0, 123000000)) - ); - assert_eq!( - Ok(Duration::milliseconds(123765)), - Duration::from_std(StdDuration::new(123, 765000000)) - ); - assert_eq!(Ok(Duration::nanoseconds(777)), Duration::from_std(StdDuration::new(0, 777))); - assert_eq!(Ok(MAX), Duration::from_std(StdDuration::new(9223372036854775, 807000000))); - assert_eq!( - Duration::from_std(StdDuration::new(9223372036854776, 0)), - Err(OutOfRangeError(())) - ); - assert_eq!( - Duration::from_std(StdDuration::new(9223372036854775, 807000001)), - Err(OutOfRangeError(())) - ); - } -} diff --git a/src/round.rs b/src/round.rs index c10b78c760..b528b0ef2d 100644 --- a/src/round.rs +++ b/src/round.rs @@ -3,7 +3,7 @@ use crate::datetime::DateTime; use crate::naive::NaiveDateTime; -use crate::oldtime::Duration; +use crate::TimeDelta; use crate::TimeZone; use crate::Timelike; use core::cmp::Ordering; @@ -46,7 +46,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); @@ -54,9 +54,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 @@ -65,9 +65,10 @@ where fn trunc_subsecs(self, digits: u16) -> T { 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 } @@ -91,14 +92,14 @@ 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`]. 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. -pub trait DurationRound: Sized { +/// `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 TimeDeltaRound: Sized { /// Error that can occur in rounding or truncating #[cfg(any(feature = "std", test))] type Err: std::error::Error; @@ -107,83 +108,83 @@ pub trait DurationRound: Sized { #[cfg(not(any(feature = "std", test)))] type Err: fmt::Debug + fmt::Display; - /// Return a copy rounded by Duration. + /// Return a copy rounded by TimeDelta. /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc}; + /// # use chrono::{DateTime, TimeDeltaRound, TimeDelta, TimeZone, Utc}; /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); /// assert_eq!( - /// dt.duration_round(Duration::milliseconds(10)).unwrap().to_string(), + /// dt.signed_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.signed_duration_round(TimeDelta::days(1)).unwrap().to_string(), /// "2018-01-12 00:00:00 UTC" /// ); /// ``` - fn duration_round(self, duration: Duration) -> Result; + fn signed_duration_round(self, signed_duration: TimeDelta) -> Result; - /// Return a copy truncated by Duration. + /// Return a copy truncated by TimeDelta. /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc}; + /// # use chrono::{DateTime, TimeDeltaRound, TimeDelta, TimeZone, Utc}; /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); /// assert_eq!( - /// dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(), + /// dt.signed_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.signed_duration_trunc(TimeDelta::days(1)).unwrap().to_string(), /// "2018-01-11 00:00:00 UTC" /// ); /// ``` - fn duration_trunc(self, duration: Duration) -> Result; + fn signed_duration_trunc(self, signed_duration: TimeDelta) -> Result; } /// The maximum number of seconds a DateTime can be to be represented as nanoseconds const MAX_SECONDS_TIMESTAMP_FOR_NANOS: i64 = 9_223_372_036; -impl DurationRound for DateTime { +impl TimeDeltaRound for DateTime { type Err = RoundingError; - fn duration_round(self, duration: Duration) -> Result { - duration_round(self.naive_local(), self, duration) + fn signed_duration_round(self, signed_duration: TimeDelta) -> Result { + signed_duration_round(self.naive_local(), self, signed_duration) } - fn duration_trunc(self, duration: Duration) -> Result { - duration_trunc(self.naive_local(), self, duration) + fn signed_duration_trunc(self, signed_duration: TimeDelta) -> Result { + signed_duration_trunc(self.naive_local(), self, signed_duration) } } -impl DurationRound for NaiveDateTime { +impl TimeDeltaRound for NaiveDateTime { type Err = RoundingError; - fn duration_round(self, duration: Duration) -> Result { - duration_round(self, self, duration) + fn signed_duration_round(self, signed_duration: TimeDelta) -> Result { + signed_duration_round(self, self, signed_duration) } - fn duration_trunc(self, duration: Duration) -> Result { - duration_trunc(self, self, duration) + fn signed_duration_trunc(self, signed_duration: TimeDelta) -> Result { + signed_duration_trunc(self, self, signed_duration) } } -fn duration_round( +fn signed_duration_round( naive: NaiveDateTime, original: T, - duration: Duration, + signed_duration: TimeDelta, ) -> Result where - T: Timelike + Add + Sub, + T: Timelike + Add + Sub, { - if let Some(span) = duration.num_nanoseconds() { + if let Some(span) = signed_duration.num_nanoseconds() { if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { return Err(RoundingError::TimestampExceedsLimit); } let stamp = naive.timestamp_nanos(); if span > stamp.abs() { - return Err(RoundingError::DurationExceedsTimestamp); + return Err(RoundingError::TimeDeltaExceedsTimestamp); } if span == 0 { return Ok(original); @@ -198,81 +199,81 @@ 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 { - Err(RoundingError::DurationExceedsLimit) + Err(RoundingError::TimeDeltaExceedsLimit) } } -fn duration_trunc( +fn signed_duration_trunc( naive: NaiveDateTime, original: T, - duration: Duration, + signed_duration: TimeDelta, ) -> Result where - T: Timelike + Add + Sub, + T: Timelike + Add + Sub, { - if let Some(span) = duration.num_nanoseconds() { + if let Some(span) = signed_duration.num_nanoseconds() { if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { return Err(RoundingError::TimestampExceedsLimit); } let stamp = naive.timestamp_nanos(); if span > stamp.abs() { - return Err(RoundingError::DurationExceedsTimestamp); + return Err(RoundingError::TimeDeltaExceedsTimestamp); } 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) + Err(RoundingError::TimeDeltaExceedsLimit) } } -/// An error from rounding by `Duration` +/// An error from rounding by `TimeDelta` /// -/// See: [`DurationRound`] +/// See: [`TimeDeltaRound`] #[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::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc}; + /// # use chrono::{DateTime, TimeDeltaRound, TimeDelta, RoundingError, TimeZone, Utc}; /// let dt = Utc.ymd(1970, 12, 12).and_hms(0, 0, 0); /// /// assert_eq!( - /// dt.duration_round(Duration::days(365)), - /// Err(RoundingError::DurationExceedsTimestamp), + /// dt.signed_duration_round(TimeDelta::days(365)), + /// Err(RoundingError::TimeDeltaExceedsTimestamp), /// ); /// ``` - DurationExceedsTimestamp, + TimeDeltaExceedsTimestamp, - /// Error when `Duration.num_nanoseconds` exceeds the limit. + /// Error when `TimeDelta.num_nanoseconds` exceeds the limit. /// /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc}; + /// # use chrono::{DateTime, TimeDeltaRound, TimeDelta, RoundingError, TimeZone, Utc}; /// let dt = Utc.ymd(2260, 12, 31).and_hms_nano(23, 59, 59, 1_75_500_000); /// /// assert_eq!( - /// dt.duration_round(Duration::days(300 * 365)), - /// Err(RoundingError::DurationExceedsLimit) + /// dt.signed_duration_round(TimeDelta::days(300 * 365)), + /// Err(RoundingError::TimeDeltaExceedsLimit) /// ); /// ``` - DurationExceedsLimit, + TimeDeltaExceedsLimit, /// Error when `DateTime.timestamp_nanos` exceeds the limit. /// /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc}; + /// # use chrono::{DateTime, TimeDeltaRound, TimeDelta, RoundingError, TimeZone, Utc}; /// let dt = Utc.ymd(2300, 12, 12).and_hms(0, 0, 0); /// - /// assert_eq!(dt.duration_round(Duration::days(1)), Err(RoundingError::TimestampExceedsLimit),); + /// assert_eq!(dt.signed_duration_round(TimeDelta::days(1)), Err(RoundingError::TimestampExceedsLimit),); /// ``` TimestampExceedsLimit, } @@ -280,11 +281,11 @@ pub enum RoundingError { impl fmt::Display for RoundingError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - RoundingError::DurationExceedsTimestamp => { - write!(f, "duration in nanoseconds exceeds timestamp") + RoundingError::TimeDeltaExceedsTimestamp => { + write!(f, "TimeDelta in nanoseconds exceeds timestamp") } - RoundingError::DurationExceedsLimit => { - write!(f, "duration exceeds num_nanoseconds limit") + RoundingError::TimeDeltaExceedsLimit => { + write!(f, "TimeDelta exceeds num_nanoseconds limit") } RoundingError::TimestampExceedsLimit => { write!(f, "timestamp exceeds num_nanoseconds limit") @@ -297,13 +298,13 @@ impl fmt::Display for RoundingError { impl std::error::Error for RoundingError { #[allow(deprecated)] fn description(&self) -> &str { - "error from rounding or truncating with DurationRound" + "error from rounding or truncating with TimeDeltaRound" } } #[cfg(test)] mod tests { - use super::{Duration, DurationRound, SubsecRound}; + use super::{SubsecRound, TimeDelta, TimeDeltaRound}; use crate::offset::{FixedOffset, TimeZone, Utc}; use crate::Timelike; @@ -394,231 +395,231 @@ mod tests { } #[test] - fn test_duration_round() { + fn test_signed_duration_round() { let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000); assert_eq!( - dt.duration_round(Duration::zero()).unwrap().to_string(), + dt.signed_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.signed_duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(), "2016-12-31 23:59:59.180 UTC" ); // round up let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0); assert_eq!( - dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + dt.signed_duration_round(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:25:00 UTC" ); // round down let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 29, 999); assert_eq!( - dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + dt.signed_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.signed_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.signed_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.signed_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.signed_duration_round(TimeDelta::days(1)).unwrap().to_string(), "2012-12-13 00:00:00 UTC" ); // timezone east let dt = FixedOffset::east(3600).ymd(2020, 10, 27).and_hms(15, 0, 0); assert_eq!( - dt.duration_round(Duration::days(1)).unwrap().to_string(), + dt.signed_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.signed_duration_round(TimeDelta::weeks(1)).unwrap().to_string(), "2020-10-29 00:00:00 +01:00" ); // timezone west let dt = FixedOffset::west(3600).ymd(2020, 10, 27).and_hms(15, 0, 0); assert_eq!( - dt.duration_round(Duration::days(1)).unwrap().to_string(), + dt.signed_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.signed_duration_round(TimeDelta::weeks(1)).unwrap().to_string(), "2020-10-29 00:00:00 -01:00" ); } #[test] - fn test_duration_round_naive() { + fn test_signed_duration_round_naive() { let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000).naive_utc(); assert_eq!( - dt.duration_round(Duration::zero()).unwrap().to_string(), + dt.signed_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.signed_duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(), "2016-12-31 23:59:59.180" ); // round up let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0).naive_utc(); assert_eq!( - dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + dt.signed_duration_round(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:25:00" ); // round down let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 29, 999).naive_utc(); assert_eq!( - dt.duration_round(Duration::minutes(5)).unwrap().to_string(), + dt.signed_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.signed_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.signed_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.signed_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.signed_duration_round(TimeDelta::days(1)).unwrap().to_string(), "2012-12-13 00:00:00" ); } #[test] - fn test_duration_round_pre_epoch() { + fn test_signed_duration_round_pre_epoch() { let dt = Utc.ymd(1969, 12, 12).and_hms(12, 12, 12); assert_eq!( - dt.duration_round(Duration::minutes(10)).unwrap().to_string(), + dt.signed_duration_round(TimeDelta::minutes(10)).unwrap().to_string(), "1969-12-12 12:10:00 UTC" ); } #[test] - fn test_duration_trunc() { + fn test_signed_duration_trunc() { let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000); assert_eq!( - dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(), + dt.signed_duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), "2016-12-31 23:59:59.170 UTC" ); // would round up let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0); assert_eq!( - dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + dt.signed_duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" ); // would round down let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 29, 999); assert_eq!( - dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + dt.signed_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.signed_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.signed_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.signed_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.signed_duration_trunc(TimeDelta::days(1)).unwrap().to_string(), "2012-12-12 00:00:00 UTC" ); // timezone east let dt = FixedOffset::east(3600).ymd(2020, 10, 27).and_hms(15, 0, 0); assert_eq!( - dt.duration_trunc(Duration::days(1)).unwrap().to_string(), + dt.signed_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.signed_duration_trunc(TimeDelta::weeks(1)).unwrap().to_string(), "2020-10-22 00:00:00 +01:00" ); // timezone west let dt = FixedOffset::west(3600).ymd(2020, 10, 27).and_hms(15, 0, 0); assert_eq!( - dt.duration_trunc(Duration::days(1)).unwrap().to_string(), + dt.signed_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.signed_duration_trunc(TimeDelta::weeks(1)).unwrap().to_string(), "2020-10-22 00:00:00 -01:00" ); } #[test] - fn test_duration_trunc_naive() { + fn test_signed_duration_trunc_naive() { let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000).naive_utc(); assert_eq!( - dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(), + dt.signed_duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), "2016-12-31 23:59:59.170" ); // would round up let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0).naive_utc(); assert_eq!( - dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + dt.signed_duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00" ); // would round down let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 29, 999).naive_utc(); assert_eq!( - dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(), + dt.signed_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.signed_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.signed_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.signed_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.signed_duration_trunc(TimeDelta::days(1)).unwrap().to_string(), "2012-12-12 00:00:00" ); } #[test] - fn test_duration_trunc_pre_epoch() { + fn test_signed_duration_trunc_pre_epoch() { let dt = Utc.ymd(1969, 12, 12).and_hms(12, 12, 12); assert_eq!( - dt.duration_trunc(Duration::minutes(10)).unwrap().to_string(), + dt.signed_duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(), "1969-12-12 12:10:00 UTC" ); } diff --git a/src/traits.rs b/src/traits.rs index 163a12852d..7d82f82a71 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -180,7 +180,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. /// @@ -229,7 +229,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),