From ee6095184d768bddd7c7d517d3e3f3279605b6bb Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Sat, 10 Sep 2022 17:22:09 +0200 Subject: [PATCH] Make most constructors fallible (relates #815) --- benches/chrono.rs | 10 +- ci/core-test/src/lib.rs | 2 +- src/date.rs | 205 ++- src/datetime/mod.rs | 273 ++-- src/datetime/serde.rs | 139 +- src/datetime/tests.rs | 342 +++-- src/error.rs | 88 ++ src/format/mod.rs | 6 +- src/format/parse.rs | 32 +- src/format/parsed.rs | 289 +++-- src/format/strftime.rs | 22 +- src/lib.rs | 113 +- src/month.rs | 17 +- src/naive/date.rs | 1765 ++++++++++++-------------- src/naive/datetime/mod.rs | 862 +++++++------ src/naive/datetime/serde.rs | 171 +-- src/naive/datetime/tests.rs | 175 +-- src/naive/isoweek.rs | 26 +- src/naive/time/mod.rs | 656 +++++----- src/naive/time/serde.rs | 2 +- src/naive/time/tests.rs | 260 ++-- src/offset/fixed.rs | 124 +- src/offset/local/mod.rs | 127 +- src/offset/local/tz_info/rule.rs | 49 +- src/offset/local/tz_info/timezone.rs | 25 +- src/offset/local/unix.rs | 47 +- src/offset/local/windows.rs | 60 +- src/offset/mod.rs | 408 +++--- src/offset/utc.rs | 64 +- src/round.rs | 87 +- src/traits.rs | 35 +- tests/wasm.rs | 4 +- 32 files changed, 3383 insertions(+), 3102 deletions(-) create mode 100644 src/error.rs diff --git a/benches/chrono.rs b/benches/chrono.rs index c44a2a15b6..c3d4c93616 100644 --- a/benches/chrono.rs +++ b/benches/chrono.rs @@ -35,14 +35,14 @@ fn bench_datetime_from_str(c: &mut Criterion) { } fn bench_datetime_to_rfc2822(c: &mut Criterion) { - let pst = FixedOffset::east(8 * 60 * 60); - let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 84_660_000); + let pst = FixedOffset::east(8 * 60 * 60).unwrap(); + let dt = pst.ymd(2018, 1, 11).unwrap().and_hms_nano(10, 5, 13, 84_660_000).unwrap(); c.bench_function("bench_datetime_to_rfc2822", |b| b.iter(|| black_box(dt).to_rfc2822())); } fn bench_datetime_to_rfc3339(c: &mut Criterion) { - let pst = FixedOffset::east(8 * 60 * 60); - let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 84_660_000); + let pst = FixedOffset::east(8 * 60 * 60).unwrap(); + let dt = pst.ymd(2018, 1, 11).unwrap().and_hms_nano(10, 5, 13, 84_660_000).unwrap(); c.bench_function("bench_datetime_to_rfc3339", |b| b.iter(|| black_box(dt).to_rfc3339())); } @@ -90,7 +90,7 @@ fn num_days_from_ce_alt(date: &Date) -> i32 { fn bench_num_days_from_ce(c: &mut Criterion) { let mut group = c.benchmark_group("num_days_from_ce"); for year in &[1, 500, 2000, 2019] { - let d = NaiveDate::from_ymd(*year, 1, 1); + let d = NaiveDate::from_ymd(*year, 1, 1).unwrap(); group.bench_with_input(BenchmarkId::new("new", year), &d, |b, y| { b.iter(|| num_days_from_ce_alt(y)) }); diff --git a/ci/core-test/src/lib.rs b/ci/core-test/src/lib.rs index e311edb5bc..6dee038b42 100644 --- a/ci/core-test/src/lib.rs +++ b/ci/core-test/src/lib.rs @@ -3,5 +3,5 @@ use chrono::{TimeZone, Utc}; pub fn create_time() { - let _ = Utc.ymd(2019, 1, 1).and_hms(0, 0, 0); + let _ = Utc.ymd(2019, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); } diff --git a/src/date.rs b/src/date.rs index cc52053903..7e705aa9bf 100644 --- a/src/date.rs +++ b/src/date.rs @@ -17,10 +17,9 @@ use crate::format::Locale; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::{DelayedFormat, Item, StrftimeItems}; use crate::naive::{IsoWeek, NaiveDate, NaiveTime}; -use crate::offset::{TimeZone, Utc}; +use crate::offset::{FixedTimeZone, TimeZone, Utc}; use crate::time_delta::TimeDelta; -use crate::DateTime; -use crate::{Datelike, Weekday}; +use crate::{ChronoError, DateTime, Datelike, Weekday}; /// ISO 8601 calendar date with time zone. /// @@ -84,137 +83,88 @@ impl Date { /// /// Panics on invalid datetime. #[inline] - pub fn and_time(&self, time: NaiveTime) -> Option> { - let localdt = self.naive_local().and_time(time); - self.timezone().from_local_datetime(&localdt).single() + pub fn and_time(&self, time: NaiveTime) -> Result, ChronoError> { + let dt = self.naive_local().and_time(time); + self.timezone().from_local_datetime(&dt)?.single() } /// Makes a new `DateTime` from the current date, hour, minute and second. /// The offset in the current date is preserved. /// - /// Panics on invalid hour, minute and/or second. + /// Returns `Err(ChronoError)` on invalid hour, minute and/or second. #[inline] - pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> DateTime { - self.and_hms_opt(hour, min, sec).expect("invalid time") - } - - /// Makes a new `DateTime` from the current date, hour, minute and second. - /// The offset in the current date is preserved. - /// - /// Returns `None` on invalid hour, minute and/or second. - #[inline] - pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option> { - NaiveTime::from_hms_opt(hour, min, sec).and_then(|time| self.and_time(time)) + pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> Result, ChronoError> { + let time = NaiveTime::from_hms(hour, min, sec)?; + self.and_time(time) } /// Makes a new `DateTime` from the current date, hour, minute, second and millisecond. /// The millisecond part can exceed 1,000 in order to represent the leap second. /// The offset in the current date is preserved. /// - /// Panics on invalid hour, minute, second and/or millisecond. + /// Returns `Err(ChronoError)` on invalid hour, minute, second and/or millisecond. #[inline] - pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> DateTime { - self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time") - } - - /// Makes a new `DateTime` from the current date, hour, minute, second and millisecond. - /// The millisecond part can exceed 1,000 in order to represent the leap second. - /// The offset in the current date is preserved. - /// - /// Returns `None` on invalid hour, minute, second and/or millisecond. - #[inline] - pub fn and_hms_milli_opt( + pub fn and_hms_milli( &self, hour: u32, min: u32, sec: u32, milli: u32, - ) -> Option> { - NaiveTime::from_hms_milli_opt(hour, min, sec, milli).and_then(|time| self.and_time(time)) - } - - /// Makes a new `DateTime` from the current date, hour, minute, second and microsecond. - /// The microsecond part can exceed 1,000,000 in order to represent the leap second. - /// The offset in the current date is preserved. - /// - /// Panics on invalid hour, minute, second and/or microsecond. - #[inline] - pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> DateTime { - self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time") + ) -> Result, ChronoError> { + let time = NaiveTime::from_hms_milli(hour, min, sec, milli)?; + self.and_time(time) } /// Makes a new `DateTime` from the current date, hour, minute, second and microsecond. /// The microsecond part can exceed 1,000,000 in order to represent the leap second. /// The offset in the current date is preserved. /// - /// Returns `None` on invalid hour, minute, second and/or microsecond. + /// Returns `Err(ChronoError)` on invalid hour, minute, second and/or microsecond. #[inline] - pub fn and_hms_micro_opt( + pub fn and_hms_micro( &self, hour: u32, min: u32, sec: u32, micro: u32, - ) -> Option> { - NaiveTime::from_hms_micro_opt(hour, min, sec, micro).and_then(|time| self.and_time(time)) - } - - /// Makes a new `DateTime` from the current date, hour, minute, second and nanosecond. - /// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second. - /// The offset in the current date is preserved. - /// - /// Panics on invalid hour, minute, second and/or nanosecond. - #[inline] - pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> DateTime { - self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time") + ) -> Result, ChronoError> { + let time = NaiveTime::from_hms_micro(hour, min, sec, micro)?; + self.and_time(time) } /// Makes a new `DateTime` from the current date, hour, minute, second and nanosecond. /// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second. /// The offset in the current date is preserved. /// - /// Returns `None` on invalid hour, minute, second and/or nanosecond. + /// Returns `Err(ChronoError)` on invalid hour, minute, second and/or nanosecond. #[inline] - pub fn and_hms_nano_opt( + pub fn and_hms_nano( &self, hour: u32, min: u32, sec: u32, nano: u32, - ) -> Option> { - NaiveTime::from_hms_nano_opt(hour, min, sec, nano).and_then(|time| self.and_time(time)) - } - - /// Makes a new `Date` for the next date. - /// - /// Panics when `self` is the last representable date. - #[inline] - pub fn succ(&self) -> Date { - self.succ_opt().expect("out of bound") + ) -> Result, ChronoError> { + let time = NaiveTime::from_hms_nano(hour, min, sec, nano)?; + self.and_time(time) } /// Makes a new `Date` for the next date. /// - /// Returns `None` when `self` is the last representable date. + /// Returns `Err(ChronoError)` when `self` is the last representable date. #[inline] - pub fn succ_opt(&self) -> Option> { - self.date.succ_opt().map(|date| Date::from_utc(date, self.offset.clone())) + pub fn succ(&self) -> Result, ChronoError> { + let date = self.date.succ()?; + Ok(Date::from_utc(date, self.offset.clone())) } /// Makes a new `Date` for the prior date. /// - /// Panics when `self` is the first representable date. + /// Returns `Err(ChronoError)` when `self` is the first representable date. #[inline] - pub fn pred(&self) -> Date { - self.pred_opt().expect("out of bound") - } - - /// Makes a new `Date` for the prior date. - /// - /// Returns `None` when `self` is the first representable date. - #[inline] - pub fn pred_opt(&self) -> Option> { - self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone())) + pub fn pred_opt(&self) -> Result, ChronoError> { + let date = self.date.pred()?; + Ok(Date::from_utc(date, self.offset.clone())) } /// Retrieves an associated offset from UTC. @@ -232,26 +182,33 @@ impl Date { /// Changes the associated time zone. /// This does not change the actual `Date` (but will change the string representation). #[inline] - pub fn with_timezone(&self, tz: &Tz2) -> Date { + pub fn with_timezone(&self, tz: &Tz2) -> Result, ChronoError> { tz.from_utc_date(&self.date) } + /// Changes the associated time zone. + /// This does not change the actual `Date` (but will change the string representation). + #[inline] + pub fn with_fixed_timezone(&self, tz: &Tz2) -> Date { + tz.from_utc_date_fixed(&self.date) + } + /// Adds given `Duration` to the current date. /// /// Returns `None` when it will result in overflow. #[inline] - pub fn checked_add_signed(self, rhs: TimeDelta) -> Option> { + pub fn checked_add_signed(self, rhs: TimeDelta) -> Result, ChronoError> { let date = self.date.checked_add_signed(rhs)?; - Some(Date { date, offset: self.offset }) + Ok(Date { date, offset: self.offset }) } /// Subtracts given `Duration` from the current date. /// /// Returns `None` when it will result in overflow. #[inline] - pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option> { + pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result, ChronoError> { let date = self.date.checked_sub_signed(rhs)?; - Some(Date { date, offset: self.offset }) + Ok(Date { date, offset: self.offset }) } /// Subtracts another `Date` from the current date. @@ -300,11 +257,12 @@ impl Date { } /// Maps the local date to other date with given conversion function. -fn map_local(d: &Date, mut f: F) -> Option> +fn map_local(d: &Date, mut f: F) -> Result, ChronoError> where - F: FnMut(NaiveDate) -> Option, + F: FnMut(NaiveDate) -> Result, { - f(d.naive_local()).and_then(|date| d.timezone().from_local_date(&date).single()) + let date = f(d.naive_local())?; + d.timezone().from_local_date(&date)?.single() } impl Date @@ -331,9 +289,10 @@ where /// ```rust /// use chrono::prelude::*; /// - /// let date_time: Date = Utc.ymd(2017, 04, 02); + /// let date_time: Date = Utc.ymd(2017, 04, 02)?.single()?; /// let formatted = format!("{}", date_time.format("%d/%m/%Y")); /// assert_eq!(formatted, "02/04/2017"); + /// Ok::<_, chrono::ChronoError>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -418,37 +377,37 @@ impl Datelike for Date { } #[inline] - fn with_year(&self, year: i32) -> Option> { + fn with_year(&self, year: i32) -> Result, ChronoError> { map_local(self, |date| date.with_year(year)) } #[inline] - fn with_month(&self, month: u32) -> Option> { + fn with_month(&self, month: u32) -> Result, ChronoError> { map_local(self, |date| date.with_month(month)) } #[inline] - fn with_month0(&self, month0: u32) -> Option> { + fn with_month0(&self, month0: u32) -> Result, ChronoError> { map_local(self, |date| date.with_month0(month0)) } #[inline] - fn with_day(&self, day: u32) -> Option> { + fn with_day(&self, day: u32) -> Result, ChronoError> { map_local(self, |date| date.with_day(day)) } #[inline] - fn with_day0(&self, day0: u32) -> Option> { + fn with_day0(&self, day0: u32) -> Result, ChronoError> { map_local(self, |date| date.with_day0(day0)) } #[inline] - fn with_ordinal(&self, ordinal: u32) -> Option> { + fn with_ordinal(&self, ordinal: u32) -> Result, ChronoError> { map_local(self, |date| date.with_ordinal(ordinal)) } #[inline] - fn with_ordinal0(&self, ordinal0: u32) -> Option> { + fn with_ordinal0(&self, ordinal0: u32) -> Result, ChronoError> { map_local(self, |date| date.with_ordinal0(ordinal0)) } } @@ -555,36 +514,38 @@ 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() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); + let one_year_ago = + Utc::today().unwrap() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); // A bit more than 2 years. - let two_year_ago = Utc::today() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); + let two_year_ago = + Utc::today().unwrap() - 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)); + assert_eq!(Utc::today().unwrap().years_since(one_year_ago), Some(1)); + assert_eq!(Utc::today().unwrap().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() + TimeDelta::weeks(12); - assert_eq!(Utc::today().years_since(future), None); + let future = Utc::today().unwrap() + TimeDelta::weeks(12); + assert_eq!(Utc::today().unwrap().years_since(future), None); } #[test] fn test_date_add_assign() { - let naivedate = NaiveDate::from_ymd(2000, 1, 1); + let naivedate = NaiveDate::from_ymd(2000, 1, 1).unwrap(); let date = Date::::from_utc(naivedate, Utc); let mut date_add = date; 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); + let timezone = FixedOffset::east(60 * 60).unwrap(); + let date = date.with_fixed_timezone(&timezone); + let date_add = date_add.with_fixed_timezone(&timezone); 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); + let timezone = FixedOffset::west(2 * 60 * 60).unwrap(); + let date = date.with_fixed_timezone(&timezone); + let date_add = date_add.with_fixed_timezone(&timezone); assert_eq!(date_add, date + TimeDelta::days(5)); } @@ -592,9 +553,9 @@ mod tests { #[test] #[cfg(feature = "clock")] fn test_date_add_assign_local() { - let naivedate = NaiveDate::from_ymd(2000, 1, 1); + let naivedate = NaiveDate::from_ymd(2000, 1, 1).unwrap(); - let date = Local.from_utc_date(&naivedate); + let date = Local.from_utc_date(&naivedate).unwrap(); let mut date_add = date; date_add += TimeDelta::days(5); @@ -603,22 +564,22 @@ mod tests { #[test] fn test_date_sub_assign() { - let naivedate = NaiveDate::from_ymd(2000, 1, 1); + let naivedate = NaiveDate::from_ymd(2000, 1, 1).unwrap(); let date = Date::::from_utc(naivedate, Utc); let mut date_sub = date; 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); + let timezone = FixedOffset::east(60 * 60).unwrap(); + let date = date.with_fixed_timezone(&timezone); + let date_sub = date_sub.with_fixed_timezone(&timezone); 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); + let timezone = FixedOffset::west(2 * 60 * 60).unwrap(); + let date = date.with_fixed_timezone(&timezone); + let date_sub = date_sub.with_fixed_timezone(&timezone); assert_eq!(date_sub, date - TimeDelta::days(5)); } @@ -626,9 +587,9 @@ mod tests { #[test] #[cfg(feature = "clock")] fn test_date_sub_assign_local() { - let naivedate = NaiveDate::from_ymd(2000, 1, 1); + let naivedate = NaiveDate::from_ymd(2000, 1, 1).unwrap(); - let date = Local.from_utc_date(&naivedate); + let date = Local.from_utc_date(&naivedate).unwrap(); let mut date_sub = date; date_sub -= TimeDelta::days(5); diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 1ae0d9c42d..a38d48d414 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -11,6 +11,7 @@ use alloc::string::{String, ToString}; #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::cmp::Ordering; +use core::convert::TryFrom; use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::{fmt, hash, str}; #[cfg(feature = "std")] @@ -25,13 +26,13 @@ use rkyv::{Archive, Deserialize, Serialize}; use crate::format::DelayedFormat; #[cfg(feature = "unstable-locales")] use crate::format::Locale; -use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems}; +use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems, OUT_OF_RANGE}; use crate::format::{Fixed, Item}; use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime}; #[cfg(feature = "clock")] use crate::offset::Local; -use crate::offset::{FixedOffset, Offset, TimeZone, Utc}; -use crate::{Date, Datelike, Months, TimeDelta, Timelike, Weekday}; +use crate::offset::{FixedOffset, FixedTimeZone, Offset, TimeZone, Utc}; +use crate::{ChronoError, Date, Datelike, Months, TimeDelta, Timelike, Weekday}; /// documented at re-export site #[cfg(feature = "serde")] @@ -99,8 +100,9 @@ impl DateTime { /// ``` /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc}; /// - /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc); - /// assert_eq!(Utc.timestamp(61, 0), dt); + /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0)?, Utc); + /// assert_eq!(Utc.timestamp(61, 0)?, dt); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` // // note: this constructor is purposely not named to `new` to discourage the direct usage. @@ -119,19 +121,20 @@ impl DateTime { /// use chrono::naive::NaiveDate; /// use chrono::offset::{Utc, FixedOffset}; /// - /// let naivedatetime_utc = NaiveDate::from_ymd(2000, 1, 12).and_hms(2, 0, 0); + /// let naivedatetime_utc = NaiveDate::from_ymd(2000, 1, 12)?.and_hms(2, 0, 0)?; /// let datetime_utc = DateTime::::from_utc(naivedatetime_utc, Utc); /// - /// let timezone_east = FixedOffset::east(8 * 60 * 60); - /// let naivedatetime_east = NaiveDate::from_ymd(2000, 1, 12).and_hms(10, 0, 0); + /// let timezone_east = FixedOffset::east(8 * 60 * 60)?; + /// let naivedatetime_east = NaiveDate::from_ymd(2000, 1, 12)?.and_hms(10, 0, 0)?; /// let datetime_east = DateTime::::from_local(naivedatetime_east, timezone_east); /// - /// let timezone_west = FixedOffset::west(7 * 60 * 60); - /// let naivedatetime_west = NaiveDate::from_ymd(2000, 1, 11).and_hms(19, 0, 0); + /// let timezone_west = FixedOffset::west(7 * 60 * 60)?; + /// let naivedatetime_west = NaiveDate::from_ymd(2000, 1, 11)?.and_hms(19, 0, 0)?; /// let datetime_west = DateTime::::from_local(naivedatetime_west, timezone_west); - - /// assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east)); - /// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)); + /// + /// assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east)?); + /// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { @@ -149,12 +152,13 @@ impl DateTime { /// ``` /// use chrono::prelude::*; /// - /// let date: Date = Utc.ymd(2020, 1, 1); - /// let dt: DateTime = date.and_hms(0, 0, 0); + /// let date: Date = Utc.ymd(2020, 1, 1)?.single()?; + /// let dt: DateTime = date.and_hms(0, 0, 0)?; /// /// assert_eq!(dt.date(), date); /// - /// assert_eq!(dt.date().and_hms(1, 1, 1), date.and_hms(1, 1, 1)); + /// assert_eq!(dt.date().and_hms(1, 1, 1)?, date.and_hms(1, 1, 1)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn date(&self) -> Date { @@ -169,14 +173,14 @@ impl DateTime { /// ``` /// use chrono::prelude::*; /// - /// let date: DateTime = Utc.ymd(2020, 1, 1).and_hms(0, 0, 0); - /// let other: DateTime = FixedOffset::east(23).ymd(2020, 1, 1).and_hms(0, 0, 0); + /// let date: DateTime = Utc.ymd(2020, 1, 1)?.and_hms(0, 0, 0)?; + /// let other: DateTime = FixedOffset::east(23)?.ymd(2020, 1, 1)?.and_hms(0, 0, 0)?; /// assert_eq!(date.date_naive(), other.date_naive()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn date_naive(&self) -> NaiveDate { - let local = self.naive_local(); - NaiveDate::from_ymd(local.year(), local.month(), local.day()) + self.naive_local().date() } /// Retrieves a time component. @@ -206,11 +210,12 @@ impl DateTime { /// use chrono::Utc; /// use chrono::TimeZone; /// - /// let dt = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 444); + /// let dt = Utc.ymd(1970, 1, 1)?.and_hms_milli(0, 0, 1, 444)?; /// assert_eq!(dt.timestamp_millis(), 1_444); /// - /// let dt = Utc.ymd(2001, 9, 9).and_hms_milli(1, 46, 40, 555); + /// let dt = Utc.ymd(2001, 9, 9)?.and_hms_milli(1, 46, 40, 555)?; /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp_millis(&self) -> i64 { @@ -230,11 +235,12 @@ impl DateTime { /// use chrono::Utc; /// use chrono::TimeZone; /// - /// let dt = Utc.ymd(1970, 1, 1).and_hms_micro(0, 0, 1, 444); + /// let dt = Utc.ymd(1970, 1, 1)?.and_hms_micro(0, 0, 1, 444)?; /// assert_eq!(dt.timestamp_micros(), 1_000_444); /// - /// let dt = Utc.ymd(2001, 9, 9).and_hms_micro(1, 46, 40, 555); + /// let dt = Utc.ymd(2001, 9, 9)?.and_hms_micro(1, 46, 40, 555)?; /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp_micros(&self) -> i64 { @@ -254,11 +260,12 @@ impl DateTime { /// use chrono::Utc; /// use chrono::TimeZone; /// - /// let dt = Utc.ymd(1970, 1, 1).and_hms_nano(0, 0, 1, 444); + /// let dt = Utc.ymd(1970, 1, 1)?.and_hms_nano(0, 0, 1, 444)?; /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444); /// - /// let dt = Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 40, 555); + /// let dt = Utc.ymd(2001, 9, 9)?.and_hms_nano(1, 46, 40, 555)?; /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp_nanos(&self) -> i64 { @@ -310,18 +317,25 @@ impl DateTime { /// Changes the associated time zone. /// The returned `DateTime` references the same instant of time from the perspective of the provided time zone. #[inline] - pub fn with_timezone(&self, tz: &Tz2) -> DateTime { + pub fn with_timezone(&self, tz: &Tz2) -> Result, ChronoError> { tz.from_utc_datetime(&self.datetime) } + /// Changes the associated time zone. + /// The returned `DateTime` references the same instant of time from the perspective of the provided time zone. + #[inline] + pub fn with_fixed_timezone(&self, tz: &Tz2) -> DateTime { + tz.from_utc_datetime_fixed(&self.datetime) + } + /// Adds given `Duration` to the current date and time. /// /// Returns `None` when it will result in overflow. #[inline] - pub fn checked_add_signed(self, rhs: TimeDelta) -> Option> { + pub fn checked_add_signed(self, rhs: TimeDelta) -> Result, ChronoError> { let datetime = self.datetime.checked_add_signed(rhs)?; let tz = self.timezone(); - Some(tz.from_utc_datetime(&datetime)) + tz.from_utc_datetime(&datetime) } /// Adds given `Months` to the current date and time. @@ -330,21 +344,19 @@ impl DateTime { /// local time is not valid on the newly calculated date. /// /// See [`NaiveDate::checked_add_months`] for more details on behavior - pub fn checked_add_months(self, rhs: Months) -> Option> { - self.naive_local() - .checked_add_months(rhs)? - .and_local_timezone(Tz::from_offset(&self.offset)) - .single() + pub fn checked_add_months(self, rhs: Months) -> Result, ChronoError> { + let datetime = self.naive_local().checked_add_months(rhs)?; + datetime.and_local_timezone(Tz::from_offset(&self.offset)) } /// Subtracts given `Duration` from the current date and time. /// /// Returns `None` when it will result in overflow. #[inline] - pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option> { + pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result, ChronoError> { let datetime = self.datetime.checked_sub_signed(rhs)?; let tz = self.timezone(); - Some(tz.from_utc_datetime(&datetime)) + tz.from_utc_datetime(&datetime) } /// Subtracts given `Months` from the current date and time. @@ -353,31 +365,25 @@ impl DateTime { /// local time is not valid on the newly calculated date. /// /// See [`NaiveDate::checked_sub_months`] for more details on behavior - pub fn checked_sub_months(self, rhs: Months) -> Option> { - self.naive_local() - .checked_sub_months(rhs)? - .and_local_timezone(Tz::from_offset(&self.offset)) - .single() + pub fn checked_sub_months(self, rhs: Months) -> Result, ChronoError> { + let dt = self.naive_local().checked_sub_months(rhs)?; + dt.and_local_timezone(Tz::from_offset(&self.offset)) } /// Add a duration in [`Days`] to the date part of the `DateTime` /// /// Returns `None` if the resulting date would be out of range. - pub fn checked_add_days(self, days: Days) -> Option { - self.datetime - .checked_add_days(days)? - .and_local_timezone(TimeZone::from_offset(&self.offset)) - .single() + pub fn checked_add_days(self, days: Days) -> Result { + let dt = self.datetime.checked_add_days(days)?; + dt.and_local_timezone(TimeZone::from_offset(&self.offset)) } /// Subtract a duration in [`Days`] from the date part of the `DateTime` /// /// Returns `None` if the resulting date would be out of range. - pub fn checked_sub_days(self, days: Days) -> Option { - self.datetime - .checked_sub_days(days)? - .and_local_timezone(TimeZone::from_offset(&self.offset)) - .single() + pub fn checked_sub_days(self, days: Days) -> Result { + let dt = self.datetime.checked_sub_days(days)?; + dt.and_local_timezone(TimeZone::from_offset(&self.offset)) } /// Subtracts another `DateTime` from the current date and time. @@ -424,7 +430,7 @@ impl DateTime { impl Default for DateTime { fn default() -> Self { - Utc.from_utc_datetime(&NaiveDateTime::default()) + Utc.from_utc_datetime_fixed(&NaiveDateTime::default()) } } @@ -432,13 +438,14 @@ impl Default for DateTime { #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] impl Default for DateTime { fn default() -> Self { - Local.from_utc_datetime(&NaiveDateTime::default()) + // TODO: Cannot avoid fallible operation, so this probably has to be removed. + Local.from_utc_datetime(&NaiveDateTime::default()).unwrap() } } impl Default for DateTime { fn default() -> Self { - FixedOffset::west(0).from_utc_datetime(&NaiveDateTime::default()) + FixedOffset::UTC.from_utc_datetime_fixed(&NaiveDateTime::default()) } } @@ -449,19 +456,21 @@ impl From> for DateTime { /// Conversion is done via [`DateTime::with_timezone`]. Note that the converted value returned by /// this will be created with a fixed timezone offset of 0. fn from(src: DateTime) -> Self { - src.with_timezone(&FixedOffset::east(0)) + src.with_fixed_timezone(&FixedOffset::UTC) } } /// Convert a `DateTime` instance into a `DateTime` instance. #[cfg(feature = "clock")] #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] -impl From> for DateTime { +impl TryFrom> for DateTime { + type Error = ChronoError; + /// Convert this `DateTime` instance into a `DateTime` instance. /// /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in timezones. - fn from(src: DateTime) -> Self { - src.with_timezone(&Local) + fn try_from(value: DateTime) -> Result { + value.with_timezone(&Local) } } @@ -472,20 +481,22 @@ impl From> for DateTime { /// Conversion is performed via [`DateTime::with_timezone`], accounting for the timezone /// difference. fn from(src: DateTime) -> Self { - src.with_timezone(&Utc) + src.with_fixed_timezone(&Utc) } } /// Convert a `DateTime` instance into a `DateTime` instance. #[cfg(feature = "clock")] #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] -impl From> for DateTime { +impl TryFrom> for DateTime { + type Error = ChronoError; + /// Convert this `DateTime` instance into a `DateTime` instance. /// /// Conversion is performed via [`DateTime::with_timezone`]. Returns the equivalent value in local /// time. - fn from(src: DateTime) -> Self { - src.with_timezone(&Local) + fn try_from(value: DateTime) -> Result { + value.with_timezone(&Local) } } @@ -498,7 +509,7 @@ impl From> for DateTime { /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in /// timezones. fn from(src: DateTime) -> Self { - src.with_timezone(&Utc) + src.with_fixed_timezone(&Utc) } } @@ -511,16 +522,17 @@ impl From> for DateTime { /// Conversion is performed via [`DateTime::with_timezone`]. Note that the converted value returned /// by this will be created with a fixed timezone offset of 0. fn from(src: DateTime) -> Self { - src.with_timezone(&FixedOffset::east(0)) + src.with_fixed_timezone(&FixedOffset::UTC) } } /// Maps the local datetime to other datetime with given conversion function. -fn map_local(dt: &DateTime, mut f: F) -> Option> +fn map_local(dt: &DateTime, mut f: F) -> Result, ChronoError> where - F: FnMut(NaiveDateTime) -> Option, + F: FnMut(NaiveDateTime) -> Result, { - f(dt.naive_local()).and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single()) + let datetime = f(dt.naive_local())?; + dt.timezone().from_local_datetime(&datetime)?.single() } impl DateTime { @@ -533,9 +545,10 @@ impl DateTime { /// ``` /// # use chrono::{DateTime, FixedOffset, TimeZone}; /// assert_eq!( - /// DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(), - /// FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9) + /// DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT")?, + /// FixedOffset::east(0)?.ymd(2015, 2, 18)?.and_hms(23, 16, 9)? /// ); + /// # Ok::<_, Box>(()) /// ``` pub fn parse_from_rfc2822(s: &str) -> ParseResult> { const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC2822)]; @@ -574,9 +587,9 @@ impl DateTime { /// ```rust /// use chrono::{DateTime, FixedOffset, TimeZone}; /// - /// let dt = DateTime::parse_from_str( - /// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z"); - /// assert_eq!(dt, Ok(FixedOffset::east(0).ymd(1983, 4, 13).and_hms_milli(12, 9, 14, 274))); + /// let dt = DateTime::parse_from_str("1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z")?; + /// assert_eq!(dt, FixedOffset::east(0)?.ymd(1983, 4, 13)?.and_hms_milli(12, 9, 14, 274)?); + /// # Ok::<_, Box>(()) /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult> { let mut parsed = Parsed::new(); @@ -616,7 +629,7 @@ where /// /// ```rust /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 26).and_hms_micro(18, 30, 9, 453_829); + /// let dt = Utc.ymd(2018, 1, 26)?.and_hms_micro(18, 30, 9, 453_829)?; /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false), /// "2018-01-26T18:30:09.453+00:00"); /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true), @@ -624,10 +637,11 @@ where /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), /// "2018-01-26T18:30:09Z"); /// - /// let pst = FixedOffset::east(8 * 60 * 60); - /// let dt = pst.ymd(2018, 1, 26).and_hms_micro(10, 30, 9, 453_829); + /// let pst = FixedOffset::east(8 * 60 * 60)?; + /// let dt = pst.ymd(2018, 1, 26)?.and_hms_micro(10, 30, 9, 453_829)?; /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), /// "2018-01-26T10:30:09+08:00"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -694,9 +708,10 @@ where /// ```rust /// use chrono::prelude::*; /// - /// let date_time: DateTime = Utc.ymd(2017, 04, 02).and_hms(12, 50, 32); + /// let date_time: DateTime = Utc.ymd(2017, 04, 02)?.and_hms(12, 50, 32)?; /// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M")); /// assert_eq!(formatted, "02/04/2017 12:50"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -784,37 +799,37 @@ impl Datelike for DateTime { } #[inline] - fn with_year(&self, year: i32) -> Option> { + fn with_year(&self, year: i32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_year(year)) } #[inline] - fn with_month(&self, month: u32) -> Option> { + fn with_month(&self, month: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_month(month)) } #[inline] - fn with_month0(&self, month0: u32) -> Option> { + fn with_month0(&self, month0: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_month0(month0)) } #[inline] - fn with_day(&self, day: u32) -> Option> { + fn with_day(&self, day: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_day(day)) } #[inline] - fn with_day0(&self, day0: u32) -> Option> { + fn with_day0(&self, day0: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_day0(day0)) } #[inline] - fn with_ordinal(&self, ordinal: u32) -> Option> { + fn with_ordinal(&self, ordinal: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_ordinal(ordinal)) } #[inline] - fn with_ordinal0(&self, ordinal0: u32) -> Option> { + fn with_ordinal0(&self, ordinal0: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_ordinal0(ordinal0)) } } @@ -838,22 +853,22 @@ impl Timelike for DateTime { } #[inline] - fn with_hour(&self, hour: u32) -> Option> { + fn with_hour(&self, hour: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_hour(hour)) } #[inline] - fn with_minute(&self, min: u32) -> Option> { + fn with_minute(&self, min: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_minute(min)) } #[inline] - fn with_second(&self, sec: u32) -> Option> { + fn with_second(&self, sec: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_second(sec)) } #[inline] - fn with_nanosecond(&self, nano: u32) -> Option> { + fn with_nanosecond(&self, nano: u32) -> Result, ChronoError> { map_local(self, |datetime| datetime.with_nanosecond(nano)) } } @@ -878,13 +893,14 @@ impl PartialOrd> for DateTime { /// ``` /// use chrono::prelude::*; /// - /// let earlier = Utc.ymd(2015, 5, 15).and_hms(2, 0, 0).with_timezone(&FixedOffset::west(1 * 3600)); - /// let later = Utc.ymd(2015, 5, 15).and_hms(3, 0, 0).with_timezone(&FixedOffset::west(5 * 3600)); + /// let earlier = Utc.ymd(2015, 5, 15)?.and_hms(2, 0, 0)?.with_timezone(&FixedOffset::west(1 * 3600)?)?; + /// let later = Utc.ymd(2015, 5, 15)?.and_hms(3, 0, 0)?.with_timezone(&FixedOffset::west(5 * 3600)?)?; /// /// assert_eq!(earlier.to_string(), "2015-05-15 01:00:00 -01:00"); /// assert_eq!(later.to_string(), "2015-05-14 22:00:00 -05:00"); /// /// assert!(later > earlier); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` fn partial_cmp(&self, other: &DateTime) -> Option { self.datetime.partial_cmp(&other.datetime) @@ -918,7 +934,7 @@ impl AddAssign for DateTime { let datetime = self.datetime.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed"); let tz = self.timezone(); - *self = tz.from_utc_datetime(&datetime); + *self = tz.from_utc_datetime(&datetime).unwrap(); } } @@ -945,7 +961,7 @@ impl SubAssign for DateTime { let datetime = self.datetime.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed"); let tz = self.timezone(); - *self = tz.from_utc_datetime(&datetime) + *self = tz.from_utc_datetime(&datetime).unwrap(); } } @@ -1012,7 +1028,8 @@ impl str::FromStr for DateTime { type Err = ParseError; fn from_str(s: &str) -> ParseResult> { - s.parse::>().map(|dt| dt.with_timezone(&Utc)) + let dt = s.parse::>()?; + dt.with_timezone(&Utc).map_err(|_| OUT_OF_RANGE) } } @@ -1033,7 +1050,8 @@ impl str::FromStr for DateTime { type Err = ParseError; fn from_str(s: &str) -> ParseResult> { - s.parse::>().map(|dt| dt.with_timezone(&Local)) + let dt = s.parse::>()?; + dt.with_timezone(&Local).map_err(|_| OUT_OF_RANGE) } } @@ -1054,7 +1072,9 @@ impl From for DateTime { } } }; - Utc.timestamp(sec, nsec) + + // TODO: remove this conversion since it can panic or can we make it not panic? + Utc.timestamp(sec, nsec).unwrap() } } @@ -1062,7 +1082,8 @@ impl From for DateTime { #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] impl From for DateTime { fn from(t: SystemTime) -> DateTime { - DateTime::::from(t).with_timezone(&Local) + // TODO: can we get rid of this panic? + DateTime::::from(t).with_timezone(&Local).unwrap() } } @@ -1146,25 +1167,30 @@ impl From> for js_sys::Date { #[test] fn test_add_sub_months() { - let utc_dt = Utc.ymd(2018, 9, 5).and_hms(23, 58, 0); - assert_eq!(utc_dt + Months::new(15), Utc.ymd(2019, 12, 5).and_hms(23, 58, 0)); + let utc_dt = Utc.ymd(2018, 9, 5).unwrap().and_hms(23, 58, 0).unwrap(); + assert_eq!(utc_dt + Months::new(15), Utc.ymd(2019, 12, 5).unwrap().and_hms(23, 58, 0).unwrap()); - let utc_dt = Utc.ymd(2020, 1, 31).and_hms(23, 58, 0); - assert_eq!(utc_dt + Months::new(1), Utc.ymd(2020, 2, 29).and_hms(23, 58, 0)); - assert_eq!(utc_dt + Months::new(2), Utc.ymd(2020, 3, 31).and_hms(23, 58, 0)); + let utc_dt = Utc.ymd(2020, 1, 31).unwrap().and_hms(23, 58, 0).unwrap(); + assert_eq!(utc_dt + Months::new(1), Utc.ymd(2020, 2, 29).unwrap().and_hms(23, 58, 0).unwrap()); + assert_eq!(utc_dt + Months::new(2), Utc.ymd(2020, 3, 31).unwrap().and_hms(23, 58, 0).unwrap()); - let utc_dt = Utc.ymd(2018, 9, 5).and_hms(23, 58, 0); - assert_eq!(utc_dt - Months::new(15), Utc.ymd(2017, 6, 5).and_hms(23, 58, 0)); + let utc_dt = Utc.ymd(2018, 9, 5).unwrap().and_hms(23, 58, 0).unwrap(); + assert_eq!(utc_dt - Months::new(15), Utc.ymd(2017, 6, 5).unwrap().and_hms(23, 58, 0).unwrap()); - let utc_dt = Utc.ymd(2020, 3, 31).and_hms(23, 58, 0); - assert_eq!(utc_dt - Months::new(1), Utc.ymd(2020, 2, 29).and_hms(23, 58, 0)); - assert_eq!(utc_dt - Months::new(2), Utc.ymd(2020, 1, 31).and_hms(23, 58, 0)); + let utc_dt = Utc.ymd(2020, 3, 31).unwrap().and_hms(23, 58, 0).unwrap(); + assert_eq!(utc_dt - Months::new(1), Utc.ymd(2020, 2, 29).unwrap().and_hms(23, 58, 0).unwrap()); + assert_eq!(utc_dt - Months::new(2), Utc.ymd(2020, 1, 31).unwrap().and_hms(23, 58, 0).unwrap()); } #[test] fn test_auto_conversion() { - let utc_dt = Utc.ymd(2018, 9, 5).and_hms(23, 58, 0); - let cdt_dt = FixedOffset::west(5 * 60 * 60).ymd(2018, 9, 5).and_hms(18, 58, 0); + let utc_dt = Utc.ymd(2018, 9, 5).unwrap().and_hms(23, 58, 0).unwrap(); + let cdt_dt = FixedOffset::west(5 * 60 * 60) + .unwrap() + .ymd(2018, 9, 5) + .unwrap() + .and_hms(18, 58, 0) + .unwrap(); let utc_dt2: DateTime = cdt_dt.into(); assert_eq!(utc_dt, utc_dt2); } @@ -1177,16 +1203,22 @@ where E: ::core::fmt::Debug, { assert_eq!( - to_string_utc(&Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), + to_string_utc(&Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap()).ok(), Some(r#""2014-07-24T12:34:06Z""#.into()) ); assert_eq!( - to_string_fixed(&FixedOffset::east(3660).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), + to_string_fixed( + &FixedOffset::east(3660).unwrap().ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() + ) + .ok(), Some(r#""2014-07-24T12:34:06+01:01""#.into()) ); assert_eq!( - to_string_fixed(&FixedOffset::east(3650).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), + to_string_fixed( + &FixedOffset::east(3650).unwrap().ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() + ) + .ok(), Some(r#""2014-07-24T12:34:06+01:00:50""#.into()) ); } @@ -1209,31 +1241,40 @@ fn test_decodable_json( assert_eq!( norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()), - norm(&Some(Utc.ymd(2014, 7, 24).and_hms(12, 34, 6))) + norm(&Some(Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap())) ); assert_eq!( norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()), - norm(&Some(Utc.ymd(2014, 7, 24).and_hms(12, 34, 6))) + norm(&Some(Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap())) ); assert_eq!( norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()), - norm(&Some(FixedOffset::east(0).ymd(2014, 7, 24).and_hms(12, 34, 6))) + norm(&Some( + FixedOffset::east(0).unwrap().ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() + )) ); assert_eq!( norm(&fixed_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()), - norm(&Some(FixedOffset::east(60 * 60 + 23 * 60).ymd(2014, 7, 24).and_hms(13, 57, 6))) + norm(&Some( + FixedOffset::east(60 * 60 + 23 * 60) + .unwrap() + .ymd(2014, 7, 24) + .unwrap() + .and_hms(13, 57, 6) + .unwrap() + )) ); // we don't know the exact local offset but we can check that // the conversion didn't change the instant itself assert_eq!( local_from_str(r#""2014-07-24T12:34:06Z""#).expect("local shouuld parse"), - Utc.ymd(2014, 7, 24).and_hms(12, 34, 6) + Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() ); assert_eq!( local_from_str(r#""2014-07-24T13:57:06+01:23""#).expect("local should parse with offset"), - Utc.ymd(2014, 7, 24).and_hms(12, 34, 6) + Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() ); assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); diff --git a/src/datetime/serde.rs b/src/datetime/serde.rs index 6a662b2189..3fe72f62ac 100644 --- a/src/datetime/serde.rs +++ b/src/datetime/serde.rs @@ -1,10 +1,10 @@ #![cfg_attr(docsrs, doc(cfg(feature = "serde")))] use core::fmt; +use serde::de::Error; use serde::{de, ser}; use super::DateTime; -use crate::naive::datetime::serde::serde_from; #[cfg(feature = "clock")] use crate::offset::Local; use crate::offset::{FixedOffset, TimeZone, Utc}; @@ -77,7 +77,7 @@ impl<'de> de::Deserialize<'de> for DateTime { where D: de::Deserializer<'de>, { - deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Utc)) + deserializer.deserialize_str(DateTimeVisitor)?.with_timezone(&Utc).map_err(D::Error::custom) } } @@ -95,7 +95,10 @@ impl<'de> de::Deserialize<'de> for DateTime { where D: de::Deserializer<'de>, { - deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Local)) + deserializer + .deserialize_str(DateTimeVisitor)? + .with_timezone(&Local) + .map_err(D::Error::custom) } } @@ -115,7 +118,7 @@ impl<'de> de::Deserialize<'de> for DateTime { /// time: DateTime /// } /// -/// let time = Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733); +/// let time = Utc.ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -124,7 +127,7 @@ impl<'de> de::Deserialize<'de> for DateTime { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<_, Box>(()) /// ``` pub mod ts_nanoseconds { use core::fmt; @@ -133,8 +136,6 @@ pub mod ts_nanoseconds { use crate::offset::TimeZone; use crate::{DateTime, Utc}; - use super::serde_from; - /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch /// /// Intended for use with `serde`s `serialize_with` attribute. @@ -152,11 +153,11 @@ pub mod ts_nanoseconds { /// } /// /// let my_s = S { - /// time: Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733), + /// time: Utc.ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -182,7 +183,7 @@ pub mod ts_nanoseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -205,10 +206,7 @@ pub mod ts_nanoseconds { where E: de::Error, { - serde_from( - Utc.timestamp_opt(value / 1_000_000_000, (value % 1_000_000_000) as u32), - &value, - ) + Utc.timestamp(value / 1_000_000_000, (value % 1_000_000_000) as u32).map_err(E::custom) } /// Deserialize a timestamp in nanoseconds since the epoch @@ -216,10 +214,8 @@ pub mod ts_nanoseconds { where E: de::Error, { - serde_from( - Utc.timestamp_opt((value / 1_000_000_000) as i64, (value % 1_000_000_000) as u32), - &value, - ) + Utc.timestamp((value / 1_000_000_000) as i64, (value % 1_000_000_000) as u32) + .map_err(E::custom) } } } @@ -240,7 +236,7 @@ pub mod ts_nanoseconds { /// time: Option> /// } /// -/// let time = Some(Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733)); +/// let time = Some(Utc.ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -249,7 +245,7 @@ pub mod ts_nanoseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<_, Box>(()) /// ``` pub mod ts_nanoseconds_option { use core::fmt; @@ -276,11 +272,11 @@ pub mod ts_nanoseconds_option { /// } /// /// let my_s = S { - /// time: Some(Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733)), + /// time: Some(Utc.ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -309,7 +305,7 @@ pub mod ts_nanoseconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where @@ -369,7 +365,7 @@ pub mod ts_nanoseconds_option { /// time: DateTime /// } /// -/// let time = Utc.ymd(2018, 5, 17).and_hms_micro(02, 04, 59, 918355); +/// let time = Utc.ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -378,13 +374,12 @@ pub mod ts_nanoseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<_, Box>(()) /// ``` pub mod ts_microseconds { use core::fmt; use serde::{de, ser}; - use super::serde_from; use crate::offset::TimeZone; use crate::{DateTime, Utc}; @@ -405,11 +400,11 @@ pub mod ts_microseconds { /// } /// /// let my_s = S { - /// time: Utc.ymd(2018, 5, 17).and_hms_micro(02, 04, 59, 918355), + /// time: Utc.ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -435,7 +430,7 @@ pub mod ts_microseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -458,10 +453,8 @@ pub mod ts_microseconds { where E: de::Error, { - serde_from( - Utc.timestamp_opt(value / 1_000_000, ((value % 1_000_000) * 1_000) as u32), - &value, - ) + Utc.timestamp(value / 1_000_000, ((value % 1_000_000) * 1_000) as u32) + .map_err(E::custom) } /// Deserialize a timestamp in milliseconds since the epoch @@ -469,10 +462,8 @@ pub mod ts_microseconds { where E: de::Error, { - serde_from( - Utc.timestamp_opt((value / 1_000_000) as i64, ((value % 1_000_000) * 1_000) as u32), - &value, - ) + Utc.timestamp((value / 1_000_000) as i64, ((value % 1_000_000) * 1_000) as u32) + .map_err(E::custom) } } } @@ -493,7 +484,7 @@ pub mod ts_microseconds { /// time: Option> /// } /// -/// let time = Some(Utc.ymd(2018, 5, 17).and_hms_micro(02, 04, 59, 918355)); +/// let time = Some(Utc.ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -502,7 +493,7 @@ pub mod ts_microseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<_, Box>(()) /// ``` pub mod ts_microseconds_option { use core::fmt; @@ -528,11 +519,11 @@ pub mod ts_microseconds_option { /// } /// /// let my_s = S { - /// time: Some(Utc.ymd(2018, 5, 17).and_hms_micro(02, 04, 59, 918355)), + /// time: Some(Utc.ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -561,7 +552,7 @@ pub mod ts_microseconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where @@ -621,7 +612,7 @@ pub mod ts_microseconds_option { /// time: DateTime /// } /// -/// let time = Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918); +/// let time = Utc.ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -630,13 +621,12 @@ pub mod ts_microseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<_, Box>(()) /// ``` pub mod ts_milliseconds { use core::fmt; use serde::{de, ser}; - use super::serde_from; use crate::offset::TimeZone; use crate::{DateTime, Utc}; @@ -657,11 +647,11 @@ pub mod ts_milliseconds { /// } /// /// let my_s = S { - /// time: Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918), + /// time: Utc.ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -687,13 +677,13 @@ pub mod ts_milliseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, { - d.deserialize_i64(MilliSecondsTimestampVisitor).map(|dt| dt.with_timezone(&Utc)) + Ok(d.deserialize_i64(MilliSecondsTimestampVisitor)?.with_fixed_timezone(&Utc)) } pub(super) struct MilliSecondsTimestampVisitor; @@ -710,7 +700,7 @@ pub mod ts_milliseconds { where E: de::Error, { - serde_from(Utc.timestamp_opt(value / 1000, ((value % 1000) * 1_000_000) as u32), &value) + Utc.timestamp(value / 1000, ((value % 1000) * 1_000_000) as u32).map_err(E::custom) } /// Deserialize a timestamp in milliseconds since the epoch @@ -718,10 +708,8 @@ pub mod ts_milliseconds { where E: de::Error, { - serde_from( - Utc.timestamp_opt((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32), - &value, - ) + Utc.timestamp((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32) + .map_err(E::custom) } } } @@ -742,7 +730,7 @@ pub mod ts_milliseconds { /// time: Option> /// } /// -/// let time = Some(Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918)); +/// let time = Some(Utc.ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -751,7 +739,7 @@ pub mod ts_milliseconds { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<_, Box>(()) /// ``` pub mod ts_milliseconds_option { use core::fmt; @@ -777,11 +765,11 @@ pub mod ts_milliseconds_option { /// } /// /// let my_s = S { - /// time: Some(Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918)), + /// time: Some(Utc.ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -817,19 +805,19 @@ pub mod ts_milliseconds_option { /// } /// /// let my_s: E = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; - /// assert_eq!(my_s, E::V(S { time: Some(Utc.timestamp(1526522699, 918000000)) })); + /// assert_eq!(my_s, E::V(S { time: Some(Utc.timestamp(1526522699, 918000000)?) })); /// let s: E = serde_json::from_str(r#"{ "time": null }"#)?; /// assert_eq!(s, E::V(S { time: None })); /// let t: E = serde_json::from_str(r#"{}"#)?; /// assert_eq!(t, E::V(S { time: None })); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where D: de::Deserializer<'de>, { - d.deserialize_option(OptionMilliSecondsTimestampVisitor) - .map(|opt| opt.map(|dt| dt.with_timezone(&Utc))) + Ok(d.deserialize_option(OptionMilliSecondsTimestampVisitor)? + .map(|dt| dt.with_fixed_timezone(&Utc))) } struct OptionMilliSecondsTimestampVisitor; @@ -883,7 +871,7 @@ pub mod ts_milliseconds_option { /// time: DateTime /// } /// -/// let time = Utc.ymd(2015, 5, 15).and_hms(10, 0, 0); +/// let time = Utc.ymd(2015, 5, 15)?.and_hms(10, 0, 0)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -892,13 +880,12 @@ pub mod ts_milliseconds_option { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<_, Box>(()) /// ``` pub mod ts_seconds { use core::fmt; use serde::{de, ser}; - use super::serde_from; use crate::offset::TimeZone; use crate::{DateTime, Utc}; @@ -919,11 +906,11 @@ pub mod ts_seconds { /// } /// /// let my_s = S { - /// time: Utc.ymd(2015, 5, 15).and_hms(10, 0, 0), + /// time: Utc.ymd(2015, 5, 15)?.and_hms(10, 0, 0)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1431684000}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -949,7 +936,7 @@ pub mod ts_seconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -972,7 +959,7 @@ pub mod ts_seconds { where E: de::Error, { - serde_from(Utc.timestamp_opt(value, 0), &value) + Utc.timestamp(value, 0).map_err(E::custom) } /// Deserialize a timestamp in seconds since the epoch @@ -980,7 +967,7 @@ pub mod ts_seconds { where E: de::Error, { - serde_from(Utc.timestamp_opt(value as i64, 0), &value) + Utc.timestamp(value as i64, 0).map_err(E::custom) } } } @@ -1001,7 +988,7 @@ pub mod ts_seconds { /// time: Option> /// } /// -/// let time = Some(Utc.ymd(2015, 5, 15).and_hms(10, 0, 0)); +/// let time = Some(Utc.ymd(2015, 5, 15)?.and_hms(10, 0, 0)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -1010,7 +997,7 @@ pub mod ts_seconds { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<_, Box>(()) /// ``` pub mod ts_seconds_option { use core::fmt; @@ -1036,11 +1023,11 @@ pub mod ts_seconds_option { /// } /// /// let my_s = S { - /// time: Some(Utc.ymd(2015, 5, 15).and_hms(10, 0, 0)), + /// time: Some(Utc.ymd(2015, 5, 15)?.and_hms(10, 0, 0)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1431684000}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -1069,7 +1056,7 @@ pub mod ts_seconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<_, Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where @@ -1134,7 +1121,7 @@ fn test_serde_bincode() { // it is not self-describing. use bincode::{deserialize, serialize}; - let dt = Utc.ymd(2014, 7, 24).and_hms(12, 34, 6); + let dt = Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap(); let encoded = serialize(&dt).unwrap(); let decoded: DateTime = deserialize(&encoded).unwrap(); assert_eq!(dt, decoded); diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 6c2b900f3a..18b1eb5b0a 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -9,135 +9,177 @@ use crate::offset::{FixedOffset, TimeZone, Utc}; use crate::Datelike; use crate::TimeDelta; +macro_rules! ymd { + ($year:expr, $month:expr, $day:expr) => { + NaiveDate::from_ymd($year, $month, $day).unwrap() + }; +} + #[test] fn test_datetime_offset() { - let est = FixedOffset::west(5 * 60 * 60); - let edt = FixedOffset::west(4 * 60 * 60); - let kst = FixedOffset::east(9 * 60 * 60); + let est = FixedOffset::west(5 * 60 * 60).unwrap(); + let edt = FixedOffset::west(4 * 60 * 60).unwrap(); + let kst = FixedOffset::east(9 * 60 * 60).unwrap(); - assert_eq!(format!("{}", Utc.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06 07:08:09 UTC"); - assert_eq!(format!("{}", edt.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06 07:08:09 -04:00"); - assert_eq!(format!("{}", kst.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06 07:08:09 +09:00"); - assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06T07:08:09Z"); - assert_eq!(format!("{:?}", edt.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06T07:08:09-04:00"); - assert_eq!(format!("{:?}", kst.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06T07:08:09+09:00"); + assert_eq!( + format!("{}", Utc.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + "2014-05-06 07:08:09 UTC" + ); + assert_eq!( + format!("{}", edt.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + "2014-05-06 07:08:09 -04:00" + ); + assert_eq!( + format!("{}", kst.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + "2014-05-06 07:08:09 +09:00" + ); + assert_eq!( + format!("{:?}", Utc.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + "2014-05-06T07:08:09Z" + ); + assert_eq!( + format!("{:?}", edt.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + "2014-05-06T07:08:09-04:00" + ); + assert_eq!( + format!("{:?}", kst.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + "2014-05-06T07:08:09+09:00" + ); // edge cases - assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(0, 0, 0)), "2014-05-06T00:00:00Z"); - assert_eq!(format!("{:?}", edt.ymd(2014, 5, 6).and_hms(0, 0, 0)), "2014-05-06T00:00:00-04:00"); - assert_eq!(format!("{:?}", kst.ymd(2014, 5, 6).and_hms(0, 0, 0)), "2014-05-06T00:00:00+09:00"); - assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(23, 59, 59)), "2014-05-06T23:59:59Z"); assert_eq!( - format!("{:?}", edt.ymd(2014, 5, 6).and_hms(23, 59, 59)), + format!("{:?}", Utc.ymd(2014, 5, 6).unwrap().and_hms(0, 0, 0).unwrap()), + "2014-05-06T00:00:00Z" + ); + assert_eq!( + format!("{:?}", edt.ymd(2014, 5, 6).unwrap().and_hms(0, 0, 0).unwrap()), + "2014-05-06T00:00:00-04:00" + ); + assert_eq!( + format!("{:?}", kst.ymd(2014, 5, 6).unwrap().and_hms(0, 0, 0).unwrap()), + "2014-05-06T00:00:00+09:00" + ); + assert_eq!( + format!("{:?}", Utc.ymd(2014, 5, 6).unwrap().and_hms(23, 59, 59).unwrap()), + "2014-05-06T23:59:59Z" + ); + assert_eq!( + format!("{:?}", edt.ymd(2014, 5, 6).unwrap().and_hms(23, 59, 59).unwrap()), "2014-05-06T23:59:59-04:00" ); assert_eq!( - format!("{:?}", kst.ymd(2014, 5, 6).and_hms(23, 59, 59)), + format!("{:?}", kst.ymd(2014, 5, 6).unwrap().and_hms(23, 59, 59).unwrap()), "2014-05-06T23:59:59+09:00" ); - 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 + TimeDelta::seconds(3600 + 60 + 1), Utc.ymd(2014, 5, 6).and_hms(8, 9, 10)); + let dt = Utc.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap(); + assert_eq!(dt, edt.ymd(2014, 5, 6).unwrap().and_hms(3, 8, 9).unwrap()); assert_eq!( - dt.signed_duration_since(edt.ymd(2014, 5, 6).and_hms(10, 11, 12)), + dt + TimeDelta::seconds(3600 + 60 + 1), + Utc.ymd(2014, 5, 6).unwrap().and_hms(8, 9, 10).unwrap() + ); + assert_eq!( + dt.signed_duration_since(edt.ymd(2014, 5, 6).unwrap().and_hms(10, 11, 12).unwrap()), TimeDelta::seconds(-7 * 3600 - 3 * 60 - 3) ); - assert_eq!(*Utc.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Utc); - assert_eq!(*edt.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), edt); - assert!(*edt.ymd(2014, 5, 6).and_hms(7, 8, 9).offset() != est); + assert_eq!(*Utc.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap().offset(), Utc); + assert_eq!(*edt.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap().offset(), edt); + assert!(*edt.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap().offset() != est); } #[test] fn test_datetime_date_and_time() { - let tz = FixedOffset::east(5 * 60 * 60); - let d = tz.ymd(2014, 5, 6).and_hms(7, 8, 9); - assert_eq!(d.time(), NaiveTime::from_hms(7, 8, 9)); - assert_eq!(d.date(), tz.ymd(2014, 5, 6)); - assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2014, 5, 6)); - assert_eq!(d.date().and_time(d.time()), Some(d)); - - let tz = FixedOffset::east(4 * 60 * 60); - let d = tz.ymd(2016, 5, 4).and_hms(3, 2, 1); - assert_eq!(d.time(), NaiveTime::from_hms(3, 2, 1)); - assert_eq!(d.date(), tz.ymd(2016, 5, 4)); - assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2016, 5, 4)); - assert_eq!(d.date().and_time(d.time()), Some(d)); - - let tz = FixedOffset::west(13 * 60 * 60); - let d = tz.ymd(2017, 8, 9).and_hms(12, 34, 56); - assert_eq!(d.time(), NaiveTime::from_hms(12, 34, 56)); - assert_eq!(d.date(), tz.ymd(2017, 8, 9)); - assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2017, 8, 9)); - assert_eq!(d.date().and_time(d.time()), Some(d)); - - let utc_d = Utc.ymd(2017, 8, 9).and_hms(12, 34, 56); + let tz = FixedOffset::east(5 * 60 * 60).unwrap(); + let d = tz.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap(); + assert_eq!(d.time(), NaiveTime::from_hms(7, 8, 9).unwrap()); + assert_eq!(d.date(), tz.ymd(2014, 5, 6).unwrap().unwrap()); + assert_eq!(d.date().naive_local(), ymd!(2014, 5, 6)); + assert_eq!(d.date().and_time(d.time()), Ok(d)); + + let tz = FixedOffset::east(4 * 60 * 60).unwrap(); + let d = tz.ymd(2016, 5, 4).unwrap().and_hms(3, 2, 1).unwrap(); + assert_eq!(d.time(), NaiveTime::from_hms(3, 2, 1).unwrap()); + assert_eq!(d.date(), tz.ymd(2016, 5, 4).unwrap().unwrap()); + assert_eq!(d.date().naive_local(), ymd!(2016, 5, 4)); + assert_eq!(d.date().and_time(d.time()), Ok(d)); + + let tz = FixedOffset::west(13 * 60 * 60).unwrap(); + let d = tz.ymd(2017, 8, 9).unwrap().and_hms(12, 34, 56).unwrap(); + assert_eq!(d.time(), NaiveTime::from_hms(12, 34, 56).unwrap()); + assert_eq!(d.date(), tz.ymd(2017, 8, 9).unwrap().unwrap()); + assert_eq!(d.date().naive_local(), ymd!(2017, 8, 9)); + assert_eq!(d.date().and_time(d.time()), Ok(d)); + + let utc_d = Utc.ymd(2017, 8, 9).unwrap().and_hms(12, 34, 56).unwrap(); assert!(utc_d < d); } #[test] #[cfg(feature = "clock")] fn test_datetime_with_timezone() { - let local_now = Local::now(); - let utc_now = local_now.with_timezone(&Utc); - let local_now2 = utc_now.with_timezone(&Local); + let local_now = Local::now().unwrap(); + let utc_now = local_now.with_timezone(&Utc).unwrap(); + let local_now2 = utc_now.with_timezone(&Local).unwrap(); assert_eq!(local_now, local_now2); } #[test] fn test_datetime_rfc2822_and_rfc3339() { - let edt = FixedOffset::east(5 * 60 * 60); + let edt = FixedOffset::east(5 * 60 * 60).unwrap(); assert_eq!( - Utc.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc2822(), + Utc.ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap().to_rfc2822(), "Wed, 18 Feb 2015 23:16:09 +0000" ); - assert_eq!(Utc.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc3339(), "2015-02-18T23:16:09+00:00"); assert_eq!( - edt.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc2822(), + Utc.ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap().to_rfc3339(), + "2015-02-18T23:16:09+00:00" + ); + assert_eq!( + edt.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap().to_rfc2822(), "Wed, 18 Feb 2015 23:16:09 +0500" ); assert_eq!( - edt.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc3339(), + edt.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap().to_rfc3339(), "2015-02-18T23:16:09.150+05:00" ); assert_eq!( - edt.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc2822(), + edt.ymd(2015, 2, 18).unwrap().and_hms_micro(23, 59, 59, 1_234_567).unwrap().to_rfc2822(), "Wed, 18 Feb 2015 23:59:60 +0500" ); assert_eq!( - edt.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc3339(), + edt.ymd(2015, 2, 18).unwrap().and_hms_micro(23, 59, 59, 1_234_567).unwrap().to_rfc3339(), "2015-02-18T23:59:60.234567+05:00" ); assert_eq!( DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"), - Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)) + Ok(FixedOffset::east(0).unwrap().ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap()) ); assert_eq!( DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000"), - Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)) + Ok(FixedOffset::east(0).unwrap().ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap()) ); assert_eq!( DateTime::parse_from_rfc3339("2015-02-18T23:16:09Z"), - Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)) + Ok(FixedOffset::east(0).unwrap().ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap()) ); assert_eq!( DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"), - Ok(edt.ymd(2015, 2, 18).and_hms_milli(23, 59, 59, 1_000)) + Ok(edt.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 59, 59, 1_000).unwrap()) ); assert!(DateTime::parse_from_rfc2822("31 DEC 262143 23:59 -2359").is_err()); assert_eq!( DateTime::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"), - Ok(edt.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567)) + Ok(edt.ymd(2015, 2, 18).unwrap().and_hms_micro(23, 59, 59, 1_234_567).unwrap()) ); } #[test] fn test_rfc3339_opts() { use crate::SecondsFormat::*; - let pst = FixedOffset::east(8 * 60 * 60); - let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 84_660_000); + let pst = FixedOffset::east(8 * 60 * 60).unwrap(); + let dt = pst.ymd(2018, 1, 11).unwrap().and_hms_nano(10, 5, 13, 84_660_000).unwrap(); assert_eq!(dt.to_rfc3339_opts(Secs, false), "2018-01-11T10:05:13+08:00"); assert_eq!(dt.to_rfc3339_opts(Secs, true), "2018-01-11T10:05:13+08:00"); assert_eq!(dt.to_rfc3339_opts(Millis, false), "2018-01-11T10:05:13.084+08:00"); @@ -159,7 +201,7 @@ fn test_rfc3339_opts() { #[should_panic] fn test_rfc3339_opts_nonexhaustive() { use crate::SecondsFormat; - let dt = Utc.ymd(1999, 10, 9).and_hms(1, 2, 3); + let dt = Utc.ymd(1999, 10, 9).unwrap().and_hms(1, 2, 3).unwrap(); dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true); } @@ -167,38 +209,53 @@ fn test_rfc3339_opts_nonexhaustive() { fn test_datetime_from_str() { assert_eq!( "2015-02-18T23:16:9.15Z".parse::>(), - Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)) + Ok(FixedOffset::east(0) + .unwrap() + .ymd(2015, 2, 18) + .unwrap() + .and_hms_milli(23, 16, 9, 150) + .unwrap()) ); assert_eq!( "2015-02-18T23:16:9.15Z".parse::>(), - Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)) + Ok(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) ); assert_eq!( "2015-02-18T23:16:9.15 UTC".parse::>(), - Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)) + Ok(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) ); assert_eq!( "2015-02-18T23:16:9.15UTC".parse::>(), - Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)) + Ok(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) ); assert_eq!( "2015-2-18T23:16:9.15Z".parse::>(), - Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)) + Ok(FixedOffset::east(0) + .unwrap() + .ymd(2015, 2, 18) + .unwrap() + .and_hms_milli(23, 16, 9, 150) + .unwrap()) ); assert_eq!( "2015-2-18T13:16:9.15-10:00".parse::>(), - Ok(FixedOffset::west(10 * 3600).ymd(2015, 2, 18).and_hms_milli(13, 16, 9, 150)) + Ok(FixedOffset::west(10 * 3600) + .unwrap() + .ymd(2015, 2, 18) + .unwrap() + .and_hms_milli(13, 16, 9, 150) + .unwrap()) ); assert!("2015-2-18T23:16:9.15".parse::>().is_err()); assert_eq!( "2015-2-18T23:16:9.15Z".parse::>(), - Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)) + Ok(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) ); assert_eq!( "2015-2-18T13:16:9.15-10:00".parse::>(), - Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)) + Ok(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) ); assert!("2015-2-18T23:16:9.15".parse::>().is_err()); @@ -207,7 +264,9 @@ fn test_datetime_from_str() { #[test] fn test_datetime_parse_from_str() { - let ymdhms = |y, m, d, h, n, s, off| FixedOffset::east(off).ymd(y, m, d).and_hms(h, n, s); + let ymdhms = |y, m, d, h, n, s, off| { + FixedOffset::east(off).unwrap().ymd(y, m, d).unwrap().and_hms(h, n, s).unwrap() + }; assert_eq!( DateTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), Ok(ymdhms(2014, 5, 7, 12, 34, 56, 570 * 60)) @@ -217,26 +276,26 @@ fn test_datetime_parse_from_str() { .is_err()); assert_eq!( Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT"), - Ok(Utc.ymd(2013, 8, 9).and_hms(23, 54, 35)) + Ok(Utc.ymd(2013, 8, 9).unwrap().and_hms(23, 54, 35).unwrap()) ); } #[test] fn test_to_string_round_trip() { - let dt = Utc.ymd(2000, 1, 1).and_hms(0, 0, 0); + let dt = Utc.ymd(2000, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); let _dt: DateTime = dt.to_string().parse().unwrap(); - let ndt_fixed = dt.with_timezone(&FixedOffset::east(3600)); + let ndt_fixed = dt.with_fixed_timezone(&FixedOffset::east(3600).unwrap()); let _dt: DateTime = ndt_fixed.to_string().parse().unwrap(); - let ndt_fixed = dt.with_timezone(&FixedOffset::east(0)); + let ndt_fixed = dt.with_fixed_timezone(&FixedOffset::east(0).unwrap()); let _dt: DateTime = ndt_fixed.to_string().parse().unwrap(); } #[test] #[cfg(feature = "clock")] fn test_to_string_round_trip_with_local() { - let ndt = Local::now(); + let ndt = Local::now().unwrap(); let _dt: DateTime = ndt.to_string().parse().unwrap(); } @@ -244,15 +303,15 @@ fn test_to_string_round_trip_with_local() { #[cfg(feature = "clock")] fn test_datetime_format_with_local() { // if we are not around the year boundary, local and UTC date should have the same year - let dt = Local::now().with_month(5).unwrap(); - assert_eq!(dt.format("%Y").to_string(), dt.with_timezone(&Utc).format("%Y").to_string()); + let dt = Local::now().unwrap().with_month(5).unwrap(); + assert_eq!(dt.format("%Y").to_string(), dt.with_fixed_timezone(&Utc).format("%Y").to_string()); } #[test] #[cfg(feature = "clock")] fn test_datetime_is_copy() { // UTC is known to be `Copy`. - let a = Utc::now(); + let a = Utc::now().unwrap(); let b = a; assert_eq!(a, b); } @@ -273,7 +332,7 @@ fn test_datetime_is_send() { #[test] fn test_subsecond_part() { - let datetime = Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 1234567); + let datetime = Utc.ymd(2014, 7, 8).unwrap().and_hms_nano(9, 10, 11, 1234567).unwrap(); assert_eq!(1, datetime.timestamp_subsec_millis()); assert_eq!(1234, datetime.timestamp_subsec_micros()); @@ -285,83 +344,102 @@ fn test_subsecond_part() { fn test_from_system_time() { use std::time::Duration; - let epoch = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0); + let epoch = Utc.ymd(1970, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); 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)), - Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos) + Utc.ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() ); assert_eq!( DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), - Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1) + Utc.ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1).unwrap() ); // DateTime -> SystemTime assert_eq!(SystemTime::from(epoch), UNIX_EPOCH); assert_eq!( - SystemTime::from(Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos)), + SystemTime::from(Utc.ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap()), UNIX_EPOCH + Duration::new(999_999_999, nanos) ); assert_eq!( - SystemTime::from(Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1)), + SystemTime::from(Utc.ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1).unwrap()), UNIX_EPOCH - Duration::new(999_999_999, 999_999_999) ); // DateTime -> SystemTime (via `with_timezone`) #[cfg(feature = "clock")] { - assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH); + assert_eq!(SystemTime::from(epoch.with_timezone(&Local).unwrap()), UNIX_EPOCH); } - assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400))), UNIX_EPOCH); - assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800))), UNIX_EPOCH); + assert_eq!( + SystemTime::from(epoch.with_fixed_timezone(&FixedOffset::east(32400).unwrap())), + UNIX_EPOCH + ); + assert_eq!( + SystemTime::from(epoch.with_fixed_timezone(&FixedOffset::west(28800).unwrap())), + UNIX_EPOCH + ); } #[test] #[cfg(target_os = "windows")] fn test_from_system_time() { + use std::convert::TryFrom; use std::time::Duration; let nanos = 999_999_000; - let epoch = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0); + let epoch = Utc.ymd(1970, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); // SystemTime -> DateTime assert_eq!(DateTime::::from(UNIX_EPOCH), epoch); assert_eq!( DateTime::::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)), - Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos) + Utc.ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() ); assert_eq!( DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), - Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1_000) + Utc.ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1_000).unwrap() ); // DateTime -> SystemTime - assert_eq!(SystemTime::from(epoch), UNIX_EPOCH); + assert_eq!(SystemTime::try_from(epoch).unwrap(), UNIX_EPOCH); assert_eq!( - SystemTime::from(Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos)), + SystemTime::try_from(Utc.ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap()) + .unwrap(), UNIX_EPOCH + Duration::new(999_999_999, nanos) ); assert_eq!( - SystemTime::from(Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1_000)), + SystemTime::try_from( + Utc.ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1_000).unwrap() + ) + .unwrap(), UNIX_EPOCH - Duration::new(999_999_999, nanos) ); // DateTime -> SystemTime (via `with_timezone`) #[cfg(feature = "clock")] { - assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH); + assert_eq!(SystemTime::try_from(epoch.with_timezone(&Local).unwrap()).unwrap(), UNIX_EPOCH); } - assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400))), UNIX_EPOCH); - assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800))), UNIX_EPOCH); + assert_eq!( + SystemTime::try_from(epoch.with_fixed_timezone(&FixedOffset::east(32400).unwrap())) + .unwrap(), + UNIX_EPOCH + ); + assert_eq!( + SystemTime::try_from(epoch.with_fixed_timezone(&FixedOffset::west(28800).unwrap())) + .unwrap(), + UNIX_EPOCH + ); } #[test] fn test_datetime_format_alignment() { - let datetime = Utc.ymd(2007, 1, 2); + let datetime = Utc.ymd(2007, 1, 2).unwrap().unwrap(); // Item::Literal let percent = datetime.format("%%"); @@ -392,21 +470,21 @@ fn test_datetime_format_alignment() { #[test] fn test_datetime_from_local() { // 2000-01-12T02:00:00Z - let naivedatetime_utc = NaiveDate::from_ymd(2000, 1, 12).and_hms(2, 0, 0); + let naivedatetime_utc = ymd!(2000, 1, 12).and_hms(2, 0, 0).unwrap(); let datetime_utc = DateTime::::from_utc(naivedatetime_utc, Utc); // 2000-01-12T10:00:00+8:00:00 - let timezone_east = FixedOffset::east(8 * 60 * 60); - let naivedatetime_east = NaiveDate::from_ymd(2000, 1, 12).and_hms(10, 0, 0); + let timezone_east = FixedOffset::east(8 * 60 * 60).unwrap(); + let naivedatetime_east = ymd!(2000, 1, 12).and_hms(10, 0, 0).unwrap(); let datetime_east = DateTime::::from_local(naivedatetime_east, timezone_east); // 2000-01-11T19:00:00-7:00:00 - let timezone_west = FixedOffset::west(7 * 60 * 60); - let naivedatetime_west = NaiveDate::from_ymd(2000, 1, 11).and_hms(19, 0, 0); + let timezone_west = FixedOffset::west(7 * 60 * 60).unwrap(); + let naivedatetime_west = ymd!(2000, 1, 11).and_hms(19, 0, 0).unwrap(); let datetime_west = DateTime::::from_local(naivedatetime_west, timezone_west); - assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east)); - assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)); + assert_eq!(datetime_east, datetime_utc.with_fixed_timezone(&timezone_east)); + assert_eq!(datetime_west, datetime_utc.with_fixed_timezone(&timezone_west)); } #[test] @@ -415,36 +493,38 @@ 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() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); + let one_year_ago = + Utc::today().unwrap() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); // A bit more than 2 years. - let two_year_ago = Utc::today() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); + let two_year_ago = + Utc::today().unwrap() - 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)); + assert_eq!(Utc::today().unwrap().years_since(one_year_ago), Some(1)); + assert_eq!(Utc::today().unwrap().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() + TimeDelta::weeks(12); - assert_eq!(Utc::today().years_since(future), None); + let future = Utc::today().unwrap() + TimeDelta::weeks(12); + assert_eq!(Utc::today().unwrap().years_since(future), None); } #[test] fn test_datetime_add_assign() { - let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0); + let naivedatetime = ymd!(2000, 1, 1).and_hms(0, 0, 0).unwrap(); let datetime = DateTime::::from_utc(naivedatetime, Utc); let mut datetime_add = datetime; 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); + let timezone = FixedOffset::east(60 * 60).unwrap(); + let datetime = datetime.with_timezone(&timezone).unwrap(); + let datetime_add = datetime_add.with_timezone(&timezone).unwrap(); 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); + let timezone = FixedOffset::west(2 * 60 * 60).unwrap(); + let datetime = datetime.with_timezone(&timezone).unwrap(); + let datetime_add = datetime_add.with_timezone(&timezone).unwrap(); assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); } @@ -452,10 +532,10 @@ fn test_datetime_add_assign() { #[test] #[cfg(feature = "clock")] fn test_datetime_add_assign_local() { - let naivedatetime = NaiveDate::from_ymd(2022, 1, 1).and_hms(0, 0, 0); + let naivedatetime = ymd!(2022, 1, 1).and_hms(0, 0, 0).unwrap(); - let datetime = Local.from_utc_datetime(&naivedatetime); - let mut datetime_add = Local.from_utc_datetime(&naivedatetime); + let datetime = Local.from_utc_datetime(&naivedatetime).unwrap(); + let mut datetime_add = Local.from_utc_datetime(&naivedatetime).unwrap(); // ensure we cross a DST transition for i in 1..=365 { @@ -466,22 +546,22 @@ fn test_datetime_add_assign_local() { #[test] fn test_datetime_sub_assign() { - let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).and_hms(12, 0, 0); + let naivedatetime = ymd!(2000, 1, 1).and_hms(12, 0, 0).unwrap(); let datetime = DateTime::::from_utc(naivedatetime, Utc); let mut datetime_sub = datetime; 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); + let timezone = FixedOffset::east(60 * 60).unwrap(); + let datetime = datetime.with_timezone(&timezone).unwrap(); + let datetime_sub = datetime_sub.with_timezone(&timezone).unwrap(); 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); + let timezone = FixedOffset::west(2 * 60 * 60).unwrap(); + let datetime = datetime.with_timezone(&timezone).unwrap(); + let datetime_sub = datetime_sub.with_timezone(&timezone).unwrap(); assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); } @@ -489,10 +569,10 @@ fn test_datetime_sub_assign() { #[test] #[cfg(feature = "clock")] fn test_datetime_sub_assign_local() { - let naivedatetime = NaiveDate::from_ymd(2022, 1, 1).and_hms(0, 0, 0); + let naivedatetime = ymd!(2022, 1, 1).and_hms(0, 0, 0).unwrap(); - let datetime = Local.from_utc_datetime(&naivedatetime); - let mut datetime_sub = Local.from_utc_datetime(&naivedatetime); + let datetime = Local.from_utc_datetime(&naivedatetime).unwrap(); + let mut datetime_sub = Local.from_utc_datetime(&naivedatetime).unwrap(); // ensure we cross a DST transition for i in 1..=365 { diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000000..9a64ff0558 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,88 @@ +use core::fmt; +#[cfg(windows)] +use std::io; + +/// Internal representation of the chrono error. +#[derive(Debug)] +pub(crate) enum ChronoErrorKind { + InvalidDate, + InvalidTime, + InvalidDateTime, + InvalidTimeZone, + AmbiguousDate, + #[cfg(unix)] + MissingDate, + #[cfg(windows)] + SystemTimeBeforeEpoch, + #[cfg(windows)] + SystemError(io::Error), +} + +/// The error raised for an invalid date time. +#[derive(Debug)] +pub struct ChronoError { + kind: ChronoErrorKind, +} + +impl ChronoError { + /// Internal constructor for a chrono error. + #[inline] + pub(crate) fn new(kind: ChronoErrorKind) -> Self { + Self { kind } + } +} + +impl fmt::Display for ChronoError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.kind { + ChronoErrorKind::InvalidDate => write!(f, "invalid date"), + ChronoErrorKind::InvalidTime => write!(f, "invalid time"), + ChronoErrorKind::InvalidDateTime => write!(f, "invalid date time"), + ChronoErrorKind::InvalidTimeZone => write!(f, "invalid time zone"), + ChronoErrorKind::AmbiguousDate => write!(f, "tried to operate over ambiguous date"), + #[cfg(unix)] + ChronoErrorKind::MissingDate => write!(f, "missing date"), + #[cfg(windows)] + ChronoErrorKind::SystemTimeBeforeEpoch => write!(f, "system time before Unix epoch"), + #[cfg(windows)] + ChronoErrorKind::SystemError(error) => write!(f, "system error: {error}"), + } + } +} + +impl From for ChronoError { + #[inline] + fn from(kind: ChronoErrorKind) -> Self { + Self::new(kind) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ChronoError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self.kind { + #[cfg(windows)] + ChronoErrorKind::SystemError(error) => Some(error), + _ => None, + } + } +} + +/// Implementation used in many test cases. +#[cfg(test)] +impl PartialEq for ChronoError { + fn eq(&self, other: &Self) -> bool { + self.kind == other.kind + } +} + +#[cfg(test)] +impl PartialEq for ChronoErrorKind { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + #[cfg(windows)] + (Self::SystemError(l0), Self::SystemError(r0)) => l0.kind() == r0.kind(), + _ => core::mem::discriminant(self) == core::mem::discriminant(other), + } + } +} diff --git a/src/format/mod.rs b/src/format/mod.rs index ff0363bb94..9376b6b52e 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -20,14 +20,14 @@ //! # use std::error::Error; //! use chrono::prelude::*; //! -//! let date_time = Utc.ymd(2020, 11, 10).and_hms(0, 1, 32); +//! let date_time = Utc.ymd(2020, 11, 10)?.and_hms(0, 1, 32)?; //! //! let formatted = format!("{}", date_time.format("%Y-%m-%d %H:%M:%S")); //! assert_eq!(formatted, "2020-11-10 00:01:32"); //! //! let parsed = Utc.datetime_from_str(&formatted, "%Y-%m-%d %H:%M:%S")?; //! assert_eq!(parsed, date_time); -//! # Ok::<(), chrono::ParseError>(()) +//! # Ok::<_, Box>(()) //! ``` #[cfg(feature = "alloc")] @@ -430,7 +430,7 @@ impl Error for ParseError { } // to be used in this module and submodules -const OUT_OF_RANGE: ParseError = ParseError(ParseErrorKind::OutOfRange); +pub(crate) const OUT_OF_RANGE: ParseError = ParseError(ParseErrorKind::OutOfRange); const IMPOSSIBLE: ParseError = ParseError(ParseErrorKind::Impossible); const NOT_ENOUGH: ParseError = ParseError(ParseErrorKind::NotEnough); const INVALID: ParseError = ParseError(ParseErrorKind::Invalid); diff --git a/src/format/parse.rs b/src/format/parse.rs index 02771b2e42..e223d54317 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -892,7 +892,7 @@ fn parse_rfc850() { static RFC850_FMT: &str = "%A, %d-%b-%y %T GMT"; let dt_str = "Sunday, 06-Nov-94 08:49:37 GMT"; - let dt = Utc.ymd(1994, 11, 6).and_hms(8, 49, 37); + let dt = Utc.ymd(1994, 11, 6).unwrap().and_hms(8, 49, 37).unwrap(); // Check that the format is what we expect assert_eq!(dt.format(RFC850_FMT).to_string(), dt_str); @@ -903,12 +903,30 @@ fn parse_rfc850() { // Check that the rest of the weekdays parse correctly (this test originally failed because // Sunday parsed incorrectly). let testdates = [ - (Utc.ymd(1994, 11, 7).and_hms(8, 49, 37), "Monday, 07-Nov-94 08:49:37 GMT"), - (Utc.ymd(1994, 11, 8).and_hms(8, 49, 37), "Tuesday, 08-Nov-94 08:49:37 GMT"), - (Utc.ymd(1994, 11, 9).and_hms(8, 49, 37), "Wednesday, 09-Nov-94 08:49:37 GMT"), - (Utc.ymd(1994, 11, 10).and_hms(8, 49, 37), "Thursday, 10-Nov-94 08:49:37 GMT"), - (Utc.ymd(1994, 11, 11).and_hms(8, 49, 37), "Friday, 11-Nov-94 08:49:37 GMT"), - (Utc.ymd(1994, 11, 12).and_hms(8, 49, 37), "Saturday, 12-Nov-94 08:49:37 GMT"), + ( + Utc.ymd(1994, 11, 7).unwrap().and_hms(8, 49, 37).unwrap(), + "Monday, 07-Nov-94 08:49:37 GMT", + ), + ( + Utc.ymd(1994, 11, 8).unwrap().and_hms(8, 49, 37).unwrap(), + "Tuesday, 08-Nov-94 08:49:37 GMT", + ), + ( + Utc.ymd(1994, 11, 9).unwrap().and_hms(8, 49, 37).unwrap(), + "Wednesday, 09-Nov-94 08:49:37 GMT", + ), + ( + Utc.ymd(1994, 11, 10).unwrap().and_hms(8, 49, 37).unwrap(), + "Thursday, 10-Nov-94 08:49:37 GMT", + ), + ( + Utc.ymd(1994, 11, 11).unwrap().and_hms(8, 49, 37).unwrap(), + "Friday, 11-Nov-94 08:49:37 GMT", + ), + ( + Utc.ymd(1994, 11, 12).unwrap().and_hms(8, 49, 37).unwrap(), + "Saturday, 12-Nov-94 08:49:37 GMT", + ), ]; for val in &testdates { diff --git a/src/format/parsed.rs b/src/format/parsed.rs index 9e29700e21..99801249f5 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -10,7 +10,7 @@ use num_integer::div_rem; use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; -use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone}; +use crate::offset::{FixedOffset, Offset, TimeZone}; use crate::{DateTime, Datelike, TimeDelta, Timelike, Weekday}; /// Parsed parts of date and time. There are two classes of methods: @@ -397,13 +397,13 @@ impl Parsed { let (verified, parsed_date) = match (given_year, given_isoyear, self) { (Some(year), _, &Parsed { month: Some(month), day: Some(day), .. }) => { // year, month, day - let date = NaiveDate::from_ymd_opt(year, month, day).ok_or(OUT_OF_RANGE)?; + let date = NaiveDate::from_ymd(year, month, day).map_err(|_| OUT_OF_RANGE)?; (verify_isoweekdate(date) && verify_ordinal(date), date) } (Some(year), _, &Parsed { ordinal: Some(ordinal), .. }) => { // year, day of the year - let date = NaiveDate::from_yo_opt(year, ordinal).ok_or(OUT_OF_RANGE)?; + let date = NaiveDate::from_yo(year, ordinal).map_err(|_| OUT_OF_RANGE)?; (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date) } @@ -413,7 +413,7 @@ impl Parsed { &Parsed { week_from_sun: Some(week_from_sun), weekday: Some(weekday), .. }, ) => { // year, week (starting at 1st Sunday), day of the week - let newyear = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?; + let newyear = NaiveDate::from_yo(year, 1).map_err(|_| OUT_OF_RANGE)?; let firstweek = match newyear.weekday() { Weekday::Sun => 0, Weekday::Mon => 6, @@ -433,7 +433,7 @@ impl Parsed { + weekday.num_days_from_sunday() as i32; let date = newyear .checked_add_signed(TimeDelta::days(i64::from(ndays))) - .ok_or(OUT_OF_RANGE)?; + .map_err(|_| OUT_OF_RANGE)?; if date.year() != year { return Err(OUT_OF_RANGE); } // early exit for correct error @@ -447,7 +447,7 @@ impl Parsed { &Parsed { week_from_mon: Some(week_from_mon), weekday: Some(weekday), .. }, ) => { // year, week (starting at 1st Monday), day of the week - let newyear = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?; + let newyear = NaiveDate::from_yo(year, 1).map_err(|_| OUT_OF_RANGE)?; let firstweek = match newyear.weekday() { Weekday::Sun => 1, Weekday::Mon => 0, @@ -467,7 +467,7 @@ impl Parsed { + weekday.num_days_from_monday() as i32; let date = newyear .checked_add_signed(TimeDelta::days(i64::from(ndays))) - .ok_or(OUT_OF_RANGE)?; + .map_err(|_| OUT_OF_RANGE)?; if date.year() != year { return Err(OUT_OF_RANGE); } // early exit for correct error @@ -477,8 +477,8 @@ impl Parsed { (_, Some(isoyear), &Parsed { isoweek: Some(isoweek), weekday: Some(weekday), .. }) => { // ISO year, week, day of the week - let date = NaiveDate::from_isoywd_opt(isoyear, isoweek, weekday); - let date = date.ok_or(OUT_OF_RANGE)?; + let date = + NaiveDate::from_isoywd(isoyear, isoweek, weekday).map_err(|_| OUT_OF_RANGE)?; (verify_ymd(date) && verify_ordinal(date), date) } @@ -533,7 +533,7 @@ impl Parsed { None => 0, }; - NaiveTime::from_hms_nano_opt(hour, minute, second, nano).ok_or(OUT_OF_RANGE) + NaiveTime::from_hms_nano(hour, minute, second, nano).map_err(|_| OUT_OF_RANGE) } /// Returns a parsed naive date and time out of given fields, @@ -576,8 +576,7 @@ impl Parsed { // reconstruct date and time fields from timestamp let ts = timestamp.checked_add(i64::from(offset)).ok_or(OUT_OF_RANGE)?; - let datetime = NaiveDateTime::from_timestamp_opt(ts, 0); - let mut datetime = datetime.ok_or(OUT_OF_RANGE)?; + let mut datetime = NaiveDateTime::from_timestamp(ts, 0).map_err(|_| OUT_OF_RANGE)?; // fill year, ordinal, hour, minute and second fields from timestamp. // if existing fields are consistent, this will allow the full date/time reconstruction. @@ -617,7 +616,8 @@ impl Parsed { /// Returns a parsed fixed time zone offset out of given fields. pub fn to_fixed_offset(&self) -> ParseResult { - self.offset.and_then(FixedOffset::east_opt).ok_or(OUT_OF_RANGE) + let offset = self.offset.ok_or(OUT_OF_RANGE)?; + FixedOffset::east(offset).map_err(|_| OUT_OF_RANGE) } /// Returns a parsed timezone-aware date and time out of given fields. @@ -629,18 +629,15 @@ impl Parsed { pub fn to_datetime(&self) -> ParseResult> { let offset = self.offset.ok_or(NOT_ENOUGH)?; let datetime = self.to_naive_datetime_with_offset(offset)?; - let offset = FixedOffset::east_opt(offset).ok_or(OUT_OF_RANGE)?; + let offset = FixedOffset::east(offset).map_err(|_| OUT_OF_RANGE)?; // this is used to prevent an overflow when calling FixedOffset::from_local_datetime + // TODO: is this still needed? datetime .checked_sub_signed(TimeDelta::seconds(i64::from(offset.local_minus_utc()))) - .ok_or(OUT_OF_RANGE)?; + .map_err(|_| OUT_OF_RANGE)?; - match offset.from_local_datetime(&datetime) { - LocalResult::None => Err(IMPOSSIBLE), - LocalResult::Single(t) => Ok(t), - LocalResult::Ambiguous(..) => Err(NOT_ENOUGH), - } + offset.from_local_datetime(&datetime).and_then(|dt| dt.single()).map_err(|_| OUT_OF_RANGE) } /// Returns a parsed timezone-aware date and time out of given fields, @@ -659,9 +656,10 @@ impl Parsed { // make a naive `DateTime` from given timestamp and (if any) nanosecond. // an empty `nanosecond` is always equal to zero, so missing nanosecond is fine. let nanosecond = self.nanosecond.unwrap_or(0); - let dt = NaiveDateTime::from_timestamp_opt(timestamp, nanosecond); - let dt = dt.ok_or(OUT_OF_RANGE)?; - guessed_offset = tz.offset_from_utc_datetime(&dt).fix().local_minus_utc(); + let dt = + NaiveDateTime::from_timestamp(timestamp, nanosecond).map_err(|_| OUT_OF_RANGE)?; + guessed_offset = + tz.offset_from_utc_datetime(&dt).map_err(|_| OUT_OF_RANGE)?.fix().local_minus_utc(); } // checks if the given `DateTime` has a consistent `Offset` with given `self.offset`. @@ -676,24 +674,16 @@ impl Parsed { // `guessed_offset` should be correct when `self.timestamp` is given. // it will be 0 otherwise, but this is fine as the algorithm ignores offset for that case. let datetime = self.to_naive_datetime_with_offset(guessed_offset)?; - match tz.from_local_datetime(&datetime) { - LocalResult::None => Err(IMPOSSIBLE), - LocalResult::Single(t) => { - if check_offset(&t) { - Ok(t) - } else { - Err(IMPOSSIBLE) - } - } - LocalResult::Ambiguous(min, max) => { - // try to disambiguate two possible local dates by offset. - match (check_offset(&min), check_offset(&max)) { - (false, false) => Err(IMPOSSIBLE), - (false, true) => Ok(max), - (true, false) => Ok(min), - (true, true) => Err(NOT_ENOUGH), - } - } + + let dt = tz + .from_local_datetime(&datetime) + .and_then(|dt| dt.single()) + .map_err(|_| OUT_OF_RANGE)?; + + if check_offset(&dt) { + Ok(dt) + } else { + Err(IMPOSSIBLE) } } } @@ -707,6 +697,12 @@ mod tests { use crate::Datelike; use crate::Weekday::*; + macro_rules! ymd { + ($year:expr, $month:expr, $day:expr) => { + NaiveDate::from_ymd($year, $month, $day).unwrap() + }; + } + #[test] fn test_parsed_set_fields() { // year*, isoyear* @@ -786,25 +782,29 @@ mod tests { ) } - let ymd = |y, m, d| Ok(NaiveDate::from_ymd(y, m, d)); - // ymd: omission of fields assert_eq!(parse!(), Err(NOT_ENOUGH)); assert_eq!(parse!(year: 1984), Err(NOT_ENOUGH)); assert_eq!(parse!(year: 1984, month: 1), Err(NOT_ENOUGH)); - assert_eq!(parse!(year: 1984, month: 1, day: 2), ymd(1984, 1, 2)); + assert_eq!(parse!(year: 1984, month: 1, day: 2), Ok(ymd!(1984, 1, 2))); assert_eq!(parse!(year: 1984, day: 2), Err(NOT_ENOUGH)); assert_eq!(parse!(year_div_100: 19), Err(NOT_ENOUGH)); assert_eq!(parse!(year_div_100: 19, year_mod_100: 84), Err(NOT_ENOUGH)); assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 1), Err(NOT_ENOUGH)); - assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 1, day: 2), ymd(1984, 1, 2)); + assert_eq!( + parse!(year_div_100: 19, year_mod_100: 84, month: 1, day: 2), + Ok(ymd!(1984, 1, 2)) + ); assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, day: 2), Err(NOT_ENOUGH)); assert_eq!(parse!(year_div_100: 19, month: 1, day: 2), Err(NOT_ENOUGH)); - assert_eq!(parse!(year_mod_100: 70, month: 1, day: 2), ymd(1970, 1, 2)); - assert_eq!(parse!(year_mod_100: 69, month: 1, day: 2), ymd(2069, 1, 2)); + assert_eq!(parse!(year_mod_100: 70, month: 1, day: 2), Ok(ymd!(1970, 1, 2))); + assert_eq!(parse!(year_mod_100: 69, month: 1, day: 2), Ok(ymd!(2069, 1, 2))); // ymd: out-of-range conditions - assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 2, day: 29), ymd(1984, 2, 29)); + assert_eq!( + parse!(year_div_100: 19, year_mod_100: 84, month: 2, day: 29), + Ok(ymd!(1984, 2, 29)) + ); assert_eq!( parse!(year_div_100: 19, year_mod_100: 83, month: 2, day: 29), Err(OUT_OF_RANGE) @@ -815,7 +815,7 @@ mod tests { ); assert_eq!( parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 31), - ymd(1983, 12, 31) + Ok(ymd!(1983, 12, 31)) ); assert_eq!( parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 32), @@ -830,13 +830,13 @@ mod tests { Err(OUT_OF_RANGE) ); assert_eq!(parse!(year_div_100: 19, year_mod_100: -1, month: 1, day: 1), Err(OUT_OF_RANGE)); - assert_eq!(parse!(year_div_100: 0, year_mod_100: 0, month: 1, day: 1), ymd(0, 1, 1)); + assert_eq!(parse!(year_div_100: 0, year_mod_100: 0, month: 1, day: 1), Ok(ymd!(0, 1, 1))); assert_eq!(parse!(year_div_100: -1, year_mod_100: 42, month: 1, day: 1), Err(OUT_OF_RANGE)); let max_year = NaiveDate::MAX.year(); assert_eq!( parse!(year_div_100: max_year / 100, year_mod_100: max_year % 100, month: 1, day: 1), - ymd(max_year, 1, 1) + Ok(ymd!(max_year, 1, 1)) ); assert_eq!( parse!(year_div_100: (max_year + 1) / 100, @@ -845,13 +845,13 @@ mod tests { ); // ymd: conflicting inputs - assert_eq!(parse!(year: 1984, year_div_100: 19, month: 1, day: 1), ymd(1984, 1, 1)); + assert_eq!(parse!(year: 1984, year_div_100: 19, month: 1, day: 1), Ok(ymd!(1984, 1, 1))); assert_eq!(parse!(year: 1984, year_div_100: 20, month: 1, day: 1), Err(IMPOSSIBLE)); - assert_eq!(parse!(year: 1984, year_mod_100: 84, month: 1, day: 1), ymd(1984, 1, 1)); + assert_eq!(parse!(year: 1984, year_mod_100: 84, month: 1, day: 1), Ok(ymd!(1984, 1, 1))); assert_eq!(parse!(year: 1984, year_mod_100: 83, month: 1, day: 1), Err(IMPOSSIBLE)); assert_eq!( parse!(year: 1984, year_div_100: 19, year_mod_100: 84, month: 1, day: 1), - ymd(1984, 1, 1) + Ok(ymd!(1984, 1, 1)) ); assert_eq!( parse!(year: 1984, year_div_100: 18, year_mod_100: 94, month: 1, day: 1), @@ -878,32 +878,32 @@ mod tests { assert_eq!(parse!(year: 2000, weekday: Sun), Err(NOT_ENOUGH)); assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Fri), Err(OUT_OF_RANGE)); assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Fri), Err(OUT_OF_RANGE)); - assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sat), ymd(2000, 1, 1)); - assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Sat), ymd(2000, 1, 1)); - assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sun), ymd(2000, 1, 2)); - assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sun), ymd(2000, 1, 2)); - assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Mon), ymd(2000, 1, 3)); - assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Mon), ymd(2000, 1, 3)); - assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sat), ymd(2000, 1, 8)); - assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sat), ymd(2000, 1, 8)); - assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sun), ymd(2000, 1, 9)); - assert_eq!(parse!(year: 2000, week_from_sun: 2, weekday: Sun), ymd(2000, 1, 9)); - assert_eq!(parse!(year: 2000, week_from_mon: 2, weekday: Mon), ymd(2000, 1, 10)); - assert_eq!(parse!(year: 2000, week_from_sun: 52, weekday: Sat), ymd(2000, 12, 30)); - assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Sun), ymd(2000, 12, 31)); + assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sat), Ok(ymd!(2000, 1, 1))); + assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Sat), Ok(ymd!(2000, 1, 1))); + assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sun), Ok(ymd!(2000, 1, 2))); + assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sun), Ok(ymd!(2000, 1, 2))); + assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Mon), Ok(ymd!(2000, 1, 3))); + assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Mon), Ok(ymd!(2000, 1, 3))); + assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sat), Ok(ymd!(2000, 1, 8))); + assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sat), Ok(ymd!(2000, 1, 8))); + assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sun), Ok(ymd!(2000, 1, 9))); + assert_eq!(parse!(year: 2000, week_from_sun: 2, weekday: Sun), Ok(ymd!(2000, 1, 9))); + assert_eq!(parse!(year: 2000, week_from_mon: 2, weekday: Mon), Ok(ymd!(2000, 1, 10))); + assert_eq!(parse!(year: 2000, week_from_sun: 52, weekday: Sat), Ok(ymd!(2000, 12, 30))); + assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Sun), Ok(ymd!(2000, 12, 31))); assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Mon), Err(OUT_OF_RANGE)); assert_eq!(parse!(year: 2000, week_from_sun: 0xffffffff, weekday: Mon), Err(OUT_OF_RANGE)); assert_eq!(parse!(year: 2006, week_from_sun: 0, weekday: Sat), Err(OUT_OF_RANGE)); - assert_eq!(parse!(year: 2006, week_from_sun: 1, weekday: Sun), ymd(2006, 1, 1)); + assert_eq!(parse!(year: 2006, week_from_sun: 1, weekday: Sun), Ok(ymd!(2006, 1, 1))); // weekdates: conflicting inputs assert_eq!( parse!(year: 2000, week_from_mon: 1, week_from_sun: 1, weekday: Sat), - ymd(2000, 1, 8) + Ok(ymd!(2000, 1, 8)) ); assert_eq!( parse!(year: 2000, week_from_mon: 1, week_from_sun: 2, weekday: Sun), - ymd(2000, 1, 9) + Ok(ymd!(2000, 1, 9)) ); assert_eq!( parse!(year: 2000, week_from_mon: 1, week_from_sun: 1, weekday: Sun), @@ -916,27 +916,27 @@ mod tests { // ISO weekdates assert_eq!(parse!(isoyear: 2004, isoweek: 53), Err(NOT_ENOUGH)); - assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Fri), ymd(2004, 12, 31)); - assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Sat), ymd(2005, 1, 1)); + assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Fri), Ok(ymd!(2004, 12, 31))); + assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Sat), Ok(ymd!(2005, 1, 1))); assert_eq!(parse!(isoyear: 2004, isoweek: 0xffffffff, weekday: Sat), Err(OUT_OF_RANGE)); assert_eq!(parse!(isoyear: 2005, isoweek: 0, weekday: Thu), Err(OUT_OF_RANGE)); - assert_eq!(parse!(isoyear: 2005, isoweek: 5, weekday: Thu), ymd(2005, 2, 3)); + assert_eq!(parse!(isoyear: 2005, isoweek: 5, weekday: Thu), Ok(ymd!(2005, 2, 3))); assert_eq!(parse!(isoyear: 2005, weekday: Thu), Err(NOT_ENOUGH)); // year and ordinal assert_eq!(parse!(ordinal: 123), Err(NOT_ENOUGH)); assert_eq!(parse!(year: 2000, ordinal: 0), Err(OUT_OF_RANGE)); - assert_eq!(parse!(year: 2000, ordinal: 1), ymd(2000, 1, 1)); - assert_eq!(parse!(year: 2000, ordinal: 60), ymd(2000, 2, 29)); - assert_eq!(parse!(year: 2000, ordinal: 61), ymd(2000, 3, 1)); - assert_eq!(parse!(year: 2000, ordinal: 366), ymd(2000, 12, 31)); + assert_eq!(parse!(year: 2000, ordinal: 1), Ok(ymd!(2000, 1, 1))); + assert_eq!(parse!(year: 2000, ordinal: 60), Ok(ymd!(2000, 2, 29))); + assert_eq!(parse!(year: 2000, ordinal: 61), Ok(ymd!(2000, 3, 1))); + assert_eq!(parse!(year: 2000, ordinal: 366), Ok(ymd!(2000, 12, 31))); assert_eq!(parse!(year: 2000, ordinal: 367), Err(OUT_OF_RANGE)); assert_eq!(parse!(year: 2000, ordinal: 0xffffffff), Err(OUT_OF_RANGE)); assert_eq!(parse!(year: 2100, ordinal: 0), Err(OUT_OF_RANGE)); - assert_eq!(parse!(year: 2100, ordinal: 1), ymd(2100, 1, 1)); - assert_eq!(parse!(year: 2100, ordinal: 59), ymd(2100, 2, 28)); - assert_eq!(parse!(year: 2100, ordinal: 60), ymd(2100, 3, 1)); - assert_eq!(parse!(year: 2100, ordinal: 365), ymd(2100, 12, 31)); + assert_eq!(parse!(year: 2100, ordinal: 1), Ok(ymd!(2100, 1, 1))); + assert_eq!(parse!(year: 2100, ordinal: 59), Ok(ymd!(2100, 2, 28))); + assert_eq!(parse!(year: 2100, ordinal: 60), Ok(ymd!(2100, 3, 1))); + assert_eq!(parse!(year: 2100, ordinal: 365), Ok(ymd!(2100, 12, 31))); assert_eq!(parse!(year: 2100, ordinal: 366), Err(OUT_OF_RANGE)); assert_eq!(parse!(year: 2100, ordinal: 0xffffffff), Err(OUT_OF_RANGE)); @@ -944,12 +944,12 @@ mod tests { assert_eq!( parse!(year: 2014, month: 12, day: 31, ordinal: 365, isoyear: 2015, isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed), - ymd(2014, 12, 31) + Ok(ymd!(2014, 12, 31)) ); assert_eq!( parse!(year: 2014, month: 12, ordinal: 365, isoyear: 2015, isoweek: 1, week_from_sun: 52, week_from_mon: 52), - ymd(2014, 12, 31) + Ok(ymd!(2014, 12, 31)) ); assert_eq!( parse!(year: 2014, month: 12, day: 31, ordinal: 365, isoyear: 2014, isoweek: 53, @@ -973,21 +973,27 @@ mod tests { ) } - let hms = |h, m, s| Ok(NaiveTime::from_hms(h, m, s)); - let hmsn = |h, m, s, n| Ok(NaiveTime::from_hms_nano(h, m, s, n)); + let hms = |h, m, s| NaiveTime::from_hms(h, m, s).unwrap(); + let hmsn = |h, m, s, n| NaiveTime::from_hms_nano(h, m, s, n).unwrap(); // omission of fields assert_eq!(parse!(), Err(NOT_ENOUGH)); assert_eq!(parse!(hour_div_12: 0), Err(NOT_ENOUGH)); assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1), Err(NOT_ENOUGH)); - assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23), hms(1, 23, 0)); - assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 45), hms(1, 23, 45)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23), Ok(hms(1, 23, 0))); + assert_eq!( + parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 45), + Ok(hms(1, 23, 45)) + ); assert_eq!( parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 45, nanosecond: 678_901_234), - hmsn(1, 23, 45, 678_901_234) + Ok(hmsn(1, 23, 45, 678_901_234)) + ); + assert_eq!( + parse!(hour_div_12: 1, hour_mod_12: 11, minute: 45, second: 6), + Ok(hms(23, 45, 6)) ); - assert_eq!(parse!(hour_div_12: 1, hour_mod_12: 11, minute: 45, second: 6), hms(23, 45, 6)); assert_eq!(parse!(hour_mod_12: 1, minute: 23), Err(NOT_ENOUGH)); assert_eq!( parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, nanosecond: 456_789_012), @@ -1011,12 +1017,12 @@ mod tests { // leap seconds assert_eq!( parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 60), - hmsn(1, 23, 59, 1_000_000_000) + Ok(hmsn(1, 23, 59, 1_000_000_000)) ); assert_eq!( parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 60, nanosecond: 999_999_999), - hmsn(1, 23, 59, 1_999_999_999) + Ok(hmsn(1, 23, 59, 1_999_999_999)) ); } @@ -1029,32 +1035,34 @@ mod tests { ($($k:ident: $v:expr),*) => (parse!(offset = 0; $($k: $v),*)) } - let ymdhms = |y, m, d, h, n, s| Ok(NaiveDate::from_ymd(y, m, d).and_hms(h, n, s)); - let ymdhmsn = - |y, m, d, h, n, s, nano| Ok(NaiveDate::from_ymd(y, m, d).and_hms_nano(h, n, s, nano)); + let ymdhms = + |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).unwrap().and_hms(h, n, s).unwrap(); + let ymdhmsn = |y, m, d, h, n, s, nano| { + NaiveDate::from_ymd(y, m, d).unwrap().and_hms_nano(h, n, s, nano).unwrap() + }; // omission of fields assert_eq!(parse!(), Err(NOT_ENOUGH)); assert_eq!( parse!(year: 2015, month: 1, day: 30, hour_div_12: 1, hour_mod_12: 2, minute: 38), - ymdhms(2015, 1, 30, 14, 38, 0) + Ok(ymdhms(2015, 1, 30, 14, 38, 0)) ); assert_eq!( parse!(year: 1997, month: 1, day: 30, hour_div_12: 1, hour_mod_12: 2, minute: 38, second: 5), - ymdhms(1997, 1, 30, 14, 38, 5) + Ok(ymdhms(1997, 1, 30, 14, 38, 5)) ); assert_eq!( parse!(year: 2012, ordinal: 34, hour_div_12: 0, hour_mod_12: 5, minute: 6, second: 7, nanosecond: 890_123_456), - ymdhmsn(2012, 2, 3, 5, 6, 7, 890_123_456) + Ok(ymdhmsn(2012, 2, 3, 5, 6, 7, 890_123_456)) ); - assert_eq!(parse!(timestamp: 0), ymdhms(1970, 1, 1, 0, 0, 0)); - assert_eq!(parse!(timestamp: 1, nanosecond: 0), ymdhms(1970, 1, 1, 0, 0, 1)); - assert_eq!(parse!(timestamp: 1, nanosecond: 1), ymdhmsn(1970, 1, 1, 0, 0, 1, 1)); - assert_eq!(parse!(timestamp: 1_420_000_000), ymdhms(2014, 12, 31, 4, 26, 40)); - assert_eq!(parse!(timestamp: -0x1_0000_0000), ymdhms(1833, 11, 24, 17, 31, 44)); + assert_eq!(parse!(timestamp: 0), Ok(ymdhms(1970, 1, 1, 0, 0, 0))); + assert_eq!(parse!(timestamp: 1, nanosecond: 0), Ok(ymdhms(1970, 1, 1, 0, 0, 1))); + assert_eq!(parse!(timestamp: 1, nanosecond: 1), Ok(ymdhmsn(1970, 1, 1, 0, 0, 1, 1))); + assert_eq!(parse!(timestamp: 1_420_000_000), Ok(ymdhms(2014, 12, 31, 4, 26, 40))); + assert_eq!(parse!(timestamp: -0x1_0000_0000), Ok(ymdhms(1833, 11, 24, 17, 31, 44))); // full fields assert_eq!( @@ -1063,7 +1071,7 @@ mod tests { isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed, hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, nanosecond: 12_345_678, timestamp: 1_420_000_000), - ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678) + Ok(ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678)) ); assert_eq!( parse!(year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31, @@ -1080,42 +1088,42 @@ mod tests { isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed, hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, nanosecond: 12_345_678, timestamp: 1_419_967_600), - ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678) + Ok(ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678)) ); // more timestamps - let max_days_from_year_1970 = - NaiveDate::MAX.signed_duration_since(NaiveDate::from_ymd(1970, 1, 1)); - let year_0_from_year_1970 = - 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)); + let max_days_from_year_1970 = NaiveDate::MAX.signed_duration_since(ymd!(1970, 1, 1)); + let year_0_from_year_1970 = ymd!(0, 1, 1).signed_duration_since(ymd!(1970, 1, 1)); + let min_days_from_year_1970 = NaiveDate::MIN.signed_duration_since(ymd!(1970, 1, 1)); assert_eq!( parse!(timestamp: min_days_from_year_1970.num_seconds()), - ymdhms(NaiveDate::MIN.year(), 1, 1, 0, 0, 0) + Ok(ymdhms(NaiveDate::MIN.year(), 1, 1, 0, 0, 0)) ); assert_eq!( parse!(timestamp: year_0_from_year_1970.num_seconds()), - ymdhms(0, 1, 1, 0, 0, 0) + Ok(ymdhms(0, 1, 1, 0, 0, 0)) ); assert_eq!( parse!(timestamp: max_days_from_year_1970.num_seconds() + 86399), - ymdhms(NaiveDate::MAX.year(), 12, 31, 23, 59, 59) + Ok(ymdhms(NaiveDate::MAX.year(), 12, 31, 23, 59, 59)) ); // leap seconds #1: partial fields assert_eq!(parse!(second: 59, timestamp: 1_341_100_798), Err(IMPOSSIBLE)); - assert_eq!(parse!(second: 59, timestamp: 1_341_100_799), ymdhms(2012, 6, 30, 23, 59, 59)); + assert_eq!( + parse!(second: 59, timestamp: 1_341_100_799), + Ok(ymdhms(2012, 6, 30, 23, 59, 59)) + ); assert_eq!(parse!(second: 59, timestamp: 1_341_100_800), Err(IMPOSSIBLE)); assert_eq!( parse!(second: 60, timestamp: 1_341_100_799), - ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000) + Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)) ); assert_eq!( parse!(second: 60, timestamp: 1_341_100_800), - ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000) + Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)) ); - assert_eq!(parse!(second: 0, timestamp: 1_341_100_800), ymdhms(2012, 7, 1, 0, 0, 0)); + assert_eq!(parse!(second: 0, timestamp: 1_341_100_800), Ok(ymdhms(2012, 7, 1, 0, 0, 0))); assert_eq!(parse!(second: 1, timestamp: 1_341_100_800), Err(IMPOSSIBLE)); assert_eq!(parse!(second: 60, timestamp: 1_341_100_801), Err(IMPOSSIBLE)); @@ -1129,7 +1137,7 @@ mod tests { assert_eq!( parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, minute: 59, second: 59, timestamp: 1_341_100_799), - ymdhms(2012, 6, 30, 23, 59, 59) + Ok(ymdhms(2012, 6, 30, 23, 59, 59)) ); assert_eq!( parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, @@ -1139,17 +1147,17 @@ mod tests { assert_eq!( parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, minute: 59, second: 60, timestamp: 1_341_100_799), - ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000) + Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)) ); assert_eq!( parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, minute: 59, second: 60, timestamp: 1_341_100_800), - ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000) + Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)) ); assert_eq!( parse!(year: 2012, ordinal: 183, hour_div_12: 0, hour_mod_12: 0, minute: 0, second: 0, timestamp: 1_341_100_800), - ymdhms(2012, 7, 1, 0, 0, 0) + Ok(ymdhms(2012, 7, 1, 0, 0, 0)) ); assert_eq!( parse!(year: 2012, ordinal: 183, hour_div_12: 0, hour_mod_12: 0, @@ -1179,7 +1187,12 @@ mod tests { } let ymdhmsn = |y, m, d, h, n, s, nano, off| { - Ok(FixedOffset::east(off).ymd(y, m, d).and_hms_nano(h, n, s, nano)) + FixedOffset::east(off) + .unwrap() + .ymd(y, m, d) + .unwrap() + .and_hms_nano(h, n, s, nano) + .unwrap() }; assert_eq!(parse!(offset: 0), Err(NOT_ENOUGH)); @@ -1191,17 +1204,17 @@ mod tests { assert_eq!( parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, nanosecond: 12_345_678, offset: 0), - ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678, 0) + Ok(ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678, 0)) ); assert_eq!( parse!(year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1, minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400), - ymdhmsn(2014, 12, 31, 13, 26, 40, 12_345_678, 32400) + Ok(ymdhmsn(2014, 12, 31, 13, 26, 40, 12_345_678, 32400)) ); assert_eq!( parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 1, minute: 42, second: 4, nanosecond: 12_345_678, offset: -9876), - ymdhmsn(2014, 12, 31, 1, 42, 4, 12_345_678, -9876) + Ok(ymdhmsn(2014, 12, 31, 1, 42, 4, 12_345_678, -9876)) ); assert_eq!( parse!(year: 2015, ordinal: 1, hour_div_12: 0, hour_mod_12: 4, @@ -1223,7 +1236,7 @@ mod tests { parse!(Utc; year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, nanosecond: 12_345_678, offset: 0), - Ok(Utc.ymd(2014, 12, 31).and_hms_nano(4, 26, 40, 12_345_678)) + Ok(Utc.ymd(2014, 12, 31).unwrap().and_hms_nano(4, 26, 40, 12_345_678).unwrap()) ); assert_eq!( parse!(Utc; @@ -1232,31 +1245,41 @@ mod tests { Err(IMPOSSIBLE) ); assert_eq!( - parse!(FixedOffset::east(32400); + parse!(FixedOffset::east(32400).unwrap(); year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, nanosecond: 12_345_678, offset: 0), Err(IMPOSSIBLE) ); assert_eq!( - parse!(FixedOffset::east(32400); + parse!(FixedOffset::east(32400).unwrap(); year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1, minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400), - Ok(FixedOffset::east(32400).ymd(2014, 12, 31).and_hms_nano(13, 26, 40, 12_345_678)) + Ok(FixedOffset::east(32400) + .unwrap() + .ymd(2014, 12, 31) + .unwrap() + .and_hms_nano(13, 26, 40, 12_345_678) + .unwrap()) ); // single result from timestamp assert_eq!( parse!(Utc; timestamp: 1_420_000_000, offset: 0), - Ok(Utc.ymd(2014, 12, 31).and_hms(4, 26, 40)) + Ok(Utc.ymd(2014, 12, 31).unwrap().and_hms(4, 26, 40).unwrap()) ); assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 32400), Err(IMPOSSIBLE)); assert_eq!( - parse!(FixedOffset::east(32400); timestamp: 1_420_000_000, offset: 0), + parse!(FixedOffset::east(32400).unwrap(); timestamp: 1_420_000_000, offset: 0), Err(IMPOSSIBLE) ); assert_eq!( - parse!(FixedOffset::east(32400); timestamp: 1_420_000_000, offset: 32400), - Ok(FixedOffset::east(32400).ymd(2014, 12, 31).and_hms(13, 26, 40)) + parse!(FixedOffset::east(32400).unwrap(); timestamp: 1_420_000_000, offset: 32400), + Ok(FixedOffset::east(32400) + .unwrap() + .ymd(2014, 12, 31) + .unwrap() + .and_hms(13, 26, 40) + .unwrap()) ); // TODO test with a variable time zone (for None and Ambiguous cases) diff --git a/src/format/strftime.rs b/src/format/strftime.rs index 31509a0ff4..6f6bca9fd9 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -552,7 +552,12 @@ fn test_strftime_items() { fn test_strftime_docs() { use crate::{DateTime, FixedOffset, TimeZone, Timelike, Utc}; - let dt = FixedOffset::east(34200).ymd(2001, 7, 8).and_hms_nano(0, 34, 59, 1_026_490_708); + let dt = FixedOffset::east(34200) + .unwrap() + .ymd(2001, 7, 8) + .unwrap() + .and_hms_nano(0, 34, 59, 1_026_490_708) + .unwrap(); // date specifiers assert_eq!(dt.format("%Y").to_string(), "2001"); @@ -617,19 +622,19 @@ fn test_strftime_docs() { assert_eq!(dt.format("%+").to_string(), "2001-07-08T00:34:60.026490708+09:30"); assert_eq!( - dt.with_timezone(&Utc).format("%+").to_string(), + dt.with_timezone(&Utc).unwrap().format("%+").to_string(), "2001-07-07T15:04:60.026490708+00:00" ); assert_eq!( - dt.with_timezone(&Utc), + dt.with_timezone(&Utc).unwrap(), DateTime::parse_from_str("2001-07-07T15:04:60.026490708Z", "%+").unwrap() ); assert_eq!( - dt.with_timezone(&Utc), + dt.with_timezone(&Utc).unwrap(), DateTime::parse_from_str("2001-07-07T15:04:60.026490708UTC", "%+").unwrap() ); assert_eq!( - dt.with_timezone(&Utc), + dt.with_timezone(&Utc).unwrap(), DateTime::parse_from_str("2001-07-07t15:04:60.026490708utc", "%+").unwrap() ); @@ -650,7 +655,12 @@ fn test_strftime_docs() { fn test_strftime_docs_localized() { use crate::{FixedOffset, TimeZone}; - let dt = FixedOffset::east(34200).ymd(2001, 7, 8).and_hms_nano(0, 34, 59, 1_026_490_708); + let dt = FixedOffset::east(34200) + .unwrap() + .ymd(2001, 7, 8) + .unwrap() + .and_hms_nano(0, 34, 59, 1_026_490_708) + .unwrap(); // date specifiers assert_eq!(dt.format_localized("%b", Locale::fr_BE).to_string(), "jui"); diff --git a/src/lib.rs b/src/lib.rs index 4c3f086b25..456b69aa5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,9 +99,10 @@ //! ```rust //! use chrono::prelude::*; //! -//! let utc: DateTime = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z` -//! let local: DateTime = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00` +//! let utc: DateTime = Utc::now()?; // e.g. `2014-11-28T12:45:59.324310806Z` +//! let local: DateTime = Local::now()?; // e.g. `2014-11-28T21:45:59.324310806+09:00` //! # let _ = utc; let _ = local; +//! # Ok::<_, chrono::ChronoError>(()) //! ``` //! //! Alternatively, you can create your own date and time. @@ -110,30 +111,29 @@ //! //! ```rust //! use chrono::prelude::*; -//! use chrono::offset::LocalResult; //! -//! let dt = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z` +//! let dt = Utc.ymd(2014, 7, 8)?.and_hms(9, 10, 11)?; // `2014-07-08T09:10:11Z` //! // July 8 is 188th day of the year 2014 (`o` for "ordinal") -//! assert_eq!(dt, Utc.yo(2014, 189).and_hms(9, 10, 11)); +//! assert_eq!(dt, Utc.yo(2014, 189)?.and_hms(9, 10, 11)?); //! // July 8 is Tuesday in ISO week 28 of the year 2014. -//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11)); +//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue)?.and_hms(9, 10, 11)?); //! -//! let dt = Utc.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); // `2014-07-08T09:10:11.012Z` -//! assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_micro(9, 10, 11, 12_000)); -//! assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 12_000_000)); +//! let dt = Utc.ymd(2014, 7, 8)?.and_hms_milli(9, 10, 11, 12)?; // `2014-07-08T09:10:11.012Z` +//! assert_eq!(dt, Utc.ymd(2014, 7, 8)?.and_hms_micro(9, 10, 11, 12_000)?); +//! assert_eq!(dt, Utc.ymd(2014, 7, 8)?.and_hms_nano(9, 10, 11, 12_000_000)?); //! //! // dynamic verification -//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33), -//! LocalResult::Single(Utc.ymd(2014, 7, 8).and_hms(21, 15, 33))); -//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None); -//! assert_eq!(Utc.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None); +//! assert!(Utc.ymd(2014, 7, 8)?.and_hms(21, 15, 33).is_ok()); +//! assert!(Utc.ymd(2014, 7, 8)?.and_hms(80, 15, 33).is_err()); +//! assert!(Utc.ymd(2014, 7, 38).is_err()); //! //! // other time zone objects can be used to construct a local datetime. //! // obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical. -//! let local_dt = Local.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); -//! let fixed_dt = FixedOffset::east(9 * 3600).ymd(2014, 7, 8).and_hms_milli(18, 10, 11, 12); +//! let local_dt = Local.ymd(2014, 7, 8)?.and_hms_milli(9, 10, 11, 12)?; +//! let fixed_dt = FixedOffset::east(9 * 3600)?.ymd(2014, 7, 8)?.and_hms_milli(18, 10, 11, 12)?; //! assert_eq!(dt, fixed_dt); //! # let _ = local_dt; +//! # Ok::<_, chrono::ChronoError>(()) //! ``` //! //! Various properties are available to the date and time, and can be altered individually. @@ -147,7 +147,7 @@ //! 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); +//! let dt = FixedOffset::east(9*3600)?.ymd(2014, 11, 28)?.and_hms_nano(21, 45, 59, 324310806)?; //! //! // property accessors //! assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28)); @@ -160,23 +160,24 @@ //! //! // time zone accessor and manipulation //! assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600); -//! assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600)); -//! assert_eq!(dt.with_timezone(&Utc), Utc.ymd(2014, 11, 28).and_hms_nano(12, 45, 59, 324310806)); +//! assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600)?); +//! assert_eq!(dt.with_fixed_timezone(&Utc), Utc.ymd(2014, 11, 28)?.and_hms_nano(12, 45, 59, 324310806)?); //! //! // a sample of property manipulations (validates dynamically) -//! assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday -//! assert_eq!(dt.with_day(32), None); -//! assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November 29, 301 BCE +//! assert_eq!(dt.with_day(29)?.weekday(), Weekday::Sat); // 2014-11-29 is Saturday +//! assert!(dt.with_day(32).is_err()); +//! assert_eq!(dt.with_year(-300)?.num_days_from_ce(), -109606); // November 29, 301 BCE //! //! // 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); +//! 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), 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) - TimeDelta::seconds(1_000_000_000), -//! Utc.ymd(1938, 4, 24).and_hms(22, 13, 20)); +//! 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)? - TimeDelta::seconds(1_000_000_000), +//! Utc.ymd(1938, 4, 24)?.and_hms(22, 13, 20)?); +//! # Ok::<_, chrono::ChronoError>(()) //! ``` //! //! ### Formatting and Parsing @@ -206,8 +207,8 @@ //! use chrono::prelude::*; //! //! # #[cfg(feature = "unstable-locales")] -//! # fn test() { -//! let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9); +//! # fn main() -> Result<(), chrono::ChronoError> { +//! let dt = Utc.ymd(2014, 11, 28)?.and_hms(12, 0, 9)?; //! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09"); //! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014"); //! assert_eq!(dt.format_localized("%A %e %B %Y, %T", Locale::fr_BE).to_string(), "vendredi 28 novembre 2014, 12:00:09"); @@ -219,14 +220,9 @@ //! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z"); //! //! // Note that milli/nanoseconds are only printed if they are non-zero -//! let dt_nano = Utc.ymd(2014, 11, 28).and_hms_nano(12, 0, 9, 1); +//! let dt_nano = Utc.ymd(2014, 11, 28)?.and_hms_nano(12, 0, 9, 1)?; //! assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z"); -//! # } -//! # #[cfg(not(feature = "unstable-locales"))] -//! # fn test() {} -//! # if cfg!(feature = "unstable-locales") { -//! # test(); -//! # } +//! # Ok(()) } //! ``` //! //! Parsing can be done with three methods: @@ -259,24 +255,24 @@ //! ```rust //! use chrono::prelude::*; //! -//! let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9); -//! let fixed_dt = dt.with_timezone(&FixedOffset::east(9*3600)); +//! let dt = Utc.ymd(2014, 11, 28)?.and_hms(12, 0, 9)?; +//! let fixed_dt = dt.with_timezone(&FixedOffset::east(9*3600)?)?; //! //! // method 1 -//! assert_eq!("2014-11-28T12:00:09Z".parse::>(), Ok(dt.clone())); -//! assert_eq!("2014-11-28T21:00:09+09:00".parse::>(), Ok(dt.clone())); -//! assert_eq!("2014-11-28T21:00:09+09:00".parse::>(), Ok(fixed_dt.clone())); +//! assert_eq!("2014-11-28T12:00:09Z".parse::>()?, dt.clone()); +//! assert_eq!("2014-11-28T21:00:09+09:00".parse::>()?, dt.clone()); +//! assert_eq!("2014-11-28T21:00:09+09:00".parse::>()?, fixed_dt.clone()); //! //! // method 2 -//! assert_eq!(DateTime::parse_from_str("2014-11-28 21:00:09 +09:00", "%Y-%m-%d %H:%M:%S %z"), -//! Ok(fixed_dt.clone())); -//! assert_eq!(DateTime::parse_from_rfc2822("Fri, 28 Nov 2014 21:00:09 +0900"), -//! Ok(fixed_dt.clone())); -//! assert_eq!(DateTime::parse_from_rfc3339("2014-11-28T21:00:09+09:00"), Ok(fixed_dt.clone())); +//! assert_eq!(DateTime::parse_from_str("2014-11-28 21:00:09 +09:00", "%Y-%m-%d %H:%M:%S %z")?, +//! fixed_dt.clone()); +//! assert_eq!(DateTime::parse_from_rfc2822("Fri, 28 Nov 2014 21:00:09 +0900")?, +//! fixed_dt.clone()); +//! assert_eq!(DateTime::parse_from_rfc3339("2014-11-28T21:00:09+09:00")?, fixed_dt.clone()); //! //! // method 3 -//! assert_eq!(Utc.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone())); -//! assert_eq!(Utc.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone())); +//! assert_eq!(Utc.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S")?, dt.clone()); +//! assert_eq!(Utc.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y")?, dt.clone()); //! //! // oops, the year is missing! //! assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err()); @@ -284,6 +280,7 @@ //! assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err()); //! // oops, the weekday is incorrect! //! assert!(Utc.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err()); +//! # Ok::<_, Box>(()) //! ``` //! //! Again : See [`format::strftime`](./format/strftime/index.html#specifiers) @@ -305,12 +302,13 @@ //! use chrono::{DateTime, TimeZone, Utc}; //! //! // Construct a datetime from epoch: -//! let dt = Utc.timestamp(1_500_000_000, 0); +//! let dt = Utc.timestamp(1_500_000_000, 0)?; //! assert_eq!(dt.to_rfc2822(), "Fri, 14 Jul 2017 02:40:00 +0000"); //! //! // Get epoch value from a datetime: -//! let dt = DateTime::parse_from_rfc2822("Fri, 14 Jul 2017 02:40:00 +0000").unwrap(); +//! let dt = DateTime::parse_from_rfc2822("Fri, 14 Jul 2017 02:40:00 +0000")?; //! assert_eq!(dt.timestamp(), 1_500_000_000); +//! # Ok::<_, Box>(()) //! ``` //! //! ### Individual date @@ -321,16 +319,16 @@ //! //! ```rust //! use chrono::prelude::*; -//! use chrono::offset::LocalResult; //! //! # // these *may* fail, but only very rarely. just rerun the test if you were that unfortunate ;) -//! assert_eq!(Utc::today(), Utc::now().date()); -//! assert_eq!(Local::today(), Local::now().date()); +//! assert_eq!(Utc::today()?, Utc::now()?.date()); +//! assert_eq!(Local::today()?, Local::now()?.date()); //! -//! assert_eq!(Utc.ymd(2014, 11, 28).weekday(), Weekday::Fri); -//! assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None); -//! assert_eq!(Utc.ymd(2014, 11, 28).and_hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(), +//! assert_eq!(Utc.ymd(2014, 11, 28)?.single()?.weekday(), Weekday::Fri); +//! assert!(Utc.ymd(2014, 11, 31).is_err()); +//! assert_eq!(Utc.ymd(2014, 11, 28)?.and_hms_milli(7, 8, 9, 10)?.format("%H%M%S").to_string(), //! "070809"); +//! # Ok::<_, chrono::ChronoError>(()) //! ``` //! //! There is no timezone-aware `Time` due to the lack of usefulness and also the complexity. @@ -440,6 +438,9 @@ mod datetime; #[allow(deprecated)] pub use datetime::{DateTime, SecondsFormat, MAX_DATETIME, MIN_DATETIME}; +mod error; +pub use self::error::ChronoError; + pub mod format; /// L10n locales. #[cfg(feature = "unstable-locales")] diff --git a/src/month.rs b/src/month.rs index 8b2f10ea84..6d1154012c 100644 --- a/src/month.rs +++ b/src/month.rs @@ -10,21 +10,26 @@ use crate::OutOfRange; /// This enum is just a convenience implementation. /// The month in dates created by DateLike objects does not return this enum. /// -/// It is possible to convert from a date to a month independently +/// It is possible to convert from a date to a month independently. +/// /// ``` /// use chrono::prelude::*; /// use std::convert::TryFrom; -/// let date = Utc.ymd(2019, 10, 28).and_hms(9, 10, 11); +/// let date = Utc.ymd(2019, 10, 28)?.and_hms(9, 10, 11)?; /// // `2019-10-28T09:10:11Z` /// let month = Month::try_from(u8::try_from(date.month()).unwrap()).ok(); -/// assert_eq!(month, Some(Month::October)) +/// assert_eq!(month, Some(Month::October)); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` +/// /// Or from a Month to an integer usable by dates +/// /// ``` /// # use chrono::prelude::*; /// let month = Month::January; -/// let dt = Utc.ymd(2019, month.number_from_month(), 28).and_hms(9, 10, 11); +/// let dt = Utc.ymd(2019, month.number_from_month(), 28)?.and_hms(9, 10, 11)?; /// assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28)); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// Allows mapping from and to month, from 1-January to 12-December. /// Can be Serialized/Deserialized with serde @@ -317,11 +322,11 @@ mod tests { assert_eq!(Month::try_from(12), Ok(Month::December)); assert_eq!(Month::try_from(13), Err(OutOfRange::new())); - let date = Utc.ymd(2019, 10, 28).and_hms(9, 10, 11); + let date = Utc.ymd(2019, 10, 28).unwrap().and_hms(9, 10, 11).unwrap(); assert_eq!(Month::try_from(date.month() as u8), Ok(Month::October)); let month = Month::January; - let dt = Utc.ymd(2019, month.number_from_month(), 28).and_hms(9, 10, 11); + let dt = Utc.ymd(2019, month.number_from_month(), 28).unwrap().and_hms(9, 10, 11).unwrap(); assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28)); } diff --git a/src/naive/date.rs b/src/naive/date.rs index 2d2ae2c446..983cb51d3d 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -13,13 +13,14 @@ use num_integer::div_mod_floor; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; +use crate::error::ChronoErrorKind; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::DelayedFormat; 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::{Datelike, TimeDelta, Weekday}; +use crate::{ChronoError, Datelike, TimeDelta, Weekday}; use super::internals::{self, DateImpl, Mdf, Of, YearFlags}; use super::isoweek; @@ -66,9 +67,10 @@ impl NaiveWeek { /// ``` /// use chrono::{NaiveDate, Weekday}; /// - /// let date = NaiveDate::from_ymd(2022, 4, 18); + /// let date = NaiveDate::from_ymd(2022, 4, 18)?; /// let week = date.week(Weekday::Mon); /// assert!(week.first_day() <= date); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn first_day(&self) -> NaiveDate { @@ -85,9 +87,10 @@ impl NaiveWeek { /// ``` /// use chrono::{NaiveDate, Weekday}; /// - /// let date = NaiveDate::from_ymd(2022, 4, 18); + /// let date = NaiveDate::from_ymd(2022, 4, 18)?; /// let week = date.week(Weekday::Mon); /// assert!(week.last_day() >= date); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn last_day(&self) -> NaiveDate { @@ -103,10 +106,11 @@ impl NaiveWeek { /// ``` /// use chrono::{NaiveDate, Weekday}; /// - /// let date = NaiveDate::from_ymd(2022, 4, 18); + /// let date = NaiveDate::from_ymd(2022, 4, 18)?; /// let week = date.week(Weekday::Mon); /// let days = week.days(); /// assert!(days.contains(&date)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn days(&self) -> RangeInclusive { @@ -191,61 +195,41 @@ pub const MIN_DATE: NaiveDate = NaiveDate::MIN; #[deprecated(since = "0.4.20", note = "Use NaiveDate::MAX instead")] pub const MAX_DATE: NaiveDate = NaiveDate::MAX; -// as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`, -// we use a separate run-time test. -#[test] -fn test_date_bounds() { - let calculated_min = NaiveDate::from_ymd(MIN_YEAR, 1, 1); - let calculated_max = NaiveDate::from_ymd(MAX_YEAR, 12, 31); - assert!( - NaiveDate::MIN == calculated_min, - "`NaiveDate::MIN` should have a year flag {:?}", - calculated_min.of().flags() - ); - assert!( - NaiveDate::MAX == calculated_max, - "`NaiveDate::MAX` should have a year flag {:?}", - calculated_max.of().flags() - ); - - // let's also check that the entire range do not exceed 2^44 seconds - // (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!( - maxsecs < (1 << MAX_BITS), - "The entire `NaiveDate` range somehow exceeds 2^{} seconds", - MAX_BITS - ); -} - impl NaiveDate { + /// The minimum possible `NaiveDate` (January 1, 262145 BCE). + pub const MIN: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ }; + /// The maximum possible `NaiveDate` (December 31, 262143 CE). + pub const MAX: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ }; + /// Date that corresponds to the start of the unix epoch. + pub(crate) const UNIX_EPOCH: NaiveDate = NaiveDate { ymdf: (1970 << 13) | (1 << 4) | 0o12 }; + /// Makes a new `NaiveDate` from year and packed ordinal-flags, with a verification. - fn from_of(year: i32, of: Of) -> Option { + fn from_of(year: i32, of: Of) -> Result { if (MIN_YEAR..=MAX_YEAR).contains(&year) && of.valid() { let Of(of) = of; - Some(NaiveDate { ymdf: (year << 13) | (of as DateImpl) }) + Ok(NaiveDate { ymdf: (year << 13) | (of as DateImpl) }) } else { - None + Err(ChronoError::new(ChronoErrorKind::InvalidDate)) } } /// Makes a new `NaiveDate` from year and packed month-day-flags, with a verification. - fn from_mdf(year: i32, mdf: Mdf) -> Option { + fn from_mdf(year: i32, mdf: Mdf) -> Result { NaiveDate::from_of(year, mdf.to_of()) } - /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) - /// (year, month and day). + /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) (year, + /// month and day). /// - /// Panics on the out-of-range date, invalid month and/or day. + /// Returns `Err(ChronoError)` on the out-of-range date, invalid month + /// and/or day. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_ymd(2015, 3, 14); + /// let d = NaiveDate::from_ymd(2015, 3, 14)?; /// assert_eq!(d.year(), 2015); /// assert_eq!(d.month(), 3); /// assert_eq!(d.day(), 14); @@ -254,46 +238,36 @@ impl NaiveDate { /// assert_eq!(d.iso_week().week(), 11); /// assert_eq!(d.weekday(), Weekday::Sat); /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE - /// ``` - pub fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate { - NaiveDate::from_ymd_opt(year, month, day).expect("invalid or out-of-range date") - } - - /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) - /// (year, month and day). - /// - /// Returns `None` on the out-of-range date, invalid month and/or day. /// - /// # Example - /// - /// ``` - /// use chrono::NaiveDate; - /// - /// let from_ymd_opt = NaiveDate::from_ymd_opt; + /// let from_ymd = NaiveDate::from_ymd; /// - /// assert!(from_ymd_opt(2015, 3, 14).is_some()); - /// assert!(from_ymd_opt(2015, 0, 14).is_none()); - /// assert!(from_ymd_opt(2015, 2, 29).is_none()); - /// assert!(from_ymd_opt(-4, 2, 29).is_some()); // 5 BCE is a leap year - /// assert!(from_ymd_opt(400000, 1, 1).is_none()); - /// assert!(from_ymd_opt(-400000, 1, 1).is_none()); + /// assert!(from_ymd(2015, 3, 14).is_ok()); + /// assert!(from_ymd(2015, 0, 14).is_err()); + /// assert!(from_ymd(2015, 2, 29).is_err()); + /// assert!(from_ymd(-4, 2, 29).is_ok()); // 5 BCE is a leap year + /// assert!(from_ymd(400000, 1, 1).is_err()); + /// assert!(from_ymd(-400000, 1, 1).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option { + pub fn from_ymd(year: i32, month: u32, day: u32) -> Result { let flags = YearFlags::from_year(year); NaiveDate::from_mdf(year, Mdf::new(month, day, flags)) } - /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) - /// (year and day of the year). + /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) (year and + /// day of the year). /// - /// Panics on the out-of-range date and/or invalid day of year. + /// Returns `Err(ChronoError)` on the out-of-range date and/or invalid day + /// of year. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_yo(2015, 73); + /// let from_yo = NaiveDate::from_yo; + /// + /// let d = from_yo(2015, 73)?; /// assert_eq!(d.ordinal(), 73); /// assert_eq!(d.year(), 2015); /// assert_eq!(d.month(), 3); @@ -302,48 +276,35 @@ impl NaiveDate { /// assert_eq!(d.iso_week().week(), 11); /// assert_eq!(d.weekday(), Weekday::Sat); /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE - /// ``` - pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate { - NaiveDate::from_yo_opt(year, ordinal).expect("invalid or out-of-range date") - } - - /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) - /// (year and day of the year). - /// - /// Returns `None` on the out-of-range date and/or invalid day of year. - /// - /// # Example - /// - /// ``` - /// use chrono::NaiveDate; /// - /// let from_yo_opt = NaiveDate::from_yo_opt; - /// - /// assert!(from_yo_opt(2015, 100).is_some()); - /// assert!(from_yo_opt(2015, 0).is_none()); - /// assert!(from_yo_opt(2015, 365).is_some()); - /// assert!(from_yo_opt(2015, 366).is_none()); - /// assert!(from_yo_opt(-4, 366).is_some()); // 5 BCE is a leap year - /// assert!(from_yo_opt(400000, 1).is_none()); - /// assert!(from_yo_opt(-400000, 1).is_none()); + /// assert!(from_yo(2015, 100).is_ok()); + /// assert!(from_yo(2015, 0).is_err()); + /// assert!(from_yo(2015, 365).is_ok()); + /// assert!(from_yo(2015, 366).is_err()); + /// assert!(from_yo(-4, 366).is_ok()); // 5 BCE is a leap year + /// assert!(from_yo(400000, 1).is_err()); + /// assert!(from_yo(-400000, 1).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn from_yo_opt(year: i32, ordinal: u32) -> Option { + pub fn from_yo(year: i32, ordinal: u32) -> Result { let flags = YearFlags::from_year(year); NaiveDate::from_of(year, Of::new(ordinal, flags)) } - /// Makes a new `NaiveDate` from the [ISO week date](#week-date) - /// (year, week number and day of the week). - /// The resulting `NaiveDate` may have a different year from the input year. + /// Makes a new `NaiveDate` from the [ISO week date](#week-date) (year, week + /// number and day of the week). The resulting `NaiveDate` may have a + /// different year from the input year. /// - /// Panics on the out-of-range date and/or invalid week number. + /// Returns `Err(ChronoError)` on the out-of-range date and/or invalid week + /// number. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_isoywd(2015, 11, Weekday::Sat); + /// let d = NaiveDate::from_isoywd(2015, 11, Weekday::Sat)?; + /// /// assert_eq!(d.iso_week().year(), 2015); /// assert_eq!(d.iso_week().week(), 11); /// assert_eq!(d.weekday(), Weekday::Sat); @@ -352,32 +313,23 @@ impl NaiveDate { /// assert_eq!(d.day(), 14); /// assert_eq!(d.ordinal(), 73); // day of year /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate { - NaiveDate::from_isoywd_opt(year, week, weekday).expect("invalid or out-of-range date") - } - - /// Makes a new `NaiveDate` from the [ISO week date](#week-date) - /// (year, week number and day of the week). - /// The resulting `NaiveDate` may have a different year from the input year. /// - /// Returns `None` on the out-of-range date and/or invalid week number. - /// - /// # Example + /// Examples showcasing errors. /// /// ``` - /// use chrono::{NaiveDate, Weekday}; - /// - /// let from_ymd = NaiveDate::from_ymd; - /// let from_isoywd_opt = NaiveDate::from_isoywd_opt; - /// - /// assert_eq!(from_isoywd_opt(2015, 0, Weekday::Sun), None); - /// assert_eq!(from_isoywd_opt(2015, 10, Weekday::Sun), Some(from_ymd(2015, 3, 8))); - /// assert_eq!(from_isoywd_opt(2015, 30, Weekday::Mon), Some(from_ymd(2015, 7, 20))); - /// assert_eq!(from_isoywd_opt(2015, 60, Weekday::Mon), None); + /// # use chrono::{NaiveDate, Weekday}; + /// # let from_ymd = NaiveDate::from_ymd; + /// # let from_isoywd = NaiveDate::from_isoywd; + /// assert!(from_isoywd(2015, 0, Weekday::Sun).is_err()); + /// assert_eq!(from_isoywd(2015, 10, Weekday::Sun)?, from_ymd(2015, 3, 8)?); + /// assert_eq!(from_isoywd(2015, 30, Weekday::Mon)?, from_ymd(2015, 7, 20)?); + /// assert!(from_isoywd(2015, 60, Weekday::Mon).is_err()); /// - /// assert_eq!(from_isoywd_opt(400000, 10, Weekday::Fri), None); - /// assert_eq!(from_isoywd_opt(-400000, 10, Weekday::Sat), None); + /// assert!(from_isoywd(400000, 10, Weekday::Fri).is_err()); + /// assert!(from_isoywd(-400000, 10, Weekday::Sat).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// The year number of ISO week date may differ from that of the calendar date. @@ -385,23 +337,24 @@ impl NaiveDate { /// ``` /// # use chrono::{NaiveDate, Weekday}; /// # let from_ymd = NaiveDate::from_ymd; - /// # let from_isoywd_opt = NaiveDate::from_isoywd_opt; + /// # let from_isoywd = NaiveDate::from_isoywd; /// // Mo Tu We Th Fr Sa Su /// // 2014-W52 22 23 24 25 26 27 28 has 4+ days of new year, /// // 2015-W01 29 30 31 1 2 3 4 <- so this is the first week - /// assert_eq!(from_isoywd_opt(2014, 52, Weekday::Sun), Some(from_ymd(2014, 12, 28))); - /// assert_eq!(from_isoywd_opt(2014, 53, Weekday::Mon), None); - /// assert_eq!(from_isoywd_opt(2015, 1, Weekday::Mon), Some(from_ymd(2014, 12, 29))); + /// assert_eq!(from_isoywd(2014, 52, Weekday::Sun)?, from_ymd(2014, 12, 28)?); + /// assert!(from_isoywd(2014, 53, Weekday::Mon).is_err()); + /// assert_eq!(from_isoywd(2015, 1, Weekday::Mon)?, from_ymd(2014, 12, 29)?); /// /// // 2015-W52 21 22 23 24 25 26 27 has 4+ days of old year, /// // 2015-W53 28 29 30 31 1 2 3 <- so this is the last week /// // 2016-W01 4 5 6 7 8 9 10 - /// assert_eq!(from_isoywd_opt(2015, 52, Weekday::Sun), Some(from_ymd(2015, 12, 27))); - /// assert_eq!(from_isoywd_opt(2015, 53, Weekday::Sun), Some(from_ymd(2016, 1, 3))); - /// assert_eq!(from_isoywd_opt(2015, 54, Weekday::Mon), None); - /// assert_eq!(from_isoywd_opt(2016, 1, Weekday::Mon), Some(from_ymd(2016, 1, 4))); + /// assert_eq!(from_isoywd(2015, 52, Weekday::Sun)?, from_ymd(2015, 12, 27)?); + /// assert_eq!(from_isoywd(2015, 53, Weekday::Sun)?, from_ymd(2016, 1, 3)?); + /// assert!(from_isoywd(2015, 54, Weekday::Mon).is_err()); + /// assert_eq!(from_isoywd(2016, 1, Weekday::Mon)?, from_ymd(2016, 1, 4)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option { + pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> Result { let flags = YearFlags::from_year(year); let nweeks = flags.nisoweeks(); if 1 <= week && week <= nweeks { @@ -428,7 +381,7 @@ impl NaiveDate { } } } else { - None + Err(ChronoError::new(ChronoErrorKind::InvalidDate)) } } @@ -442,7 +395,7 @@ impl NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_num_days_from_ce(735671); + /// let d = NaiveDate::from_num_days_from_ce(735671)?; /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE /// assert_eq!(d.year(), 2015); /// assert_eq!(d.month(), 3); @@ -451,6 +404,7 @@ impl NaiveDate { /// assert_eq!(d.iso_week().year(), 2015); /// assert_eq!(d.iso_week().week(), 11); /// assert_eq!(d.weekday(), Weekday::Sat); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// While not directly supported by Chrono, @@ -460,47 +414,31 @@ impl NaiveDate { /// (Note that this panics when `jd` is out of range.) /// /// ``` - /// use chrono::NaiveDate; + /// use chrono::{NaiveDate, ChronoError}; /// - /// fn jd_to_date(jd: i32) -> NaiveDate { + /// fn jd_to_date(jd: i32) -> Result { /// // keep in mind that the Julian day number is 0-based /// // while this method requires an 1-based number. /// NaiveDate::from_num_days_from_ce(jd - 1721425) /// } /// /// // January 1, 4713 BCE in Julian = November 24, 4714 BCE in Gregorian - /// assert_eq!(jd_to_date(0), NaiveDate::from_ymd(-4713, 11, 24)); + /// assert_eq!(jd_to_date(0)?, NaiveDate::from_ymd(-4713, 11, 24)?); /// - /// assert_eq!(jd_to_date(1721426), NaiveDate::from_ymd(1, 1, 1)); - /// assert_eq!(jd_to_date(2450000), NaiveDate::from_ymd(1995, 10, 9)); - /// assert_eq!(jd_to_date(2451545), NaiveDate::from_ymd(2000, 1, 1)); - /// ``` - #[inline] - pub fn from_num_days_from_ce(days: i32) -> NaiveDate { - NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date") - } - - /// Makes a new `NaiveDate` from a day's number in the proleptic Gregorian calendar, with - /// January 1, 1 being day 1. - /// - /// Returns `None` if the date is out of range. - /// - /// # Example - /// - /// ``` - /// use chrono::NaiveDate; - /// - /// let from_ndays_opt = NaiveDate::from_num_days_from_ce_opt; - /// let from_ymd = NaiveDate::from_ymd; + /// assert_eq!(jd_to_date(1721426)?, NaiveDate::from_ymd(1, 1, 1)?); + /// assert_eq!(jd_to_date(2450000)?, NaiveDate::from_ymd(1995, 10, 9)?); + /// assert_eq!(jd_to_date(2451545)?, NaiveDate::from_ymd(2000, 1, 1)?); /// - /// assert_eq!(from_ndays_opt(730_000), Some(from_ymd(1999, 9, 3))); - /// assert_eq!(from_ndays_opt(1), Some(from_ymd(1, 1, 1))); - /// assert_eq!(from_ndays_opt(0), Some(from_ymd(0, 12, 31))); - /// assert_eq!(from_ndays_opt(-1), Some(from_ymd(0, 12, 30))); - /// assert_eq!(from_ndays_opt(100_000_000), None); - /// assert_eq!(from_ndays_opt(-100_000_000), None); + /// assert_eq!(NaiveDate::from_num_days_from_ce(730_000)?, NaiveDate::from_ymd(1999, 9, 3)?); + /// assert_eq!(NaiveDate::from_num_days_from_ce(1)?, NaiveDate::from_ymd(1, 1, 1)?); + /// assert_eq!(NaiveDate::from_num_days_from_ce(0)?, NaiveDate::from_ymd(0, 12, 31)?); + /// assert_eq!(NaiveDate::from_num_days_from_ce(-1)?, NaiveDate::from_ymd(0, 12, 30)?); + /// assert!(NaiveDate::from_num_days_from_ce(100_000_000).is_err()); + /// assert!(NaiveDate::from_num_days_from_ce(-100_000_000).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn from_num_days_from_ce_opt(days: i32) -> Option { + #[inline] + pub fn from_num_days_from_ce(days: i32) -> Result { let days = days + 365; // make December 31, 1 BCE equal to day 0 let (year_div_400, cycle) = div_mod_floor(days, 146_097); let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); @@ -508,16 +446,14 @@ impl NaiveDate { NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)) } - /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week - /// since the beginning of the given month. For instance, if you want the 2nd Friday of March - /// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. - /// - /// # Panics - /// - /// The resulting `NaiveDate` is guaranteed to be in `month`. If `n` is larger than the number - /// of `weekday` in `month` (eg. the 6th Friday of March 2017) then this function will panic. + /// Makes a new `NaiveDate` by counting the number of occurrences of a + /// particular day-of-week since the beginning of the given month. For + /// instance, if you want the 2nd Friday of March 2017, you would use + /// `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. /// - /// `n` is 1-indexed. Passing `n=0` will cause a panic. + /// Returns `Err(ChronoError)` if `n` out-of-range; ie. if `n` is larger + /// than the number of `weekday` in `month` (eg. the 6th Friday of March + /// 2017), or if `n == 0`. /// /// # Example /// @@ -527,41 +463,27 @@ impl NaiveDate { /// let from_weekday_of_month = NaiveDate::from_weekday_of_month; /// let from_ymd = NaiveDate::from_ymd; /// - /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Wed, 1), from_ymd(2018, 8, 1)); - /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 1), from_ymd(2018, 8, 3)); - /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Tue, 2), from_ymd(2018, 8, 14)); - /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 4), from_ymd(2018, 8, 24)); - /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 5), from_ymd(2018, 8, 31)); - /// ``` - pub fn from_weekday_of_month(year: i32, month: u32, weekday: Weekday, n: u8) -> NaiveDate { - NaiveDate::from_weekday_of_month_opt(year, month, weekday, n).expect("out-of-range date") - } - - /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week - /// since the beginning of the given month. For instance, if you want the 2nd Friday of March - /// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. `n` is 1-indexed. - /// + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Wed, 1)?, from_ymd(2018, 8, 1)?); + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 1)?, from_ymd(2018, 8, 3)?); + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Tue, 2)?, from_ymd(2018, 8, 14)?); + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 4)?, from_ymd(2018, 8, 24)?); + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 5)?, from_ymd(2018, 8, 31)?); + /// assert_eq!(NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)?, NaiveDate::from_ymd(2017, 3, 10)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - /// use chrono::{NaiveDate, Weekday}; - /// assert_eq!(NaiveDate::from_weekday_of_month_opt(2017, 3, Weekday::Fri, 2), - /// NaiveDate::from_ymd_opt(2017, 3, 10)) - /// ``` - /// - /// Returns `None` if `n` out-of-range; ie. if `n` is larger than the number of `weekday` in - /// `month` (eg. the 6th Friday of March 2017), or if `n == 0`. - pub fn from_weekday_of_month_opt( + pub fn from_weekday_of_month( year: i32, month: u32, weekday: Weekday, n: u8, - ) -> Option { + ) -> Result { if n == 0 { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidDate)); } - let first = NaiveDate::from_ymd(year, month, 1).weekday(); + let first = NaiveDate::from_ymd(year, month, 1)?.weekday(); let first_to_dow = (7 + weekday.number_from_monday() - first.number_from_monday()) % 7; let day = (u32::from(n) - 1) * 7 + first_to_dow + 1; - NaiveDate::from_ymd_opt(year, month, day) + NaiveDate::from_ymd(year, month, day) } /// Parses a string with the specified format string and returns a new `NaiveDate`. @@ -575,10 +497,11 @@ impl NaiveDate { /// /// let parse_from_str = NaiveDate::parse_from_str; /// - /// assert_eq!(parse_from_str("2015-09-05", "%Y-%m-%d"), - /// Ok(NaiveDate::from_ymd(2015, 9, 5))); - /// assert_eq!(parse_from_str("5sep2015", "%d%b%Y"), - /// Ok(NaiveDate::from_ymd(2015, 9, 5))); + /// assert_eq!(parse_from_str("2015-09-05", "%Y-%m-%d")?, + /// NaiveDate::from_ymd(2015, 9, 5)?); + /// assert_eq!(parse_from_str("5sep2015", "%d%b%Y")?, + /// NaiveDate::from_ymd(2015, 9, 5)?); + /// # Ok::<_, Box>(()) /// ``` /// /// Time and offset is ignored for the purpose of parsing. @@ -586,8 +509,9 @@ impl NaiveDate { /// ``` /// # use chrono::NaiveDate; /// # let parse_from_str = NaiveDate::parse_from_str; - /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), - /// Ok(NaiveDate::from_ymd(2014, 5, 17))); + /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z")?, + /// NaiveDate::from_ymd(2014, 5, 17)?); + /// # Ok::<_, Box>(()) /// ``` /// /// Out-of-bound dates or insufficient fields are errors. @@ -616,62 +540,64 @@ impl NaiveDate { /// /// If the day would be out of range for the resulting month, use the last day for that month. /// - /// Returns `None` if the resulting date would be out of range. + /// Returns `Err(ChronoError)` if the resulting date would be out of range. /// /// ``` /// # use chrono::{NaiveDate, Months}; /// assert_eq!( - /// NaiveDate::from_ymd(2022, 2, 20).checked_add_months(Months::new(6)), - /// Some(NaiveDate::from_ymd(2022, 8, 20)) + /// NaiveDate::from_ymd(2022, 2, 20)?.checked_add_months(Months::new(6))?, + /// NaiveDate::from_ymd(2022, 8, 20)? /// ); /// assert_eq!( - /// NaiveDate::from_ymd(2022, 7, 31).checked_add_months(Months::new(2)), - /// Some(NaiveDate::from_ymd(2022, 9, 30)) + /// NaiveDate::from_ymd(2022, 7, 31)?.checked_add_months(Months::new(2))?, + /// NaiveDate::from_ymd(2022, 9, 30)? /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn checked_add_months(self, months: Months) -> Option { + pub fn checked_add_months(self, months: Months) -> Result { if months.0 == 0 { - return Some(self); + return Ok(self); } - match months.0 <= core::i32::MAX as u32 { - true => self.diff_months(months.0 as i32), - false => None, - } + let d = i32::try_from(months.0).ok().ok_or(ChronoErrorKind::InvalidDate)?; + self.diff_months(d) } /// Subtract a duration in [`Months`] from the date /// /// If the day would be out of range for the resulting month, use the last day for that month. /// - /// Returns `None` if the resulting date would be out of range. + /// Returns `Err(ChronoError)` if the resulting date would be out of range. /// /// ``` - /// # use chrono::{NaiveDate, Months}; + /// use chrono::{NaiveDate, Months}; + /// /// assert_eq!( - /// NaiveDate::from_ymd(2022, 2, 20).checked_sub_months(Months::new(6)), - /// Some(NaiveDate::from_ymd(2021, 8, 20)) + /// NaiveDate::from_ymd(2022, 2, 20)?.checked_sub_months(Months::new(6))?, + /// NaiveDate::from_ymd(2021, 8, 20)? /// ); /// - /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1) - /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)), - /// None + /// assert!( + /// NaiveDate::from_ymd(2014, 1, 1)? + /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)) + /// .is_err() /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn checked_sub_months(self, months: Months) -> Option { + pub fn checked_sub_months(self, months: Months) -> Result { if months.0 == 0 { - return Some(self); + return Ok(self); } - // Copy `i32::MAX` here so we don't have to do a complicated cast - match months.0 <= 2_147_483_647 { - true => self.diff_months(-(months.0 as i32)), - false => None, - } + let d = i32::try_from(months.0) + .ok() + .and_then(|n| n.checked_neg()) + .ok_or(ChronoErrorKind::InvalidDate)?; + + self.diff_months(d) } - fn diff_months(self, months: i32) -> Option { + fn diff_months(self, months: i32) -> Result { let (years, left) = ((months / 12), (months % 12)); // Determine new year (without taking months into account for now @@ -679,7 +605,7 @@ impl NaiveDate { let year = if (years > 0 && years > (MAX_YEAR - self.year())) || (years < 0 && years < (MIN_YEAR - self.year())) { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidDate)); } else { self.year() + years }; @@ -689,13 +615,13 @@ impl NaiveDate { let month = self.month() as i32 + left; let (year, month) = if month <= 0 { if year == MIN_YEAR { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidDate)); } (year - 1, month + 12) } else if month > 12 { if year == MAX_YEAR { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidDate)); } (year + 1, month - 12) @@ -715,47 +641,56 @@ impl NaiveDate { /// Add a duration in [`Days`] to the date /// - /// Returns `None` if the resulting date would be out of range. + /// Returns `Err(ChronoError)` if the resulting date would be out of range. /// /// ``` - /// # use chrono::{NaiveDate, Days}; + /// use chrono::{NaiveDate, Days}; + /// /// assert_eq!( - /// NaiveDate::from_ymd(2022, 2, 20).checked_add_days(Days::new(9)), - /// Some(NaiveDate::from_ymd(2022, 3, 1)) + /// NaiveDate::from_ymd(2022, 2, 20)?.checked_add_days(Days::new(9))?, + /// NaiveDate::from_ymd(2022, 3, 1)? /// ); /// assert_eq!( - /// NaiveDate::from_ymd(2022, 7, 31).checked_add_days(Days::new(2)), - /// Some(NaiveDate::from_ymd(2022, 8, 2)) + /// NaiveDate::from_ymd(2022, 7, 31)?.checked_add_days(Days::new(2))?, + /// NaiveDate::from_ymd(2022, 8, 2)? /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn checked_add_days(self, days: Days) -> Option { + pub fn checked_add_days(self, days: Days) -> Result { if days.0 == 0 { - return Some(self); + return Ok(self); } - i64::try_from(days.0).ok().and_then(|d| self.diff_days(d)) + let d = i64::try_from(days.0).ok().ok_or(ChronoErrorKind::InvalidDate)?; + self.diff_days(d) } /// Subtract a duration in [`Days`] from the date /// - /// Returns `None` if the resulting date would be out of range. + /// Returns `Err(ChronoError)` if the resulting date would be out of range. /// /// ``` - /// # use chrono::{NaiveDate, Days}; + /// use chrono::{NaiveDate, Days}; + /// /// assert_eq!( - /// NaiveDate::from_ymd(2022, 2, 20).checked_sub_days(Days::new(6)), - /// Some(NaiveDate::from_ymd(2022, 2, 14)) + /// NaiveDate::from_ymd(2022, 2, 20)?.checked_sub_days(Days::new(6))?, + /// NaiveDate::from_ymd(2022, 2, 14)? /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn checked_sub_days(self, days: Days) -> Option { + pub fn checked_sub_days(self, days: Days) -> Result { if days.0 == 0 { - return Some(self); + return Ok(self); } - i64::try_from(days.0).ok().and_then(|d| self.diff_days(-d)) + let d = i64::try_from(days.0) + .ok() + .and_then(|n| n.checked_neg()) + .ok_or(ChronoErrorKind::InvalidDate)?; + self.diff_days(d) } - fn diff_days(self, days: i64) -> Option { + fn diff_days(self, days: i64) -> Result { self.checked_add_signed(TimeDelta::days(days)) } @@ -766,12 +701,13 @@ impl NaiveDate { /// ``` /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime}; /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); - /// let t = NaiveTime::from_hms_milli(12, 34, 56, 789); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; + /// let t = NaiveTime::from_hms_milli(12, 34, 56, 789)?; /// /// let dt: NaiveDateTime = d.and_time(t); /// assert_eq!(dt.date(), d); /// assert_eq!(dt.time(), t); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn and_time(&self, time: NaiveTime) -> NaiveDateTime { @@ -790,95 +726,72 @@ impl NaiveDate { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; /// - /// let dt: NaiveDateTime = d.and_hms(12, 34, 56); + /// let dt: NaiveDateTime = d.and_hms(12, 34, 56)?; /// assert_eq!(dt.year(), 2015); /// assert_eq!(dt.weekday(), Weekday::Wed); /// assert_eq!(dt.second(), 56); + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; + /// assert!(d.and_hms(12, 34, 56).is_ok()); + /// assert!(d.and_hms(12, 34, 60).is_err()); // use `and_hms_milli` instead + /// assert!(d.and_hms(12, 60, 56).is_err()); + /// assert!(d.and_hms(24, 34, 56).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime { - self.and_hms_opt(hour, min, sec).expect("invalid time") + pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> Result { + let time = NaiveTime::from_hms(hour, min, sec)?; + Ok(self.and_time(time)) } - /// Makes a new `NaiveDateTime` from the current date, hour, minute and second. - /// - /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here; - /// use `NaiveDate::and_hms_*_opt` methods with a subsecond parameter instead. - /// - /// Returns `None` on invalid hour, minute and/or second. - /// - /// # Example - /// - /// ``` - /// use chrono::NaiveDate; - /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); - /// assert!(d.and_hms_opt(12, 34, 56).is_some()); - /// assert!(d.and_hms_opt(12, 34, 60).is_none()); // use `and_hms_milli_opt` instead - /// assert!(d.and_hms_opt(12, 60, 56).is_none()); - /// assert!(d.and_hms_opt(24, 34, 56).is_none()); - /// ``` - #[inline] - pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option { - NaiveTime::from_hms_opt(hour, min, sec).map(|time| self.and_time(time)) + /// Makes a new `NaiveDateTime` with the time set to midnight. + pub(crate) fn and_midnight(&self) -> NaiveDateTime { + self.and_time(NaiveTime::midnight()) } - /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second + /// and millisecond. /// - /// The millisecond part can exceed 1,000 - /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// The millisecond part can exceed 1,000 in order to represent the [leap + /// second](./struct.NaiveTime.html#leap-second-handling). /// - /// Panics on invalid hour, minute, second and/or millisecond. + /// Returns `Err(ChronoError)` on invalid hour, minute, second and/or + /// millisecond. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; /// - /// let dt: NaiveDateTime = d.and_hms_milli(12, 34, 56, 789); + /// let dt: NaiveDateTime = d.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.year(), 2015); /// assert_eq!(dt.weekday(), Weekday::Wed); /// assert_eq!(dt.second(), 56); /// assert_eq!(dt.nanosecond(), 789_000_000); - /// ``` - #[inline] - pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> NaiveDateTime { - self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time") - } - - /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. - /// - /// The millisecond part can exceed 1,000 - /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). - /// - /// Returns `None` on invalid hour, minute, second and/or millisecond. - /// - /// # Example /// - /// ``` - /// use chrono::NaiveDate; - /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); - /// assert!(d.and_hms_milli_opt(12, 34, 56, 789).is_some()); - /// assert!(d.and_hms_milli_opt(12, 34, 59, 1_789).is_some()); // leap second - /// assert!(d.and_hms_milli_opt(12, 34, 59, 2_789).is_none()); - /// assert!(d.and_hms_milli_opt(12, 34, 60, 789).is_none()); - /// assert!(d.and_hms_milli_opt(12, 60, 56, 789).is_none()); - /// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none()); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; + /// assert!(d.and_hms_milli(12, 34, 56, 789).is_ok()); + /// assert!(d.and_hms_milli(12, 34, 59, 1_789).is_ok()); // leap second + /// assert!(d.and_hms_milli(12, 34, 59, 2_789).is_err()); + /// assert!(d.and_hms_milli(12, 34, 60, 789).is_err()); + /// assert!(d.and_hms_milli(12, 60, 56, 789).is_err()); + /// assert!(d.and_hms_milli(24, 34, 56, 789).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn and_hms_milli_opt( + pub fn and_hms_milli( &self, hour: u32, min: u32, sec: u32, milli: u32, - ) -> Option { - NaiveTime::from_hms_milli_opt(hour, min, sec, milli).map(|time| self.and_time(time)) + ) -> Result { + let time = NaiveTime::from_hms_milli(hour, min, sec, milli)?; + Ok(self.and_time(time)) } /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. @@ -886,55 +799,40 @@ impl NaiveDate { /// The microsecond part can exceed 1,000,000 /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). /// - /// Panics on invalid hour, minute, second and/or microsecond. + /// Returns `Err(ChronoError)` on invalid hour, minute, second and/or microsecond. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; /// - /// let dt: NaiveDateTime = d.and_hms_micro(12, 34, 56, 789_012); + /// let dt: NaiveDateTime = d.and_hms_micro(12, 34, 56, 789_012)?; /// assert_eq!(dt.year(), 2015); /// assert_eq!(dt.weekday(), Weekday::Wed); /// assert_eq!(dt.second(), 56); /// assert_eq!(dt.nanosecond(), 789_012_000); - /// ``` - #[inline] - pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> NaiveDateTime { - self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time") - } - - /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. - /// - /// The microsecond part can exceed 1,000,000 - /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). - /// - /// Returns `None` on invalid hour, minute, second and/or microsecond. - /// - /// # Example /// - /// ``` - /// use chrono::NaiveDate; - /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); - /// assert!(d.and_hms_micro_opt(12, 34, 56, 789_012).is_some()); - /// assert!(d.and_hms_micro_opt(12, 34, 59, 1_789_012).is_some()); // leap second - /// assert!(d.and_hms_micro_opt(12, 34, 59, 2_789_012).is_none()); - /// assert!(d.and_hms_micro_opt(12, 34, 60, 789_012).is_none()); - /// assert!(d.and_hms_micro_opt(12, 60, 56, 789_012).is_none()); - /// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none()); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; + /// assert!(d.and_hms_micro(12, 34, 56, 789_012).is_ok()); + /// assert!(d.and_hms_micro(12, 34, 59, 1_789_012).is_ok()); // leap second + /// assert!(d.and_hms_micro(12, 34, 59, 2_789_012).is_err()); + /// assert!(d.and_hms_micro(12, 34, 60, 789_012).is_err()); + /// assert!(d.and_hms_micro(12, 60, 56, 789_012).is_err()); + /// assert!(d.and_hms_micro(24, 34, 56, 789_012).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn and_hms_micro_opt( + pub fn and_hms_micro( &self, hour: u32, min: u32, sec: u32, micro: u32, - ) -> Option { - NaiveTime::from_hms_micro_opt(hour, min, sec, micro).map(|time| self.and_time(time)) + ) -> Result { + let time = NaiveTime::from_hms_micro(hour, min, sec, micro)?; + Ok(self.and_time(time)) } /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. @@ -942,55 +840,40 @@ impl NaiveDate { /// The nanosecond part can exceed 1,000,000,000 /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). /// - /// Panics on invalid hour, minute, second and/or nanosecond. + /// Returns `Err(ChronoError)` on invalid hour, minute, second and/or nanosecond. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; /// - /// let dt: NaiveDateTime = d.and_hms_nano(12, 34, 56, 789_012_345); + /// let dt: NaiveDateTime = d.and_hms_nano(12, 34, 56, 789_012_345)?; /// assert_eq!(dt.year(), 2015); /// assert_eq!(dt.weekday(), Weekday::Wed); /// assert_eq!(dt.second(), 56); /// assert_eq!(dt.nanosecond(), 789_012_345); - /// ``` - #[inline] - pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> NaiveDateTime { - self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time") - } - - /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. - /// - /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). - /// - /// Returns `None` on invalid hour, minute, second and/or nanosecond. - /// - /// # Example /// - /// ``` - /// use chrono::NaiveDate; - /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); - /// assert!(d.and_hms_nano_opt(12, 34, 56, 789_012_345).is_some()); - /// assert!(d.and_hms_nano_opt(12, 34, 59, 1_789_012_345).is_some()); // leap second - /// assert!(d.and_hms_nano_opt(12, 34, 59, 2_789_012_345).is_none()); - /// assert!(d.and_hms_nano_opt(12, 34, 60, 789_012_345).is_none()); - /// assert!(d.and_hms_nano_opt(12, 60, 56, 789_012_345).is_none()); - /// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none()); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; + /// assert!(d.and_hms_nano(12, 34, 56, 789_012_345).is_ok()); + /// assert!(d.and_hms_nano(12, 34, 59, 1_789_012_345).is_ok()); // leap second + /// assert!(d.and_hms_nano(12, 34, 59, 2_789_012_345).is_err()); + /// assert!(d.and_hms_nano(12, 34, 60, 789_012_345).is_err()); + /// assert!(d.and_hms_nano(12, 60, 56, 789_012_345).is_err()); + /// assert!(d.and_hms_nano(24, 34, 56, 789_012_345).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn and_hms_nano_opt( + pub fn and_hms_nano( &self, hour: u32, min: u32, sec: u32, nano: u32, - ) -> Option { - NaiveTime::from_hms_nano_opt(hour, min, sec, nano).map(|time| self.and_time(time)) + ) -> Result { + let time = NaiveTime::from_hms_nano(hour, min, sec, nano)?; + Ok(self.and_time(time)) } /// Returns the packed month-day-flags. @@ -1007,120 +890,104 @@ impl NaiveDate { /// Makes a new `NaiveDate` with the packed month-day-flags changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDate` would be invalid. #[inline] - fn with_mdf(&self, mdf: Mdf) -> Option { + fn with_mdf(&self, mdf: Mdf) -> Result { self.with_of(mdf.to_of()) } /// Makes a new `NaiveDate` with the packed ordinal-flags changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDate` would be invalid. #[inline] - fn with_of(&self, of: Of) -> Option { + fn with_of(&self, of: Of) -> Result { if of.valid() { let Of(of) = of; - Some(NaiveDate { ymdf: (self.ymdf & !0b1_1111_1111_1111) | of as DateImpl }) + Ok(NaiveDate { ymdf: (self.ymdf & !0b1_1111_1111_1111) | of as DateImpl }) } else { - None + Err(ChronoError::new(ChronoErrorKind::InvalidDate)) } } /// Makes a new `NaiveDate` for the next calendar date. /// - /// Panics when `self` is the last representable date. + /// Returns `Err(ChronoError)` when `self` is the last representable date. /// /// # Example /// /// ``` /// use chrono::NaiveDate; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).succ(), NaiveDate::from_ymd(2015, 6, 4)); - /// assert_eq!(NaiveDate::from_ymd(2015, 6, 30).succ(), NaiveDate::from_ymd(2015, 7, 1)); - /// assert_eq!(NaiveDate::from_ymd(2015, 12, 31).succ(), NaiveDate::from_ymd(2016, 1, 1)); - /// ``` - #[inline] - pub fn succ(&self) -> NaiveDate { - self.succ_opt().expect("out of bound") - } - - /// Makes a new `NaiveDate` for the next calendar date. - /// - /// Returns `None` when `self` is the last representable date. - /// - /// # Example + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3)?.succ()?, NaiveDate::from_ymd(2015, 6, 4)?); + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 30)?.succ()?, NaiveDate::from_ymd(2015, 7, 1)?); + /// assert_eq!(NaiveDate::from_ymd(2015, 12, 31)?.succ()?, NaiveDate::from_ymd(2016, 1, 1)?); /// - /// ``` - /// use chrono::NaiveDate; - /// - /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).succ_opt(), - /// Some(NaiveDate::from_ymd(2015, 6, 4))); - /// assert_eq!(NaiveDate::MAX.succ_opt(), None); + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3)?.succ()?, + /// NaiveDate::from_ymd(2015, 6, 4)?); + /// assert!(NaiveDate::MAX.succ().is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn succ_opt(&self) -> Option { - self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1)) + pub fn succ(&self) -> Result { + match self.with_of(self.of().succ()) { + Ok(date) => Ok(date), + Err(..) => NaiveDate::from_ymd(self.year() + 1, 1, 1), + } } /// Makes a new `NaiveDate` for the previous calendar date. /// - /// Panics when `self` is the first representable date. + /// Returns `Err(ChronoError)` when `self` is the first representable date. /// /// # Example /// /// ``` /// use chrono::NaiveDate; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).pred(), NaiveDate::from_ymd(2015, 6, 2)); - /// assert_eq!(NaiveDate::from_ymd(2015, 6, 1).pred(), NaiveDate::from_ymd(2015, 5, 31)); - /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).pred(), NaiveDate::from_ymd(2014, 12, 31)); - /// ``` - #[inline] - pub fn pred(&self) -> NaiveDate { - self.pred_opt().expect("out of bound") - } - - /// Makes a new `NaiveDate` for the previous calendar date. - /// - /// Returns `None` when `self` is the first representable date. - /// - /// # Example + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3)?.pred()?, NaiveDate::from_ymd(2015, 6, 2)?); + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 1)?.pred()?, NaiveDate::from_ymd(2015, 5, 31)?); + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1)?.pred()?, NaiveDate::from_ymd(2014, 12, 31)?); /// - /// ``` - /// use chrono::NaiveDate; - /// - /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).pred_opt(), - /// Some(NaiveDate::from_ymd(2015, 6, 2))); - /// assert_eq!(NaiveDate::MIN.pred_opt(), None); + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3)?.pred()?, + /// NaiveDate::from_ymd(2015, 6, 2)?); + /// assert!(NaiveDate::MIN.pred().is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn pred_opt(&self) -> Option { - self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31)) + pub fn pred(&self) -> Result { + match self.with_of(self.of().pred()) { + Ok(date) => Ok(date), + Err(..) => NaiveDate::from_ymd(self.year() - 1, 12, 31), + } } /// Adds the `days` part of given `Duration` to the current date. /// - /// Returns `None` when it will result in overflow. + /// Returns `Err(ChronoError)` when it will result in overflow. /// /// # Example /// /// ``` /// use chrono::{TimeDelta, NaiveDate}; /// - /// let d = NaiveDate::from_ymd(2015, 9, 5); - /// assert_eq!(d.checked_add_signed(TimeDelta::days(40)), - /// Some(NaiveDate::from_ymd(2015, 10, 15))); - /// assert_eq!(d.checked_add_signed(TimeDelta::days(-40)), - /// Some(NaiveDate::from_ymd(2015, 7, 27))); - /// 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: TimeDelta) -> Option { + /// let d = NaiveDate::from_ymd(2015, 9, 5)?; + /// assert_eq!(d.checked_add_signed(TimeDelta::days(40))?, + /// NaiveDate::from_ymd(2015, 10, 15)?); + /// assert_eq!(d.checked_add_signed(TimeDelta::days(-40))?, + /// NaiveDate::from_ymd(2015, 7, 27)?); + /// assert!(d.checked_add_signed(TimeDelta::days(1_000_000_000)).is_err()); + /// assert!(d.checked_add_signed(TimeDelta::days(-1_000_000_000)).is_err()); + /// assert!(NaiveDate::MAX.checked_add_signed(TimeDelta::days(1)).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) + /// ``` + pub fn checked_add_signed(self, rhs: TimeDelta) -> Result { 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()); - let cycle = (cycle as i32).checked_add(i32::try_from(rhs.num_days()).ok()?)?; + let cycle = i32::try_from(rhs.num_days()) + .ok() + .and_then(|n| (cycle as i32).checked_add(n)) + .ok_or(ChronoErrorKind::InvalidDate)?; let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097); year_div_400 += cycle_div_400y; @@ -1131,27 +998,31 @@ impl NaiveDate { /// Subtracts the `days` part of given `TimeDelta` from the current date. /// - /// Returns `None` when it will result in overflow. + /// Returns `Err(ChronoError)` when it will result in overflow. /// /// # Example /// /// ``` /// use chrono::{TimeDelta, NaiveDate}; /// - /// let d = NaiveDate::from_ymd(2015, 9, 5); - /// assert_eq!(d.checked_sub_signed(TimeDelta::days(40)), - /// Some(NaiveDate::from_ymd(2015, 7, 27))); - /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-40)), - /// Some(NaiveDate::from_ymd(2015, 10, 15))); - /// 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: TimeDelta) -> Option { + /// let d = NaiveDate::from_ymd(2015, 9, 5)?; + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(40))?, + /// NaiveDate::from_ymd(2015, 7, 27)?); + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-40))?, + /// NaiveDate::from_ymd(2015, 10, 15)?); + /// assert!(d.checked_sub_signed(TimeDelta::days(1_000_000_000)).is_err()); + /// assert!(d.checked_sub_signed(TimeDelta::days(-1_000_000_000)).is_err()); + /// assert!(NaiveDate::MIN.checked_sub_signed(TimeDelta::days(1)).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) + /// ``` + pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result { 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()); - let cycle = (cycle as i32).checked_sub(i32::try_from(rhs.num_days()).ok()?)?; + let cycle = i32::try_from(rhs.num_days()) + .ok() + .and_then(|n| (cycle as i32).checked_sub(n)) + .ok_or(ChronoErrorKind::InvalidDate)?; let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097); year_div_400 += cycle_div_400y; @@ -1174,13 +1045,14 @@ impl 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)), 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)); + /// 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)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` pub fn signed_duration_since(self, rhs: NaiveDate) -> TimeDelta { let year1 = self.year(); @@ -1207,9 +1079,10 @@ impl NaiveDate { /// use chrono::format::strftime::StrftimeItems; /// /// let fmt = StrftimeItems::new("%Y-%m-%d"); - /// let d = NaiveDate::from_ymd(2015, 9, 5); + /// let d = NaiveDate::from_ymd(2015, 9, 5)?; /// assert_eq!(d.format_with_items(fmt.clone()).to_string(), "2015-09-05"); - /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); + /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -1218,8 +1091,9 @@ impl NaiveDate { /// # use chrono::NaiveDate; /// # use chrono::format::strftime::StrftimeItems; /// # let fmt = StrftimeItems::new("%Y-%m-%d").clone(); - /// # let d = NaiveDate::from_ymd(2015, 9, 5); + /// # let d = NaiveDate::from_ymd(2015, 9, 5)?; /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -1251,18 +1125,20 @@ impl NaiveDate { /// ``` /// use chrono::NaiveDate; /// - /// let d = NaiveDate::from_ymd(2015, 9, 5); + /// let d = NaiveDate::from_ymd(2015, 9, 5)?; /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); /// assert_eq!(d.format("%A, %-d %B, %C%y").to_string(), "Saturday, 5 September, 2015"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. /// /// ``` /// # use chrono::NaiveDate; - /// # let d = NaiveDate::from_ymd(2015, 9, 5); + /// # let d = NaiveDate::from_ymd(2015, 9, 5)?; /// assert_eq!(format!("{}", d.format("%Y-%m-%d")), "2015-09-05"); /// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -1279,23 +1155,24 @@ impl NaiveDate { /// # use chrono::NaiveDate; /// /// let expected = [ - /// NaiveDate::from_ymd(2016, 2, 27), - /// NaiveDate::from_ymd(2016, 2, 28), - /// NaiveDate::from_ymd(2016, 2, 29), - /// NaiveDate::from_ymd(2016, 3, 1), + /// NaiveDate::from_ymd(2016, 2, 27)?, + /// NaiveDate::from_ymd(2016, 2, 28)?, + /// NaiveDate::from_ymd(2016, 2, 29)?, + /// NaiveDate::from_ymd(2016, 3, 1)?, /// ]; /// /// let mut count = 0; - /// for (idx, d) in NaiveDate::from_ymd(2016, 2, 27).iter_days().take(4).enumerate() { + /// for (idx, d) in NaiveDate::from_ymd(2016, 2, 27)?.iter_days().take(4).enumerate() { /// assert_eq!(d, expected[idx]); /// count += 1; /// } /// assert_eq!(count, 4); /// - /// for d in NaiveDate::from_ymd(2016, 3, 1).iter_days().rev().take(4) { + /// for d in NaiveDate::from_ymd(2016, 3, 1)?.iter_days().rev().take(4) { /// count -= 1; /// assert_eq!(d, expected[count]); /// } + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn iter_days(&self) -> NaiveDateDaysIterator { @@ -1310,23 +1187,24 @@ impl NaiveDate { /// # use chrono::NaiveDate; /// /// let expected = [ - /// NaiveDate::from_ymd(2016, 2, 27), - /// NaiveDate::from_ymd(2016, 3, 5), - /// NaiveDate::from_ymd(2016, 3, 12), - /// NaiveDate::from_ymd(2016, 3, 19), + /// NaiveDate::from_ymd(2016, 2, 27)?, + /// NaiveDate::from_ymd(2016, 3, 5)?, + /// NaiveDate::from_ymd(2016, 3, 12)?, + /// NaiveDate::from_ymd(2016, 3, 19)?, /// ]; /// /// let mut count = 0; - /// for (idx, d) in NaiveDate::from_ymd(2016, 2, 27).iter_weeks().take(4).enumerate() { + /// for (idx, d) in NaiveDate::from_ymd(2016, 2, 27)?.iter_weeks().take(4).enumerate() { /// assert_eq!(d, expected[idx]); /// count += 1; /// } /// assert_eq!(count, 4); /// - /// for d in NaiveDate::from_ymd(2016, 3, 19).iter_weeks().rev().take(4) { + /// for d in NaiveDate::from_ymd(2016, 3, 19)?.iter_weeks().rev().take(4) { /// count -= 1; /// assert_eq!(d, expected[count]); /// } + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn iter_weeks(&self) -> NaiveDateWeeksIterator { @@ -1339,11 +1217,6 @@ impl NaiveDate { pub fn week(&self, start: Weekday) -> NaiveWeek { NaiveWeek { date: *self, start } } - - /// The minimum possible `NaiveDate` (January 1, 262145 BCE). - pub const MIN: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ }; - /// The maximum possible `NaiveDate` (December 31, 262143 CE). - pub const MAX: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ }; } impl Datelike for NaiveDate { @@ -1354,8 +1227,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).year(), 2015); - /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).year(), -308); // 309 BCE + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.year(), 2015); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.year(), -308); // 309 BCE + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn year(&self) -> i32 { @@ -1371,8 +1245,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month(), 9); - /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month(), 3); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.month(), 9); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.month(), 3); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn month(&self) -> u32 { @@ -1388,8 +1263,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month0(), 8); - /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month0(), 2); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.month0(), 8); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.month0(), 2); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn month0(&self) -> u32 { @@ -1405,8 +1281,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day(), 8); - /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day(), 14); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.day(), 8); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.day(), 14); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Combined with [`NaiveDate::pred`](#method.pred), @@ -1414,22 +1291,23 @@ impl Datelike for NaiveDate { /// (Note that this panics when `year` is out of range.) /// /// ``` - /// use chrono::{NaiveDate, Datelike}; + /// use chrono::{NaiveDate, Datelike, ChronoError}; /// - /// fn ndays_in_month(year: i32, month: u32) -> u32 { + /// fn ndays_in_month(year: i32, month: u32) -> Result { /// // the first day of the next month... /// let (y, m) = if month == 12 { (year + 1, 1) } else { (year, month + 1) }; - /// let d = NaiveDate::from_ymd(y, m, 1); + /// let d = NaiveDate::from_ymd(y, m, 1)?; /// /// // ...is preceded by the last day of the original month - /// d.pred().day() + /// Ok(d.pred()?.day()) /// } /// - /// assert_eq!(ndays_in_month(2015, 8), 31); - /// assert_eq!(ndays_in_month(2015, 9), 30); - /// assert_eq!(ndays_in_month(2015, 12), 31); - /// assert_eq!(ndays_in_month(2016, 2), 29); - /// assert_eq!(ndays_in_month(2017, 2), 28); + /// assert_eq!(ndays_in_month(2015, 8)?, 31); + /// assert_eq!(ndays_in_month(2015, 9)?, 30); + /// assert_eq!(ndays_in_month(2015, 12)?, 31); + /// assert_eq!(ndays_in_month(2016, 2)?, 29); + /// assert_eq!(ndays_in_month(2017, 2)?, 28); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn day(&self) -> u32 { @@ -1445,8 +1323,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day0(), 7); - /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day0(), 13); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.day0(), 7); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.day0(), 13); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn day0(&self) -> u32 { @@ -1462,8 +1341,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal(), 251); - /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal(), 74); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.ordinal(), 251); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.ordinal(), 74); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Combined with [`NaiveDate::pred`](#method.pred), @@ -1471,21 +1351,22 @@ impl Datelike for NaiveDate { /// (Note that this panics when `year` is out of range.) /// /// ``` - /// use chrono::{NaiveDate, Datelike}; + /// use chrono::{NaiveDate, Datelike, ChronoError}; /// - /// fn ndays_in_year(year: i32) -> u32 { + /// fn ndays_in_year(year: i32) -> Result { /// // the first day of the next year... - /// let d = NaiveDate::from_ymd(year + 1, 1, 1); + /// let d = NaiveDate::from_ymd(year + 1, 1, 1)?; /// /// // ...is preceded by the last day of the original year - /// d.pred().ordinal() + /// Ok(d.pred()?.ordinal()) /// } /// - /// assert_eq!(ndays_in_year(2015), 365); - /// assert_eq!(ndays_in_year(2016), 366); - /// assert_eq!(ndays_in_year(2017), 365); - /// assert_eq!(ndays_in_year(2000), 366); - /// assert_eq!(ndays_in_year(2100), 365); + /// assert_eq!(ndays_in_year(2015)?, 365); + /// assert_eq!(ndays_in_year(2016)?, 366); + /// assert_eq!(ndays_in_year(2017)?, 365); + /// assert_eq!(ndays_in_year(2000)?, 366); + /// assert_eq!(ndays_in_year(2100)?, 365); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn ordinal(&self) -> u32 { @@ -1501,8 +1382,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal0(), 250); - /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal0(), 73); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.ordinal0(), 250); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.ordinal0(), 73); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn ordinal0(&self) -> u32 { @@ -1516,8 +1398,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).weekday(), Weekday::Tue); - /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).weekday(), Weekday::Fri); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.weekday(), Weekday::Tue); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.weekday(), Weekday::Fri); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn weekday(&self) -> Weekday { @@ -1531,28 +1414,28 @@ impl Datelike for NaiveDate { /// Makes a new `NaiveDate` with the year number changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(2016), - /// Some(NaiveDate::from_ymd(2016, 9, 8))); - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(-308), - /// Some(NaiveDate::from_ymd(-308, 9, 8))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.with_year(2016)?, NaiveDate::from_ymd(2016, 9, 8)?); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.with_year(-308)?, NaiveDate::from_ymd(-308, 9, 8)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// A leap day (February 29) is a good example that this method can return `None`. /// /// ``` /// # use chrono::{NaiveDate, Datelike}; - /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2015).is_none()); - /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2020).is_some()); + /// assert!(NaiveDate::from_ymd(2016, 2, 29)?.with_year(2015).is_err()); + /// assert!(NaiveDate::from_ymd(2016, 2, 29)?.with_year(2020).is_ok()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_year(&self, year: i32) -> Option { + fn with_year(&self, year: i32) -> Result { // we need to operate with `mdf` since we should keep the month and day number as is let mdf = self.mdf(); @@ -1565,125 +1448,128 @@ impl Datelike for NaiveDate { /// Makes a new `NaiveDate` with the month number (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDate` would be + /// invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(10), - /// Some(NaiveDate::from_ymd(2015, 10, 8))); - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(13), None); // no month 13 - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month(2), None); // no February 30 + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.with_month(10)?, NaiveDate::from_ymd(2015, 10, 8)?); + /// assert!(NaiveDate::from_ymd(2015, 9, 8)?.with_month(13).is_err()); // no month 13 + /// assert!(NaiveDate::from_ymd(2015, 9, 30)?.with_month(2).is_err()); // no February 30 + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_month(&self, month: u32) -> Option { + fn with_month(&self, month: u32) -> Result { self.with_mdf(self.mdf().with_month(month)) } /// Makes a new `NaiveDate` with the month number (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDate` would be + /// invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(9), - /// Some(NaiveDate::from_ymd(2015, 10, 8))); - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(12), None); // no month 13 - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month0(1), None); // no February 30 + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.with_month0(9)?, + /// NaiveDate::from_ymd(2015, 10, 8)?); + /// assert!(NaiveDate::from_ymd(2015, 9, 8)?.with_month0(12).is_err()); // no month 13 + /// assert!(NaiveDate::from_ymd(2015, 9, 30)?.with_month0(1).is_err()); // no February 30 + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_month0(&self, month0: u32) -> Option { + fn with_month0(&self, month0: u32) -> Result { self.with_mdf(self.mdf().with_month(month0 + 1)) } /// Makes a new `NaiveDate` with the day of month (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(30), - /// Some(NaiveDate::from_ymd(2015, 9, 30))); - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(31), - /// None); // no September 31 + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.with_day(30)?, + /// NaiveDate::from_ymd(2015, 9, 30)?); + /// assert!(NaiveDate::from_ymd(2015, 9, 8)?.with_day(31).is_err()); // no September 31 + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_day(&self, day: u32) -> Option { + fn with_day(&self, day: u32) -> Result { self.with_mdf(self.mdf().with_day(day)) } /// Makes a new `NaiveDate` with the day of month (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(29), - /// Some(NaiveDate::from_ymd(2015, 9, 30))); - /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(30), - /// None); // no September 31 + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.with_day0(29)?, + /// NaiveDate::from_ymd(2015, 9, 30)?); + /// assert!(NaiveDate::from_ymd(2015, 9, 8)?.with_day0(30).is_err()); // no September 31 + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_day0(&self, day0: u32) -> Option { + fn with_day0(&self, day0: u32) -> Result { self.with_mdf(self.mdf().with_day(day0 + 1)) } /// Makes a new `NaiveDate` with the day of year (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(60), - /// Some(NaiveDate::from_ymd(2015, 3, 1))); - /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(366), - /// None); // 2015 had only 365 days + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1)?.with_ordinal(60)?, + /// NaiveDate::from_ymd(2015, 3, 1)?); + /// assert!(NaiveDate::from_ymd(2015, 1, 1)?.with_ordinal(366).is_err()); // 2015 had only 365 days /// - /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal(60), - /// Some(NaiveDate::from_ymd(2016, 2, 29))); - /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal(366), - /// Some(NaiveDate::from_ymd(2016, 12, 31))); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal(60)?, + /// NaiveDate::from_ymd(2016, 2, 29)?); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal(366)?, + /// NaiveDate::from_ymd(2016, 12, 31)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_ordinal(&self, ordinal: u32) -> Option { + fn with_ordinal(&self, ordinal: u32) -> Result { self.with_of(self.of().with_ordinal(ordinal)) } /// Makes a new `NaiveDate` with the day of year (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(59), - /// Some(NaiveDate::from_ymd(2015, 3, 1))); - /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(365), - /// None); // 2015 had only 365 days + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1)?.with_ordinal0(59)?, + /// NaiveDate::from_ymd(2015, 3, 1)?); + /// assert!(NaiveDate::from_ymd(2015, 1, 1)?.with_ordinal0(365).is_err()); // 2015 had only 365 days /// - /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal0(59), - /// Some(NaiveDate::from_ymd(2016, 2, 29))); - /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal0(365), - /// Some(NaiveDate::from_ymd(2016, 12, 31))); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal0(59)?, + /// NaiveDate::from_ymd(2016, 2, 29)?); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal0(365)?, + /// NaiveDate::from_ymd(2016, 12, 31)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_ordinal0(&self, ordinal0: u32) -> Option { + fn with_ordinal0(&self, ordinal0: u32) -> Result { self.with_of(self.of().with_ordinal(ordinal0 + 1)) } } @@ -1701,14 +1587,15 @@ impl Datelike for NaiveDate { /// /// let from_ymd = NaiveDate::from_ymd; /// -/// 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)); +/// 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)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Add for NaiveDate { type Output = NaiveDate; @@ -1742,12 +1629,13 @@ impl Add for NaiveDate { /// /// let from_ymd = NaiveDate::from_ymd; /// - /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(1), from_ymd(2014, 2, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(11), from_ymd(2014, 12, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(12), from_ymd(2015, 1, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(13), from_ymd(2015, 2, 1)); - /// assert_eq!(from_ymd(2014, 1, 31) + Months::new(1), from_ymd(2014, 2, 28)); - /// assert_eq!(from_ymd(2020, 1, 31) + Months::new(1), from_ymd(2020, 2, 29)); + /// assert_eq!(from_ymd(2014, 1, 1)? + Months::new(1), from_ymd(2014, 2, 1)?); + /// assert_eq!(from_ymd(2014, 1, 1)? + Months::new(11), from_ymd(2014, 12, 1)?); + /// assert_eq!(from_ymd(2014, 1, 1)? + Months::new(12), from_ymd(2015, 1, 1)?); + /// assert_eq!(from_ymd(2014, 1, 1)? + Months::new(13), from_ymd(2015, 2, 1)?); + /// assert_eq!(from_ymd(2014, 1, 31)? + Months::new(1), from_ymd(2014, 2, 28)?); + /// assert_eq!(from_ymd(2020, 1, 31)? + Months::new(1), from_ymd(2020, 2, 29)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` fn add(self, months: Months) -> Self::Output { self.checked_add_months(months).unwrap() @@ -1770,9 +1658,10 @@ impl Sub for NaiveDate { /// /// let from_ymd = NaiveDate::from_ymd; /// - /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(11), from_ymd(2013, 2, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(12), from_ymd(2013, 1, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1)); + /// assert_eq!(from_ymd(2014, 1, 1)? - Months::new(11), from_ymd(2013, 2, 1)?); + /// assert_eq!(from_ymd(2014, 1, 1)? - Months::new(12), from_ymd(2013, 1, 1)?); + /// assert_eq!(from_ymd(2014, 1, 1)? - Months::new(13), from_ymd(2012, 12, 1)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` fn sub(self, months: Months) -> Self::Output { self.checked_sub_months(months).unwrap() @@ -1809,14 +1698,15 @@ impl Sub for NaiveDate { /// /// let from_ymd = NaiveDate::from_ymd; /// -/// 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)); +/// 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)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Sub for NaiveDate { type Output = NaiveDate; @@ -1850,13 +1740,14 @@ impl SubAssign for NaiveDate { /// /// let from_ymd = NaiveDate::from_ymd; /// -/// 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)); +/// 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)); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Sub for NaiveDate { type Output = TimeDelta; @@ -1883,7 +1774,7 @@ impl Iterator for NaiveDateDaysIterator { // current < NaiveDate::MAX from here on: let current = self.value; // This can't panic because current is < NaiveDate::MAX: - self.value = current.succ(); + self.value = current.succ().ok()?; Some(current) } @@ -1901,7 +1792,7 @@ impl DoubleEndedIterator for NaiveDateDaysIterator { return None; } let current = self.value; - self.value = current.pred(); + self.value = current.pred().ok()?; Some(current) } } @@ -1956,22 +1847,25 @@ impl DoubleEndedIterator for NaiveDateWeeksIterator { /// ``` /// use chrono::NaiveDate; /// -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5)?), "2015-09-05"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(0, 1, 1)?), "0000-01-01"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31)?), "9999-12-31"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. /// /// ``` /// # use chrono::NaiveDate; -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(-1, 1, 1)?), "-0001-01-01"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31)?), "+10000-12-31"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl fmt::Debug for NaiveDate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let year = self.year(); let mdf = self.mdf(); + if (0..=9999).contains(&year) { write!(f, "{:04}-{:02}-{:02}", year, mdf.month(), mdf.day()) } else { @@ -1991,17 +1885,19 @@ impl fmt::Debug for NaiveDate { /// ``` /// use chrono::NaiveDate; /// -/// assert_eq!(format!("{}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05"); -/// assert_eq!(format!("{}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01"); -/// assert_eq!(format!("{}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd(2015, 9, 5)?), "2015-09-05"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd(0, 1, 1)?), "0000-01-01"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd(9999, 12, 31)?), "9999-12-31"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. /// /// ``` /// # use chrono::NaiveDate; -/// assert_eq!(format!("{}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01"); -/// assert_eq!(format!("{}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd(-1, 1, 1)?), "-0001-01-01"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd(10000, 12, 31)?), "+10000-12-31"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl fmt::Display for NaiveDate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -2017,13 +1913,14 @@ impl fmt::Display for NaiveDate { /// ``` /// use chrono::NaiveDate; /// -/// let d = NaiveDate::from_ymd(2015, 9, 18); -/// assert_eq!("2015-09-18".parse::(), Ok(d)); +/// let d = NaiveDate::from_ymd(2015, 9, 18)?; +/// assert_eq!("2015-09-18".parse::()?, d); /// -/// let d = NaiveDate::from_ymd(12345, 6, 7); -/// assert_eq!("+12345-6-7".parse::(), Ok(d)); +/// let d = NaiveDate::from_ymd(12345, 6, 7)?; +/// assert_eq!("+12345-6-7".parse::()?, d); /// /// assert!("foo".parse::().is_err()); +/// # Ok::<_, Box>(()) /// ``` impl str::FromStr for NaiveDate { type Err = ParseError; @@ -2054,11 +1951,12 @@ impl str::FromStr for NaiveDate { /// use chrono::NaiveDate; /// /// let default_date = NaiveDate::default(); -/// assert_eq!(default_date, NaiveDate::from_ymd(1970, 1, 1)); +/// assert_eq!(default_date, NaiveDate::from_ymd(1970, 1, 1)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Default for NaiveDate { fn default() -> Self { - NaiveDate::from_ymd(1970, 1, 1) + NaiveDate::UNIX_EPOCH } } @@ -2068,9 +1966,18 @@ where F: Fn(&NaiveDate) -> Result, E: ::std::fmt::Debug, { - assert_eq!(to_string(&NaiveDate::from_ymd(2014, 7, 24)).ok(), Some(r#""2014-07-24""#.into())); - assert_eq!(to_string(&NaiveDate::from_ymd(0, 1, 1)).ok(), Some(r#""0000-01-01""#.into())); - assert_eq!(to_string(&NaiveDate::from_ymd(-1, 12, 31)).ok(), Some(r#""-0001-12-31""#.into())); + assert_eq!( + to_string(&NaiveDate::from_ymd(2014, 7, 24).unwrap()).ok(), + Some(r#""2014-07-24""#.into()) + ); + assert_eq!( + to_string(&NaiveDate::from_ymd(0, 1, 1).unwrap()).ok(), + Some(r#""0000-01-01""#.into()) + ); + assert_eq!( + to_string(&NaiveDate::from_ymd(-1, 12, 31).unwrap()).ok(), + Some(r#""-0001-12-31""#.into()) + ); assert_eq!(to_string(&NaiveDate::MIN).ok(), Some(r#""-262144-01-01""#.into())); assert_eq!(to_string(&NaiveDate::MAX).ok(), Some(r#""+262143-12-31""#.into())); } @@ -2083,14 +1990,14 @@ where { use std::{i32, i64}; - assert_eq!(from_str(r#""2016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8))); - assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8))); - assert_eq!(from_str(r#""+002016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8))); - assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1))); - assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1))); - assert_eq!(from_str(r#""-0001-12-31""#).ok(), Some(NaiveDate::from_ymd(-1, 12, 31))); - assert_eq!(from_str(r#""-262144-01-01""#).ok(), Some(NaiveDate::MIN)); - assert_eq!(from_str(r#""+262143-12-31""#).ok(), Some(NaiveDate::MAX)); + assert_eq!(from_str(r#""2016-07-08""#).unwrap(), NaiveDate::from_ymd(2016, 7, 8).unwrap()); + assert_eq!(from_str(r#""2016-7-8""#).unwrap(), NaiveDate::from_ymd(2016, 7, 8).unwrap()); + assert_eq!(from_str(r#""+002016-07-08""#).unwrap(), NaiveDate::from_ymd(2016, 7, 8).unwrap()); + assert_eq!(from_str(r#""0000-01-01""#).unwrap(), NaiveDate::from_ymd(0, 1, 1).unwrap()); + assert_eq!(from_str(r#""0-1-1""#).unwrap(), NaiveDate::from_ymd(0, 1, 1).unwrap()); + assert_eq!(from_str(r#""-0001-12-31""#).unwrap(), NaiveDate::from_ymd(-1, 12, 31).unwrap()); + assert_eq!(from_str(r#""-262144-01-01""#).unwrap(), NaiveDate::MIN); + assert_eq!(from_str(r#""+262143-12-31""#).unwrap(), NaiveDate::MAX); // bad formats assert!(from_str(r#""""#).is_err()); @@ -2190,7 +2097,7 @@ mod serde { // it is not self-describing. use bincode::{deserialize, serialize}; - let d = NaiveDate::from_ymd(2014, 7, 24); + let d = NaiveDate::from_ymd(2014, 7, 24).unwrap(); let encoded = serialize(&d).unwrap(); let decoded: NaiveDate = deserialize(&encoded).unwrap(); assert_eq!(d, decoded); @@ -2200,95 +2107,99 @@ mod serde { #[cfg(test)] mod tests { use super::{ - Days, Months, NaiveDate, MAX_DAYS_FROM_YEAR_0, MAX_YEAR, MIN_DAYS_FROM_YEAR_0, MIN_YEAR, + Days, Months, NaiveDate, MAX_BITS, MAX_DAYS_FROM_YEAR_0, MAX_YEAR, MIN_DAYS_FROM_YEAR_0, + MIN_YEAR, }; + use crate::error::ChronoErrorKind; use crate::time_delta::TimeDelta; - use crate::{Datelike, Weekday}; + use crate::{ChronoError, Datelike, Weekday}; use std::{ convert::{TryFrom, TryInto}, i32, u32, }; + macro_rules! ymd { + ($year:expr, $month:expr, $day:expr) => { + NaiveDate::from_ymd($year, $month, $day).unwrap() + }; + } + + // as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`, + // we use a separate run-time test. + #[test] + fn test_date_bounds() { + let calculated_min = ymd!(MIN_YEAR, 1, 1); + let calculated_max = ymd!(MAX_YEAR, 12, 31); + assert!( + NaiveDate::MIN == calculated_min, + "`NaiveDate::MIN` should have a year flag {:?}", + calculated_min.of().flags() + ); + assert!( + NaiveDate::MAX == calculated_max, + "`NaiveDate::MAX` should have a year flag {:?}", + calculated_max.of().flags() + ); + + // let's also check that the entire range do not exceed 2^44 seconds + // (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!( + maxsecs < (1 << MAX_BITS), + "The entire `NaiveDate` range somehow exceeds 2^{} seconds", + MAX_BITS + ); + } + #[test] fn diff_months() { // identity - assert_eq!( - NaiveDate::from_ymd(2022, 8, 3).checked_add_months(Months::new(0)), - Some(NaiveDate::from_ymd(2022, 8, 3)) - ); + assert_eq!(ymd!(2022, 8, 3).checked_add_months(Months::new(0)), Ok(ymd!(2022, 8, 3))); // add with months exceeding `i32::MAX` - assert_eq!( - NaiveDate::from_ymd(2022, 8, 3).checked_add_months(Months::new(i32::MAX as u32 + 1)), - None - ); + assert!(ymd!(2022, 8, 3).checked_add_months(Months::new(i32::MAX as u32 + 1)).is_err()); // sub with months exceeindg `i32::MIN` - assert_eq!( - NaiveDate::from_ymd(2022, 8, 3) - .checked_sub_months(Months::new((i32::MIN as i64).abs() as u32 + 1)), - None - ); + assert!(ymd!(2022, 8, 3) + .checked_sub_months(Months::new((i32::MIN as i64).abs() as u32 + 1)) + .is_err()); // add overflowing year - assert_eq!(NaiveDate::MAX.checked_add_months(Months::new(1)), None); + assert!(NaiveDate::MAX.checked_add_months(Months::new(1)).is_err()); // add underflowing year - assert_eq!(NaiveDate::MIN.checked_sub_months(Months::new(1)), None); + assert!(NaiveDate::MIN.checked_sub_months(Months::new(1)).is_err()); // sub crossing year 0 boundary assert_eq!( - NaiveDate::from_ymd(2022, 8, 3).checked_sub_months(Months::new(2050 * 12)), - Some(NaiveDate::from_ymd(-28, 8, 3)) + ymd!(2022, 8, 3).checked_sub_months(Months::new(2050 * 12)), + Ok(ymd!(-28, 8, 3)) ); // add crossing year boundary - assert_eq!( - NaiveDate::from_ymd(2022, 8, 3).checked_add_months(Months::new(6)), - Some(NaiveDate::from_ymd(2023, 2, 3)) - ); + assert_eq!(ymd!(2022, 8, 3).checked_add_months(Months::new(6)), Ok(ymd!(2023, 2, 3))); // sub crossing year boundary - assert_eq!( - NaiveDate::from_ymd(2022, 8, 3).checked_sub_months(Months::new(10)), - Some(NaiveDate::from_ymd(2021, 10, 3)) - ); + assert_eq!(ymd!(2022, 8, 3).checked_sub_months(Months::new(10)), Ok(ymd!(2021, 10, 3))); // add clamping day, non-leap year - assert_eq!( - NaiveDate::from_ymd(2022, 1, 29).checked_add_months(Months::new(1)), - Some(NaiveDate::from_ymd(2022, 2, 28)) - ); + assert_eq!(ymd!(2022, 1, 29).checked_add_months(Months::new(1)), Ok(ymd!(2022, 2, 28))); // add to leap day - assert_eq!( - NaiveDate::from_ymd(2022, 10, 29).checked_add_months(Months::new(16)), - Some(NaiveDate::from_ymd(2024, 2, 29)) - ); + assert_eq!(ymd!(2022, 10, 29).checked_add_months(Months::new(16)), Ok(ymd!(2024, 2, 29))); // add into december - assert_eq!( - NaiveDate::from_ymd(2022, 10, 31).checked_add_months(Months::new(2)), - Some(NaiveDate::from_ymd(2022, 12, 31)) - ); + assert_eq!(ymd!(2022, 10, 31).checked_add_months(Months::new(2)), Ok(ymd!(2022, 12, 31))); // sub into december - assert_eq!( - NaiveDate::from_ymd(2022, 10, 31).checked_sub_months(Months::new(10)), - Some(NaiveDate::from_ymd(2021, 12, 31)) - ); + assert_eq!(ymd!(2022, 10, 31).checked_sub_months(Months::new(10)), Ok(ymd!(2021, 12, 31))); // add into january - assert_eq!( - NaiveDate::from_ymd(2022, 8, 3).checked_add_months(Months::new(5)), - Some(NaiveDate::from_ymd(2023, 1, 3)) - ); + assert_eq!(ymd!(2022, 8, 3).checked_add_months(Months::new(5)), Ok(ymd!(2023, 1, 3))); // sub into january - assert_eq!( - NaiveDate::from_ymd(2022, 8, 3).checked_sub_months(Months::new(7)), - Some(NaiveDate::from_ymd(2022, 1, 3)) - ); + assert_eq!(ymd!(2022, 8, 3).checked_sub_months(Months::new(7)), Ok(ymd!(2022, 1, 3))); } #[test] @@ -2297,20 +2208,20 @@ mod tests { for y in range_inclusive(NaiveDate::MIN.year(), NaiveDate::MAX.year()) { // even months - let d4 = NaiveDate::from_ymd(y, 4, 4); - let d6 = NaiveDate::from_ymd(y, 6, 6); - let d8 = NaiveDate::from_ymd(y, 8, 8); - let d10 = NaiveDate::from_ymd(y, 10, 10); - let d12 = NaiveDate::from_ymd(y, 12, 12); + let d4 = ymd!(y, 4, 4); + let d6 = ymd!(y, 6, 6); + let d8 = ymd!(y, 8, 8); + let d10 = ymd!(y, 10, 10); + let d12 = ymd!(y, 12, 12); // nine to five, seven-eleven - let d59 = NaiveDate::from_ymd(y, 5, 9); - let d95 = NaiveDate::from_ymd(y, 9, 5); - let d711 = NaiveDate::from_ymd(y, 7, 11); - let d117 = NaiveDate::from_ymd(y, 11, 7); + let d59 = ymd!(y, 5, 9); + let d95 = ymd!(y, 9, 5); + let d711 = ymd!(y, 7, 11); + let d117 = ymd!(y, 11, 7); // "March 0" - let d30 = NaiveDate::from_ymd(y, 3, 1).pred(); + let d30 = ymd!(y, 3, 1).pred().unwrap(); let weekday = d30.weekday(); let other_dates = [d4, d6, d8, d10, d12, d59, d95, d711, d117]; @@ -2320,77 +2231,76 @@ mod tests { #[test] fn test_date_from_ymd() { - let ymd_opt = NaiveDate::from_ymd_opt; + let from_ymd = NaiveDate::from_ymd; - assert!(ymd_opt(2012, 0, 1).is_none()); - assert!(ymd_opt(2012, 1, 1).is_some()); - assert!(ymd_opt(2012, 2, 29).is_some()); - assert!(ymd_opt(2014, 2, 29).is_none()); - assert!(ymd_opt(2014, 3, 0).is_none()); - assert!(ymd_opt(2014, 3, 1).is_some()); - assert!(ymd_opt(2014, 3, 31).is_some()); - assert!(ymd_opt(2014, 3, 32).is_none()); - assert!(ymd_opt(2014, 12, 31).is_some()); - assert!(ymd_opt(2014, 13, 1).is_none()); + assert!(from_ymd(2012, 0, 1).is_err()); + assert!(from_ymd(2012, 1, 1).is_ok()); + assert!(from_ymd(2012, 2, 29).is_ok()); + assert!(from_ymd(2014, 2, 29).is_err()); + assert!(from_ymd(2014, 3, 0).is_err()); + assert!(from_ymd(2014, 3, 1).is_ok()); + assert!(from_ymd(2014, 3, 31).is_ok()); + assert!(from_ymd(2014, 3, 32).is_err()); + assert!(from_ymd(2014, 12, 31).is_ok()); + assert!(from_ymd(2014, 13, 1).is_err()); } #[test] fn test_date_from_yo() { - let yo_opt = NaiveDate::from_yo_opt; + let from_yo = NaiveDate::from_yo; let ymd = NaiveDate::from_ymd; - assert_eq!(yo_opt(2012, 0), None); - assert_eq!(yo_opt(2012, 1), Some(ymd(2012, 1, 1))); - assert_eq!(yo_opt(2012, 2), Some(ymd(2012, 1, 2))); - assert_eq!(yo_opt(2012, 32), Some(ymd(2012, 2, 1))); - assert_eq!(yo_opt(2012, 60), Some(ymd(2012, 2, 29))); - assert_eq!(yo_opt(2012, 61), Some(ymd(2012, 3, 1))); - assert_eq!(yo_opt(2012, 100), Some(ymd(2012, 4, 9))); - assert_eq!(yo_opt(2012, 200), Some(ymd(2012, 7, 18))); - assert_eq!(yo_opt(2012, 300), Some(ymd(2012, 10, 26))); - assert_eq!(yo_opt(2012, 366), Some(ymd(2012, 12, 31))); - assert_eq!(yo_opt(2012, 367), None); - - assert_eq!(yo_opt(2014, 0), None); - assert_eq!(yo_opt(2014, 1), Some(ymd(2014, 1, 1))); - assert_eq!(yo_opt(2014, 2), Some(ymd(2014, 1, 2))); - assert_eq!(yo_opt(2014, 32), Some(ymd(2014, 2, 1))); - assert_eq!(yo_opt(2014, 59), Some(ymd(2014, 2, 28))); - assert_eq!(yo_opt(2014, 60), Some(ymd(2014, 3, 1))); - assert_eq!(yo_opt(2014, 100), Some(ymd(2014, 4, 10))); - assert_eq!(yo_opt(2014, 200), Some(ymd(2014, 7, 19))); - assert_eq!(yo_opt(2014, 300), Some(ymd(2014, 10, 27))); - assert_eq!(yo_opt(2014, 365), Some(ymd(2014, 12, 31))); - assert_eq!(yo_opt(2014, 366), None); + assert!(from_yo(2012, 0).is_err()); + assert_eq!(from_yo(2012, 1), Ok(ymd(2012, 1, 1).unwrap())); + assert_eq!(from_yo(2012, 2), Ok(ymd(2012, 1, 2).unwrap())); + assert_eq!(from_yo(2012, 32), Ok(ymd(2012, 2, 1).unwrap())); + assert_eq!(from_yo(2012, 60), Ok(ymd(2012, 2, 29).unwrap())); + assert_eq!(from_yo(2012, 61), Ok(ymd(2012, 3, 1).unwrap())); + assert_eq!(from_yo(2012, 100), Ok(ymd(2012, 4, 9).unwrap())); + assert_eq!(from_yo(2012, 200), Ok(ymd(2012, 7, 18).unwrap())); + assert_eq!(from_yo(2012, 300), Ok(ymd(2012, 10, 26).unwrap())); + assert_eq!(from_yo(2012, 366), Ok(ymd(2012, 12, 31).unwrap())); + assert!(from_yo(2012, 367).is_err()); + + assert!(from_yo(2014, 0).is_err()); + assert_eq!(from_yo(2014, 1), Ok(ymd(2014, 1, 1).unwrap())); + assert_eq!(from_yo(2014, 2), Ok(ymd(2014, 1, 2).unwrap())); + assert_eq!(from_yo(2014, 32), Ok(ymd(2014, 2, 1).unwrap())); + assert_eq!(from_yo(2014, 59), Ok(ymd(2014, 2, 28).unwrap())); + assert_eq!(from_yo(2014, 60), Ok(ymd(2014, 3, 1).unwrap())); + assert_eq!(from_yo(2014, 100), Ok(ymd(2014, 4, 10).unwrap())); + assert_eq!(from_yo(2014, 200), Ok(ymd(2014, 7, 19).unwrap())); + assert_eq!(from_yo(2014, 300), Ok(ymd(2014, 10, 27).unwrap())); + assert_eq!(from_yo(2014, 365), Ok(ymd(2014, 12, 31).unwrap())); + assert!(from_yo(2014, 366).is_err()); } #[test] fn test_date_from_isoywd() { - let isoywd_opt = NaiveDate::from_isoywd_opt; - let ymd = NaiveDate::from_ymd; - - assert_eq!(isoywd_opt(2004, 0, Weekday::Sun), None); - assert_eq!(isoywd_opt(2004, 1, Weekday::Mon), Some(ymd(2003, 12, 29))); - assert_eq!(isoywd_opt(2004, 1, Weekday::Sun), Some(ymd(2004, 1, 4))); - assert_eq!(isoywd_opt(2004, 2, Weekday::Mon), Some(ymd(2004, 1, 5))); - assert_eq!(isoywd_opt(2004, 2, Weekday::Sun), Some(ymd(2004, 1, 11))); - assert_eq!(isoywd_opt(2004, 52, Weekday::Mon), Some(ymd(2004, 12, 20))); - assert_eq!(isoywd_opt(2004, 52, Weekday::Sun), Some(ymd(2004, 12, 26))); - assert_eq!(isoywd_opt(2004, 53, Weekday::Mon), Some(ymd(2004, 12, 27))); - assert_eq!(isoywd_opt(2004, 53, Weekday::Sun), Some(ymd(2005, 1, 2))); - assert_eq!(isoywd_opt(2004, 54, Weekday::Mon), None); - - assert_eq!(isoywd_opt(2011, 0, Weekday::Sun), None); - assert_eq!(isoywd_opt(2011, 1, Weekday::Mon), Some(ymd(2011, 1, 3))); - assert_eq!(isoywd_opt(2011, 1, Weekday::Sun), Some(ymd(2011, 1, 9))); - assert_eq!(isoywd_opt(2011, 2, Weekday::Mon), Some(ymd(2011, 1, 10))); - assert_eq!(isoywd_opt(2011, 2, Weekday::Sun), Some(ymd(2011, 1, 16))); - - assert_eq!(isoywd_opt(2018, 51, Weekday::Mon), Some(ymd(2018, 12, 17))); - assert_eq!(isoywd_opt(2018, 51, Weekday::Sun), Some(ymd(2018, 12, 23))); - assert_eq!(isoywd_opt(2018, 52, Weekday::Mon), Some(ymd(2018, 12, 24))); - assert_eq!(isoywd_opt(2018, 52, Weekday::Sun), Some(ymd(2018, 12, 30))); - assert_eq!(isoywd_opt(2018, 53, Weekday::Mon), None); + let from_isoywd = NaiveDate::from_isoywd; + + assert!(from_isoywd(2004, 0, Weekday::Sun).is_err()); + assert_eq!(from_isoywd(2004, 1, Weekday::Mon), Ok(ymd!(2003, 12, 29))); + assert_eq!(from_isoywd(2004, 1, Weekday::Sun), Ok(ymd!(2004, 1, 4))); + assert_eq!(from_isoywd(2004, 2, Weekday::Mon), Ok(ymd!(2004, 1, 5))); + assert_eq!(from_isoywd(2004, 2, Weekday::Sun), Ok(ymd!(2004, 1, 11))); + assert_eq!(from_isoywd(2004, 52, Weekday::Mon), Ok(ymd!(2004, 12, 20))); + assert_eq!(from_isoywd(2004, 52, Weekday::Sun), Ok(ymd!(2004, 12, 26))); + assert_eq!(from_isoywd(2004, 53, Weekday::Mon), Ok(ymd!(2004, 12, 27))); + assert_eq!(from_isoywd(2004, 53, Weekday::Sun), Ok(ymd!(2005, 1, 2))); + assert!(from_isoywd(2004, 54, Weekday::Mon).is_err()); + + assert!(from_isoywd(2011, 0, Weekday::Sun).is_err()); + assert_eq!(from_isoywd(2011, 1, Weekday::Mon), Ok(ymd!(2011, 1, 3))); + assert_eq!(from_isoywd(2011, 1, Weekday::Sun), Ok(ymd!(2011, 1, 9))); + assert_eq!(from_isoywd(2011, 2, Weekday::Mon), Ok(ymd!(2011, 1, 10))); + assert_eq!(from_isoywd(2011, 2, Weekday::Sun), Ok(ymd!(2011, 1, 16))); + + assert_eq!(from_isoywd(2018, 51, Weekday::Mon), Ok(ymd!(2018, 12, 17))); + assert_eq!(from_isoywd(2018, 51, Weekday::Sun), Ok(ymd!(2018, 12, 23))); + assert_eq!(from_isoywd(2018, 52, Weekday::Mon), Ok(ymd!(2018, 12, 24))); + assert_eq!(from_isoywd(2018, 52, Weekday::Sun), Ok(ymd!(2018, 12, 30))); + assert!(from_isoywd(2018, 53, Weekday::Mon).is_err()); } #[test] @@ -2408,8 +2318,9 @@ mod tests { ] .iter() { - let d = NaiveDate::from_isoywd_opt(year, week, weekday); - if let Some(d) = d { + let d = NaiveDate::from_isoywd(year, week, weekday); + + if let Ok(d) = d { assert_eq!(d.weekday(), weekday); let w = d.iso_week(); assert_eq!(w.year(), year); @@ -2422,10 +2333,11 @@ mod tests { for year in 2000..2401 { for month in 1..13 { for day in 1..32 { - let d = NaiveDate::from_ymd_opt(year, month, day); - if let Some(d) = d { + let d = NaiveDate::from_ymd(year, month, day); + + if let Ok(d) = d { let w = d.iso_week(); - let d_ = NaiveDate::from_isoywd(w.year(), w.week(), d.weekday()); + let d_ = NaiveDate::from_isoywd(w.year(), w.week(), d.weekday()).unwrap(); assert_eq!(d, d_); } } @@ -2435,63 +2347,63 @@ mod tests { #[test] fn test_date_from_num_days_from_ce() { - let from_ndays_from_ce = NaiveDate::from_num_days_from_ce_opt; - assert_eq!(from_ndays_from_ce(1), Some(NaiveDate::from_ymd(1, 1, 1))); - assert_eq!(from_ndays_from_ce(2), Some(NaiveDate::from_ymd(1, 1, 2))); - assert_eq!(from_ndays_from_ce(31), Some(NaiveDate::from_ymd(1, 1, 31))); - assert_eq!(from_ndays_from_ce(32), Some(NaiveDate::from_ymd(1, 2, 1))); - assert_eq!(from_ndays_from_ce(59), Some(NaiveDate::from_ymd(1, 2, 28))); - assert_eq!(from_ndays_from_ce(60), Some(NaiveDate::from_ymd(1, 3, 1))); - assert_eq!(from_ndays_from_ce(365), Some(NaiveDate::from_ymd(1, 12, 31))); - assert_eq!(from_ndays_from_ce(365 + 1), Some(NaiveDate::from_ymd(2, 1, 1))); - assert_eq!(from_ndays_from_ce(365 * 2 + 1), Some(NaiveDate::from_ymd(3, 1, 1))); - assert_eq!(from_ndays_from_ce(365 * 3 + 1), Some(NaiveDate::from_ymd(4, 1, 1))); - assert_eq!(from_ndays_from_ce(365 * 4 + 2), Some(NaiveDate::from_ymd(5, 1, 1))); - assert_eq!(from_ndays_from_ce(146097 + 1), Some(NaiveDate::from_ymd(401, 1, 1))); - assert_eq!(from_ndays_from_ce(146097 * 5 + 1), Some(NaiveDate::from_ymd(2001, 1, 1))); - assert_eq!(from_ndays_from_ce(719163), Some(NaiveDate::from_ymd(1970, 1, 1))); - assert_eq!(from_ndays_from_ce(0), Some(NaiveDate::from_ymd(0, 12, 31))); // 1 BCE - assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd(0, 1, 1))); - assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd(-1, 12, 31))); // 2 BCE + let from_ndays_from_ce = NaiveDate::from_num_days_from_ce; + assert_eq!(from_ndays_from_ce(1), Ok(ymd!(1, 1, 1))); + assert_eq!(from_ndays_from_ce(2), Ok(ymd!(1, 1, 2))); + assert_eq!(from_ndays_from_ce(31), Ok(ymd!(1, 1, 31))); + assert_eq!(from_ndays_from_ce(32), Ok(ymd!(1, 2, 1))); + assert_eq!(from_ndays_from_ce(59), Ok(ymd!(1, 2, 28))); + assert_eq!(from_ndays_from_ce(60), Ok(ymd!(1, 3, 1))); + assert_eq!(from_ndays_from_ce(365), Ok(ymd!(1, 12, 31))); + assert_eq!(from_ndays_from_ce(365 + 1), Ok(ymd!(2, 1, 1))); + assert_eq!(from_ndays_from_ce(365 * 2 + 1), Ok(ymd!(3, 1, 1))); + assert_eq!(from_ndays_from_ce(365 * 3 + 1), Ok(ymd!(4, 1, 1))); + assert_eq!(from_ndays_from_ce(365 * 4 + 2), Ok(ymd!(5, 1, 1))); + assert_eq!(from_ndays_from_ce(146097 + 1), Ok(ymd!(401, 1, 1))); + assert_eq!(from_ndays_from_ce(146097 * 5 + 1), Ok(ymd!(2001, 1, 1))); + assert_eq!(from_ndays_from_ce(719163), Ok(ymd!(1970, 1, 1))); + assert_eq!(from_ndays_from_ce(0), Ok(ymd!(0, 12, 31))); // 1 BCE + assert_eq!(from_ndays_from_ce(-365), Ok(ymd!(0, 1, 1))); + assert_eq!(from_ndays_from_ce(-366), Ok(ymd!(-1, 12, 31))); // 2 BCE for days in (-9999..10001).map(|x| x * 100) { - assert_eq!(from_ndays_from_ce(days).map(|d| d.num_days_from_ce()), Some(days)); + assert_eq!(from_ndays_from_ce(days).map(|d| d.num_days_from_ce()), Ok(days)); } - assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce()), Some(NaiveDate::MIN)); - assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce() - 1), None); - assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce()), Some(NaiveDate::MAX)); - assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce() + 1), None); + assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce()), Ok(NaiveDate::MIN)); + assert!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce() - 1).is_err()); + assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce()), Ok(NaiveDate::MAX)); + assert!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce() + 1).is_err()); } #[test] - fn test_date_from_weekday_of_month_opt() { - let ymwd = NaiveDate::from_weekday_of_month_opt; - assert_eq!(ymwd(2018, 8, Weekday::Tue, 0), None); - assert_eq!(ymwd(2018, 8, Weekday::Wed, 1), Some(NaiveDate::from_ymd(2018, 8, 1))); - assert_eq!(ymwd(2018, 8, Weekday::Thu, 1), Some(NaiveDate::from_ymd(2018, 8, 2))); - assert_eq!(ymwd(2018, 8, Weekday::Sun, 1), Some(NaiveDate::from_ymd(2018, 8, 5))); - assert_eq!(ymwd(2018, 8, Weekday::Mon, 1), Some(NaiveDate::from_ymd(2018, 8, 6))); - assert_eq!(ymwd(2018, 8, Weekday::Tue, 1), Some(NaiveDate::from_ymd(2018, 8, 7))); - assert_eq!(ymwd(2018, 8, Weekday::Wed, 2), Some(NaiveDate::from_ymd(2018, 8, 8))); - assert_eq!(ymwd(2018, 8, Weekday::Sun, 2), Some(NaiveDate::from_ymd(2018, 8, 12))); - assert_eq!(ymwd(2018, 8, Weekday::Thu, 3), Some(NaiveDate::from_ymd(2018, 8, 16))); - assert_eq!(ymwd(2018, 8, Weekday::Thu, 4), Some(NaiveDate::from_ymd(2018, 8, 23))); - assert_eq!(ymwd(2018, 8, Weekday::Thu, 5), Some(NaiveDate::from_ymd(2018, 8, 30))); - assert_eq!(ymwd(2018, 8, Weekday::Fri, 5), Some(NaiveDate::from_ymd(2018, 8, 31))); - assert_eq!(ymwd(2018, 8, Weekday::Sat, 5), None); + fn test_from_weekday_of_month() { + let from_weekday_of_month = NaiveDate::from_weekday_of_month; + assert!(from_weekday_of_month(2018, 8, Weekday::Tue, 0).is_err()); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Wed, 1).unwrap(), ymd!(2018, 8, 1)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Thu, 1).unwrap(), ymd!(2018, 8, 2)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Sun, 1).unwrap(), ymd!(2018, 8, 5)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Mon, 1).unwrap(), ymd!(2018, 8, 6)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Tue, 1).unwrap(), ymd!(2018, 8, 7)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Wed, 2).unwrap(), ymd!(2018, 8, 8)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Sun, 2).unwrap(), ymd!(2018, 8, 12)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Thu, 3).unwrap(), ymd!(2018, 8, 16)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Thu, 4).unwrap(), ymd!(2018, 8, 23)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Thu, 5).unwrap(), ymd!(2018, 8, 30)); + assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 5).unwrap(), ymd!(2018, 8, 31)); + assert!(from_weekday_of_month(2018, 8, Weekday::Sat, 5).is_err()); } #[test] fn test_date_fields() { fn check(year: i32, month: u32, day: u32, ordinal: u32) { - let d1 = NaiveDate::from_ymd(year, month, day); + let d1 = ymd!(year, month, day); assert_eq!(d1.year(), year); assert_eq!(d1.month(), month); assert_eq!(d1.day(), day); assert_eq!(d1.ordinal(), ordinal); - let d2 = NaiveDate::from_yo(year, ordinal); + let d2 = NaiveDate::from_yo(year, ordinal).unwrap(); assert_eq!(d2.year(), year); assert_eq!(d2.month(), month); assert_eq!(d2.day(), day); @@ -2523,118 +2435,136 @@ mod tests { #[test] fn test_date_weekday() { - assert_eq!(NaiveDate::from_ymd(1582, 10, 15).weekday(), Weekday::Fri); + assert_eq!(ymd!(1582, 10, 15).weekday(), Weekday::Fri); // May 20, 1875 = ISO 8601 reference date - assert_eq!(NaiveDate::from_ymd(1875, 5, 20).weekday(), Weekday::Thu); - assert_eq!(NaiveDate::from_ymd(2000, 1, 1).weekday(), Weekday::Sat); + assert_eq!(ymd!(1875, 5, 20).weekday(), Weekday::Thu); + assert_eq!(ymd!(2000, 1, 1).weekday(), Weekday::Sat); } #[test] fn test_date_with_fields() { - let d = NaiveDate::from_ymd(2000, 2, 29); - assert_eq!(d.with_year(-400), Some(NaiveDate::from_ymd(-400, 2, 29))); - assert_eq!(d.with_year(-100), None); - assert_eq!(d.with_year(1600), Some(NaiveDate::from_ymd(1600, 2, 29))); - assert_eq!(d.with_year(1900), None); - assert_eq!(d.with_year(2000), Some(NaiveDate::from_ymd(2000, 2, 29))); - assert_eq!(d.with_year(2001), None); - assert_eq!(d.with_year(2004), Some(NaiveDate::from_ymd(2004, 2, 29))); - assert_eq!(d.with_year(i32::MAX), None); - - let d = NaiveDate::from_ymd(2000, 4, 30); - assert_eq!(d.with_month(0), None); - assert_eq!(d.with_month(1), Some(NaiveDate::from_ymd(2000, 1, 30))); - assert_eq!(d.with_month(2), None); - assert_eq!(d.with_month(3), Some(NaiveDate::from_ymd(2000, 3, 30))); - assert_eq!(d.with_month(4), Some(NaiveDate::from_ymd(2000, 4, 30))); - assert_eq!(d.with_month(12), Some(NaiveDate::from_ymd(2000, 12, 30))); - assert_eq!(d.with_month(13), None); - assert_eq!(d.with_month(u32::MAX), None); - - let d = NaiveDate::from_ymd(2000, 2, 8); - assert_eq!(d.with_day(0), None); - assert_eq!(d.with_day(1), Some(NaiveDate::from_ymd(2000, 2, 1))); - assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd(2000, 2, 29))); - assert_eq!(d.with_day(30), None); - assert_eq!(d.with_day(u32::MAX), None); - - let d = NaiveDate::from_ymd(2000, 5, 5); - assert_eq!(d.with_ordinal(0), None); - assert_eq!(d.with_ordinal(1), Some(NaiveDate::from_ymd(2000, 1, 1))); - assert_eq!(d.with_ordinal(60), Some(NaiveDate::from_ymd(2000, 2, 29))); - assert_eq!(d.with_ordinal(61), Some(NaiveDate::from_ymd(2000, 3, 1))); - assert_eq!(d.with_ordinal(366), Some(NaiveDate::from_ymd(2000, 12, 31))); - assert_eq!(d.with_ordinal(367), None); - assert_eq!(d.with_ordinal(u32::MAX), None); + let d = ymd!(2000, 2, 29); + assert_eq!(d.with_year(-400), Ok(ymd!(-400, 2, 29))); + assert!(d.with_year(-100).is_err()); + assert_eq!(d.with_year(1600), Ok(ymd!(1600, 2, 29))); + assert!(d.with_year(1900).is_err()); + assert_eq!(d.with_year(2000), Ok(ymd!(2000, 2, 29))); + assert!(d.with_year(2001).is_err()); + assert_eq!(d.with_year(2004), Ok(ymd!(2004, 2, 29))); + assert!(d.with_year(i32::MAX).is_err()); + + let d = ymd!(2000, 4, 30); + assert!(d.with_month(0).is_err()); + assert_eq!(d.with_month(1), Ok(ymd!(2000, 1, 30))); + assert!(d.with_month(2).is_err()); + assert_eq!(d.with_month(3), Ok(ymd!(2000, 3, 30))); + assert_eq!(d.with_month(4), Ok(ymd!(2000, 4, 30))); + assert_eq!(d.with_month(12), Ok(ymd!(2000, 12, 30))); + assert!(d.with_month(13).is_err()); + assert!(d.with_month(u32::MAX).is_err()); + + let d = ymd!(2000, 2, 8); + assert!(d.with_day(0).is_err()); + assert_eq!(d.with_day(1), Ok(ymd!(2000, 2, 1))); + assert_eq!(d.with_day(29), Ok(ymd!(2000, 2, 29))); + assert!(d.with_day(30).is_err()); + assert!(d.with_day(u32::MAX).is_err()); + + let d = ymd!(2000, 5, 5); + assert!(d.with_ordinal(0).is_err()); + assert_eq!(d.with_ordinal(1), Ok(ymd!(2000, 1, 1))); + assert_eq!(d.with_ordinal(60), Ok(ymd!(2000, 2, 29))); + assert_eq!(d.with_ordinal(61), Ok(ymd!(2000, 3, 1))); + assert_eq!(d.with_ordinal(366), Ok(ymd!(2000, 12, 31))); + assert!(d.with_ordinal(367).is_err()); + assert!(d.with_ordinal(u32::MAX).is_err()); } #[test] fn test_date_num_days_from_ce() { - assert_eq!(NaiveDate::from_ymd(1, 1, 1).num_days_from_ce(), 1); + assert_eq!(ymd!(1, 1, 1).num_days_from_ce(), 1); for year in -9999..10001 { assert_eq!( - NaiveDate::from_ymd(year, 1, 1).num_days_from_ce(), - NaiveDate::from_ymd(year - 1, 12, 31).num_days_from_ce() + 1 + ymd!(year, 1, 1).num_days_from_ce(), + ymd!(year - 1, 12, 31).num_days_from_ce() + 1 ); } } #[test] fn test_date_succ() { - let ymd = NaiveDate::from_ymd; - assert_eq!(ymd(2014, 5, 6).succ_opt(), Some(ymd(2014, 5, 7))); - assert_eq!(ymd(2014, 5, 31).succ_opt(), Some(ymd(2014, 6, 1))); - assert_eq!(ymd(2014, 12, 31).succ_opt(), Some(ymd(2015, 1, 1))); - assert_eq!(ymd(2016, 2, 28).succ_opt(), Some(ymd(2016, 2, 29))); - assert_eq!(ymd(NaiveDate::MAX.year(), 12, 31).succ_opt(), None); + assert_eq!(ymd!(2014, 5, 6).succ(), Ok(ymd!(2014, 5, 7))); + assert_eq!(ymd!(2014, 5, 31).succ(), Ok(ymd!(2014, 6, 1))); + assert_eq!(ymd!(2014, 12, 31).succ(), Ok(ymd!(2015, 1, 1))); + assert_eq!(ymd!(2016, 2, 28).succ(), Ok(ymd!(2016, 2, 29))); + assert!(ymd!(NaiveDate::MAX.year(), 12, 31).succ().is_err()); } #[test] fn test_date_pred() { - let ymd = NaiveDate::from_ymd; - assert_eq!(ymd(2016, 3, 1).pred_opt(), Some(ymd(2016, 2, 29))); - assert_eq!(ymd(2015, 1, 1).pred_opt(), Some(ymd(2014, 12, 31))); - assert_eq!(ymd(2014, 6, 1).pred_opt(), Some(ymd(2014, 5, 31))); - assert_eq!(ymd(2014, 5, 7).pred_opt(), Some(ymd(2014, 5, 6))); - assert_eq!(ymd(NaiveDate::MIN.year(), 1, 1).pred_opt(), None); + assert_eq!(ymd!(2016, 3, 1).pred(), Ok(ymd!(2016, 2, 29))); + assert_eq!(ymd!(2015, 1, 1).pred(), Ok(ymd!(2014, 12, 31))); + assert_eq!(ymd!(2014, 6, 1).pred(), Ok(ymd!(2014, 5, 31))); + assert_eq!(ymd!(2014, 5, 7).pred(), Ok(ymd!(2014, 5, 6))); + assert!(ymd!(NaiveDate::MIN.year(), 1, 1).pred().is_err()); } #[test] fn test_date_add() { - 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)); + fn check( + (y1, m1, d1): (i32, u32, u32), + rhs: TimeDelta, + ymd: Result<(i32, u32, u32), ChronoError>, + ) { + let lhs = ymd!(y1, m1, d1); + let sum = ymd.map(|(y, m, d)| ymd!(y, m, d)); assert_eq!(lhs.checked_add_signed(rhs), sum); assert_eq!(lhs.checked_sub_signed(-rhs), sum); } - check((2014, 1, 1), TimeDelta::zero(), Some((2014, 1, 1))); - check((2014, 1, 1), TimeDelta::seconds(86399), Some((2014, 1, 1))); + check((2014, 1, 1), TimeDelta::zero(), Ok((2014, 1, 1))); + check((2014, 1, 1), TimeDelta::seconds(86399), Ok((2014, 1, 1))); // always round towards zero - 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((2014, 1, 1), TimeDelta::seconds(-86399), Ok((2014, 1, 1))); + check((2014, 1, 1), TimeDelta::days(1), Ok((2014, 1, 2))); + check((2014, 1, 1), TimeDelta::days(-1), Ok((2013, 12, 31))); + check((2014, 1, 1), TimeDelta::days(364), Ok((2014, 12, 31))); + check((2014, 1, 1), TimeDelta::days(365 * 4 + 1), Ok((2018, 1, 1))); + check((2014, 1, 1), TimeDelta::days(365 * 400 + 97), Ok((2414, 1, 1))); - check((-7, 1, 1), TimeDelta::days(365 * 12 + 3), Some((5, 1, 1))); + check((-7, 1, 1), TimeDelta::days(365 * 12 + 3), Ok((5, 1, 1))); // overflow check - check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64), Some((MAX_YEAR, 12, 31))); - check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1), None); - check((0, 1, 1), TimeDelta::max_value(), None); - check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64), Some((MIN_YEAR, 1, 1))); - check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1), None); - check((0, 1, 1), TimeDelta::min_value(), None); + check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64), Ok((MAX_YEAR, 12, 31))); + check( + (0, 1, 1), + TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1), + Err(ChronoError::new(ChronoErrorKind::InvalidDate)), + ); + check( + (0, 1, 1), + TimeDelta::max_value(), + Err(ChronoError::new(ChronoErrorKind::InvalidDate)), + ); + check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64), Ok((MIN_YEAR, 1, 1))); + check( + (0, 1, 1), + TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1), + Err(ChronoError::new(ChronoErrorKind::InvalidDate)), + ); + check( + (0, 1, 1), + TimeDelta::min_value(), + Err(ChronoError::new(ChronoErrorKind::InvalidDate)), + ); } #[test] fn test_date_sub() { 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); + let lhs = ymd!(y1, m1, d1); + let rhs = ymd!(y2, m2, d2); assert_eq!(lhs.signed_duration_since(rhs), diff); assert_eq!(rhs.signed_duration_since(lhs), -diff); } @@ -2652,35 +2582,43 @@ mod tests { #[test] fn test_date_add_days() { - fn check((y1, m1, d1): (i32, u32, u32), rhs: Days, 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)); + fn check( + (y1, m1, d1): (i32, u32, u32), + rhs: Days, + ymd: Result<(i32, u32, u32), ChronoError>, + ) { + let lhs = ymd!(y1, m1, d1); + let sum = ymd.map(|(y, m, d)| ymd!(y, m, d)); assert_eq!(lhs.checked_add_days(rhs), sum); } - check((2014, 1, 1), Days::new(0), Some((2014, 1, 1))); + check((2014, 1, 1), Days::new(0), Ok((2014, 1, 1))); // always round towards zero - check((2014, 1, 1), Days::new(1), Some((2014, 1, 2))); - check((2014, 1, 1), Days::new(364), Some((2014, 12, 31))); - check((2014, 1, 1), Days::new(365 * 4 + 1), Some((2018, 1, 1))); - check((2014, 1, 1), Days::new(365 * 400 + 97), Some((2414, 1, 1))); + check((2014, 1, 1), Days::new(1), Ok((2014, 1, 2))); + check((2014, 1, 1), Days::new(364), Ok((2014, 12, 31))); + check((2014, 1, 1), Days::new(365 * 4 + 1), Ok((2018, 1, 1))); + check((2014, 1, 1), Days::new(365 * 400 + 97), Ok((2414, 1, 1))); - check((-7, 1, 1), Days::new(365 * 12 + 3), Some((5, 1, 1))); + check((-7, 1, 1), Days::new(365 * 12 + 3), Ok((5, 1, 1))); // overflow check check( (0, 1, 1), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()), - Some((MAX_YEAR, 12, 31)), + Ok((MAX_YEAR, 12, 31)), + ); + check( + (0, 1, 1), + Days::new(u64::try_from(MAX_DAYS_FROM_YEAR_0).unwrap() + 1), + Err(ChronoError::new(ChronoErrorKind::InvalidDate)), ); - check((0, 1, 1), Days::new(u64::try_from(MAX_DAYS_FROM_YEAR_0).unwrap() + 1), None); } #[test] fn test_date_sub_days() { fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: Days) { - let lhs = NaiveDate::from_ymd(y1, m1, d1); - let rhs = NaiveDate::from_ymd(y2, m2, d2); + let lhs = ymd!(y1, m1, d1); + let rhs = ymd!(y2, m2, d2); assert_eq!(lhs - diff, rhs); } @@ -2697,39 +2635,37 @@ mod tests { #[test] fn test_date_addassignment() { - let ymd = NaiveDate::from_ymd; - let mut date = ymd(2016, 10, 1); + let mut date = ymd!(2016, 10, 1); date += TimeDelta::days(10); - assert_eq!(date, ymd(2016, 10, 11)); + assert_eq!(date, ymd!(2016, 10, 11)); date += TimeDelta::days(30); - assert_eq!(date, ymd(2016, 11, 10)); + assert_eq!(date, ymd!(2016, 11, 10)); } #[test] fn test_date_subassignment() { - let ymd = NaiveDate::from_ymd; - let mut date = ymd(2016, 10, 11); + let mut date = ymd!(2016, 10, 11); date -= TimeDelta::days(10); - assert_eq!(date, ymd(2016, 10, 1)); + assert_eq!(date, ymd!(2016, 10, 1)); date -= TimeDelta::days(2); - assert_eq!(date, ymd(2016, 9, 29)); + assert_eq!(date, ymd!(2016, 9, 29)); } #[test] fn test_date_fmt() { - assert_eq!(format!("{:?}", NaiveDate::from_ymd(2012, 3, 4)), "2012-03-04"); - assert_eq!(format!("{:?}", NaiveDate::from_ymd(0, 3, 4)), "0000-03-04"); - assert_eq!(format!("{:?}", NaiveDate::from_ymd(-307, 3, 4)), "-0307-03-04"); - assert_eq!(format!("{:?}", NaiveDate::from_ymd(12345, 3, 4)), "+12345-03-04"); + assert_eq!(format!("{:?}", ymd!(2012, 3, 4)), "2012-03-04"); + assert_eq!(format!("{:?}", ymd!(0, 3, 4)), "0000-03-04"); + assert_eq!(format!("{:?}", ymd!(-307, 3, 4)), "-0307-03-04"); + assert_eq!(format!("{:?}", ymd!(12345, 3, 4)), "+12345-03-04"); - assert_eq!(NaiveDate::from_ymd(2012, 3, 4).to_string(), "2012-03-04"); - assert_eq!(NaiveDate::from_ymd(0, 3, 4).to_string(), "0000-03-04"); - assert_eq!(NaiveDate::from_ymd(-307, 3, 4).to_string(), "-0307-03-04"); - assert_eq!(NaiveDate::from_ymd(12345, 3, 4).to_string(), "+12345-03-04"); + assert_eq!(ymd!(2012, 3, 4).to_string(), "2012-03-04"); + assert_eq!(ymd!(0, 3, 4).to_string(), "0000-03-04"); + assert_eq!(ymd!(-307, 3, 4).to_string(), "-0307-03-04"); + assert_eq!(ymd!(12345, 3, 4).to_string(), "+12345-03-04"); // the format specifier should have no effect on `NaiveTime` - assert_eq!(format!("{:+30?}", NaiveDate::from_ymd(1234, 5, 6)), "1234-05-06"); - assert_eq!(format!("{:30?}", NaiveDate::from_ymd(12345, 6, 7)), "+12345-06-07"); + assert_eq!(format!("{:+30?}", ymd!(1234, 5, 6)), "1234-05-06"); + assert_eq!(format!("{:30?}", ymd!(12345, 6, 7)), "+12345-06-07"); } #[test] @@ -2785,18 +2721,17 @@ mod tests { #[test] fn test_date_parse_from_str() { - let ymd = NaiveDate::from_ymd; assert_eq!( NaiveDate::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), - Ok(ymd(2014, 5, 7)) + Ok(ymd!(2014, 5, 7)) ); // ignore time and offset assert_eq!( NaiveDate::parse_from_str("2015-W06-1=2015-033", "%G-W%V-%u = %Y-%j"), - Ok(ymd(2015, 2, 2)) + Ok(ymd!(2015, 2, 2)) ); assert_eq!( NaiveDate::parse_from_str("Fri, 09 Aug 13", "%a, %d %b %y"), - Ok(ymd(2013, 8, 9)) + Ok(ymd!(2013, 8, 9)) ); assert!(NaiveDate::parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err()); assert!(NaiveDate::parse_from_str("2014-57", "%Y-%m-%d").is_err()); @@ -2805,7 +2740,7 @@ mod tests { #[test] fn test_date_format() { - let d = NaiveDate::from_ymd(2012, 3, 4); + let d = ymd!(2012, 3, 4); assert_eq!(d.format("%Y,%C,%y,%G,%g").to_string(), "2012,20,12,2012,12"); assert_eq!(d.format("%m,%b,%h,%B").to_string(), "03,Mar,Mar,March"); assert_eq!(d.format("%d,%e").to_string(), "04, 4"); @@ -2818,44 +2753,38 @@ mod tests { assert_eq!(d.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); // non-four-digit years - assert_eq!(NaiveDate::from_ymd(12345, 1, 1).format("%Y").to_string(), "+12345"); - assert_eq!(NaiveDate::from_ymd(1234, 1, 1).format("%Y").to_string(), "1234"); - assert_eq!(NaiveDate::from_ymd(123, 1, 1).format("%Y").to_string(), "0123"); - assert_eq!(NaiveDate::from_ymd(12, 1, 1).format("%Y").to_string(), "0012"); - assert_eq!(NaiveDate::from_ymd(1, 1, 1).format("%Y").to_string(), "0001"); - assert_eq!(NaiveDate::from_ymd(0, 1, 1).format("%Y").to_string(), "0000"); - assert_eq!(NaiveDate::from_ymd(-1, 1, 1).format("%Y").to_string(), "-0001"); - assert_eq!(NaiveDate::from_ymd(-12, 1, 1).format("%Y").to_string(), "-0012"); - assert_eq!(NaiveDate::from_ymd(-123, 1, 1).format("%Y").to_string(), "-0123"); - assert_eq!(NaiveDate::from_ymd(-1234, 1, 1).format("%Y").to_string(), "-1234"); - assert_eq!(NaiveDate::from_ymd(-12345, 1, 1).format("%Y").to_string(), "-12345"); + assert_eq!(ymd!(12345, 1, 1).format("%Y").to_string(), "+12345"); + assert_eq!(ymd!(1234, 1, 1).format("%Y").to_string(), "1234"); + assert_eq!(ymd!(123, 1, 1).format("%Y").to_string(), "0123"); + assert_eq!(ymd!(12, 1, 1).format("%Y").to_string(), "0012"); + assert_eq!(ymd!(1, 1, 1).format("%Y").to_string(), "0001"); + assert_eq!(ymd!(0, 1, 1).format("%Y").to_string(), "0000"); + assert_eq!(ymd!(-1, 1, 1).format("%Y").to_string(), "-0001"); + assert_eq!(ymd!(-12, 1, 1).format("%Y").to_string(), "-0012"); + assert_eq!(ymd!(-123, 1, 1).format("%Y").to_string(), "-0123"); + assert_eq!(ymd!(-1234, 1, 1).format("%Y").to_string(), "-1234"); + assert_eq!(ymd!(-12345, 1, 1).format("%Y").to_string(), "-12345"); // corner cases - assert_eq!( - NaiveDate::from_ymd(2007, 12, 31).format("%G,%g,%U,%W,%V").to_string(), - "2008,08,53,53,01" - ); - assert_eq!( - NaiveDate::from_ymd(2010, 1, 3).format("%G,%g,%U,%W,%V").to_string(), - "2009,09,01,00,53" - ); + assert_eq!(ymd!(2007, 12, 31).format("%G,%g,%U,%W,%V").to_string(), "2008,08,53,53,01"); + assert_eq!(ymd!(2010, 1, 3).format("%G,%g,%U,%W,%V").to_string(), "2009,09,01,00,53"); } #[test] fn test_day_iterator_limit() { - assert_eq!(NaiveDate::from_ymd(262143, 12, 29).iter_days().take(4).count(), 2); - assert_eq!(NaiveDate::from_ymd(-262144, 1, 3).iter_days().rev().take(4).count(), 2); + assert_eq!(ymd!(262143, 12, 29).iter_days().take(4).count(), 2); + assert_eq!(ymd!(-262144, 1, 3).iter_days().rev().take(4).count(), 2); } #[test] fn test_week_iterator_limit() { - assert_eq!(NaiveDate::from_ymd(262143, 12, 12).iter_weeks().take(4).count(), 2); - assert_eq!(NaiveDate::from_ymd(-262144, 1, 15).iter_weeks().rev().take(4).count(), 2); + assert_eq!(ymd!(262143, 12, 12).iter_weeks().take(4).count(), 2); + assert_eq!(ymd!(-262144, 1, 15).iter_weeks().rev().take(4).count(), 2); } #[test] fn test_naiveweek() { - let date = NaiveDate::from_ymd(2022, 5, 18); + let date = ymd!(2022, 5, 18); let asserts = vec![ (Weekday::Mon, "2022-05-16", "2022-05-22"), (Weekday::Tue, "2022-05-17", "2022-05-23"), diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 90f0a08377..8696d72085 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -13,12 +13,13 @@ use num_integer::div_mod_floor; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; +use crate::error::ChronoErrorKind; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::DelayedFormat; use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems}; use crate::format::{Fixed, Item, Numeric, Pad}; use crate::naive::{Days, IsoWeek, NaiveDate, NaiveTime}; -use crate::{DateTime, Datelike, LocalResult, Months, TimeDelta, TimeZone, Timelike, Weekday}; +use crate::{ChronoError, DateTime, Datelike, Months, TimeDelta, TimeZone, Timelike, Weekday}; /// Tools to help serializing/deserializing `NaiveDateTime`s #[cfg(feature = "serde")] @@ -51,8 +52,9 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX; /// ``` /// use chrono::{NaiveDate, NaiveDateTime}; /// -/// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11); +/// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8)?.and_hms(9, 10, 11)?; /// # let _ = dt; +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// You can use typical [date-like](../trait.Datelike.html) and @@ -61,11 +63,12 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX; /// /// ``` /// # use chrono::{NaiveDate, NaiveDateTime}; -/// # let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11); +/// # let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8)?.and_hms(9, 10, 11)?; /// use chrono::{Datelike, Timelike, Weekday}; /// /// assert_eq!(dt.weekday(), Weekday::Fri); /// assert_eq!(dt.num_seconds_from_midnight(), 33011); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` #[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -75,6 +78,9 @@ pub struct NaiveDateTime { } impl NaiveDateTime { + pub(crate) const UNIX_EPOCH: NaiveDateTime = + NaiveDateTime { date: NaiveDate::UNIX_EPOCH, time: NaiveTime::MIDNIGHT }; + /// Makes a new `NaiveDateTime` from date and time components. /// Equivalent to [`date.and_time(time)`](./struct.NaiveDate.html#method.and_time) /// and many other helper constructors on `NaiveDate`. @@ -84,86 +90,66 @@ impl NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime}; /// - /// let d = NaiveDate::from_ymd(2015, 6, 3); - /// let t = NaiveTime::from_hms_milli(12, 34, 56, 789); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; + /// let t = NaiveTime::from_hms_milli(12, 34, 56, 789)?; /// /// let dt = NaiveDateTime::new(d, t); /// assert_eq!(dt.date(), d); /// assert_eq!(dt.time(), t); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn new(date: NaiveDate, time: NaiveTime) -> NaiveDateTime { NaiveDateTime { date, time } } - /// Makes a new `NaiveDateTime` corresponding to a UTC date and time, - /// from the number of non-leap seconds - /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp") - /// and the number of nanoseconds since the last whole non-leap second. + /// Makes a new `NaiveDateTime` corresponding to a UTC date and time, from + /// the number of non-leap seconds since the midnight UTC on January 1, 1970 + /// (aka "UNIX timestamp") and the number of nanoseconds since the last + /// whole non-leap second. /// /// For a non-naive version of this function see /// [`TimeZone::timestamp`](../offset/trait.TimeZone.html#method.timestamp). /// /// The nanosecond part can exceed 1,000,000,000 in order to represent the - /// [leap second](./struct.NaiveTime.html#leap-second-handling). (The true "UNIX - /// timestamp" cannot represent a leap second unambiguously.) + /// [leap second](./struct.NaiveTime.html#leap-second-handling). (The true + /// "UNIX timestamp" cannot represent a leap second unambiguously.) /// - /// Panics on the out-of-range number of seconds and/or invalid nanosecond. + /// Returns `Err(ChronoError)` on the out-of-range number of seconds and/or + /// invalid nanosecond. /// /// # Example /// /// ``` /// use chrono::{NaiveDateTime, NaiveDate}; + /// use std::i64; /// - /// let dt = NaiveDateTime::from_timestamp(0, 42_000_000); - /// assert_eq!(dt, NaiveDate::from_ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 42)); - /// - /// let dt = NaiveDateTime::from_timestamp(1_000_000_000, 0); - /// assert_eq!(dt, NaiveDate::from_ymd(2001, 9, 9).and_hms(1, 46, 40)); - /// ``` - #[inline] - pub fn from_timestamp(secs: i64, nsecs: u32) -> NaiveDateTime { - let datetime = NaiveDateTime::from_timestamp_opt(secs, nsecs); - datetime.expect("invalid or out-of-range datetime") - } - - /// Makes a new `NaiveDateTime` corresponding to a UTC date and time, - /// from the number of non-leap seconds - /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp") - /// and the number of nanoseconds since the last whole non-leap second. - /// - /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). - /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.) - /// - /// Returns `None` on the out-of-range number of seconds and/or invalid nanosecond. - /// - /// # Example + /// let dt = NaiveDateTime::from_timestamp(0, 42_000_000)?; + /// assert_eq!(dt, NaiveDate::from_ymd(1970, 1, 1)?.and_hms_milli(0, 0, 0, 42)?); /// - /// ``` - /// use chrono::{NaiveDateTime, NaiveDate}; - /// use std::i64; + /// let dt = NaiveDateTime::from_timestamp(1_000_000_000, 0)?; + /// assert_eq!(dt, NaiveDate::from_ymd(2001, 9, 9)?.and_hms(1, 46, 40)?); /// - /// let from_timestamp_opt = NaiveDateTime::from_timestamp_opt; + /// let from_timestamp = NaiveDateTime::from_timestamp; /// - /// assert!(from_timestamp_opt(0, 0).is_some()); - /// assert!(from_timestamp_opt(0, 999_999_999).is_some()); - /// assert!(from_timestamp_opt(0, 1_500_000_000).is_some()); // leap second - /// assert!(from_timestamp_opt(0, 2_000_000_000).is_none()); - /// assert!(from_timestamp_opt(i64::MAX, 0).is_none()); + /// assert!(from_timestamp(0, 0).is_ok()); + /// assert!(from_timestamp(0, 999_999_999).is_ok()); + /// assert!(from_timestamp(0, 1_500_000_000).is_ok()); // leap second + /// assert!(from_timestamp(0, 2_000_000_000).is_err()); + /// assert!(from_timestamp(i64::MAX, 0).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option { + pub fn from_timestamp(secs: i64, nsecs: u32) -> Result { let (days, secs) = div_mod_floor(secs, 86_400); let date = i32::try_from(days) .ok() .and_then(|days| days.checked_add(719_163)) - .and_then(NaiveDate::from_num_days_from_ce_opt); - let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs); - match (date, time) { - (Some(date), Some(time)) => Some(NaiveDateTime { date, time }), - (_, _) => None, - } + .ok_or(ChronoError::new(ChronoErrorKind::InvalidDateTime)) + .and_then(NaiveDate::from_num_days_from_ce)?; + + let time = NaiveTime::from_num_seconds_from_midnight(secs as u32, nsecs)?; + Ok(NaiveDateTime { date, time }) } /// Parses a string with the specified format string and returns a new `NaiveDateTime`. @@ -178,9 +164,10 @@ impl NaiveDateTime { /// let parse_from_str = NaiveDateTime::parse_from_str; /// /// assert_eq!(parse_from_str("2015-09-05 23:56:04", "%Y-%m-%d %H:%M:%S"), - /// Ok(NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4))); + /// Ok(NaiveDate::from_ymd(2015, 9, 5)?.and_hms(23, 56, 4)?)); /// assert_eq!(parse_from_str("5sep2015pm012345.6789", "%d%b%Y%p%I%M%S%.f"), - /// Ok(NaiveDate::from_ymd(2015, 9, 5).and_hms_micro(13, 23, 45, 678_900))); + /// Ok(NaiveDate::from_ymd(2015, 9, 5)?.and_hms_micro(13, 23, 45, 678_900)?)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Offset is ignored for the purpose of parsing. @@ -189,7 +176,8 @@ impl NaiveDateTime { /// # use chrono::{NaiveDateTime, NaiveDate}; /// # let parse_from_str = NaiveDateTime::parse_from_str; /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), - /// Ok(NaiveDate::from_ymd(2014, 5, 17).and_hms(12, 34, 56))); + /// Ok(NaiveDate::from_ymd(2014, 5, 17)?.and_hms(12, 34, 56)?)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// [Leap seconds](./struct.NaiveTime.html#leap-second-handling) are correctly handled by @@ -200,7 +188,8 @@ impl NaiveDateTime { /// # use chrono::{NaiveDateTime, NaiveDate}; /// # let parse_from_str = NaiveDateTime::parse_from_str; /// assert_eq!(parse_from_str("2015-07-01 08:59:60.123", "%Y-%m-%d %H:%M:%S%.f"), - /// Ok(NaiveDate::from_ymd(2015, 7, 1).and_hms_milli(8, 59, 59, 1_123))); + /// Ok(NaiveDate::from_ymd(2015, 7, 1)?.and_hms_milli(8, 59, 59, 1_123)?)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Missing seconds are assumed to be zero, @@ -210,12 +199,13 @@ impl NaiveDateTime { /// # use chrono::{NaiveDateTime, NaiveDate}; /// # let parse_from_str = NaiveDateTime::parse_from_str; /// assert_eq!(parse_from_str("94/9/4 7:15", "%y/%m/%d %H:%M"), - /// Ok(NaiveDate::from_ymd(1994, 9, 4).and_hms(7, 15, 0))); + /// Ok(NaiveDate::from_ymd(1994, 9, 4)?.and_hms(7, 15, 0)?)); /// /// assert!(parse_from_str("04m33s", "%Mm%Ss").is_err()); /// assert!(parse_from_str("94/9/4 12", "%y/%m/%d %H").is_err()); /// assert!(parse_from_str("94/9/4 17:60", "%y/%m/%d %H:%M").is_err()); /// assert!(parse_from_str("94/9/4 24:00:00", "%y/%m/%d %H:%M:%S").is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// All parsed fields should be consistent to each other, otherwise it's an error. @@ -240,8 +230,9 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11); - /// assert_eq!(dt.date(), NaiveDate::from_ymd(2016, 7, 8)); + /// let dt = NaiveDate::from_ymd(2016, 7, 8)?.and_hms(9, 10, 11)?; + /// assert_eq!(dt.date(), NaiveDate::from_ymd(2016, 7, 8)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn date(&self) -> NaiveDate { @@ -255,8 +246,9 @@ impl NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveTime}; /// - /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11); - /// assert_eq!(dt.time(), NaiveTime::from_hms(9, 10, 11)); + /// let dt = NaiveDate::from_ymd(2016, 7, 8)?.and_hms(9, 10, 11)?; + /// assert_eq!(dt.time(), NaiveTime::from_hms(9, 10, 11)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn time(&self) -> NaiveTime { @@ -273,17 +265,18 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 980); + /// let dt = NaiveDate::from_ymd(1970, 1, 1)?.and_hms_milli(0, 0, 1, 980)?; /// assert_eq!(dt.timestamp(), 1); /// - /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms(1, 46, 40); + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms(1, 46, 40)?; /// assert_eq!(dt.timestamp(), 1_000_000_000); /// - /// let dt = NaiveDate::from_ymd(1969, 12, 31).and_hms(23, 59, 59); + /// let dt = NaiveDate::from_ymd(1969, 12, 31)?.and_hms(23, 59, 59)?; /// assert_eq!(dt.timestamp(), -1); /// - /// let dt = NaiveDate::from_ymd(-1, 1, 1).and_hms(0, 0, 0); + /// let dt = NaiveDate::from_ymd(-1, 1, 1)?.and_hms(0, 0, 0)?; /// assert_eq!(dt.timestamp(), -62198755200); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp(&self) -> i64 { @@ -308,14 +301,15 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 444); + /// let dt = NaiveDate::from_ymd(1970, 1, 1)?.and_hms_milli(0, 0, 1, 444)?; /// assert_eq!(dt.timestamp_millis(), 1_444); /// - /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms_milli(1, 46, 40, 555); + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_milli(1, 46, 40, 555)?; /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); /// - /// let dt = NaiveDate::from_ymd(1969, 12, 31).and_hms_milli(23, 59, 59, 100); + /// let dt = NaiveDate::from_ymd(1969, 12, 31)?.and_hms_milli(23, 59, 59, 100)?; /// assert_eq!(dt.timestamp_millis(), -900); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp_millis(&self) -> i64 { @@ -338,11 +332,12 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_micro(0, 0, 1, 444); + /// let dt = NaiveDate::from_ymd(1970, 1, 1)?.and_hms_micro(0, 0, 1, 444)?; /// assert_eq!(dt.timestamp_micros(), 1_000_444); /// - /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms_micro(1, 46, 40, 555); + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_micro(1, 46, 40, 555)?; /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp_micros(&self) -> i64 { @@ -370,18 +365,19 @@ impl NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime}; /// - /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_nano(0, 0, 1, 444); + /// let dt = NaiveDate::from_ymd(1970, 1, 1)?.and_hms_nano(0, 0, 1, 444)?; /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444); /// - /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms_nano(1, 46, 40, 555); + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_nano(1, 46, 40, 555)?; /// /// const A_BILLION: i64 = 1_000_000_000; /// let nanos = dt.timestamp_nanos(); /// assert_eq!(nanos, 1_000_000_000_000_000_555); /// assert_eq!( /// dt, - /// NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32) + /// NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32)? /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp_nanos(&self) -> i64 { @@ -399,11 +395,12 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_nano(9, 10, 11, 123_456_789); + /// let dt = NaiveDate::from_ymd(2016, 7, 8)?.and_hms_nano(9, 10, 11, 123_456_789)?; /// assert_eq!(dt.timestamp_subsec_millis(), 123); /// - /// let dt = NaiveDate::from_ymd(2015, 7, 1).and_hms_nano(8, 59, 59, 1_234_567_890); + /// let dt = NaiveDate::from_ymd(2015, 7, 1)?.and_hms_nano(8, 59, 59, 1_234_567_890)?; /// assert_eq!(dt.timestamp_subsec_millis(), 1_234); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp_subsec_millis(&self) -> u32 { @@ -420,11 +417,12 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_nano(9, 10, 11, 123_456_789); + /// let dt = NaiveDate::from_ymd(2016, 7, 8)?.and_hms_nano(9, 10, 11, 123_456_789)?; /// assert_eq!(dt.timestamp_subsec_micros(), 123_456); /// - /// let dt = NaiveDate::from_ymd(2015, 7, 1).and_hms_nano(8, 59, 59, 1_234_567_890); + /// let dt = NaiveDate::from_ymd(2015, 7, 1)?.and_hms_nano(8, 59, 59, 1_234_567_890)?; /// assert_eq!(dt.timestamp_subsec_micros(), 1_234_567); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp_subsec_micros(&self) -> u32 { @@ -441,11 +439,12 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_nano(9, 10, 11, 123_456_789); + /// let dt = NaiveDate::from_ymd(2016, 7, 8)?.and_hms_nano(9, 10, 11, 123_456_789)?; /// assert_eq!(dt.timestamp_subsec_nanos(), 123_456_789); /// - /// let dt = NaiveDate::from_ymd(2015, 7, 1).and_hms_nano(8, 59, 59, 1_234_567_890); + /// let dt = NaiveDate::from_ymd(2015, 7, 1)?.and_hms_nano(8, 59, 59, 1_234_567_890)?; /// assert_eq!(dt.timestamp_subsec_nanos(), 1_234_567_890); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn timestamp_subsec_nanos(&self) -> u32 { @@ -459,39 +458,39 @@ impl NaiveDateTime { /// except when the `NaiveDateTime` itself represents a leap second /// in which case the assumption becomes that **there is exactly a single leap second ever**. /// - /// Returns `None` when it will result in overflow. + /// Returns `Err(ChronoError)` when it will result in overflow. /// /// # Example /// /// ``` /// use chrono::{TimeDelta, NaiveDate}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let d = NaiveDate::from_ymd(2016, 7, 8)?; /// - /// 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(TimeDelta::zero()), - /// Some(hms(3, 5, 7))); - /// 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(TimeDelta::seconds(-1)), - /// Some(hms(3, 5, 6))); - /// 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(TimeDelta::seconds(86_400)), - /// Some(from_ymd(2016, 7, 9).and_hms(3, 5, 7))); + /// assert_eq!(hms(3, 5, 7)?.checked_add_signed(TimeDelta::zero())?, + /// hms(3, 5, 7)?); + /// assert_eq!(hms(3, 5, 7)?.checked_add_signed(TimeDelta::seconds(1))?, + /// hms(3, 5, 8)?); + /// assert_eq!(hms(3, 5, 7)?.checked_add_signed(TimeDelta::seconds(-1))?, + /// hms(3, 5, 6)?); + /// assert_eq!(hms(3, 5, 7)?.checked_add_signed(TimeDelta::seconds(3600 + 60))?, + /// hms(4, 6, 7)?); + /// assert_eq!(hms(3, 5, 7)?.checked_add_signed(TimeDelta::seconds(86_400))?, + /// NaiveDate::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(TimeDelta::milliseconds(450)), - /// Some(hmsm(3, 5, 8, 430))); + /// assert_eq!(hmsm(3, 5, 7, 980)?.checked_add_signed(TimeDelta::milliseconds(450))?, + /// hmsm(3, 5, 8, 430)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// - /// Overflow returns `None`. + /// Overflow returns `Err(ChronoError)`. /// /// ``` - /// # 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(TimeDelta::days(1_000_000_000)), None); + /// use chrono::{TimeDelta, NaiveDate}; + /// assert!(NaiveDate::from_ymd(2016, 7, 8)?.and_hms(3, 5, 7)?.checked_add_signed(TimeDelta::days(1_000_000_000)).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, @@ -500,38 +499,39 @@ impl NaiveDateTime { /// ``` /// # 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(TimeDelta::zero()), - /// Some(hmsm(3, 5, 59, 1_300))); - /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(-500)), - /// Some(hmsm(3, 5, 59, 800))); - /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(500)), - /// Some(hmsm(3, 5, 59, 1_800))); - /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(800)), - /// Some(hmsm(3, 6, 0, 100))); - /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(10)), - /// Some(hmsm(3, 6, 9, 300))); - /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(-10)), - /// Some(hmsm(3, 5, 50, 300))); - /// 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: TimeDelta) -> Option { + /// # let hmsm = |h, m, s, milli| Ok::<_, chrono::ChronoError>(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(TimeDelta::zero())?, + /// hmsm(3, 5, 59, 1_300)?); + /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(-500))?, + /// hmsm(3, 5, 59, 800)?); + /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(500))?, + /// hmsm(3, 5, 59, 1_800)?); + /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(800))?, + /// hmsm(3, 6, 0, 100)?); + /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(10))?, + /// hmsm(3, 6, 9, 300)?); + /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(-10))?, + /// hmsm(3, 5, 50, 300)?); + /// assert_eq!(leap.checked_add_signed(TimeDelta::days(1))?, + /// from_ymd(2016, 7, 9)?.and_hms_milli(3, 5, 59, 300)?); + /// # Ok::<_, chrono::ChronoError>(()) + /// ``` + pub fn checked_add_signed(self, rhs: TimeDelta) -> Result { let (time, rhs) = self.time.overflowing_add_signed(rhs); // early checking to avoid overflow in OldTimeDelta::seconds if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidDateTime)); } let date = self.date.checked_add_signed(TimeDelta::seconds(rhs))?; - Some(NaiveDateTime { date, time }) + Ok(NaiveDateTime { date, time }) } /// Adds given `Months` to the current date and time. /// - /// Returns `None` when it will result in overflow. + /// Returns `Err(ChronoError)` when it will result in overflow. /// /// Overflow returns `None`. /// @@ -542,19 +542,20 @@ impl NaiveDateTime { /// use chrono::{Months, NaiveDate, NaiveDateTime}; /// /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1).and_hms(1, 0, 0) - /// .checked_add_months(Months::new(1)), - /// Some(NaiveDate::from_ymd(2014, 2, 1).and_hms(1, 0, 0)) + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)? + /// .checked_add_months(Months::new(1))?, + /// NaiveDate::from_ymd(2014, 2, 1)?.and_hms(1, 0, 0)? /// ); /// - /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1).and_hms(1, 0, 0) - /// .checked_add_months(Months::new(core::i32::MAX as u32 + 1)), - /// None + /// assert!( + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)? + /// .checked_add_months(Months::new(core::i32::MAX as u32 + 1)) + /// .is_err() /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn checked_add_months(self, rhs: Months) -> Option { - Some(Self { date: self.date.checked_add_months(rhs)?, time: self.time }) + pub fn checked_add_months(self, rhs: Months) -> Result { + Ok(Self { date: self.date.checked_add_months(rhs)?, time: self.time }) } /// Subtracts given `TimeDelta` from the current date and time. @@ -564,39 +565,38 @@ impl NaiveDateTime { /// except when the `NaiveDateTime` itself represents a leap second /// in which case the assumption becomes that **there is exactly a single leap second ever**. /// - /// Returns `None` when it will result in overflow. + /// Returns `Err(ChronoError)` when it will result in overflow. /// /// # Example /// /// ``` /// use chrono::{TimeDelta, NaiveDate}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let d = NaiveDate::from_ymd(2016, 7, 8)?; /// - /// 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(TimeDelta::zero()), - /// Some(hms(3, 5, 7))); - /// 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(TimeDelta::seconds(-1)), - /// Some(hms(3, 5, 8))); - /// 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(TimeDelta::seconds(86_400)), - /// Some(from_ymd(2016, 7, 7).and_hms(3, 5, 7))); + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::zero())?, + /// d.and_hms(3, 5, 7)?); + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::seconds(1))?, + /// d.and_hms(3, 5, 6)?); + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::seconds(-1))?, + /// d.and_hms(3, 5, 8)?); + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::seconds(3600 + 60))?, + /// d.and_hms(2, 4, 7)?); + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::seconds(86_400))?, + /// NaiveDate::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(TimeDelta::milliseconds(670)), - /// Some(hmsm(3, 5, 6, 780))); + /// assert_eq!(d.and_hms_milli(3, 5, 7, 450)?.checked_sub_signed(TimeDelta::milliseconds(670))?, + /// d.and_hms_milli(3, 5, 6, 780)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Overflow returns `None`. /// /// ``` /// # 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(TimeDelta::days(1_000_000_000)), None); + /// let dt = NaiveDate::from_ymd(2016, 7, 8)?.and_hms(3, 5, 7)?; + /// assert!(dt.checked_sub_signed(TimeDelta::days(1_000_000_000)).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, @@ -605,34 +605,35 @@ impl NaiveDateTime { /// ``` /// # 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(TimeDelta::zero()), - /// Some(hmsm(3, 5, 59, 1_300))); - /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(200)), - /// Some(hmsm(3, 5, 59, 1_100))); - /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(500)), - /// Some(hmsm(3, 5, 59, 800))); - /// assert_eq!(leap.checked_sub_signed(TimeDelta::seconds(60)), - /// Some(hmsm(3, 5, 0, 300))); - /// 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: TimeDelta) -> Option { + /// # let hmsm = |h, m, s, milli| Ok::<_, chrono::ChronoError>(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(TimeDelta::zero())?, + /// hmsm(3, 5, 59, 1_300)?); + /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(200))?, + /// hmsm(3, 5, 59, 1_100)?); + /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(500))?, + /// hmsm(3, 5, 59, 800)?); + /// assert_eq!(leap.checked_sub_signed(TimeDelta::seconds(60))?, + /// hmsm(3, 5, 0, 300)?); + /// assert_eq!(leap.checked_sub_signed(TimeDelta::days(1))?, + /// from_ymd(2016, 7, 7)?.and_hms_milli(3, 6, 0, 300)?); + /// # Ok::<_, chrono::ChronoError>(()) + /// ``` + pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result { let (time, rhs) = self.time.overflowing_sub_signed(rhs); // early checking to avoid overflow in OldTimeDelta::seconds if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidDateTime)); } let date = self.date.checked_sub_signed(TimeDelta::seconds(rhs))?; - Some(NaiveDateTime { date, time }) + Ok(NaiveDateTime { date, time }) } /// Subtracts given `Months` from the current date and time. /// - /// Returns `None` when it will result in overflow. + /// Returns `Err(ChronoError)` when it will result in overflow. /// /// Overflow returns `None`. /// @@ -643,33 +644,35 @@ impl NaiveDateTime { /// use chrono::{Months, NaiveDate, NaiveDateTime}; /// /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1).and_hms(1, 0, 0) - /// .checked_sub_months(Months::new(1)), - /// Some(NaiveDate::from_ymd(2013, 12, 1).and_hms(1, 0, 0)) + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)? + /// .checked_sub_months(Months::new(1))?, + /// NaiveDate::from_ymd(2013, 12, 1)?.and_hms(1, 0, 0)? /// ); /// - /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1).and_hms(1, 0, 0) - /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)), - /// None + /// assert!( + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)? + /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)) + /// .is_err() /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn checked_sub_months(self, rhs: Months) -> Option { - Some(Self { date: self.date.checked_sub_months(rhs)?, time: self.time }) + pub fn checked_sub_months(self, rhs: Months) -> Result { + Ok(Self { date: self.date.checked_sub_months(rhs)?, time: self.time }) } /// Add a duration in [`Days`] to the date part of the `NaiveDateTime` /// - /// Returns `None` if the resulting date would be out of range. - pub fn checked_add_days(self, days: Days) -> Option { - Some(Self { date: self.date.checked_add_days(days)?, ..self }) + /// Returns `Err(ChronoError)` if the resulting date would be out of range. + pub fn checked_add_days(self, days: Days) -> Result { + Ok(Self { date: self.date.checked_add_days(days)?, ..self }) } - /// Subtract a duration in [`Days`] from the date part of the `NaiveDateTime` + /// Subtract a duration in [`Days`] from the date part of the + /// `NaiveDateTime` /// - /// Returns `None` if the resulting date would be out of range. - pub fn checked_sub_days(self, days: Days) -> Option { - Some(Self { date: self.date.checked_sub_days(days)?, ..self }) + /// Returns `Err(ChronoError)` if the resulting date would be out of range. + pub fn checked_sub_days(self, days: Days) -> Result { + Ok(Self { date: self.date.checked_sub_days(days)?, ..self }) } /// Subtracts another `NaiveDateTime` from the current date and time. @@ -688,14 +691,15 @@ impl NaiveDateTime { /// /// 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)), + /// let d = from_ymd(2016, 7, 8)?; + /// assert_eq!(d.and_hms(3, 5, 7)?.signed_duration_since(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).signed_duration_since(d0.and_hms(0, 0, 0)), + /// 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)?), /// TimeDelta::seconds(189 * 86_400 + 7 * 60 + 6) + TimeDelta::milliseconds(500)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that @@ -704,11 +708,12 @@ impl NaiveDateTime { /// ``` /// # 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)), + /// 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)?), /// TimeDelta::seconds(3600) + TimeDelta::milliseconds(500)); - /// assert_eq!(from_ymd(2015, 7, 1).and_hms(1, 0, 0).signed_duration_since(leap), + /// assert_eq!(from_ymd(2015, 7, 1)?.and_hms(1, 0, 0)?.signed_duration_since(leap), /// TimeDelta::seconds(3600) - TimeDelta::milliseconds(500)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` pub fn signed_duration_since(self, rhs: NaiveDateTime) -> TimeDelta { self.date.signed_duration_since(rhs.date) + self.time.signed_duration_since(rhs.time) @@ -727,9 +732,10 @@ impl NaiveDateTime { /// use chrono::format::strftime::StrftimeItems; /// /// let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S"); - /// let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4); + /// let dt = NaiveDate::from_ymd(2015, 9, 5)?.and_hms(23, 56, 4)?; /// assert_eq!(dt.format_with_items(fmt.clone()).to_string(), "2015-09-05 23:56:04"); /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -738,8 +744,9 @@ impl NaiveDateTime { /// # use chrono::NaiveDate; /// # use chrono::format::strftime::StrftimeItems; /// # let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S").clone(); - /// # let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4); + /// # let dt = NaiveDate::from_ymd(2015, 9, 5)?.and_hms(23, 56, 4)?; /// assert_eq!(format!("{}", dt.format_with_items(fmt)), "2015-09-05 23:56:04"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -771,18 +778,20 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4); + /// let dt = NaiveDate::from_ymd(2015, 9, 5)?.and_hms(23, 56, 4)?; /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04"); /// assert_eq!(dt.format("around %l %p on %b %-d").to_string(), "around 11 PM on Sep 5"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. /// /// ``` /// # use chrono::NaiveDate; - /// # let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4); + /// # let dt = NaiveDate::from_ymd(2015, 9, 5)?.and_hms(23, 56, 4)?; /// assert_eq!(format!("{}", dt.format("%Y-%m-%d %H:%M:%S")), "2015-09-05 23:56:04"); /// assert_eq!(format!("{}", dt.format("around %l %p on %b %-d")), "around 11 PM on Sep 5"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -806,10 +815,12 @@ impl NaiveDateTime { /// /// ``` /// use chrono::{NaiveDate, Utc}; - /// let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4).and_local_timezone(Utc).unwrap(); + /// let dt = NaiveDate::from_ymd(2015, 9, 5)?.and_hms(23, 56, 4)?.and_local_timezone(Utc).unwrap(); /// assert_eq!(dt.timezone(), Utc); - pub fn and_local_timezone(&self, tz: Tz) -> LocalResult> { - tz.from_local_datetime(self) + /// # Ok::<_, chrono::ChronoError>(()) + /// ``` + pub fn and_local_timezone(&self, tz: Tz) -> Result, ChronoError> { + tz.from_local_datetime(self)?.single() } /// The minimum possible `NaiveDateTime`. @@ -828,8 +839,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.year(), 2015); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn year(&self) -> i32 { @@ -847,8 +859,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.month(), 9); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn month(&self) -> u32 { @@ -866,8 +879,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.month0(), 8); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn month0(&self) -> u32 { @@ -885,8 +899,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.day(), 25); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn day(&self) -> u32 { @@ -904,8 +919,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.day0(), 24); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn day0(&self) -> u32 { @@ -923,8 +939,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.ordinal(), 268); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn ordinal(&self) -> u32 { @@ -942,8 +959,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.ordinal0(), 267); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn ordinal0(&self) -> u32 { @@ -959,8 +977,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Weekday}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.weekday(), Weekday::Fri); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn weekday(&self) -> Weekday { @@ -974,158 +993,158 @@ impl Datelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the year number changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// - /// See also the [`NaiveDate::with_year`] method. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); - /// assert_eq!(dt.with_year(2016), Some(NaiveDate::from_ymd(2016, 9, 25).and_hms(12, 34, 56))); - /// assert_eq!(dt.with_year(-308), Some(NaiveDate::from_ymd(-308, 9, 25).and_hms(12, 34, 56))); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; + /// assert_eq!(dt.with_year(2016)?, NaiveDate::from_ymd(2016, 9, 25)?.and_hms(12, 34, 56)?); + /// assert_eq!(dt.with_year(-308)?, NaiveDate::from_ymd(-308, 9, 25)?.and_hms(12, 34, 56)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_year(&self, year: i32) -> Option { - self.date.with_year(year).map(|d| NaiveDateTime { date: d, ..*self }) + fn with_year(&self, year: i32) -> Result { + let d = self.date.with_year(year)?; + Ok(NaiveDateTime { date: d, ..*self }) } /// Makes a new `NaiveDateTime` with the month number (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// - /// See also the [`NaiveDate::with_month`] method. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56); - /// assert_eq!(dt.with_month(10), Some(NaiveDate::from_ymd(2015, 10, 30).and_hms(12, 34, 56))); - /// assert_eq!(dt.with_month(13), None); // no month 13 - /// assert_eq!(dt.with_month(2), None); // no February 30 + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 30)?.and_hms(12, 34, 56)?; + /// assert_eq!(dt.with_month(10)?, NaiveDate::from_ymd(2015, 10, 30)?.and_hms(12, 34, 56)?); + /// assert!(dt.with_month(13).is_err()); // no month 13 + /// assert!(dt.with_month(2).is_err()); // no February 30 + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_month(&self, month: u32) -> Option { - self.date.with_month(month).map(|d| NaiveDateTime { date: d, ..*self }) + fn with_month(&self, month: u32) -> Result { + let d = self.date.with_month(month)?; + Ok(NaiveDateTime { date: d, ..*self }) } /// Makes a new `NaiveDateTime` with the month number (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// - /// See also the [`NaiveDate::with_month0`] method. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56); - /// assert_eq!(dt.with_month0(9), Some(NaiveDate::from_ymd(2015, 10, 30).and_hms(12, 34, 56))); - /// assert_eq!(dt.with_month0(12), None); // no month 13 - /// assert_eq!(dt.with_month0(1), None); // no February 30 + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 30)?.and_hms(12, 34, 56)?; + /// assert_eq!(dt.with_month0(9)?, NaiveDate::from_ymd(2015, 10, 30)?.and_hms(12, 34, 56)?); + /// assert!(dt.with_month0(12).is_err()); // no month 13 + /// assert!(dt.with_month0(1).is_err()); // no February 30 + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_month0(&self, month0: u32) -> Option { - self.date.with_month0(month0).map(|d| NaiveDateTime { date: d, ..*self }) + fn with_month0(&self, month0: u32) -> Result { + let d = self.date.with_month0(month0)?; + Ok(NaiveDateTime { date: d, ..*self }) } /// Makes a new `NaiveDateTime` with the day of month (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// - /// See also the [`NaiveDate::with_day`] method. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56); - /// assert_eq!(dt.with_day(30), Some(NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56))); - /// assert_eq!(dt.with_day(31), None); // no September 31 + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms(12, 34, 56)?; + /// assert_eq!(dt.with_day(30)?, NaiveDate::from_ymd(2015, 9, 30)?.and_hms(12, 34, 56)?); + /// assert!(dt.with_day(31).is_err()); // no September 31 + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_day(&self, day: u32) -> Option { - self.date.with_day(day).map(|d| NaiveDateTime { date: d, ..*self }) + fn with_day(&self, day: u32) -> Result { + let d = self.date.with_day(day)?; + Ok(NaiveDateTime { date: d, ..*self }) } /// Makes a new `NaiveDateTime` with the day of month (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// - /// See also the [`NaiveDate::with_day0`] method. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56); - /// assert_eq!(dt.with_day0(29), Some(NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56))); - /// assert_eq!(dt.with_day0(30), None); // no September 31 + /// let dt = NaiveDate::from_ymd(2015, 9, 8)?.and_hms(12, 34, 56)?; + /// assert_eq!(dt.with_day0(29)?, NaiveDate::from_ymd(2015, 9, 30)?.and_hms(12, 34, 56)?); + /// assert!(dt.with_day0(30).is_err()); // no September 31 + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_day0(&self, day0: u32) -> Option { - self.date.with_day0(day0).map(|d| NaiveDateTime { date: d, ..*self }) + fn with_day0(&self, day0: u32) -> Result { + let d = self.date.with_day0(day0)?; + Ok(NaiveDateTime { date: d, ..*self }) } /// Makes a new `NaiveDateTime` with the day of year (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// - /// See also the [`NaiveDate::with_ordinal`] method. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56); - /// assert_eq!(dt.with_ordinal(60), - /// Some(NaiveDate::from_ymd(2015, 3, 1).and_hms(12, 34, 56))); - /// assert_eq!(dt.with_ordinal(366), None); // 2015 had only 365 days + /// let dt = NaiveDate::from_ymd(2015, 9, 8)?.and_hms(12, 34, 56)?; + /// assert_eq!(dt.with_ordinal(60)?, + /// NaiveDate::from_ymd(2015, 3, 1)?.and_hms(12, 34, 56)?); + /// assert!(dt.with_ordinal(366).is_err()); // 2015 had only 365 days /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 9, 8).and_hms(12, 34, 56); - /// assert_eq!(dt.with_ordinal(60), - /// Some(NaiveDate::from_ymd(2016, 2, 29).and_hms(12, 34, 56))); - /// assert_eq!(dt.with_ordinal(366), - /// Some(NaiveDate::from_ymd(2016, 12, 31).and_hms(12, 34, 56))); + /// let dt = NaiveDate::from_ymd(2016, 9, 8)?.and_hms(12, 34, 56)?; + /// assert_eq!(dt.with_ordinal(60)?, + /// NaiveDate::from_ymd(2016, 2, 29)?.and_hms(12, 34, 56)?); + /// assert_eq!(dt.with_ordinal(366)?, + /// NaiveDate::from_ymd(2016, 12, 31)?.and_hms(12, 34, 56)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_ordinal(&self, ordinal: u32) -> Option { - self.date.with_ordinal(ordinal).map(|d| NaiveDateTime { date: d, ..*self }) + fn with_ordinal(&self, ordinal: u32) -> Result { + let d = self.date.with_ordinal(ordinal)?; + Ok(NaiveDateTime { date: d, ..*self }) } /// Makes a new `NaiveDateTime` with the day of year (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// - /// See also the [`NaiveDate::with_ordinal0`] method. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56); - /// assert_eq!(dt.with_ordinal0(59), - /// Some(NaiveDate::from_ymd(2015, 3, 1).and_hms(12, 34, 56))); - /// assert_eq!(dt.with_ordinal0(365), None); // 2015 had only 365 days + /// let dt = NaiveDate::from_ymd(2015, 9, 8)?.and_hms(12, 34, 56)?; + /// assert_eq!(dt.with_ordinal0(59)?, + /// NaiveDate::from_ymd(2015, 3, 1)?.and_hms(12, 34, 56)?); + /// assert!(dt.with_ordinal0(365).is_err()); // 2015 had only 365 days /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 9, 8).and_hms(12, 34, 56); - /// assert_eq!(dt.with_ordinal0(59), - /// Some(NaiveDate::from_ymd(2016, 2, 29).and_hms(12, 34, 56))); - /// assert_eq!(dt.with_ordinal0(365), - /// Some(NaiveDate::from_ymd(2016, 12, 31).and_hms(12, 34, 56))); + /// let dt = NaiveDate::from_ymd(2016, 9, 8)?.and_hms(12, 34, 56)?; + /// assert_eq!(dt.with_ordinal0(59)?, + /// NaiveDate::from_ymd(2016, 2, 29)?.and_hms(12, 34, 56)?); + /// assert_eq!(dt.with_ordinal0(365)?, + /// NaiveDate::from_ymd(2016, 12, 31)?.and_hms(12, 34, 56)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_ordinal0(&self, ordinal0: u32) -> Option { - self.date.with_ordinal0(ordinal0).map(|d| NaiveDateTime { date: d, ..*self }) + fn with_ordinal0(&self, ordinal0: u32) -> Result { + let d = self.date.with_ordinal0(ordinal0)?; + Ok(NaiveDateTime { date: d, ..*self }) } } @@ -1139,8 +1158,9 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.hour(), 12); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn hour(&self) -> u32 { @@ -1156,8 +1176,9 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.minute(), 34); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn minute(&self) -> u32 { @@ -1173,8 +1194,9 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.second(), 56); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn second(&self) -> u32 { @@ -1192,8 +1214,9 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.nanosecond(), 789_000_000); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn nanosecond(&self) -> u32 { @@ -1202,7 +1225,7 @@ impl Timelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the hour number changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// /// See also the [`NaiveTime::with_hour`] method. /// @@ -1211,19 +1234,21 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); - /// assert_eq!(dt.with_hour(7), - /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(7, 34, 56, 789))); - /// assert_eq!(dt.with_hour(24), None); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; + /// assert_eq!(dt.with_hour(7)?, + /// NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(7, 34, 56, 789)?); + /// assert!(dt.with_hour(24).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_hour(&self, hour: u32) -> Option { - self.time.with_hour(hour).map(|t| NaiveDateTime { time: t, ..*self }) + fn with_hour(&self, hour: u32) -> Result { + let t = self.time.with_hour(hour)?; + Ok(NaiveDateTime { time: t, ..*self }) } /// Makes a new `NaiveDateTime` with the minute number changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// /// See also the /// [`NaiveTime::with_minute`] method. @@ -1233,62 +1258,64 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); - /// assert_eq!(dt.with_minute(45), - /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 45, 56, 789))); - /// assert_eq!(dt.with_minute(60), None); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; + /// assert_eq!(dt.with_minute(45)?, + /// NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 45, 56, 789)?); + /// assert!(dt.with_minute(60).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_minute(&self, min: u32) -> Option { - self.time.with_minute(min).map(|t| NaiveDateTime { time: t, ..*self }) + fn with_minute(&self, min: u32) -> Result { + let t = self.time.with_minute(min)?; + Ok(NaiveDateTime { time: t, ..*self }) } /// Makes a new `NaiveDateTime` with the second number changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. As - /// with the [`NaiveDateTime::second`] method, the input range is - /// restricted to 0 through 59. - /// - /// See also the [`NaiveTime::with_second`] method. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be + /// invalid. As with the [`NaiveDateTime::second`] method, the input range + /// is restricted to 0 through 59. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); - /// assert_eq!(dt.with_second(17), - /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 17, 789))); - /// assert_eq!(dt.with_second(60), None); + /// let dt = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; + /// assert_eq!(dt.with_second(17)?, + /// NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 17, 789)?); + /// assert!(dt.with_second(60).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_second(&self, sec: u32) -> Option { - self.time.with_second(sec).map(|t| NaiveDateTime { time: t, ..*self }) + fn with_second(&self, sec: u32) -> Result { + let t = self.time.with_second(sec)?; + Ok(NaiveDateTime { time: t, ..*self }) } /// Makes a new `NaiveDateTime` with nanoseconds since the whole non-leap second changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// Returns `Err(ChronoError)` when the resulting `NaiveDateTime` would be invalid. /// As with the [`NaiveDateTime::nanosecond`] method, /// the input range can exceed 1,000,000,000 for leap seconds. /// - /// See also the [`NaiveTime::with_nanosecond`] method. - /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); - /// assert_eq!(dt.with_nanosecond(333_333_333), - /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_nano(12, 34, 56, 333_333_333))); - /// assert_eq!(dt.with_nanosecond(1_333_333_333), // leap second - /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_nano(12, 34, 56, 1_333_333_333))); - /// assert_eq!(dt.with_nanosecond(2_000_000_000), None); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; + /// assert_eq!(dt.with_nanosecond(333_333_333)?, + /// NaiveDate::from_ymd(2015, 9, 8)?.and_hms_nano(12, 34, 56, 333_333_333)?); + /// assert_eq!(dt.with_nanosecond(1_333_333_333)?, // leap second + /// NaiveDate::from_ymd(2015, 9, 8)?.and_hms_nano(12, 34, 56, 1_333_333_333)?); + /// assert!(dt.with_nanosecond(2_000_000_000).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_nanosecond(&self, nano: u32) -> Option { - self.time.with_nanosecond(nano).map(|t| NaiveDateTime { time: t, ..*self }) + fn with_nanosecond(&self, nano: u32) -> Result { + let t = self.time.with_nanosecond(nano)?; + Ok(NaiveDateTime { time: t, ..*self }) } } @@ -1307,21 +1334,20 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{TimeDelta, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; -/// -/// let d = from_ymd(2016, 7, 8); +/// let d = NaiveDate::from_ymd(2016, 7, 8)?; /// let hms = |h, m, s| d.and_hms(h, m, s); -/// 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) + TimeDelta::days(365), -/// from_ymd(2017, 7, 8).and_hms(3, 5, 7)); +/// 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), +/// NaiveDate::from_ymd(2016, 7, 9)?.and_hms(3, 5, 7)?); +/// assert_eq!(hms(3, 5, 7)? + TimeDelta::days(365), +/// NaiveDate::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) + TimeDelta::milliseconds(450), hmsm(3, 5, 8, 430)); +/// assert_eq!(hmsm(3, 5, 7, 980)? + TimeDelta::milliseconds(450), hmsm(3, 5, 8, 430)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, @@ -1330,16 +1356,17 @@ impl Timelike for NaiveDateTime { /// ``` /// # 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 + 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)); +/// # 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 + 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)); +/// from_ymd(2016, 7, 9)?.and_hms_milli(3, 5, 59, 300)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Add for NaiveDateTime { type Output = NaiveDateTime; @@ -1373,29 +1400,30 @@ impl Add for NaiveDateTime { /// use std::str::FromStr; /// /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1).and_hms(1, 0, 0) + Months::new(1), - /// NaiveDate::from_ymd(2014, 2, 1).and_hms(1, 0, 0) + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)? + Months::new(1), + /// NaiveDate::from_ymd(2014, 2, 1)?.and_hms(1, 0, 0)? /// ); /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1).and_hms(0, 2, 0) + Months::new(11), - /// NaiveDate::from_ymd(2014, 12, 1).and_hms(0, 2, 0) + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(0, 2, 0)? + Months::new(11), + /// NaiveDate::from_ymd(2014, 12, 1)?.and_hms(0, 2, 0)? /// ); /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1).and_hms(0, 0, 3) + Months::new(12), - /// NaiveDate::from_ymd(2015, 1, 1).and_hms(0, 0, 3) + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(0, 0, 3)? + Months::new(12), + /// NaiveDate::from_ymd(2015, 1, 1)?.and_hms(0, 0, 3)? /// ); /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1).and_hms(0, 0, 4) + Months::new(13), - /// NaiveDate::from_ymd(2015, 2, 1).and_hms(0, 0, 4) + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(0, 0, 4)? + Months::new(13), + /// NaiveDate::from_ymd(2015, 2, 1)?.and_hms(0, 0, 4)? /// ); /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 31).and_hms(0, 5, 0) + Months::new(1), - /// NaiveDate::from_ymd(2014, 2, 28).and_hms(0, 5, 0) + /// NaiveDate::from_ymd(2014, 1, 31)?.and_hms(0, 5, 0)? + Months::new(1), + /// NaiveDate::from_ymd(2014, 2, 28)?.and_hms(0, 5, 0)? /// ); /// assert_eq!( - /// NaiveDate::from_ymd(2020, 1, 31).and_hms(6, 0, 0) + Months::new(1), - /// NaiveDate::from_ymd(2020, 2, 29).and_hms(6, 0, 0) + /// NaiveDate::from_ymd(2020, 1, 31)?.and_hms(6, 0, 0)? + Months::new(1), + /// NaiveDate::from_ymd(2020, 2, 29)?.and_hms(6, 0, 0)? /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` fn add(self, rhs: Months) -> Self::Output { Self { date: self.date.checked_add_months(rhs).unwrap(), time: self.time } @@ -1420,19 +1448,20 @@ impl Add for NaiveDateTime { /// /// let from_ymd = NaiveDate::from_ymd; /// -/// let d = from_ymd(2016, 7, 8); +/// let d = from_ymd(2016, 7, 8)?; /// let hms = |h, m, s| d.and_hms(h, m, s); -/// 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) - TimeDelta::days(365), -/// from_ymd(2015, 7, 9).and_hms(3, 5, 7)); +/// 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)? - 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) - TimeDelta::milliseconds(670), hmsm(3, 5, 6, 780)); +/// assert_eq!(hmsm(3, 5, 7, 450)? - TimeDelta::milliseconds(670), hmsm(3, 5, 6, 780)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, @@ -1441,14 +1470,15 @@ impl Add for NaiveDateTime { /// ``` /// # 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 - 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)); +/// # let hmsm = |h, m, s, milli| Ok::<_, chrono::ChronoError>(from_ymd(2016, 7, 8)?.and_hms_milli(h, m, s, milli)?); +/// let leap = hmsm(3, 5, 59, 1_300)?; +/// 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)); +/// from_ymd(2016, 7, 7)?.and_hms_milli(3, 6, 0, 300)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Sub for NaiveDateTime { type Output = NaiveDateTime; @@ -1479,17 +1509,18 @@ impl SubAssign for NaiveDateTime { /// use std::str::FromStr; /// /// assert_eq!( -/// NaiveDate::from_ymd(2014, 01, 01).and_hms(01, 00, 00) - Months::new(11), -/// NaiveDate::from_ymd(2013, 02, 01).and_hms(01, 00, 00) +/// NaiveDate::from_ymd(2014, 01, 01)?.and_hms(01, 00, 00)? - Months::new(11), +/// NaiveDate::from_ymd(2013, 02, 01)?.and_hms(01, 00, 00)? /// ); /// assert_eq!( -/// NaiveDate::from_ymd(2014, 01, 01).and_hms(00, 02, 00) - Months::new(12), -/// NaiveDate::from_ymd(2013, 01, 01).and_hms(00, 02, 00) +/// NaiveDate::from_ymd(2014, 01, 01)?.and_hms(00, 02, 00)? - Months::new(12), +/// NaiveDate::from_ymd(2013, 01, 01)?.and_hms(00, 02, 00)? /// ); /// assert_eq!( -/// NaiveDate::from_ymd(2014, 01, 01).and_hms(00, 00, 03) - Months::new(13), -/// NaiveDate::from_ymd(2012, 12, 01).and_hms(00, 00, 03) +/// NaiveDate::from_ymd(2014, 01, 01)?.and_hms(00, 00, 03)? - Months::new(13), +/// NaiveDate::from_ymd(2012, 12, 01)?.and_hms(00, 00, 03)? /// ); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Sub for NaiveDateTime { type Output = NaiveDateTime; @@ -1515,15 +1546,14 @@ impl Sub for NaiveDateTime { /// ``` /// 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), TimeDelta::seconds(3600 + 60 + 1)); +/// let d = NaiveDate::from_ymd(2016, 7, 8)?; +/// 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), +/// let d0 = NaiveDate::from_ymd(2016, 1, 1)?; +/// assert_eq!(d.and_hms_milli(0, 7, 6, 500)? - d0.and_hms(0, 0, 0)?, /// TimeDelta::seconds(189 * 86_400 + 7 * 60 + 6) + TimeDelta::milliseconds(500)); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that no other leap @@ -1531,12 +1561,14 @@ impl Sub for NaiveDateTime { /// /// ``` /// # 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), +/// let leap = NaiveDate::from_ymd(2015, 6, 30)?.and_hms_milli(23, 59, 59, 1_500)?; +/// +/// assert_eq!(leap - NaiveDate::from_ymd(2015, 6, 30)?.and_hms(23, 0, 0)?, /// TimeDelta::seconds(3600) + TimeDelta::milliseconds(500)); -/// assert_eq!(from_ymd(2015, 7, 1).and_hms(1, 0, 0) - leap, +/// +/// assert_eq!(NaiveDate::from_ymd(2015, 7, 1)?.and_hms(1, 0, 0)? - leap, /// TimeDelta::seconds(3600) - TimeDelta::milliseconds(500)); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Sub for NaiveDateTime { type Output = TimeDelta; @@ -1579,16 +1611,18 @@ impl Sub for NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// -/// let dt = NaiveDate::from_ymd(2016, 11, 15).and_hms(7, 39, 24); +/// let dt = NaiveDate::from_ymd(2016, 11, 15)?.and_hms(7, 39, 24)?; /// assert_eq!(format!("{:?}", dt), "2016-11-15T07:39:24"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds may also be used. /// /// ``` /// # use chrono::NaiveDate; -/// let dt = NaiveDate::from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); +/// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms_milli(23, 59, 59, 1_500)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60.500"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl fmt::Debug for NaiveDateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1610,16 +1644,18 @@ impl fmt::Debug for NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// -/// let dt = NaiveDate::from_ymd(2016, 11, 15).and_hms(7, 39, 24); +/// let dt = NaiveDate::from_ymd(2016, 11, 15)?.and_hms(7, 39, 24)?; /// assert_eq!(format!("{}", dt), "2016-11-15 07:39:24"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds may also be used. /// /// ``` /// # use chrono::NaiveDate; -/// let dt = NaiveDate::from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); +/// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms_milli(23, 59, 59, 1_500)?; /// assert_eq!(format!("{}", dt), "2015-06-30 23:59:60.500"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl fmt::Display for NaiveDateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1635,13 +1671,14 @@ impl fmt::Display for NaiveDateTime { /// ``` /// use chrono::{NaiveDateTime, NaiveDate}; /// -/// let dt = NaiveDate::from_ymd(2015, 9, 18).and_hms(23, 56, 4); +/// let dt = NaiveDate::from_ymd(2015, 9, 18)?.and_hms(23, 56, 4)?; /// assert_eq!("2015-09-18T23:56:04".parse::(), Ok(dt)); /// -/// let dt = NaiveDate::from_ymd(12345, 6, 7).and_hms_milli(7, 59, 59, 1_500); // leap second +/// let dt = NaiveDate::from_ymd(12345, 6, 7)?.and_hms_milli(7, 59, 59, 1_500)?; // leap second /// assert_eq!("+12345-6-7T7:59:60.5".parse::(), Ok(dt)); /// /// assert!("foo".parse::().is_err()); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl str::FromStr for NaiveDateTime { type Err = ParseError; @@ -1683,11 +1720,12 @@ impl str::FromStr for NaiveDateTime { /// use chrono::NaiveDateTime; /// /// let default_date = NaiveDateTime::default(); -/// assert_eq!(default_date, NaiveDateTime::from_timestamp(0, 0)); +/// assert_eq!(default_date, NaiveDateTime::from_timestamp(0, 0)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Default for NaiveDateTime { fn default() -> Self { - NaiveDateTime::from_timestamp(0, 0) + NaiveDateTime::UNIX_EPOCH } } @@ -1698,27 +1736,30 @@ where E: ::std::fmt::Debug, { assert_eq!( - to_string(&NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)).ok(), + to_string(&NaiveDate::from_ymd(2016, 7, 8).unwrap().and_hms_milli(9, 10, 48, 90).unwrap()) + .ok(), Some(r#""2016-07-08T09:10:48.090""#.into()) ); assert_eq!( - to_string(&NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), + to_string(&NaiveDate::from_ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap()).ok(), Some(r#""2014-07-24T12:34:06""#.into()) ); assert_eq!( - to_string(&NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)).ok(), + to_string(&NaiveDate::from_ymd(0, 1, 1).unwrap().and_hms_milli(0, 0, 59, 1_000).unwrap()) + .ok(), Some(r#""0000-01-01T00:00:60""#.into()) ); assert_eq!( - to_string(&NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)).ok(), + to_string(&NaiveDate::from_ymd(-1, 12, 31).unwrap().and_hms_nano(23, 59, 59, 7).unwrap()) + .ok(), Some(r#""-0001-12-31T23:59:59.000000007""#.into()) ); assert_eq!( - to_string(&NaiveDate::MIN.and_hms(0, 0, 0)).ok(), + to_string(&NaiveDate::MIN.and_hms(0, 0, 0).unwrap()).ok(), Some(r#""-262144-01-01T00:00:00""#.into()) ); assert_eq!( - to_string(&NaiveDate::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)).ok(), + to_string(&NaiveDate::MAX.and_hms_nano(23, 59, 59, 1_999_999_999).unwrap()).ok(), Some(r#""+262143-12-31T23:59:60.999999999""#.into()) ); } @@ -1730,37 +1771,40 @@ where E: ::std::fmt::Debug, { assert_eq!( - from_str(r#""2016-07-08T09:10:48.090""#).ok(), - Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)) + from_str(r#""2016-07-08T09:10:48.090""#).unwrap(), + NaiveDate::from_ymd(2016, 7, 8).unwrap().and_hms_milli(9, 10, 48, 90).unwrap() + ); + assert_eq!( + from_str(r#""2016-7-8T9:10:48.09""#).unwrap(), + NaiveDate::from_ymd(2016, 7, 8).unwrap().and_hms_milli(9, 10, 48, 90).unwrap() ); assert_eq!( - from_str(r#""2016-7-8T9:10:48.09""#).ok(), - Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)) + from_str(r#""2014-07-24T12:34:06""#).unwrap(), + NaiveDate::from_ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() ); assert_eq!( - from_str(r#""2014-07-24T12:34:06""#).ok(), - Some(NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)) + from_str(r#""0000-01-01T00:00:60""#).unwrap(), + NaiveDate::from_ymd(0, 1, 1).unwrap().and_hms_milli(0, 0, 59, 1_000).unwrap() ); assert_eq!( - from_str(r#""0000-01-01T00:00:60""#).ok(), - Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)) + from_str(r#""0-1-1T0:0:60""#).unwrap(), + NaiveDate::from_ymd(0, 1, 1).unwrap().and_hms_milli(0, 0, 59, 1_000).unwrap() ); assert_eq!( - from_str(r#""0-1-1T0:0:60""#).ok(), - Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)) + from_str(r#""-0001-12-31T23:59:59.000000007""#).unwrap(), + NaiveDate::from_ymd(-1, 12, 31).unwrap().and_hms_nano(23, 59, 59, 7).unwrap() ); assert_eq!( - from_str(r#""-0001-12-31T23:59:59.000000007""#).ok(), - Some(NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)) + from_str(r#""-262144-01-01T00:00:00""#).unwrap(), + NaiveDate::MIN.and_hms(0, 0, 0).unwrap() ); - assert_eq!(from_str(r#""-262144-01-01T00:00:00""#).ok(), Some(NaiveDate::MIN.and_hms(0, 0, 0))); assert_eq!( - from_str(r#""+262143-12-31T23:59:60.999999999""#).ok(), - Some(NaiveDate::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)) + from_str(r#""+262143-12-31T23:59:60.999999999""#).unwrap(), + NaiveDate::MAX.and_hms_nano(23, 59, 59, 1_999_999_999).unwrap() ); assert_eq!( - from_str(r#""+262143-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored - Some(NaiveDate::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)) + from_str(r#""+262143-12-31T23:59:60.9999999999997""#).unwrap(), // excess digits are ignored + NaiveDate::MAX.and_hms_nano(23, 59, 59, 1_999_999_999).unwrap() ); // bad formats diff --git a/src/naive/datetime/serde.rs b/src/naive/datetime/serde.rs index 70369c3888..9c5c6eb343 100644 --- a/src/naive/datetime/serde.rs +++ b/src/naive/datetime/serde.rs @@ -4,7 +4,6 @@ use core::fmt; use serde::{de, ser}; use super::NaiveDateTime; -use crate::offset::LocalResult; /// Serialize a `NaiveDateTime` as an RFC 3339 string /// @@ -69,7 +68,7 @@ impl<'de> de::Deserialize<'de> for NaiveDateTime { /// time: NaiveDateTime /// } /// -/// let time = NaiveDate::from_ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733); +/// let time = NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -78,13 +77,12 @@ impl<'de> de::Deserialize<'de> for NaiveDateTime { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<(), Box>(()) /// ``` pub mod ts_nanoseconds { use core::fmt; use serde::{de, ser}; - use super::ne_timestamp; use crate::NaiveDateTime; /// Serialize a datetime into an integer number of nanoseconds since the epoch @@ -104,11 +102,11 @@ pub mod ts_nanoseconds { /// } /// /// let my_s = S { - /// time: NaiveDate::from_ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733), + /// time: NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where @@ -134,7 +132,7 @@ pub mod ts_nanoseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result where @@ -156,19 +154,19 @@ pub mod ts_nanoseconds { where E: de::Error, { - NaiveDateTime::from_timestamp_opt(value / 1_000_000_000, (value % 1_000_000_000) as u32) - .ok_or_else(|| E::custom(ne_timestamp(value))) + NaiveDateTime::from_timestamp(value / 1_000_000_000, (value % 1_000_000_000) as u32) + .map_err(E::custom) } fn visit_u64(self, value: u64) -> Result where E: de::Error, { - NaiveDateTime::from_timestamp_opt( + NaiveDateTime::from_timestamp( value as i64 / 1_000_000_000, (value as i64 % 1_000_000_000) as u32, ) - .ok_or_else(|| E::custom(ne_timestamp(value))) + .map_err(E::custom) } } } @@ -189,7 +187,7 @@ pub mod ts_nanoseconds { /// time: Option /// } /// -/// let time = Some(NaiveDate::from_ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733)); +/// let time = Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -198,7 +196,7 @@ pub mod ts_nanoseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<(), Box>(()) /// ``` pub mod ts_nanoseconds_option { use core::fmt; @@ -224,11 +222,11 @@ pub mod ts_nanoseconds_option { /// } /// /// let my_s = S { - /// time: Some(NaiveDate::from_ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733)), + /// time: Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn serialize(opt: &Option, serializer: S) -> Result where @@ -257,7 +255,7 @@ pub mod ts_nanoseconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -315,7 +313,7 @@ pub mod ts_nanoseconds_option { /// time: NaiveDateTime /// } /// -/// let time = NaiveDate::from_ymd(2018, 5, 17).and_hms_micro(02, 04, 59, 918355); +/// let time = NaiveDate::from_ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -324,13 +322,12 @@ pub mod ts_nanoseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<(), Box>(()) /// ``` pub mod ts_microseconds { use core::fmt; use serde::{de, ser}; - use super::ne_timestamp; use crate::NaiveDateTime; /// Serialize a datetime into an integer number of microseconds since the epoch @@ -350,11 +347,11 @@ pub mod ts_microseconds { /// } /// /// let my_s = S { - /// time: NaiveDate::from_ymd(2018, 5, 17).and_hms_micro(02, 04, 59, 918355), + /// time: NaiveDate::from_ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where @@ -380,7 +377,7 @@ pub mod ts_microseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result where @@ -402,22 +399,19 @@ pub mod ts_microseconds { where E: de::Error, { - NaiveDateTime::from_timestamp_opt( - value / 1_000_000, - ((value % 1_000_000) * 1000) as u32, - ) - .ok_or_else(|| E::custom(ne_timestamp(value))) + NaiveDateTime::from_timestamp(value / 1_000_000, ((value % 1_000_000) * 1000) as u32) + .map_err(E::custom) } fn visit_u64(self, value: u64) -> Result where E: de::Error, { - NaiveDateTime::from_timestamp_opt( + NaiveDateTime::from_timestamp( (value / 1_000_000) as i64, ((value % 1_000_000) * 1_000) as u32, ) - .ok_or_else(|| E::custom(ne_timestamp(value))) + .map_err(E::custom) } } } @@ -438,7 +432,7 @@ pub mod ts_microseconds { /// time: Option /// } /// -/// let time = Some(NaiveDate::from_ymd(2018, 5, 17).and_hms_micro(02, 04, 59, 918355)); +/// let time = Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -447,7 +441,7 @@ pub mod ts_microseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<(), Box>(()) /// ``` pub mod ts_microseconds_option { use core::fmt; @@ -473,11 +467,11 @@ pub mod ts_microseconds_option { /// } /// /// let my_s = S { - /// time: Some(NaiveDate::from_ymd(2018, 5, 17).and_hms_micro(02, 04, 59, 918355)), + /// time: Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn serialize(opt: &Option, serializer: S) -> Result where @@ -506,7 +500,7 @@ pub mod ts_microseconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -564,7 +558,7 @@ pub mod ts_microseconds_option { /// time: NaiveDateTime /// } /// -/// let time = NaiveDate::from_ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918); +/// let time = NaiveDate::from_ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -573,13 +567,12 @@ pub mod ts_microseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<(), Box>(()) /// ``` pub mod ts_milliseconds { use core::fmt; use serde::{de, ser}; - use super::ne_timestamp; use crate::NaiveDateTime; /// Serialize a datetime into an integer number of milliseconds since the epoch @@ -599,11 +592,11 @@ pub mod ts_milliseconds { /// } /// /// let my_s = S { - /// time: NaiveDate::from_ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918), + /// time: NaiveDate::from_ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where @@ -629,7 +622,7 @@ pub mod ts_milliseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result where @@ -651,19 +644,19 @@ pub mod ts_milliseconds { where E: de::Error, { - NaiveDateTime::from_timestamp_opt(value / 1000, ((value % 1000) * 1_000_000) as u32) - .ok_or_else(|| E::custom(ne_timestamp(value))) + NaiveDateTime::from_timestamp(value / 1000, ((value % 1000) * 1_000_000) as u32) + .map_err(E::custom) } fn visit_u64(self, value: u64) -> Result where E: de::Error, { - NaiveDateTime::from_timestamp_opt( + NaiveDateTime::from_timestamp( (value / 1000) as i64, ((value % 1000) * 1_000_000) as u32, ) - .ok_or_else(|| E::custom(ne_timestamp(value))) + .map_err(E::custom) } } } @@ -684,7 +677,7 @@ pub mod ts_milliseconds { /// time: Option /// } /// -/// let time = Some(NaiveDate::from_ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918)); +/// let time = Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -693,7 +686,7 @@ pub mod ts_milliseconds { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<(), Box>(()) /// ``` pub mod ts_milliseconds_option { use core::fmt; @@ -719,11 +712,11 @@ pub mod ts_milliseconds_option { /// } /// /// let my_s = S { - /// time: Some(NaiveDate::from_ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918)), + /// time: Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn serialize(opt: &Option, serializer: S) -> Result where @@ -752,7 +745,7 @@ pub mod ts_milliseconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -810,7 +803,7 @@ pub mod ts_milliseconds_option { /// time: NaiveDateTime /// } /// -/// let time = NaiveDate::from_ymd(2015, 5, 15).and_hms(10, 0, 0); +/// let time = NaiveDate::from_ymd(2015, 5, 15)?.and_hms(10, 0, 0)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -819,13 +812,12 @@ pub mod ts_milliseconds_option { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<(), Box>(()) /// ``` pub mod ts_seconds { use core::fmt; use serde::{de, ser}; - use super::ne_timestamp; use crate::NaiveDateTime; /// Serialize a datetime into an integer number of seconds since the epoch @@ -845,11 +837,11 @@ pub mod ts_seconds { /// } /// /// let my_s = S { - /// time: NaiveDate::from_ymd(2015, 5, 15).and_hms(10, 0, 0), + /// time: NaiveDate::from_ymd(2015, 5, 15)?.and_hms(10, 0, 0)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1431684000}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where @@ -875,7 +867,7 @@ pub mod ts_seconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result where @@ -897,16 +889,14 @@ pub mod ts_seconds { where E: de::Error, { - NaiveDateTime::from_timestamp_opt(value, 0) - .ok_or_else(|| E::custom(ne_timestamp(value))) + NaiveDateTime::from_timestamp(value, 0).map_err(E::custom) } fn visit_u64(self, value: u64) -> Result where E: de::Error, { - NaiveDateTime::from_timestamp_opt(value as i64, 0) - .ok_or_else(|| E::custom(ne_timestamp(value))) + NaiveDateTime::from_timestamp(value as i64, 0).map_err(E::custom) } } } @@ -927,7 +917,7 @@ pub mod ts_seconds { /// time: Option /// } /// -/// let time = Some(NaiveDate::from_ymd(2018, 5, 17).and_hms(02, 04, 59)); +/// let time = Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms(02, 04, 59)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -936,7 +926,7 @@ pub mod ts_seconds { /// assert_eq!(as_string, r#"{"time":1526522699}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// # Ok::<(), Box>(()) /// ``` pub mod ts_seconds_option { use core::fmt; @@ -962,11 +952,11 @@ pub mod ts_seconds_option { /// } /// /// let my_s = S { - /// time: Some(NaiveDate::from_ymd(2018, 5, 17).and_hms(02, 04, 59)), + /// time: Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms(02, 04, 59)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699}"#); - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn serialize(opt: &Option, serializer: S) -> Result where @@ -995,7 +985,7 @@ pub mod ts_seconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// # Ok::<(), serde_json::Error>(()) + /// # Ok::<(), Box>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -1056,7 +1046,7 @@ fn test_serde_bincode() { use crate::naive::NaiveDate; use bincode::{deserialize, serialize}; - let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90); + let dt = NaiveDate::from_ymd(2016, 7, 8).unwrap().and_hms_milli(9, 10, 48, 90).unwrap(); let encoded = serialize(&dt).unwrap(); let decoded: NaiveDateTime = deserialize(&encoded).unwrap(); assert_eq!(dt, decoded); @@ -1076,57 +1066,10 @@ fn test_serde_bincode_optional() { two: Option>, } - let expected = Test { one: Some(1), two: Some(Utc.ymd(1970, 1, 1).and_hms(0, 1, 1)) }; + let expected = + Test { one: Some(1), two: Some(Utc.ymd(1970, 1, 1).unwrap().and_hms(0, 1, 1).unwrap()) }; let bytes: Vec = serialize(&expected).unwrap(); let actual = deserialize::(&(bytes)).unwrap(); assert_eq!(expected, actual); } - -// lik? function to convert a LocalResult into a serde-ish Result -pub(crate) fn serde_from(me: LocalResult, ts: &V) -> Result -where - E: de::Error, - V: fmt::Display, - T: fmt::Display, -{ - match me { - LocalResult::None => Err(E::custom(ne_timestamp(ts))), - LocalResult::Ambiguous(min, max) => { - Err(E::custom(SerdeError::Ambiguous { timestamp: ts, min, max })) - } - LocalResult::Single(val) => Ok(val), - } -} - -enum SerdeError { - NonExistent { timestamp: V }, - Ambiguous { timestamp: V, min: D, max: D }, -} - -/// Construct a [`SerdeError::NonExistent`] -fn ne_timestamp(ts: T) -> SerdeError { - SerdeError::NonExistent:: { timestamp: ts } -} - -impl fmt::Debug for SerdeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ChronoSerdeError({})", self) - } -} - -// impl core::error::Error for SerdeError {} -impl fmt::Display for SerdeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - SerdeError::NonExistent { timestamp } => { - write!(f, "value is not a legal timestamp: {}", timestamp) - } - SerdeError::Ambiguous { timestamp, min, max } => write!( - f, - "value is an ambiguous timestamp: {}, could be either of {}, {}", - timestamp, min, max - ), - } - } -} diff --git a/src/naive/datetime/tests.rs b/src/naive/datetime/tests.rs index c313d586b5..060eb74973 100644 --- a/src/naive/datetime/tests.rs +++ b/src/naive/datetime/tests.rs @@ -1,112 +1,140 @@ use super::NaiveDateTime; +use crate::error::ChronoErrorKind; use crate::naive::NaiveDate; use crate::time_delta::TimeDelta; -use crate::{Datelike, FixedOffset, Utc}; +use crate::{ChronoError, Datelike, FixedOffset, Utc}; use std::i64; #[test] fn test_datetime_from_timestamp() { - let from_timestamp = |secs| NaiveDateTime::from_timestamp_opt(secs, 0); - let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s); - assert_eq!(from_timestamp(-1), Some(ymdhms(1969, 12, 31, 23, 59, 59))); - assert_eq!(from_timestamp(0), Some(ymdhms(1970, 1, 1, 0, 0, 0))); - assert_eq!(from_timestamp(1), Some(ymdhms(1970, 1, 1, 0, 0, 1))); - assert_eq!(from_timestamp(1_000_000_000), Some(ymdhms(2001, 9, 9, 1, 46, 40))); - assert_eq!(from_timestamp(0x7fffffff), Some(ymdhms(2038, 1, 19, 3, 14, 7))); - assert_eq!(from_timestamp(i64::MIN), None); - assert_eq!(from_timestamp(i64::MAX), None); + let from_timestamp = |secs| NaiveDateTime::from_timestamp(secs, 0); + let ymdhms = + |y, m, d, h, n, s| Ok::<_, ChronoError>(NaiveDate::from_ymd(y, m, d)?.and_hms(h, n, s)?); + assert_eq!(from_timestamp(-1), Ok(ymdhms(1969, 12, 31, 23, 59, 59).unwrap())); + assert_eq!(from_timestamp(0), Ok(ymdhms(1970, 1, 1, 0, 0, 0).unwrap())); + assert_eq!(from_timestamp(1), Ok(ymdhms(1970, 1, 1, 0, 0, 1).unwrap())); + assert_eq!(from_timestamp(1_000_000_000), Ok(ymdhms(2001, 9, 9, 1, 46, 40).unwrap())); + assert_eq!(from_timestamp(0x7fffffff), Ok(ymdhms(2038, 1, 19, 3, 14, 7).unwrap())); + assert!(from_timestamp(i64::MIN).is_err()); + assert!(from_timestamp(i64::MAX).is_err()); } #[test] fn test_datetime_add() { - fn check( - (y, m, d, h, n, s): (i32, u32, u32, u32, u32, u32), - rhs: TimeDelta, - result: Option<(i32, u32, u32, u32, u32, u32)>, - ) { - let lhs = NaiveDate::from_ymd(y, m, d).and_hms(h, n, s); - let sum = result.map(|(y, m, d, h, n, s)| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s)); - assert_eq!(lhs.checked_add_signed(rhs), sum); - assert_eq!(lhs.checked_sub_signed(-rhs), sum); + macro_rules! check { + ($input:expr, $rhs:expr, $result:expr $(,)?) => {{ + let (y, m, d, h, n, s) = $input; + let lhs = NaiveDate::from_ymd(y, m, d).unwrap().and_hms(h, n, s).unwrap(); + let sum = $result + .and_then(|(y, m, d, h, n, s)| NaiveDate::from_ymd(y, m, d)?.and_hms(h, n, s)); + assert_eq!(lhs.checked_add_signed($rhs), sum); + assert_eq!(lhs.checked_sub_signed(-$rhs), sum); + }}; } - 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))); + check!((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(3600 + 60 + 1), Ok((2014, 5, 6, 8, 9, 10))); + check!((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(-(3600 + 60 + 1)), Ok((2014, 5, 6, 6, 7, 8))); + check!((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(86399), Ok((2014, 5, 7, 7, 8, 8))); + check!((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(86_400 * 10), Ok((2014, 5, 16, 7, 8, 9))); + check!((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(-86_400 * 10), Ok((2014, 4, 26, 7, 8, 9))); + check!((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(86_400 * 10), Ok((2014, 5, 16, 7, 8, 9))); // overflow check // assumes that we have correct values for MAX/MIN_DAYS_FROM_YEAR_0 from `naive::date`. // (they are private constants, but the equivalence is tested in that module.) - let max_days_from_year_0 = NaiveDate::MAX.signed_duration_since(NaiveDate::from_ymd(0, 1, 1)); - check((0, 1, 1, 0, 0, 0), max_days_from_year_0, Some((NaiveDate::MAX.year(), 12, 31, 0, 0, 0))); - check( + let max_days_from_year_0 = + NaiveDate::MAX.signed_duration_since(NaiveDate::from_ymd(0, 1, 1).unwrap()); + check!((0, 1, 1, 0, 0, 0), max_days_from_year_0, Ok((NaiveDate::MAX.year(), 12, 31, 0, 0, 0))); + check!( (0, 1, 1, 0, 0, 0), max_days_from_year_0 + TimeDelta::seconds(86399), - Some((NaiveDate::MAX.year(), 12, 31, 23, 59, 59)), + Ok((NaiveDate::MAX.year(), 12, 31, 23, 59, 59)), + ); + check!( + (0, 1, 1, 0, 0, 0), + max_days_from_year_0 + TimeDelta::seconds(86_400), + Err(ChronoError::new(ChronoErrorKind::InvalidDate)), + ); + check!( + (0, 1, 1, 0, 0, 0), + TimeDelta::max_value(), + Err(ChronoError::new(ChronoErrorKind::InvalidDateTime)), ); - check((0, 1, 1, 0, 0, 0), max_days_from_year_0 + TimeDelta::seconds(86_400), None); - check((0, 1, 1, 0, 0, 0), TimeDelta::max_value(), None); - let min_days_from_year_0 = NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd(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 - TimeDelta::seconds(1), None); - check((0, 1, 1, 0, 0, 0), TimeDelta::min_value(), None); + let min_days_from_year_0 = + NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd(0, 1, 1).unwrap()); + check!((0, 1, 1, 0, 0, 0), min_days_from_year_0, Ok((NaiveDate::MIN.year(), 1, 1, 0, 0, 0))); + check!( + (0, 1, 1, 0, 0, 0), + min_days_from_year_0 - TimeDelta::seconds(1), + Err(ChronoError::new(ChronoErrorKind::InvalidDate)), + ); + check!( + (0, 1, 1, 0, 0, 0), + TimeDelta::min_value(), + Err(ChronoError::new(ChronoErrorKind::InvalidDateTime)), + ); } #[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 ymdhms = + |y, m, d, h, n, s| Ok::<_, ChronoError>(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)), TimeDelta::zero()); assert_eq!( - since(ymdhms(2014, 5, 6, 7, 8, 10), ymdhms(2014, 5, 6, 7, 8, 9)), + since(ymdhms(2014, 5, 6, 7, 8, 9).unwrap(), ymdhms(2014, 5, 6, 7, 8, 9).unwrap()), + TimeDelta::zero() + ); + assert_eq!( + since(ymdhms(2014, 5, 6, 7, 8, 10).unwrap(), ymdhms(2014, 5, 6, 7, 8, 9).unwrap()), TimeDelta::seconds(1) ); assert_eq!( - since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)), + since(ymdhms(2014, 5, 6, 7, 8, 9).unwrap(), ymdhms(2014, 5, 6, 7, 8, 10).unwrap()), TimeDelta::seconds(-1) ); assert_eq!( - since(ymdhms(2014, 5, 7, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)), + since(ymdhms(2014, 5, 7, 7, 8, 9).unwrap(), ymdhms(2014, 5, 6, 7, 8, 10).unwrap()), TimeDelta::seconds(86399) ); assert_eq!( - since(ymdhms(2001, 9, 9, 1, 46, 39), ymdhms(1970, 1, 1, 0, 0, 0)), + since(ymdhms(2001, 9, 9, 1, 46, 39).unwrap(), ymdhms(1970, 1, 1, 0, 0, 0).unwrap()), TimeDelta::seconds(999_999_999) ); } #[test] 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); + let ymdhms = + |y, m, d, h, n, s| Ok::<_, ChronoError>(NaiveDate::from_ymd(y, m, d)?.and_hms(h, n, s)?); + let mut date = ymdhms(2016, 10, 1, 10, 10, 10).unwrap(); date += TimeDelta::minutes(10_000_000); - assert_eq!(date, ymdhms(2035, 10, 6, 20, 50, 10)); + assert_eq!(date, ymdhms(2035, 10, 6, 20, 50, 10).unwrap()); date += TimeDelta::days(10); - assert_eq!(date, ymdhms(2035, 10, 16, 20, 50, 10)); + assert_eq!(date, ymdhms(2035, 10, 16, 20, 50, 10).unwrap()); } #[test] 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); + let ymdhms = + |y, m, d, h, n, s| Ok::<_, ChronoError>(NaiveDate::from_ymd(y, m, d)?.and_hms(h, n, s)?); + let mut date = ymdhms(2016, 10, 1, 10, 10, 10).unwrap(); date -= TimeDelta::minutes(10_000_000); - assert_eq!(date, ymdhms(1997, 9, 26, 23, 30, 10)); + assert_eq!(date, ymdhms(1997, 9, 26, 23, 30, 10).unwrap()); date -= TimeDelta::days(10); - assert_eq!(date, ymdhms(1997, 9, 16, 23, 30, 10)); + assert_eq!(date, ymdhms(1997, 9, 16, 23, 30, 10).unwrap()); } #[test] fn test_datetime_timestamp() { - let to_timestamp = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s).timestamp(); - assert_eq!(to_timestamp(1969, 12, 31, 23, 59, 59), -1); - assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 0), 0); - assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 1), 1); - assert_eq!(to_timestamp(2001, 9, 9, 1, 46, 40), 1_000_000_000); - assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff); + let to_timestamp = |y, m, d, h, n, s| { + Ok::<_, ChronoError>(NaiveDate::from_ymd(y, m, d)?.and_hms(h, n, s)?.timestamp()) + }; + assert_eq!(to_timestamp(1969, 12, 31, 23, 59, 59).unwrap(), -1); + assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 0).unwrap(), 0); + assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 1).unwrap(), 1); + assert_eq!(to_timestamp(2001, 9, 9, 1, 46, 40).unwrap(), 1_000_000_000); + assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7).unwrap(), 0x7fffffff); } #[test] @@ -156,19 +184,22 @@ fn test_datetime_from_str() { #[test] fn test_datetime_parse_from_str() { - let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s); - let ymdhmsn = |y, m, d, h, n, s, nano| NaiveDate::from_ymd(y, m, d).and_hms_nano(h, n, s, nano); + let ymdhms = + |y, m, d, h, n, s| Ok::<_, ChronoError>(NaiveDate::from_ymd(y, m, d)?.and_hms(h, n, s)?); + let ymdhmsn = |y, m, d, h, n, s, nano| { + Ok::<_, ChronoError>(NaiveDate::from_ymd(y, m, d)?.and_hms_nano(h, n, s, nano)?) + }; assert_eq!( NaiveDateTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), - Ok(ymdhms(2014, 5, 7, 12, 34, 56)) + Ok(ymdhms(2014, 5, 7, 12, 34, 56).unwrap()) ); // ignore offset assert_eq!( NaiveDateTime::parse_from_str("2015-W06-1 000000", "%G-W%V-%u%H%M%S"), - Ok(ymdhms(2015, 2, 2, 0, 0, 0)) + Ok(ymdhms(2015, 2, 2, 0, 0, 0).unwrap()) ); assert_eq!( NaiveDateTime::parse_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT"), - Ok(ymdhms(2013, 8, 9, 23, 54, 35)) + Ok(ymdhms(2013, 8, 9, 23, 54, 35).unwrap()) ); assert!(NaiveDateTime::parse_from_str( "Sat, 09 Aug 2013 23:54:35 GMT", @@ -179,35 +210,35 @@ fn test_datetime_parse_from_str() { assert!(NaiveDateTime::parse_from_str("12:34:56", "%H:%M:%S").is_err()); // insufficient assert_eq!( NaiveDateTime::parse_from_str("1441497364", "%s"), - Ok(ymdhms(2015, 9, 5, 23, 56, 4)) + Ok(ymdhms(2015, 9, 5, 23, 56, 4).unwrap()) ); assert_eq!( NaiveDateTime::parse_from_str("1283929614.1234", "%s.%f"), - Ok(ymdhmsn(2010, 9, 8, 7, 6, 54, 1234)) + Ok(ymdhmsn(2010, 9, 8, 7, 6, 54, 1234).unwrap()) ); assert_eq!( NaiveDateTime::parse_from_str("1441497364.649", "%s%.3f"), - Ok(ymdhmsn(2015, 9, 5, 23, 56, 4, 649000000)) + Ok(ymdhmsn(2015, 9, 5, 23, 56, 4, 649000000).unwrap()) ); assert_eq!( NaiveDateTime::parse_from_str("1497854303.087654", "%s%.6f"), - Ok(ymdhmsn(2017, 6, 19, 6, 38, 23, 87654000)) + Ok(ymdhmsn(2017, 6, 19, 6, 38, 23, 87654000).unwrap()) ); assert_eq!( NaiveDateTime::parse_from_str("1437742189.918273645", "%s%.9f"), - Ok(ymdhmsn(2015, 7, 24, 12, 49, 49, 918273645)) + Ok(ymdhmsn(2015, 7, 24, 12, 49, 49, 918273645).unwrap()) ); } #[test] fn test_datetime_format() { - let dt = NaiveDate::from_ymd(2010, 9, 8).and_hms_milli(7, 6, 54, 321); + let dt = NaiveDate::from_ymd(2010, 9, 8).unwrap().and_hms_milli(7, 6, 54, 321).unwrap(); assert_eq!(dt.format("%c").to_string(), "Wed Sep 8 07:06:54 2010"); assert_eq!(dt.format("%s").to_string(), "1283929614"); assert_eq!(dt.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); // a horror of leap second: coming near to you. - let dt = NaiveDate::from_ymd(2012, 6, 30).and_hms_milli(23, 59, 59, 1_000); + let dt = NaiveDate::from_ymd(2012, 6, 30).unwrap().and_hms_milli(23, 59, 59, 1_000).unwrap(); assert_eq!(dt.format("%c").to_string(), "Sat Jun 30 23:59:60 2012"); assert_eq!(dt.format("%s").to_string(), "1341100799"); // not 1341100800, it's intentional. } @@ -215,7 +246,7 @@ fn test_datetime_format() { #[test] fn test_datetime_add_sub_invariant() { // issue #37 - let base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0); + let base = NaiveDate::from_ymd(2000, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); let t = -946684799990000; let time = base + TimeDelta::microseconds(t); assert_eq!(t, time.signed_duration_since(base).num_microseconds().unwrap()); @@ -229,7 +260,7 @@ fn test_nanosecond_range() { let nanos = parsed.timestamp_nanos(); assert_eq!( parsed, - NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32) + NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap() ); let minimum = "1677-09-21T00:12:44.000000000"; @@ -237,18 +268,18 @@ fn test_nanosecond_range() { let nanos = parsed.timestamp_nanos(); assert_eq!( parsed, - NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32) + NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap() ); } #[test] fn test_and_timezone() { - let ndt = NaiveDate::from_ymd(2022, 6, 15).and_hms(18, 59, 36); + let ndt = NaiveDate::from_ymd(2022, 6, 15).unwrap().and_hms(18, 59, 36).unwrap(); let dt_utc = ndt.and_local_timezone(Utc).unwrap(); assert_eq!(dt_utc.naive_local(), ndt); assert_eq!(dt_utc.timezone(), Utc); - let offset_tz = FixedOffset::west(4 * 3600); + let offset_tz = FixedOffset::west(4 * 3600).unwrap(); let dt_offset = ndt.and_local_timezone(offset_tz).unwrap(); assert_eq!(dt_offset.naive_local(), ndt); assert_eq!(dt_offset.timezone(), offset_tz); diff --git a/src/naive/isoweek.rs b/src/naive/isoweek.rs index b3ccecdedd..37bfb24976 100644 --- a/src/naive/isoweek.rs +++ b/src/naive/isoweek.rs @@ -57,8 +57,9 @@ impl IsoWeek { /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon); + /// let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon)?; /// assert_eq!(d.iso_week().year(), 2015); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// This year number might not match the calendar year number. @@ -66,9 +67,10 @@ impl IsoWeek { /// /// ``` /// # use chrono::{NaiveDate, Datelike, Weekday}; - /// # let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon); + /// # let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon)?; /// assert_eq!(d.year(), 2014); - /// assert_eq!(d, NaiveDate::from_ymd(2014, 12, 29)); + /// assert_eq!(d, NaiveDate::from_ymd(2014, 12, 29)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn year(&self) -> i32 { @@ -84,8 +86,9 @@ impl IsoWeek { /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon); + /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon)?; /// assert_eq!(d.iso_week().week(), 15); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn week(&self) -> u32 { @@ -101,8 +104,9 @@ impl IsoWeek { /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon); + /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon)?; /// assert_eq!(d.iso_week().week0(), 14); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn week0(&self) -> u32 { @@ -119,17 +123,19 @@ impl IsoWeek { /// ``` /// use chrono::{NaiveDate, Datelike}; /// -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5).iso_week()), "2015-W36"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 3).iso_week()), "0000-W01"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31).iso_week()), "9999-W52"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5)?.iso_week()), "2015-W36"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(0, 1, 3)?.iso_week()), "0000-W01"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31)?.iso_week()), "9999-W52"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. /// /// ``` /// # use chrono::{NaiveDate, Datelike}; -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 2).iso_week()), "-0001-W52"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31).iso_week()), "+10000-W52"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(0, 1, 2)?.iso_week()), "-0001-W52"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31)?.iso_week()), "+10000-W52"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl fmt::Debug for IsoWeek { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 84305bf8f5..cc2b96d29b 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -12,11 +12,12 @@ use num_integer::div_mod_floor; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; +use crate::error::ChronoErrorKind; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::DelayedFormat; use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems}; use crate::format::{Fixed, Item, Numeric, Pad}; -use crate::{TimeDelta, Timelike}; +use crate::{ChronoError, TimeDelta, Timelike}; #[cfg(feature = "serde")] mod serde; @@ -74,10 +75,11 @@ mod tests; /// /// let t = NaiveTime::from_hms_milli(8, 59, 59, 1_000); /// -/// let dt1 = NaiveDate::from_ymd(2015, 7, 1).and_hms_micro(8, 59, 59, 1_000_000); +/// let dt1 = NaiveDate::from_ymd(2015, 7, 1)?.and_hms_micro(8, 59, 59, 1_000_000)?; /// -/// let dt2 = Utc.ymd(2015, 6, 30).and_hms_nano(23, 59, 59, 1_000_000_000); +/// let dt2 = Utc.ymd(2015, 6, 30)?.and_hms_nano(23, 59, 59, 1_000_000_000)?; /// # let _ = (t, dt1, dt2); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Note that the leap second can happen anytime given an appropriate time zone; @@ -159,8 +161,9 @@ mod tests; /// ``` /// use chrono::{Utc, TimeZone}; /// -/// let dt = Utc.ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_000); +/// let dt = Utc.ymd(2015, 6, 30)?.and_hms_milli(23, 59, 59, 1_000)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60Z"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// There are hypothetical leap seconds not on the minute boundary @@ -173,12 +176,13 @@ mod tests; /// ``` /// use chrono::{DateTime, Utc, TimeZone}; /// -/// let dt = Utc.ymd(2015, 6, 30).and_hms_milli(23, 56, 4, 1_000); +/// let dt = Utc.ymd(2015, 6, 30)?.and_hms_milli(23, 56, 4, 1_000)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z"); /// -/// let dt = Utc.ymd(2015, 6, 30).and_hms(23, 56, 5); +/// let dt = Utc.ymd(2015, 6, 30)?.and_hms(23, 56, 5)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z"); /// assert_eq!(DateTime::parse_from_rfc3339("2015-06-30T23:56:05Z").unwrap(), dt); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Since Chrono alone cannot determine any existence of leap seconds, @@ -191,52 +195,44 @@ pub struct NaiveTime { } impl NaiveTime { + /// A constant naive time which corresponds to midnight. + pub(crate) const MIDNIGHT: NaiveTime = NaiveTime { secs: 0, frac: 0 }; + /// Makes a new `NaiveTime` from hour, minute and second. /// - /// No [leap second](#leap-second-handling) is allowed here; - /// use `NaiveTime::from_hms_*` methods with a subsecond parameter instead. + /// No [leap second](#leap-second-handling) is allowed here; use + /// `NaiveTime::from_hms_*` methods with a subsecond parameter instead. /// - /// Panics on invalid hour, minute and/or second. + /// Returns `Err(ChronoError)` on invalid hour, minute and/or second. /// /// # Example /// /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let t = NaiveTime::from_hms(23, 56, 4); + /// let t = NaiveTime::from_hms(23, 56, 4)?; /// assert_eq!(t.hour(), 23); /// assert_eq!(t.minute(), 56); /// assert_eq!(t.second(), 4); /// assert_eq!(t.nanosecond(), 0); - /// ``` - #[inline] - pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime { - NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time") - } - - /// Makes a new `NaiveTime` from hour, minute and second. /// - /// No [leap second](#leap-second-handling) is allowed here; - /// use `NaiveTime::from_hms_*_opt` methods with a subsecond parameter instead. - /// - /// Returns `None` on invalid hour, minute and/or second. - /// - /// # Example - /// - /// ``` - /// use chrono::NaiveTime; - /// - /// let from_hms_opt = NaiveTime::from_hms_opt; + /// let from_hms = NaiveTime::from_hms; /// - /// assert!(from_hms_opt(0, 0, 0).is_some()); - /// assert!(from_hms_opt(23, 59, 59).is_some()); - /// assert!(from_hms_opt(24, 0, 0).is_none()); - /// assert!(from_hms_opt(23, 60, 0).is_none()); - /// assert!(from_hms_opt(23, 59, 60).is_none()); + /// assert!(from_hms(0, 0, 0).is_ok()); + /// assert!(from_hms(23, 59, 59).is_ok()); + /// assert!(from_hms(24, 0, 0).is_err()); + /// assert!(from_hms(23, 60, 0).is_err()); + /// assert!(from_hms(23, 59, 60).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option { - NaiveTime::from_hms_nano_opt(hour, min, sec, 0) + pub fn from_hms(hour: u32, min: u32, sec: u32) -> Result { + NaiveTime::from_hms_nano(hour, min, sec, 0) + } + + /// Makes a new `NaiveTime` which is set to midnight at `00:00`. + pub(crate) fn midnight() -> NaiveTime { + NaiveTime::MIDNIGHT } /// Makes a new `NaiveTime` from hour, minute, second and millisecond. @@ -244,206 +240,161 @@ impl NaiveTime { /// The millisecond part can exceed 1,000 /// in order to represent the [leap second](#leap-second-handling). /// - /// Panics on invalid hour, minute, second and/or millisecond. + /// Returns `Err(ChronoError)` on invalid hour, minute, second and/or millisecond. /// /// # Example /// /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let t = NaiveTime::from_hms_milli(23, 56, 4, 12); + /// let t = NaiveTime::from_hms_milli(23, 56, 4, 12)?; /// assert_eq!(t.hour(), 23); /// assert_eq!(t.minute(), 56); /// assert_eq!(t.second(), 4); /// assert_eq!(t.nanosecond(), 12_000_000); - /// ``` - #[inline] - pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime { - NaiveTime::from_hms_milli_opt(hour, min, sec, milli).expect("invalid time") - } - - /// Makes a new `NaiveTime` from hour, minute, second and millisecond. /// - /// The millisecond part can exceed 1,000 - /// in order to represent the [leap second](#leap-second-handling). - /// - /// Returns `None` on invalid hour, minute, second and/or millisecond. - /// - /// # Example + /// let from_hms_milli = NaiveTime::from_hms_milli; /// - /// ``` - /// use chrono::NaiveTime; - /// - /// let from_hmsm_opt = NaiveTime::from_hms_milli_opt; - /// - /// assert!(from_hmsm_opt(0, 0, 0, 0).is_some()); - /// assert!(from_hmsm_opt(23, 59, 59, 999).is_some()); - /// assert!(from_hmsm_opt(23, 59, 59, 1_999).is_some()); // a leap second after 23:59:59 - /// assert!(from_hmsm_opt(24, 0, 0, 0).is_none()); - /// assert!(from_hmsm_opt(23, 60, 0, 0).is_none()); - /// assert!(from_hmsm_opt(23, 59, 60, 0).is_none()); - /// assert!(from_hmsm_opt(23, 59, 59, 2_000).is_none()); + /// assert!(from_hms_milli(0, 0, 0, 0).is_ok()); + /// assert!(from_hms_milli(23, 59, 59, 999).is_ok()); + /// assert!(from_hms_milli(23, 59, 59, 1_999).is_ok()); // a leap second after 23:59:59 + /// assert!(from_hms_milli(24, 0, 0, 0).is_err()); + /// assert!(from_hms_milli(23, 60, 0, 0).is_err()); + /// assert!(from_hms_milli(23, 59, 60, 0).is_err()); + /// assert!(from_hms_milli(23, 59, 59, 2_000).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option { - milli - .checked_mul(1_000_000) - .and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano)) + pub fn from_hms_milli( + hour: u32, + min: u32, + sec: u32, + milli: u32, + ) -> Result { + let nano = milli.checked_mul(1_000_000).ok_or(ChronoErrorKind::InvalidTime)?; + NaiveTime::from_hms_nano(hour, min, sec, nano) } /// Makes a new `NaiveTime` from hour, minute, second and microsecond. /// - /// The microsecond part can exceed 1,000,000 - /// in order to represent the [leap second](#leap-second-handling). + /// The microsecond part can exceed 1,000,000 in order to represent the + /// [leap second](#leap-second-handling). /// - /// Panics on invalid hour, minute, second and/or microsecond. + /// Returns `Err(ChronoError)` on invalid hour, minute, second and/or + /// microsecond. /// /// # Example /// /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let t = NaiveTime::from_hms_micro(23, 56, 4, 12_345); + /// let t = NaiveTime::from_hms_micro(23, 56, 4, 12_345)?; /// assert_eq!(t.hour(), 23); /// assert_eq!(t.minute(), 56); /// assert_eq!(t.second(), 4); /// assert_eq!(t.nanosecond(), 12_345_000); - /// ``` - #[inline] - pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> NaiveTime { - NaiveTime::from_hms_micro_opt(hour, min, sec, micro).expect("invalid time") - } - - /// Makes a new `NaiveTime` from hour, minute, second and microsecond. - /// - /// The microsecond part can exceed 1,000,000 - /// in order to represent the [leap second](#leap-second-handling). - /// - /// Returns `None` on invalid hour, minute, second and/or microsecond. - /// - /// # Example - /// - /// ``` - /// use chrono::NaiveTime; /// - /// let from_hmsu_opt = NaiveTime::from_hms_micro_opt; + /// let from_hms_micro = NaiveTime::from_hms_micro; /// - /// assert!(from_hmsu_opt(0, 0, 0, 0).is_some()); - /// assert!(from_hmsu_opt(23, 59, 59, 999_999).is_some()); - /// assert!(from_hmsu_opt(23, 59, 59, 1_999_999).is_some()); // a leap second after 23:59:59 - /// assert!(from_hmsu_opt(24, 0, 0, 0).is_none()); - /// assert!(from_hmsu_opt(23, 60, 0, 0).is_none()); - /// assert!(from_hmsu_opt(23, 59, 60, 0).is_none()); - /// assert!(from_hmsu_opt(23, 59, 59, 2_000_000).is_none()); + /// assert!(from_hms_micro(0, 0, 0, 0).is_ok()); + /// assert!(from_hms_micro(23, 59, 59, 999_999).is_ok()); + /// assert!(from_hms_micro(23, 59, 59, 1_999_999).is_ok()); // a leap second after 23:59:59 + /// assert!(from_hms_micro(24, 0, 0, 0).is_err()); + /// assert!(from_hms_micro(23, 60, 0, 0).is_err()); + /// assert!(from_hms_micro(23, 59, 60, 0).is_err()); + /// assert!(from_hms_micro(23, 59, 59, 2_000_000).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn from_hms_micro_opt(hour: u32, min: u32, sec: u32, micro: u32) -> Option { - micro.checked_mul(1_000).and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano)) + pub fn from_hms_micro( + hour: u32, + min: u32, + sec: u32, + micro: u32, + ) -> Result { + let nano = micro.checked_mul(1_000).ok_or(ChronoErrorKind::InvalidTime)?; + NaiveTime::from_hms_nano(hour, min, sec, nano) } /// Makes a new `NaiveTime` from hour, minute, second and nanosecond. /// - /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-handling). + /// The nanosecond part can exceed 1,000,000,000 in order to represent the + /// [leap second](#leap-second-handling). /// - /// Panics on invalid hour, minute, second and/or nanosecond. + /// Returns `Err(ChronoError)` on invalid hour, minute, second and/or + /// nanosecond. /// /// # Example /// /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; /// assert_eq!(t.hour(), 23); /// assert_eq!(t.minute(), 56); /// assert_eq!(t.second(), 4); /// assert_eq!(t.nanosecond(), 12_345_678); - /// ``` - #[inline] - pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> NaiveTime { - NaiveTime::from_hms_nano_opt(hour, min, sec, nano).expect("invalid time") - } - - /// Makes a new `NaiveTime` from hour, minute, second and nanosecond. /// - /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-handling). + /// let from_hms_nano = NaiveTime::from_hms_nano; /// - /// Returns `None` on invalid hour, minute, second and/or nanosecond. - /// - /// # Example - /// - /// ``` - /// use chrono::NaiveTime; - /// - /// let from_hmsn_opt = NaiveTime::from_hms_nano_opt; - /// - /// assert!(from_hmsn_opt(0, 0, 0, 0).is_some()); - /// assert!(from_hmsn_opt(23, 59, 59, 999_999_999).is_some()); - /// assert!(from_hmsn_opt(23, 59, 59, 1_999_999_999).is_some()); // a leap second after 23:59:59 - /// assert!(from_hmsn_opt(24, 0, 0, 0).is_none()); - /// assert!(from_hmsn_opt(23, 60, 0, 0).is_none()); - /// assert!(from_hmsn_opt(23, 59, 60, 0).is_none()); - /// assert!(from_hmsn_opt(23, 59, 59, 2_000_000_000).is_none()); + /// assert!(from_hms_nano(0, 0, 0, 0).is_ok()); + /// assert!(from_hms_nano(23, 59, 59, 999_999_999).is_ok()); + /// assert!(from_hms_nano(23, 59, 59, 1_999_999_999).is_ok()); // a leap second after 23:59:59 + /// assert!(from_hms_nano(24, 0, 0, 0).is_err()); + /// assert!(from_hms_nano(23, 60, 0, 0).is_err()); + /// assert!(from_hms_nano(23, 59, 60, 0).is_err()); + /// assert!(from_hms_nano(23, 59, 59, 2_000_000_000).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option { + pub fn from_hms_nano( + hour: u32, + min: u32, + sec: u32, + nano: u32, + ) -> Result { if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidTime)); } let secs = hour * 3600 + min * 60 + sec; - Some(NaiveTime { secs, frac: nano }) + Ok(NaiveTime { secs, frac: nano }) } - /// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond. + /// Makes a new `NaiveTime` from the number of seconds since midnight and + /// nanosecond. /// - /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-handling). + /// The nanosecond part can exceed 1,000,000,000 in order to represent the + /// [leap second](#leap-second-handling). /// - /// Panics on invalid number of seconds and/or nanosecond. + /// Returns `Err(ChronoError)` on invalid number of seconds and/or + /// nanosecond. /// /// # Example /// /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let t = NaiveTime::from_num_seconds_from_midnight(86164, 12_345_678); + /// let t = NaiveTime::from_num_seconds_from_midnight(86164, 12_345_678)?; /// assert_eq!(t.hour(), 23); /// assert_eq!(t.minute(), 56); /// assert_eq!(t.second(), 4); /// assert_eq!(t.nanosecond(), 12_345_678); - /// ``` - #[inline] - pub fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> NaiveTime { - NaiveTime::from_num_seconds_from_midnight_opt(secs, nano).expect("invalid time") - } - - /// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond. /// - /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-handling). - /// - /// Returns `None` on invalid number of seconds and/or nanosecond. - /// - /// # Example + /// let from_num_seconds_from_midnight = NaiveTime::from_num_seconds_from_midnight; /// - /// ``` - /// use chrono::NaiveTime; - /// - /// let from_nsecs_opt = NaiveTime::from_num_seconds_from_midnight_opt; - /// - /// assert!(from_nsecs_opt(0, 0).is_some()); - /// assert!(from_nsecs_opt(86399, 999_999_999).is_some()); - /// assert!(from_nsecs_opt(86399, 1_999_999_999).is_some()); // a leap second after 23:59:59 - /// assert!(from_nsecs_opt(86_400, 0).is_none()); - /// assert!(from_nsecs_opt(86399, 2_000_000_000).is_none()); + /// assert!(from_num_seconds_from_midnight(0, 0).is_ok()); + /// assert!(from_num_seconds_from_midnight(86399, 999_999_999).is_ok()); + /// assert!(from_num_seconds_from_midnight(86399, 1_999_999_999).is_ok()); // a leap second after 23:59:59 + /// assert!(from_num_seconds_from_midnight(86_400, 0).is_err()); + /// assert!(from_num_seconds_from_midnight(86399, 2_000_000_000).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - pub fn from_num_seconds_from_midnight_opt(secs: u32, nano: u32) -> Option { + pub fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> Result { if secs >= 86_400 || nano >= 2_000_000_000 { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidTime)); } - Some(NaiveTime { secs, frac: nano }) + Ok(NaiveTime { secs, frac: nano }) } /// Parses a string with the specified format string and returns a new `NaiveTime`. @@ -457,10 +408,11 @@ impl NaiveTime { /// /// let parse_from_str = NaiveTime::parse_from_str; /// - /// assert_eq!(parse_from_str("23:56:04", "%H:%M:%S"), - /// Ok(NaiveTime::from_hms(23, 56, 4))); - /// assert_eq!(parse_from_str("pm012345.6789", "%p%I%M%S%.f"), - /// Ok(NaiveTime::from_hms_micro(13, 23, 45, 678_900))); + /// assert_eq!(parse_from_str("23:56:04", "%H:%M:%S")?, + /// NaiveTime::from_hms(23, 56, 4)?); + /// assert_eq!(parse_from_str("pm012345.6789", "%p%I%M%S%.f")?, + /// NaiveTime::from_hms_micro(13, 23, 45, 678_900)?); + /// # Ok::<_, Box>(()) /// ``` /// /// Date and offset is ignored for the purpose of parsing. @@ -468,8 +420,9 @@ impl NaiveTime { /// ``` /// # use chrono::NaiveTime; /// # let parse_from_str = NaiveTime::parse_from_str; - /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), - /// Ok(NaiveTime::from_hms(12, 34, 56))); + /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z")?, + /// NaiveTime::from_hms(12, 34, 56)?); + /// # Ok::<_, Box>(()) /// ``` /// /// [Leap seconds](#leap-second-handling) are correctly handled by @@ -479,8 +432,9 @@ impl NaiveTime { /// ``` /// # use chrono::NaiveTime; /// # let parse_from_str = NaiveTime::parse_from_str; - /// assert_eq!(parse_from_str("08:59:60.123", "%H:%M:%S%.f"), - /// Ok(NaiveTime::from_hms_milli(8, 59, 59, 1_123))); + /// assert_eq!(parse_from_str("08:59:60.123", "%H:%M:%S%.f")?, + /// NaiveTime::from_hms_milli(8, 59, 59, 1_123)?); + /// # Ok::<_, Box>(()) /// ``` /// /// Missing seconds are assumed to be zero, @@ -489,13 +443,14 @@ impl NaiveTime { /// ``` /// # use chrono::NaiveTime; /// # let parse_from_str = NaiveTime::parse_from_str; - /// assert_eq!(parse_from_str("7:15", "%H:%M"), - /// Ok(NaiveTime::from_hms(7, 15, 0))); + /// assert_eq!(parse_from_str("7:15", "%H:%M")?, + /// NaiveTime::from_hms(7, 15, 0)?); /// /// assert!(parse_from_str("04m33s", "%Mm%Ss").is_err()); /// assert!(parse_from_str("12", "%H").is_err()); /// assert!(parse_from_str("17:60", "%H:%M").is_err()); /// assert!(parse_from_str("24:00:00", "%H:%M:%S").is_err()); + /// # Ok::<_, Box>(()) /// ``` /// /// All parsed fields should be consistent to each other, otherwise it's an error. @@ -525,12 +480,13 @@ impl NaiveTime { /// /// let from_hms = NaiveTime::from_hms; /// - /// 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(TimeDelta::hours(23)), - /// (from_hms(2, 4, 5), 86_400)); - /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::hours(-7)), - /// (from_hms(20, 4, 5), -86_400)); + /// 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(TimeDelta::hours(23)), + /// (from_hms(2, 4, 5)?, 86_400)); + /// assert_eq!(from_hms(3, 4, 5)?.overflowing_add_signed(TimeDelta::hours(-7)), + /// (from_hms(20, 4, 5)?, -86_400)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` pub fn overflowing_add_signed(&self, mut rhs: TimeDelta) -> (NaiveTime, i64) { let mut secs = self.secs; @@ -607,12 +563,13 @@ impl NaiveTime { /// /// let from_hms = NaiveTime::from_hms; /// - /// 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(TimeDelta::hours(17)), - /// (from_hms(10, 4, 5), 86_400)); - /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::hours(-22)), - /// (from_hms(1, 4, 5), -86_400)); + /// 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(TimeDelta::hours(17)), + /// (from_hms(10, 4, 5)?, 86_400)); + /// assert_eq!(from_hms(3, 4, 5)?.overflowing_sub_signed(TimeDelta::hours(-22)), + /// (from_hms(1, 4, 5)?, -86_400)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] pub fn overflowing_sub_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) { @@ -638,22 +595,23 @@ impl 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)), + /// assert_eq!(since(from_hmsm(3, 5, 7, 900)?, from_hmsm(3, 5, 7, 900)?), /// TimeDelta::zero()); - /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 875)), + /// assert_eq!(since(from_hmsm(3, 5, 7, 900)?, from_hmsm(3, 5, 7, 875)?), /// TimeDelta::milliseconds(25)); - /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 6, 925)), + /// assert_eq!(since(from_hmsm(3, 5, 7, 900)?, from_hmsm(3, 5, 6, 925)?), /// TimeDelta::milliseconds(975)); - /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 0, 900)), + /// assert_eq!(since(from_hmsm(3, 5, 7, 900)?, from_hmsm(3, 5, 0, 900)?), /// TimeDelta::seconds(7)); - /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 0, 7, 900)), + /// assert_eq!(since(from_hmsm(3, 5, 7, 900)?, from_hmsm(3, 0, 7, 900)?), /// TimeDelta::seconds(5 * 60)); - /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(0, 5, 7, 900)), + /// assert_eq!(since(from_hmsm(3, 5, 7, 900)?, from_hmsm(0, 5, 7, 900)?), /// TimeDelta::seconds(3 * 3600)); - /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(4, 5, 7, 900)), + /// assert_eq!(since(from_hmsm(3, 5, 7, 900)?, from_hmsm(4, 5, 7, 900)?), /// TimeDelta::seconds(-3600)); - /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(2, 4, 6, 800)), + /// assert_eq!(since(from_hmsm(3, 5, 7, 900)?, from_hmsm(2, 4, 6, 800)?), /// TimeDelta::seconds(3600 + 60 + 1) + TimeDelta::milliseconds(100)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that @@ -663,16 +621,17 @@ impl 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)), + /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000)?, from_hmsm(3, 0, 59, 0)?), /// TimeDelta::seconds(1)); - /// assert_eq!(since(from_hmsm(3, 0, 59, 1_500), from_hmsm(3, 0, 59, 0)), + /// assert_eq!(since(from_hmsm(3, 0, 59, 1_500)?, from_hmsm(3, 0, 59, 0)?), /// TimeDelta::milliseconds(1500)); - /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(3, 0, 0, 0)), + /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000)?, from_hmsm(3, 0, 0, 0)?), /// TimeDelta::seconds(60)); - /// assert_eq!(since(from_hmsm(3, 0, 0, 0), from_hmsm(2, 59, 59, 1_000)), + /// assert_eq!(since(from_hmsm(3, 0, 0, 0)?, from_hmsm(2, 59, 59, 1_000)?), /// TimeDelta::seconds(1)); - /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(2, 59, 59, 1_000)), + /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000)?, from_hmsm(2, 59, 59, 1_000)?), /// TimeDelta::seconds(61)); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` pub fn signed_duration_since(self, rhs: NaiveTime) -> TimeDelta { // | | :leap| | | | | | | :leap| | @@ -725,9 +684,10 @@ impl NaiveTime { /// use chrono::format::strftime::StrftimeItems; /// /// let fmt = StrftimeItems::new("%H:%M:%S"); - /// let t = NaiveTime::from_hms(23, 56, 4); + /// let t = NaiveTime::from_hms(23, 56, 4)?; /// assert_eq!(t.format_with_items(fmt.clone()).to_string(), "23:56:04"); - /// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04"); + /// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -736,8 +696,9 @@ impl NaiveTime { /// # use chrono::NaiveTime; /// # use chrono::format::strftime::StrftimeItems; /// # let fmt = StrftimeItems::new("%H:%M:%S").clone(); - /// # let t = NaiveTime::from_hms(23, 56, 4); + /// # let t = NaiveTime::from_hms(23, 56, 4)?; /// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -769,20 +730,22 @@ impl NaiveTime { /// ``` /// use chrono::NaiveTime; /// - /// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; /// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04"); /// assert_eq!(t.format("%H:%M:%S%.6f").to_string(), "23:56:04.012345"); /// assert_eq!(t.format("%-I:%M %p").to_string(), "11:56 PM"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. /// /// ``` /// # use chrono::NaiveTime; - /// # let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// # let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; /// assert_eq!(format!("{}", t.format("%H:%M:%S")), "23:56:04"); /// assert_eq!(format!("{}", t.format("%H:%M:%S%.6f")), "23:56:04.012345"); /// assert_eq!(format!("{}", t.format("%-I:%M %p")), "11:56 PM"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -810,8 +773,9 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms(0, 0, 0).hour(), 0); - /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).hour(), 23); + /// assert_eq!(NaiveTime::from_hms(0, 0, 0)?.hour(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?.hour(), 23); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn hour(&self) -> u32 { @@ -825,8 +789,9 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms(0, 0, 0).minute(), 0); - /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).minute(), 56); + /// assert_eq!(NaiveTime::from_hms(0, 0, 0)?.minute(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?.minute(), 56); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn minute(&self) -> u32 { @@ -840,8 +805,9 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms(0, 0, 0).second(), 0); - /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).second(), 4); + /// assert_eq!(NaiveTime::from_hms(0, 0, 0)?.second(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?.second(), 4); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// This method never returns 60 even when it is a leap second. @@ -850,9 +816,10 @@ impl Timelike for NaiveTime { /// /// ``` /// # use chrono::{NaiveTime, Timelike}; - /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000); + /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000)?; /// assert_eq!(leap.second(), 59); /// assert_eq!(leap.format("%H:%M:%S").to_string(), "23:59:60"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn second(&self) -> u32 { @@ -868,8 +835,9 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms(0, 0, 0).nanosecond(), 0); - /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).nanosecond(), 12_345_678); + /// assert_eq!(NaiveTime::from_hms(0, 0, 0)?.nanosecond(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?.nanosecond(), 12_345_678); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds may have seemingly out-of-range return values. @@ -878,9 +846,10 @@ impl Timelike for NaiveTime { /// /// ``` /// # use chrono::{NaiveTime, Timelike}; - /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000); + /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000)?; /// assert_eq!(leap.nanosecond(), 1_000_000_000); /// assert_eq!(leap.format("%H:%M:%S%.9f").to_string(), "23:59:60.000000000"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn nanosecond(&self) -> u32 { @@ -896,17 +865,18 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); - /// assert_eq!(dt.with_hour(7), Some(NaiveTime::from_hms_nano(7, 56, 4, 12_345_678))); - /// assert_eq!(dt.with_hour(24), None); + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; + /// assert_eq!(dt.with_hour(7)?, NaiveTime::from_hms_nano(7, 56, 4, 12_345_678)?); + /// assert!(dt.with_hour(24).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_hour(&self, hour: u32) -> Option { + fn with_hour(&self, hour: u32) -> Result { if hour >= 24 { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidTime)); } let secs = hour * 3600 + self.secs % 3600; - Some(NaiveTime { secs, ..*self }) + Ok(NaiveTime { secs, ..*self }) } /// Makes a new `NaiveTime` with the minute number changed. @@ -918,17 +888,18 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); - /// assert_eq!(dt.with_minute(45), Some(NaiveTime::from_hms_nano(23, 45, 4, 12_345_678))); - /// assert_eq!(dt.with_minute(60), None); + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; + /// assert_eq!(dt.with_minute(45)?, NaiveTime::from_hms_nano(23, 45, 4, 12_345_678)?); + /// assert!(dt.with_minute(60).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_minute(&self, min: u32) -> Option { + fn with_minute(&self, min: u32) -> Result { if min >= 60 { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidTime)); } let secs = self.secs / 3600 * 3600 + min * 60 + self.secs % 60; - Some(NaiveTime { secs, ..*self }) + Ok(NaiveTime { secs, ..*self }) } /// Makes a new `NaiveTime` with the second number changed. @@ -942,17 +913,18 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); - /// assert_eq!(dt.with_second(17), Some(NaiveTime::from_hms_nano(23, 56, 17, 12_345_678))); - /// assert_eq!(dt.with_second(60), None); + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; + /// assert_eq!(dt.with_second(17)?, NaiveTime::from_hms_nano(23, 56, 17, 12_345_678)?); + /// assert!(dt.with_second(60).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_second(&self, sec: u32) -> Option { + fn with_second(&self, sec: u32) -> Result { if sec >= 60 { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidTime)); } let secs = self.secs / 60 * 60 + sec; - Some(NaiveTime { secs, ..*self }) + Ok(NaiveTime { secs, ..*self }) } /// Makes a new `NaiveTime` with nanoseconds since the whole non-leap second changed. @@ -966,10 +938,10 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); - /// assert_eq!(dt.with_nanosecond(333_333_333), - /// Some(NaiveTime::from_hms_nano(23, 56, 4, 333_333_333))); - /// assert_eq!(dt.with_nanosecond(2_000_000_000), None); + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; + /// assert_eq!(dt.with_nanosecond(333_333_333)?, NaiveTime::from_hms_nano(23, 56, 4, 333_333_333)?); + /// assert!(dt.with_nanosecond(2_000_000_000).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds can theoretically follow *any* whole second. @@ -979,16 +951,16 @@ impl Timelike for NaiveTime { /// /// ``` /// # use chrono::{NaiveTime, Timelike}; - /// # let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); - /// assert_eq!(dt.with_nanosecond(1_333_333_333), - /// Some(NaiveTime::from_hms_nano(23, 56, 4, 1_333_333_333))); + /// # let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; + /// assert_eq!(dt.with_nanosecond(1_333_333_333)?, NaiveTime::from_hms_nano(23, 56, 4, 1_333_333_333)?); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] - fn with_nanosecond(&self, nano: u32) -> Option { + fn with_nanosecond(&self, nano: u32) -> Result { if nano >= 2_000_000_000 { - return None; + return Err(ChronoError::new(ChronoErrorKind::InvalidTime)); } - Some(NaiveTime { frac: nano, ..*self }) + Ok(NaiveTime { frac: nano, ..*self }) } /// Returns the number of non-leap seconds past the last midnight. @@ -998,12 +970,13 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms(1, 2, 3).num_seconds_from_midnight(), + /// assert_eq!(NaiveTime::from_hms(1, 2, 3)?.num_seconds_from_midnight(), /// 3723); - /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).num_seconds_from_midnight(), + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?.num_seconds_from_midnight(), /// 86164); - /// assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).num_seconds_from_midnight(), + /// assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000)?.num_seconds_from_midnight(), /// 86399); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` #[inline] fn num_seconds_from_midnight(&self) -> u32 { @@ -1026,14 +999,15 @@ impl Timelike for NaiveTime { /// /// let from_hmsm = NaiveTime::from_hms_milli; /// -/// 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)); +/// 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)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// The addition wraps around. @@ -1041,9 +1015,10 @@ impl Timelike for NaiveTime { /// ``` /// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; -/// 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)); +/// 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)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, but the addition assumes that it is the only leap second happened. @@ -1051,14 +1026,15 @@ impl Timelike for NaiveTime { /// ``` /// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; -/// let leap = from_hmsm(3, 5, 59, 1_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)); +/// let leap = from_hmsm(3, 5, 59, 1_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)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Add for NaiveTime { type Output = NaiveTime; @@ -1092,12 +1068,13 @@ impl AddAssign for NaiveTime { /// /// let from_hmsm = NaiveTime::from_hms_milli; /// -/// 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)); +/// 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)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// The subtraction wraps around. @@ -1105,8 +1082,9 @@ impl AddAssign for NaiveTime { /// ``` /// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; -/// 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)); +/// 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)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that it is the only leap second happened. @@ -1114,12 +1092,14 @@ impl AddAssign for NaiveTime { /// ``` /// # use chrono::{TimeDelta, NaiveTime}; /// # let from_hmsm = NaiveTime::from_hms_milli; -/// let leap = from_hmsm(3, 5, 59, 1_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)); +/// let leap = from_hmsm(3, 5, 59, 1_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)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Sub for NaiveTime { type Output = NaiveTime; @@ -1157,15 +1137,16 @@ impl SubAssign for NaiveTime { /// /// let from_hmsm = NaiveTime::from_hms_milli; /// -/// 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), +/// 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)?, /// TimeDelta::seconds(3600 + 60 + 1) + TimeDelta::milliseconds(100)); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that @@ -1174,13 +1155,14 @@ impl SubAssign for 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), TimeDelta::seconds(1)); -/// assert_eq!(from_hmsm(3, 0, 59, 1_500) - from_hmsm(3, 0, 59, 0), +/// 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)?, /// 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), +/// 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)?, /// TimeDelta::seconds(61)); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Sub for NaiveTime { type Output = TimeDelta; @@ -1207,17 +1189,19 @@ impl Sub for NaiveTime { /// ``` /// use chrono::NaiveTime; /// -/// assert_eq!(format!("{:?}", NaiveTime::from_hms(23, 56, 4)), "23:56:04"); -/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(23, 56, 4, 12)), "23:56:04.012"); -/// assert_eq!(format!("{:?}", NaiveTime::from_hms_micro(23, 56, 4, 1234)), "23:56:04.001234"); -/// assert_eq!(format!("{:?}", NaiveTime::from_hms_nano(23, 56, 4, 123456)), "23:56:04.000123456"); +/// assert_eq!(format!("{:?}", NaiveTime::from_hms(23, 56, 4)?), "23:56:04"); +/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(23, 56, 4, 12)?), "23:56:04.012"); +/// assert_eq!(format!("{:?}", NaiveTime::from_hms_micro(23, 56, 4, 1234)?), "23:56:04.001234"); +/// assert_eq!(format!("{:?}", NaiveTime::from_hms_nano(23, 56, 4, 123456)?), "23:56:04.000123456"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds may also be used. /// /// ``` /// # use chrono::NaiveTime; -/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)), "06:59:60.500"); +/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)?), "06:59:60.500"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl fmt::Debug for NaiveTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1257,17 +1241,19 @@ impl fmt::Debug for NaiveTime { /// ``` /// use chrono::NaiveTime; /// -/// assert_eq!(format!("{}", NaiveTime::from_hms(23, 56, 4)), "23:56:04"); -/// assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 56, 4, 12)), "23:56:04.012"); -/// assert_eq!(format!("{}", NaiveTime::from_hms_micro(23, 56, 4, 1234)), "23:56:04.001234"); -/// assert_eq!(format!("{}", NaiveTime::from_hms_nano(23, 56, 4, 123456)), "23:56:04.000123456"); +/// assert_eq!(format!("{}", NaiveTime::from_hms(23, 56, 4)?), "23:56:04"); +/// assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 56, 4, 12)?), "23:56:04.012"); +/// assert_eq!(format!("{}", NaiveTime::from_hms_micro(23, 56, 4, 1234)?), "23:56:04.001234"); +/// assert_eq!(format!("{}", NaiveTime::from_hms_nano(23, 56, 4, 123456)?), "23:56:04.000123456"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` /// /// Leap seconds may also be used. /// /// ``` /// # use chrono::NaiveTime; -/// assert_eq!(format!("{}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)), "06:59:60.500"); +/// assert_eq!(format!("{}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)?), "06:59:60.500"); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl fmt::Display for NaiveTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1283,16 +1269,17 @@ impl fmt::Display for NaiveTime { /// ``` /// use chrono::NaiveTime; /// -/// let t = NaiveTime::from_hms(23, 56, 4); +/// let t = NaiveTime::from_hms(23, 56, 4)?; /// assert_eq!("23:56:04".parse::(), Ok(t)); /// -/// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); +/// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; /// assert_eq!("23:56:4.012345678".parse::(), Ok(t)); /// -/// let t = NaiveTime::from_hms_nano(23, 59, 59, 1_234_567_890); // leap second +/// let t = NaiveTime::from_hms_nano(23, 59, 59, 1_234_567_890)?; // leap second /// assert_eq!("23:59:60.23456789".parse::(), Ok(t)); /// /// assert!("foo".parse::().is_err()); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl str::FromStr for NaiveTime { type Err = ParseError; @@ -1324,11 +1311,12 @@ impl str::FromStr for NaiveTime { /// use chrono::NaiveTime; /// /// let default_time = NaiveTime::default(); -/// assert_eq!(default_time, NaiveTime::from_hms(0, 0, 0)); +/// assert_eq!(default_time, NaiveTime::from_hms(0, 0, 0)?); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` impl Default for NaiveTime { fn default() -> Self { - NaiveTime::from_hms(0, 0, 0) + NaiveTime::midnight() } } @@ -1338,27 +1326,36 @@ where F: Fn(&NaiveTime) -> Result, E: ::std::fmt::Debug, { - assert_eq!(to_string(&NaiveTime::from_hms(0, 0, 0)).ok(), Some(r#""00:00:00""#.into())); assert_eq!( - to_string(&NaiveTime::from_hms_milli(0, 0, 0, 950)).ok(), + to_string(&NaiveTime::from_hms(0, 0, 0).unwrap()).ok(), + Some(r#""00:00:00""#.into()) + ); + assert_eq!( + to_string(&NaiveTime::from_hms_milli(0, 0, 0, 950).unwrap()).ok(), Some(r#""00:00:00.950""#.into()) ); assert_eq!( - to_string(&NaiveTime::from_hms_milli(0, 0, 59, 1_000)).ok(), + to_string(&NaiveTime::from_hms_milli(0, 0, 59, 1_000).unwrap()).ok(), Some(r#""00:00:60""#.into()) ); - assert_eq!(to_string(&NaiveTime::from_hms(0, 1, 2)).ok(), Some(r#""00:01:02""#.into())); assert_eq!( - to_string(&NaiveTime::from_hms_nano(3, 5, 7, 98765432)).ok(), + to_string(&NaiveTime::from_hms(0, 1, 2).unwrap()).ok(), + Some(r#""00:01:02""#.into()) + ); + assert_eq!( + to_string(&NaiveTime::from_hms_nano(3, 5, 7, 98765432).unwrap()).ok(), Some(r#""03:05:07.098765432""#.into()) ); - assert_eq!(to_string(&NaiveTime::from_hms(7, 8, 9)).ok(), Some(r#""07:08:09""#.into())); assert_eq!( - to_string(&NaiveTime::from_hms_micro(12, 34, 56, 789)).ok(), + to_string(&NaiveTime::from_hms(7, 8, 9).unwrap()).ok(), + Some(r#""07:08:09""#.into()) + ); + assert_eq!( + to_string(&NaiveTime::from_hms_micro(12, 34, 56, 789).unwrap()).ok(), Some(r#""12:34:56.000789""#.into()) ); assert_eq!( - to_string(&NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)).ok(), + to_string(&NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999).unwrap()).ok(), Some(r#""23:59:60.999999999""#.into()) ); } @@ -1369,28 +1366,37 @@ where F: Fn(&str) -> Result, E: ::std::fmt::Debug, { - assert_eq!(from_str(r#""00:00:00""#).ok(), Some(NaiveTime::from_hms(0, 0, 0))); - assert_eq!(from_str(r#""0:0:0""#).ok(), Some(NaiveTime::from_hms(0, 0, 0))); - assert_eq!(from_str(r#""00:00:00.950""#).ok(), Some(NaiveTime::from_hms_milli(0, 0, 0, 950))); - assert_eq!(from_str(r#""0:0:0.95""#).ok(), Some(NaiveTime::from_hms_milli(0, 0, 0, 950))); - assert_eq!(from_str(r#""00:00:60""#).ok(), Some(NaiveTime::from_hms_milli(0, 0, 59, 1_000))); - assert_eq!(from_str(r#""00:01:02""#).ok(), Some(NaiveTime::from_hms(0, 1, 2))); + assert_eq!(from_str(r#""00:00:00""#).unwrap(), NaiveTime::from_hms(0, 0, 0).unwrap()); + assert_eq!(from_str(r#""0:0:0""#).unwrap(), NaiveTime::from_hms(0, 0, 0).unwrap()); + assert_eq!( + from_str(r#""00:00:00.950""#).unwrap(), + NaiveTime::from_hms_milli(0, 0, 0, 950).unwrap() + ); + assert_eq!( + from_str(r#""0:0:0.95""#).unwrap(), + NaiveTime::from_hms_milli(0, 0, 0, 950).unwrap() + ); + assert_eq!( + from_str(r#""00:00:60""#).unwrap(), + NaiveTime::from_hms_milli(0, 0, 59, 1_000).unwrap() + ); + assert_eq!(from_str(r#""00:01:02""#).unwrap(), NaiveTime::from_hms(0, 1, 2).unwrap()); assert_eq!( - from_str(r#""03:05:07.098765432""#).ok(), - Some(NaiveTime::from_hms_nano(3, 5, 7, 98765432)) + from_str(r#""03:05:07.098765432""#).unwrap(), + NaiveTime::from_hms_nano(3, 5, 7, 98765432).unwrap() ); - assert_eq!(from_str(r#""07:08:09""#).ok(), Some(NaiveTime::from_hms(7, 8, 9))); + assert_eq!(from_str(r#""07:08:09""#).unwrap(), NaiveTime::from_hms(7, 8, 9).unwrap()); assert_eq!( - from_str(r#""12:34:56.000789""#).ok(), - Some(NaiveTime::from_hms_micro(12, 34, 56, 789)) + from_str(r#""12:34:56.000789""#).unwrap(), + NaiveTime::from_hms_micro(12, 34, 56, 789).unwrap() ); assert_eq!( - from_str(r#""23:59:60.999999999""#).ok(), - Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)) + from_str(r#""23:59:60.999999999""#).unwrap(), + NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999).unwrap() ); assert_eq!( - from_str(r#""23:59:60.9999999999997""#).ok(), // excess digits are ignored - Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)) + from_str(r#""23:59:60.9999999999997""#).unwrap(), // excess digits are ignored + NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999).unwrap() ); // bad formats diff --git a/src/naive/time/serde.rs b/src/naive/time/serde.rs index 369c7a1c27..89d81590da 100644 --- a/src/naive/time/serde.rs +++ b/src/naive/time/serde.rs @@ -58,7 +58,7 @@ fn test_serde_bincode() { // it is not self-describing. use bincode::{deserialize, serialize}; - let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432); + let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432).unwrap(); let encoded = serialize(&t).unwrap(); let decoded: NaiveTime = deserialize(&encoded).unwrap(); assert_eq!(t, decoded); diff --git a/src/naive/time/tests.rs b/src/naive/time/tests.rs index 26043fb77a..a4091c91d8 100644 --- a/src/naive/time/tests.rs +++ b/src/naive/time/tests.rs @@ -6,64 +6,82 @@ use crate::{TimeDelta, Timelike}; #[test] fn test_time_from_hms_milli() { assert_eq!( - NaiveTime::from_hms_milli_opt(3, 5, 7, 0), - Some(NaiveTime::from_hms_nano(3, 5, 7, 0)) + NaiveTime::from_hms_milli(3, 5, 7, 0).unwrap(), + NaiveTime::from_hms_nano(3, 5, 7, 0).unwrap() ); assert_eq!( - NaiveTime::from_hms_milli_opt(3, 5, 7, 777), - Some(NaiveTime::from_hms_nano(3, 5, 7, 777_000_000)) + NaiveTime::from_hms_milli(3, 5, 7, 777).unwrap(), + NaiveTime::from_hms_nano(3, 5, 7, 777_000_000).unwrap() ); assert_eq!( - NaiveTime::from_hms_milli_opt(3, 5, 7, 1_999), - Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_000_000)) + NaiveTime::from_hms_milli(3, 5, 7, 1_999).unwrap(), + NaiveTime::from_hms_nano(3, 5, 7, 1_999_000_000).unwrap() ); - assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 2_000), None); - assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 5_000), None); // overflow check - assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, u32::MAX), None); + assert!(NaiveTime::from_hms_milli(3, 5, 7, 2_000).is_err()); + assert!(NaiveTime::from_hms_milli(3, 5, 7, 5_000).is_err()); // overflow check + assert!(NaiveTime::from_hms_milli(3, 5, 7, u32::MAX).is_err()); } #[test] fn test_time_from_hms_micro() { assert_eq!( - NaiveTime::from_hms_micro_opt(3, 5, 7, 0), - Some(NaiveTime::from_hms_nano(3, 5, 7, 0)) + NaiveTime::from_hms_micro(3, 5, 7, 0).unwrap(), + NaiveTime::from_hms_nano(3, 5, 7, 0).unwrap() ); assert_eq!( - NaiveTime::from_hms_micro_opt(3, 5, 7, 333), - Some(NaiveTime::from_hms_nano(3, 5, 7, 333_000)) + NaiveTime::from_hms_micro(3, 5, 7, 333).unwrap(), + NaiveTime::from_hms_nano(3, 5, 7, 333_000).unwrap() ); assert_eq!( - NaiveTime::from_hms_micro_opt(3, 5, 7, 777_777), - Some(NaiveTime::from_hms_nano(3, 5, 7, 777_777_000)) + NaiveTime::from_hms_micro(3, 5, 7, 777_777).unwrap(), + NaiveTime::from_hms_nano(3, 5, 7, 777_777_000).unwrap() ); assert_eq!( - NaiveTime::from_hms_micro_opt(3, 5, 7, 1_999_999), - Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_999_000)) + NaiveTime::from_hms_micro(3, 5, 7, 1_999_999).unwrap(), + NaiveTime::from_hms_nano(3, 5, 7, 1_999_999_000).unwrap() ); - assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 2_000_000), None); - assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 5_000_000), None); // overflow check - assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, u32::MAX), None); + assert!(NaiveTime::from_hms_micro(3, 5, 7, 2_000_000).is_err()); + assert!(NaiveTime::from_hms_micro(3, 5, 7, 5_000_000).is_err()); // overflow check + assert!(NaiveTime::from_hms_micro(3, 5, 7, u32::MAX).is_err()); } #[test] fn test_time_hms() { - assert_eq!(NaiveTime::from_hms(3, 5, 7).hour(), 3); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(0), Some(NaiveTime::from_hms(0, 5, 7))); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(23), Some(NaiveTime::from_hms(23, 5, 7))); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(24), None); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(u32::MAX), None); + assert_eq!(NaiveTime::from_hms(3, 5, 7).unwrap().hour(), 3); + assert_eq!( + NaiveTime::from_hms(3, 5, 7).unwrap().with_hour(0).unwrap(), + NaiveTime::from_hms(0, 5, 7).unwrap() + ); + assert_eq!( + NaiveTime::from_hms(3, 5, 7).unwrap().with_hour(23).unwrap(), + NaiveTime::from_hms(23, 5, 7).unwrap() + ); + assert!(NaiveTime::from_hms(3, 5, 7).unwrap().with_hour(24).is_err()); + assert!(NaiveTime::from_hms(3, 5, 7).unwrap().with_hour(u32::MAX).is_err()); - assert_eq!(NaiveTime::from_hms(3, 5, 7).minute(), 5); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(0), Some(NaiveTime::from_hms(3, 0, 7))); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(59), Some(NaiveTime::from_hms(3, 59, 7))); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(60), None); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(u32::MAX), None); + assert_eq!(NaiveTime::from_hms(3, 5, 7).unwrap().minute(), 5); + assert_eq!( + NaiveTime::from_hms(3, 5, 7).unwrap().with_minute(0).unwrap(), + NaiveTime::from_hms(3, 0, 7).unwrap() + ); + assert_eq!( + NaiveTime::from_hms(3, 5, 7).unwrap().with_minute(59).unwrap(), + NaiveTime::from_hms(3, 59, 7).unwrap() + ); + assert!(NaiveTime::from_hms(3, 5, 7).unwrap().with_minute(60).is_err()); + assert!(NaiveTime::from_hms(3, 5, 7).unwrap().with_minute(u32::MAX).is_err()); - assert_eq!(NaiveTime::from_hms(3, 5, 7).second(), 7); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(0), Some(NaiveTime::from_hms(3, 5, 0))); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(59), Some(NaiveTime::from_hms(3, 5, 59))); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(60), None); - assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(u32::MAX), None); + assert_eq!(NaiveTime::from_hms(3, 5, 7).unwrap().second(), 7); + assert_eq!( + NaiveTime::from_hms(3, 5, 7).unwrap().with_second(0).unwrap(), + NaiveTime::from_hms(3, 5, 0).unwrap() + ); + assert_eq!( + NaiveTime::from_hms(3, 5, 7).unwrap().with_second(59).unwrap(), + NaiveTime::from_hms(3, 5, 59).unwrap() + ); + assert!(NaiveTime::from_hms(3, 5, 7).unwrap().with_second(60).is_err()); + assert!(NaiveTime::from_hms(3, 5, 7).unwrap().with_second(u32::MAX).is_err()); } #[test] @@ -77,23 +95,51 @@ fn test_time_add() { let hmsm = NaiveTime::from_hms_milli; - 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, 900).unwrap(), TimeDelta::zero(), hmsm(3, 5, 7, 900).unwrap()); + check!(hmsm(3, 5, 7, 900).unwrap(), TimeDelta::milliseconds(100), hmsm(3, 5, 8, 0).unwrap()); + check!( + hmsm(3, 5, 7, 1_300).unwrap(), + TimeDelta::milliseconds(-1800), + hmsm(3, 5, 6, 500).unwrap() + ); + check!( + hmsm(3, 5, 7, 1_300).unwrap(), + TimeDelta::milliseconds(-800), + hmsm(3, 5, 7, 500).unwrap() + ); + check!( + hmsm(3, 5, 7, 1_300).unwrap(), + TimeDelta::milliseconds(-100), + hmsm(3, 5, 7, 1_200).unwrap() + ); + check!( + hmsm(3, 5, 7, 1_300).unwrap(), + TimeDelta::milliseconds(100), + hmsm(3, 5, 7, 1_400).unwrap() + ); + check!( + hmsm(3, 5, 7, 1_300).unwrap(), + TimeDelta::milliseconds(800), + hmsm(3, 5, 8, 100).unwrap() + ); + check!( + hmsm(3, 5, 7, 1_300).unwrap(), + TimeDelta::milliseconds(1800), + hmsm(3, 5, 9, 100).unwrap() + ); + check!(hmsm(3, 5, 7, 900).unwrap(), TimeDelta::seconds(86399), hmsm(3, 5, 6, 900).unwrap()); // overwrap + check!(hmsm(3, 5, 7, 900).unwrap(), TimeDelta::seconds(-86399), hmsm(3, 5, 8, 900).unwrap()); + check!(hmsm(3, 5, 7, 900).unwrap(), TimeDelta::days(12345), hmsm(3, 5, 7, 900).unwrap()); + check!(hmsm(3, 5, 7, 1_300).unwrap(), TimeDelta::days(1), hmsm(3, 5, 7, 300).unwrap()); + check!(hmsm(3, 5, 7, 1_300).unwrap(), TimeDelta::days(-1), hmsm(3, 5, 8, 300).unwrap()); // regression tests for #37 - 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)); + check!(hmsm(0, 0, 0, 0).unwrap(), TimeDelta::milliseconds(-990), hmsm(23, 59, 59, 10).unwrap()); + check!( + hmsm(0, 0, 0, 0).unwrap(), + TimeDelta::milliseconds(-9990), + hmsm(23, 59, 50, 10).unwrap() + ); } #[test] @@ -101,47 +147,47 @@ fn test_time_overflowing_add() { let hmsm = NaiveTime::from_hms_milli; assert_eq!( - hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(11)), - (hmsm(14, 4, 5, 678), 0) + hmsm(3, 4, 5, 678).unwrap().overflowing_add_signed(TimeDelta::hours(11)), + (hmsm(14, 4, 5, 678).unwrap(), 0) ); assert_eq!( - hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(23)), - (hmsm(2, 4, 5, 678), 86_400) + hmsm(3, 4, 5, 678).unwrap().overflowing_add_signed(TimeDelta::hours(23)), + (hmsm(2, 4, 5, 678).unwrap(), 86_400) ); assert_eq!( - hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(-7)), - (hmsm(20, 4, 5, 678), -86_400) + hmsm(3, 4, 5, 678).unwrap().overflowing_add_signed(TimeDelta::hours(-7)), + (hmsm(20, 4, 5, 678).unwrap(), -86_400) ); // overflowing_add_signed with leap seconds may be counter-intuitive assert_eq!( - hmsm(3, 4, 5, 1_678).overflowing_add_signed(TimeDelta::days(1)), - (hmsm(3, 4, 5, 678), 86_400) + hmsm(3, 4, 5, 1_678).unwrap().overflowing_add_signed(TimeDelta::days(1)), + (hmsm(3, 4, 5, 678).unwrap(), 86_400) ); assert_eq!( - hmsm(3, 4, 5, 1_678).overflowing_add_signed(TimeDelta::days(-1)), - (hmsm(3, 4, 6, 678), -86_400) + hmsm(3, 4, 5, 1_678).unwrap().overflowing_add_signed(TimeDelta::days(-1)), + (hmsm(3, 4, 6, 678).unwrap(), -86_400) ); } #[test] fn test_time_addassignment() { let hms = NaiveTime::from_hms; - let mut time = hms(12, 12, 12); + let mut time = hms(12, 12, 12).unwrap(); time += TimeDelta::hours(10); - assert_eq!(time, hms(22, 12, 12)); + assert_eq!(time, hms(22, 12, 12).unwrap()); time += TimeDelta::hours(10); - assert_eq!(time, hms(8, 12, 12)); + assert_eq!(time, hms(8, 12, 12).unwrap()); } #[test] fn test_time_subassignment() { let hms = NaiveTime::from_hms; - let mut time = hms(12, 12, 12); + let mut time = hms(12, 12, 12).unwrap(); time -= TimeDelta::hours(10); - assert_eq!(time, hms(2, 12, 12)); + assert_eq!(time, hms(2, 12, 12).unwrap()); time -= TimeDelta::hours(10); - assert_eq!(time, hms(16, 12, 12)); + assert_eq!(time, hms(16, 12, 12).unwrap()); } #[test] @@ -156,37 +202,68 @@ fn test_time_sub() { let hmsm = NaiveTime::from_hms_milli; - 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, 900).unwrap(), hmsm(3, 5, 7, 900).unwrap(), TimeDelta::zero()); + check!(hmsm(3, 5, 7, 900).unwrap(), hmsm(3, 5, 7, 600).unwrap(), TimeDelta::milliseconds(300)); check!( - hmsm(3, 5, 7, 200), - hmsm(2, 4, 6, 300), + hmsm(3, 5, 7, 200).unwrap(), + hmsm(2, 4, 6, 200).unwrap(), + TimeDelta::seconds(3600 + 60 + 1) + ); + check!( + hmsm(3, 5, 7, 200).unwrap(), + hmsm(2, 4, 6, 300).unwrap(), 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), 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)); + check!( + hmsm(3, 5, 7, 200).unwrap(), + hmsm(3, 5, 6, 1_800).unwrap(), + TimeDelta::milliseconds(400) + ); + check!( + hmsm(3, 5, 7, 1_200).unwrap(), + hmsm(3, 5, 6, 1_800).unwrap(), + TimeDelta::milliseconds(1400) + ); + check!( + hmsm(3, 5, 7, 1_200).unwrap(), + hmsm(3, 5, 6, 800).unwrap(), + 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) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200)); - assert_eq!(hmsm(3, 5, 6, 1_800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200)); + assert_eq!( + hmsm(3, 5, 6, 800).unwrap() + TimeDelta::milliseconds(400), + hmsm(3, 5, 7, 200).unwrap() + ); + assert_eq!( + hmsm(3, 5, 6, 1_800).unwrap() + TimeDelta::milliseconds(400), + hmsm(3, 5, 7, 200).unwrap() + ); } #[test] fn test_time_fmt() { - assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 999)), "23:59:59.999"); - assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_000)), "23:59:60"); - assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_001)), "23:59:60.001"); - assert_eq!(format!("{}", NaiveTime::from_hms_micro(0, 0, 0, 43210)), "00:00:00.043210"); - assert_eq!(format!("{}", NaiveTime::from_hms_nano(0, 0, 0, 6543210)), "00:00:00.006543210"); + assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 999).unwrap()), "23:59:59.999"); + assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_000).unwrap()), "23:59:60"); + assert_eq!( + format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_001).unwrap()), + "23:59:60.001" + ); + assert_eq!( + format!("{}", NaiveTime::from_hms_micro(0, 0, 0, 43210).unwrap()), + "00:00:00.043210" + ); + assert_eq!( + format!("{}", NaiveTime::from_hms_nano(0, 0, 0, 6543210).unwrap()), + "00:00:00.006543210" + ); // the format specifier should have no effect on `NaiveTime` - assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)), "03:05:07.009"); + assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9).unwrap()), "03:05:07.009"); } #[test] @@ -242,15 +319,15 @@ fn test_time_parse_from_str() { let hms = NaiveTime::from_hms; assert_eq!( NaiveTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), - Ok(hms(12, 34, 56)) + Ok(hms(12, 34, 56).unwrap()) ); // ignore date and offset - assert_eq!(NaiveTime::parse_from_str("PM 12:59", "%P %H:%M"), Ok(hms(12, 59, 0))); + assert_eq!(NaiveTime::parse_from_str("PM 12:59", "%P %H:%M"), Ok(hms(12, 59, 0).unwrap())); assert!(NaiveTime::parse_from_str("12:3456", "%H:%M:%S").is_err()); } #[test] fn test_time_format() { - let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432); + let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432).unwrap(); assert_eq!(t.format("%H,%k,%I,%l,%P,%p").to_string(), "03, 3,03, 3,am,AM"); assert_eq!(t.format("%M").to_string(), "05"); assert_eq!(t.format("%S,%f,%.f").to_string(), "07,098765432,.098765432"); @@ -260,19 +337,22 @@ fn test_time_format() { assert_eq!(t.format("%r").to_string(), "03:05:07 AM"); assert_eq!(t.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); - let t = NaiveTime::from_hms_micro(3, 5, 7, 432100); + let t = NaiveTime::from_hms_micro(3, 5, 7, 432100).unwrap(); assert_eq!(t.format("%S,%f,%.f").to_string(), "07,432100000,.432100"); assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".432,.432100,.432100000"); - let t = NaiveTime::from_hms_milli(3, 5, 7, 210); + let t = NaiveTime::from_hms_milli(3, 5, 7, 210).unwrap(); assert_eq!(t.format("%S,%f,%.f").to_string(), "07,210000000,.210"); assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".210,.210000,.210000000"); - let t = NaiveTime::from_hms(3, 5, 7); + let t = NaiveTime::from_hms(3, 5, 7).unwrap(); assert_eq!(t.format("%S,%f,%.f").to_string(), "07,000000000,"); assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".000,.000000,.000000000"); // corner cases - assert_eq!(NaiveTime::from_hms(13, 57, 9).format("%r").to_string(), "01:57:09 PM"); - assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).format("%X").to_string(), "23:59:60"); + assert_eq!(NaiveTime::from_hms(13, 57, 9).unwrap().format("%r").to_string(), "01:57:09 PM"); + assert_eq!( + NaiveTime::from_hms_milli(23, 59, 59, 1_000).unwrap().format("%X").to_string(), + "23:59:60" + ); } diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index 6f8bb461a2..e66e046d8b 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -10,11 +10,11 @@ use num_integer::div_mod_floor; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; -use super::{LocalResult, Offset, TimeZone}; +use super::{ChronoError, DateTime, FixedTimeZone, Offset, TimeZone}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; +use crate::offset::ChronoErrorKind; use crate::time_delta::TimeDelta; -use crate::DateTime; -use crate::Timelike; +use crate::{LocalResult, Timelike}; /// The time zone with fixed offset, from UTC-23:59:59 to UTC+23:59:59. /// @@ -29,63 +29,50 @@ pub struct FixedOffset { } impl FixedOffset { - /// Makes a new `FixedOffset` for the Eastern Hemisphere with given timezone difference. - /// The negative `secs` means the Western Hemisphere. + /// The fixed offset that matches UTC. + pub(crate) const UTC: FixedOffset = FixedOffset { local_minus_utc: 0 }; + + /// Makes a new `FixedOffset` for the Eastern Hemisphere with given timezone + /// difference. The negative `secs` means the Western Hemisphere. /// - /// Panics on the out-of-bound `secs`. + /// Returns `Err(ChronoError)` on the out-of-bound `secs`. /// /// # Example /// /// ``` /// use chrono::{FixedOffset, TimeZone}; /// let hour = 3600; - /// let datetime = FixedOffset::east(5 * hour).ymd(2016, 11, 08) - /// .and_hms(0, 0, 0); - /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00") + /// let datetime = FixedOffset::east(5 * hour)?.ymd(2016, 11, 08)?.and_hms(0, 0, 0)?; + /// assert_eq!(datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn east(secs: i32) -> FixedOffset { - FixedOffset::east_opt(secs).expect("FixedOffset::east out of bounds") - } - - /// Makes a new `FixedOffset` for the Eastern Hemisphere with given timezone difference. - /// The negative `secs` means the Western Hemisphere. - /// - /// Returns `None` on the out-of-bound `secs`. - pub fn east_opt(secs: i32) -> Option { + pub fn east(secs: i32) -> Result { if -86_400 < secs && secs < 86_400 { - Some(FixedOffset { local_minus_utc: secs }) + Ok(FixedOffset { local_minus_utc: secs }) } else { - None + Err(ChronoError::new(ChronoErrorKind::InvalidTimeZone)) } } - /// Makes a new `FixedOffset` for the Western Hemisphere with given timezone difference. - /// The negative `secs` means the Eastern Hemisphere. + /// Makes a new `FixedOffset` for the Western Hemisphere with given timezone + /// difference. The negative `secs` means the Eastern Hemisphere. /// - /// Panics on the out-of-bound `secs`. + /// Returns `Err(ChronoError)` on the out-of-bound `secs`. /// /// # Example /// /// ``` /// use chrono::{FixedOffset, TimeZone}; /// let hour = 3600; - /// let datetime = FixedOffset::west(5 * hour).ymd(2016, 11, 08) - /// .and_hms(0, 0, 0); - /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00") + /// let datetime = FixedOffset::west(5 * hour)?.ymd(2016, 11, 08)?.and_hms(0, 0, 0)?; + /// assert_eq!(datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - pub fn west(secs: i32) -> FixedOffset { - FixedOffset::west_opt(secs).expect("FixedOffset::west out of bounds") - } - - /// Makes a new `FixedOffset` for the Western Hemisphere with given timezone difference. - /// The negative `secs` means the Eastern Hemisphere. - /// - /// Returns `None` on the out-of-bound `secs`. - pub fn west_opt(secs: i32) -> Option { + pub fn west(secs: i32) -> Result { if -86_400 < secs && secs < 86_400 { - Some(FixedOffset { local_minus_utc: -secs }) + Ok(FixedOffset { local_minus_utc: -secs }) } else { - None + Err(ChronoError::new(ChronoErrorKind::InvalidTimeZone)) } } @@ -105,21 +92,38 @@ impl FixedOffset { impl TimeZone for FixedOffset { type Offset = FixedOffset; - fn from_offset(offset: &FixedOffset) -> FixedOffset { + fn from_offset(offset: &Self::Offset) -> FixedOffset { *offset } - fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult { - LocalResult::Single(*self) + fn offset_from_local_date( + &self, + _: &NaiveDate, + ) -> Result, ChronoError> { + Ok(LocalResult::Single(*self)) } - fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult { - LocalResult::Single(*self) + + fn offset_from_local_datetime( + &self, + _: &NaiveDateTime, + ) -> Result, ChronoError> { + Ok(LocalResult::Single(*self)) + } + + fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Result { + Ok(*self) } + fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Result { + Ok(*self) + } +} - fn offset_from_utc_date(&self, _utc: &NaiveDate) -> FixedOffset { +impl FixedTimeZone for FixedOffset { + fn offset_from_utc_date_fixed(&self, _: &NaiveDate) -> Self::Offset { *self } - fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> FixedOffset { + + fn offset_from_utc_datetime_fixed(&self, _: &NaiveDateTime) -> Self::Offset { *self } } @@ -229,20 +233,36 @@ mod tests { // starting from 0.3 we don't have an offset exceeding one day. // this makes everything easier! assert_eq!( - format!("{:?}", FixedOffset::east(86399).ymd(2012, 2, 29)), - "2012-02-29+23:59:59".to_string() + format!("{:?}", FixedOffset::east(86399).unwrap().ymd(2012, 2, 29).unwrap().unwrap()), + "2012-02-29+23:59:59" ); assert_eq!( - format!("{:?}", FixedOffset::east(86399).ymd(2012, 2, 29).and_hms(5, 6, 7)), - "2012-02-29T05:06:07+23:59:59".to_string() + format!( + "{:?}", + FixedOffset::east(86399) + .unwrap() + .ymd(2012, 2, 29) + .unwrap() + .and_hms(5, 6, 7) + .unwrap() + ), + "2012-02-29T05:06:07+23:59:59" ); assert_eq!( - format!("{:?}", FixedOffset::west(86399).ymd(2012, 3, 4)), - "2012-03-04-23:59:59".to_string() + format!("{:?}", FixedOffset::west(86399).unwrap().ymd(2012, 3, 4).unwrap().unwrap()), + "2012-03-04-23:59:59" ); assert_eq!( - format!("{:?}", FixedOffset::west(86399).ymd(2012, 3, 4).and_hms(5, 6, 7)), - "2012-03-04T05:06:07-23:59:59".to_string() + format!( + "{:?}", + FixedOffset::west(86399) + .unwrap() + .ymd(2012, 3, 4) + .unwrap() + .and_hms(5, 6, 7) + .unwrap() + ), + "2012-03-04T05:06:07-23:59:59" ); } } diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 7a08db2bb6..b7fdd8aa13 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -7,9 +7,9 @@ use rkyv::{Archive, Deserialize, Serialize}; use super::fixed::FixedOffset; -use super::{LocalResult, TimeZone}; use crate::naive::{NaiveDate, NaiveDateTime}; -use crate::{Date, DateTime}; +use crate::offset::LocalResult; +use crate::{ChronoError, Date, DateTime, TimeZone}; // we don't want `stub.rs` when the target_os is not wasi or emscripten // as we use js-sys to get the date instead @@ -47,8 +47,9 @@ mod tz_info; /// ``` /// use chrono::{Local, DateTime, TimeZone}; /// -/// let dt: DateTime = Local::now(); -/// let dt: DateTime = Local.timestamp(0, 0); +/// let dt: DateTime = Local::now()?; +/// let dt: DateTime = Local.timestamp(0, 0)?; +/// # Ok::<_, chrono::ChronoError>(()) /// ``` #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -56,8 +57,8 @@ pub struct Local; impl Local { /// Returns a `Date` which corresponds to the current date. - pub fn today() -> Date { - Local::now().date() + pub fn today() -> Result, ChronoError> { + Ok(Local::now()?.date()) } /// Returns a `DateTime` which corresponds to the current date and time. @@ -66,7 +67,7 @@ impl Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - pub fn now() -> DateTime { + pub fn now() -> Result, ChronoError> { inner::now() } @@ -94,29 +95,35 @@ impl TimeZone for Local { } // they are easier to define in terms of the finished date and time unlike other offsets - fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult { - self.from_local_date(local).map(|date| *date.offset()) + fn offset_from_local_date( + &self, + local: &NaiveDate, + ) -> Result, ChronoError> { + Ok(self.from_local_date(local)?.map(|o| *o.offset())) } - fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult { - self.from_local_datetime(local).map(|datetime| *datetime.offset()) + fn offset_from_local_datetime( + &self, + local: &NaiveDateTime, + ) -> Result, ChronoError> { + Ok(self.from_local_datetime(local)?.map(|o| *o.offset())) } - fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset { - *self.from_utc_date(utc).offset() + fn offset_from_utc_date(&self, utc: &NaiveDate) -> Result { + Ok(*self.from_utc_date(utc)?.offset()) } - fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset { - *self.from_utc_datetime(utc).offset() + fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Result { + Ok(*self.from_utc_datetime(utc)?.offset()) } // override them for avoiding redundant works - fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { + fn from_local_date(&self, local: &NaiveDate) -> Result>, ChronoError> { // this sounds very strange, but required for keeping `TimeZone::ymd` sane. // in the other words, we use the offset at the local midnight // but keep the actual date unaltered (much like `FixedOffset`). - let midnight = self.from_local_datetime(&local.and_hms(0, 0, 0)); - midnight.map(|datetime| Date::from_utc(*local, *datetime.offset())) + let midnight = self.from_local_datetime(&local.and_midnight())?; + Ok(midnight.map(|midnight| Date::from_utc(*local, *midnight.offset()))) } #[cfg(all( @@ -124,12 +131,12 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] - fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult> { + fn from_local_datetime(&self, local: &NaiveDateTime) -> Result, ChronoError> { 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::TimeDelta::seconds(offset.local_minus_utc() as i64); - LocalResult::Single(DateTime::from_utc(local, offset)) + Ok(DateTime::from_utc(local, offset)) } #[cfg(not(all( @@ -137,13 +144,16 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult> { + fn from_local_datetime( + &self, + local: &NaiveDateTime, + ) -> Result>, ChronoError> { inner::naive_to_local(local, true) } - fn from_utc_date(&self, utc: &NaiveDate) -> Date { - let midnight = self.from_utc_datetime(&utc.and_hms(0, 0, 0)); - Date::from_utc(*utc, *midnight.offset()) + fn from_utc_date(&self, utc: &NaiveDate) -> Result, ChronoError> { + let midnight = self.from_utc_datetime(&utc.and_midnight())?; + Ok(Date::from_utc(*utc, *midnight.offset())) } #[cfg(all( @@ -151,7 +161,7 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] - fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime { + fn from_utc_datetime(&self, utc: &NaiveDateTime) -> Result, ChronoError> { // Get the offset from the js runtime let offset = FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60); DateTime::from_utc(*utc, offset) @@ -162,10 +172,8 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime { - // this is OK to unwrap as getting local time from a UTC - // timestamp is never ambiguous - inner::naive_to_local(utc, false).unwrap() + fn from_utc_datetime(&self, utc: &NaiveDateTime) -> Result, ChronoError> { + Ok(inner::naive_to_local(utc, false)?.single()?) } } @@ -173,8 +181,11 @@ impl TimeZone for Local { mod tests { use super::Local; use crate::offset::TimeZone; - use crate::{Datelike, NaiveDate, NaiveDateTime, TimeDelta, Timelike}; + use crate::{Datelike, TimeDelta}; + #[cfg(unix)] + use crate::{NaiveDate, NaiveDateTime, Timelike}; + #[cfg(unix)] use std::{path, process}; #[cfg(unix)] @@ -206,22 +217,18 @@ mod tests { // This is used while a decision is made wheter the `date` output needs to // be exactly matched, or whether LocalResult::Ambigious should be handled // differently - match Local.from_local_datetime( - &NaiveDate::from_ymd(dt.year(), dt.month(), dt.day()).and_hms(dt.hour(), 5, 1), - ) { - crate::LocalResult::Ambiguous(a, b) => { - assert!( - format!("{}\n", a) == date_command_str - || format!("{}\n", b) == date_command_str - ) - } - crate::LocalResult::Single(a) => { - assert_eq!(format!("{}\n", a), date_command_str); - } - crate::LocalResult::None => { - assert_eq!("", date_command_str); - } - } + let dt = Local + .from_local_datetime( + &NaiveDate::from_ymd(dt.year(), dt.month(), dt.day()) + .unwrap() + .and_hms(dt.hour(), 5, 1) + .unwrap(), + ) + .unwrap() + .single() + .unwrap(); + + assert_eq!(format!("{}\n", dt), date_command_str); } #[test] @@ -237,7 +244,7 @@ mod tests { return; } - let mut date = NaiveDate::from_ymd(1975, 1, 1).and_hms(0, 0, 0); + let mut date = NaiveDate::from_ymd(1975, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); while date.year() < 2078 { if (1975..=1977).contains(&date.year()) @@ -253,9 +260,9 @@ mod tests { #[test] fn verify_correct_offsets() { - let now = Local::now(); - let from_local = Local.from_local_datetime(&now.naive_local()).unwrap(); - let from_utc = Local.from_utc_datetime(&now.naive_utc()); + let now = Local::now().unwrap(); + let from_local = Local.from_local_datetime(&now.naive_local()).unwrap().unwrap(); + let from_utc = Local.from_utc_datetime(&now.naive_utc()).unwrap(); assert_eq!(now.offset().local_minus_utc(), from_local.offset().local_minus_utc()); assert_eq!(now.offset().local_minus_utc(), from_utc.offset().local_minus_utc()); @@ -267,9 +274,9 @@ mod tests { #[test] fn verify_correct_offsets_distant_past() { // let distant_past = Local::now() - Duration::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()); + let distant_past = Local::now().unwrap() - TimeDelta::days(250 * 31); + let from_local = Local.from_local_datetime(&distant_past.naive_local()).unwrap().unwrap(); + let from_utc = Local.from_utc_datetime(&distant_past.naive_utc()).unwrap(); assert_eq!(distant_past.offset().local_minus_utc(), from_local.offset().local_minus_utc()); assert_eq!(distant_past.offset().local_minus_utc(), from_utc.offset().local_minus_utc()); @@ -280,9 +287,9 @@ mod tests { #[test] fn verify_correct_offsets_distant_future() { - 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()); + let distant_future = Local::now().unwrap() + TimeDelta::days(250 * 31); + let from_local = Local.from_local_datetime(&distant_future.naive_local()).unwrap().unwrap(); + let from_utc = Local.from_utc_datetime(&distant_future.naive_utc()).unwrap(); assert_eq!( distant_future.offset().local_minus_utc(), @@ -297,21 +304,21 @@ mod tests { #[test] fn test_local_date_sanity_check() { // issue #27 - assert_eq!(Local.ymd(2999, 12, 28).day(), 28); + assert_eq!(Local.ymd(2999, 12, 28).unwrap().unwrap().day(), 28); } #[test] fn test_leap_second() { // issue #123 - let today = Local::today(); + let today = Local::today().unwrap(); - let dt = today.and_hms_milli(1, 2, 59, 1000); + let dt = today.and_hms_milli(1, 2, 59, 1000).unwrap(); let timestr = dt.time().to_string(); // the OS API may or may not support the leap second, // but there are only two sensible options. assert!(timestr == "01:02:60" || timestr == "01:03:00", "unexpected timestr {:?}", timestr); - let dt = today.and_hms_milli(1, 2, 3, 1234); + let dt = today.and_hms_milli(1, 2, 3, 1234).unwrap(); let timestr = dt.time().to_string(); assert!( timestr == "01:02:03.234" || timestr == "01:02:04.234", diff --git a/src/offset/local/tz_info/rule.rs b/src/offset/local/tz_info/rule.rs index 7befddb5cf..f068d26136 100644 --- a/src/offset/local/tz_info/rule.rs +++ b/src/offset/local/tz_info/rule.rs @@ -6,6 +6,7 @@ use super::{ rem_euclid, Error, CUMUL_DAY_IN_MONTHS_NORMAL_YEAR, DAYS_PER_WEEK, DAY_IN_MONTHS_NORMAL_YEAR, SECONDS_PER_DAY, }; +use crate::offset::LocalResult; /// Transition rule #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -84,10 +85,10 @@ impl TransitionRule { &self, local_time: i64, year: i32, - ) -> Result, Error> { + ) -> Result>, Error> { match self { TransitionRule::Fixed(local_time_type) => { - Ok(crate::LocalResult::Single(*local_time_type)) + Ok(Some(LocalResult::Single(*local_time_type))) } TransitionRule::Alternate(alternate_time) => { alternate_time.find_local_time_type_from_local(local_time, year) @@ -232,7 +233,7 @@ impl AlternateTime { &self, local_time: i64, current_year: i32, - ) -> Result, Error> { + ) -> Result>, Error> { // Check if the current year is valid for the following computations if !(i32::min_value() + 2 <= current_year && current_year <= i32::max_value() - 2) { return Err(Error::OutOfRange("out of range date time")); @@ -253,7 +254,7 @@ impl AlternateTime { - i64::from(self.dst.ut_offset); match self.std.ut_offset.cmp(&self.dst.ut_offset) { - Ordering::Equal => Ok(crate::LocalResult::Single(self.std)), + Ordering::Equal => Ok(Some(LocalResult::Single(self.std))), Ordering::Less => { if self.dst_start.transition_date(current_year).0 < self.dst_end.transition_date(current_year).0 @@ -261,41 +262,41 @@ impl AlternateTime { // northern hemisphere // For the DST END transition, the `start` happens at a later timestamp than the `end`. if local_time <= dst_start_transition_start { - Ok(crate::LocalResult::Single(self.std)) + Ok(Some(LocalResult::Single(self.std))) } else if local_time > dst_start_transition_start && local_time < dst_start_transition_end { - Ok(crate::LocalResult::None) + Ok(None) } else if local_time >= dst_start_transition_end && local_time < dst_end_transition_end { - Ok(crate::LocalResult::Single(self.dst)) + Ok(Some(LocalResult::Single(self.dst))) } else if local_time >= dst_end_transition_end && local_time <= dst_end_transition_start { - Ok(crate::LocalResult::Ambiguous(self.std, self.dst)) + Ok(Some(LocalResult::Ambiguous(self.std, self.dst))) } else { - Ok(crate::LocalResult::Single(self.std)) + Ok(Some(LocalResult::Single(self.std))) } } else { // southern hemisphere regular DST // For the DST END transition, the `start` happens at a later timestamp than the `end`. if local_time < dst_end_transition_end { - Ok(crate::LocalResult::Single(self.dst)) + Ok(Some(LocalResult::Single(self.dst))) } else if local_time >= dst_end_transition_end && local_time <= dst_end_transition_start { - Ok(crate::LocalResult::Ambiguous(self.std, self.dst)) + Ok(Some(LocalResult::Ambiguous(self.std, self.dst))) } else if local_time > dst_end_transition_end && local_time < dst_start_transition_start { - Ok(crate::LocalResult::Single(self.std)) + Ok(Some(LocalResult::Single(self.std))) } else if local_time >= dst_start_transition_start && local_time < dst_start_transition_end { - Ok(crate::LocalResult::None) + Ok(None) } else { - Ok(crate::LocalResult::Single(self.dst)) + Ok(Some(LocalResult::Single(self.dst))) } } } @@ -306,41 +307,41 @@ impl AlternateTime { // southern hemisphere reverse DST // For the DST END transition, the `start` happens at a later timestamp than the `end`. if local_time < dst_start_transition_end { - Ok(crate::LocalResult::Single(self.std)) + Ok(Some(LocalResult::Single(self.std))) } else if local_time >= dst_start_transition_end && local_time <= dst_start_transition_start { - Ok(crate::LocalResult::Ambiguous(self.dst, self.std)) + Ok(Some(LocalResult::Ambiguous(self.dst, self.std))) } else if local_time > dst_start_transition_start && local_time < dst_end_transition_start { - Ok(crate::LocalResult::Single(self.dst)) + Ok(Some(LocalResult::Single(self.dst))) } else if local_time >= dst_end_transition_start && local_time < dst_end_transition_end { - Ok(crate::LocalResult::None) + Ok(None) } else { - Ok(crate::LocalResult::Single(self.std)) + Ok(Some(LocalResult::Single(self.std))) } } else { // northern hemisphere reverse DST // For the DST END transition, the `start` happens at a later timestamp than the `end`. if local_time <= dst_end_transition_start { - Ok(crate::LocalResult::Single(self.dst)) + Ok(Some(LocalResult::Single(self.dst))) } else if local_time > dst_end_transition_start && local_time < dst_end_transition_end { - Ok(crate::LocalResult::None) + Ok(None) } else if local_time >= dst_end_transition_end && local_time < dst_start_transition_end { - Ok(crate::LocalResult::Single(self.std)) + Ok(Some(LocalResult::Single(self.std))) } else if local_time >= dst_start_transition_end && local_time <= dst_start_transition_start { - Ok(crate::LocalResult::Ambiguous(self.dst, self.std)) + Ok(Some(LocalResult::Ambiguous(self.dst, self.std))) } else { - Ok(crate::LocalResult::Single(self.dst)) + Ok(Some(LocalResult::Single(self.dst))) } } } diff --git a/src/offset/local/tz_info/timezone.rs b/src/offset/local/tz_info/timezone.rs index 085b25c117..8f6a0ade71 100644 --- a/src/offset/local/tz_info/timezone.rs +++ b/src/offset/local/tz_info/timezone.rs @@ -7,6 +7,7 @@ use std::{cmp::Ordering, fmt, str}; use super::rule::{AlternateTime, TransitionRule}; use super::{parser, Error, DAYS_PER_WEEK, SECONDS_PER_DAY}; +use crate::offset::LocalResult; /// Time zone #[derive(Debug, Clone, Eq, PartialEq)] @@ -123,7 +124,7 @@ impl TimeZone { &self, local_time: i64, year: i32, - ) -> Result, Error> { + ) -> Result>, Error> { self.as_ref().find_local_time_type_from_local(local_time, year) } @@ -205,7 +206,7 @@ impl<'a> TimeZoneRef<'a> { &self, local_time: i64, year: i32, - ) -> Result, Error> { + ) -> Result>, Error> { // #TODO: this is wrong as we need 'local_time_to_local_leap_time ? // but ... does the local time even include leap seconds ?? // let unix_leap_time = match self.unix_time_to_unix_leap_time(local_time) { @@ -234,26 +235,26 @@ impl<'a> TimeZoneRef<'a> { // bakwards transition, eg from DST to regular // this means a given local time could have one of two possible offsets if local_leap_time < transition_end { - return Ok(crate::LocalResult::Single(prev.unwrap())); + return Ok(Some(LocalResult::Single(prev.unwrap()))); } else if local_leap_time >= transition_end && local_leap_time <= transition_start { if prev.unwrap().ut_offset < after_ltt.ut_offset { - return Ok(crate::LocalResult::Ambiguous(prev.unwrap(), after_ltt)); + return Ok(Some(LocalResult::Ambiguous(prev.unwrap(), after_ltt))); } else { - return Ok(crate::LocalResult::Ambiguous(after_ltt, prev.unwrap())); + return Ok(Some(LocalResult::Ambiguous(after_ltt, prev.unwrap()))); } } } Ordering::Equal => { // should this ever happen? presumably we have to handle it anyway. if local_leap_time < transition_start { - return Ok(crate::LocalResult::Single(prev.unwrap())); + return Ok(Some(LocalResult::Single(prev.unwrap()))); } else if local_leap_time == transition_end { if prev.unwrap().ut_offset < after_ltt.ut_offset { - return Ok(crate::LocalResult::Ambiguous(prev.unwrap(), after_ltt)); + return Ok(Some(LocalResult::Ambiguous(prev.unwrap(), after_ltt))); } else { - return Ok(crate::LocalResult::Ambiguous(after_ltt, prev.unwrap())); + return Ok(Some(LocalResult::Ambiguous(after_ltt, prev.unwrap()))); } } } @@ -261,11 +262,11 @@ impl<'a> TimeZoneRef<'a> { // forwards transition, eg from regular to DST // this means that times that are skipped are invalid local times if local_leap_time <= transition_start { - return Ok(crate::LocalResult::Single(prev.unwrap())); + return Ok(Some(LocalResult::Single(prev.unwrap()))); } else if local_leap_time < transition_end { - return Ok(crate::LocalResult::None); + return Ok(None); } else if local_leap_time == transition_end { - return Ok(crate::LocalResult::Single(after_ltt)); + return Ok(Some(LocalResult::Single(after_ltt))); } } } @@ -282,7 +283,7 @@ impl<'a> TimeZoneRef<'a> { err => err, } } else { - Ok(crate::LocalResult::Single(self.local_time_types[0])) + Ok(Some(LocalResult::Single(self.local_time_types[0]))) } } diff --git a/src/offset/local/unix.rs b/src/offset/local/unix.rs index 3ca2f4a6a5..6c242edc55 100644 --- a/src/offset/local/unix.rs +++ b/src/offset/local/unix.rs @@ -12,14 +12,23 @@ use std::{cell::RefCell, env, fs, time::SystemTime}; use super::tz_info::TimeZone; use super::{DateTime, FixedOffset, Local, NaiveDateTime}; -use crate::{Datelike, LocalResult, Utc}; +use crate::error::ChronoErrorKind; +use crate::offset::LocalResult; +use crate::{ChronoError, Datelike, Utc}; -pub(super) fn now() -> DateTime { - let now = Utc::now().naive_utc(); - naive_to_local(&now, false).unwrap() +pub(super) fn now() -> Result, ChronoError> { + let now = Utc::now()?.naive_utc(); + + match naive_to_local(&now, false)? { + LocalResult::Single(dt) => Ok(dt), + _ => Err(ChronoError::new(ChronoErrorKind::AmbiguousDate)), + } } -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult> { +pub(super) fn naive_to_local( + d: &NaiveDateTime, + local: bool, +) -> Result>, ChronoError> { TZ_INFO.with(|maybe_cache| { maybe_cache.borrow_mut().get_or_insert_with(Cache::default).offset(*d, local) }) @@ -123,7 +132,11 @@ impl Default for Cache { } impl Cache { - fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult> { + fn offset( + &mut self, + d: NaiveDateTime, + local: bool, + ) -> Result>, ChronoError> { if self.source.out_of_date() { *self = Cache::default(); } @@ -134,9 +147,9 @@ impl Cache { .find_local_time_type(d.timestamp()) .expect("unable to select local time type") .offset(), - ); + )?; - return LocalResult::Single(DateTime::from_utc(d, offset)); + return Ok(LocalResult::Single(DateTime::from_utc(d, offset))); } // we pass through the year as the year of a local point in time must either be valid in that locale, or @@ -146,19 +159,19 @@ impl Cache { .find_local_time_type_from_local(d.timestamp(), d.year()) .expect("unable to select local time type") { - LocalResult::None => LocalResult::None, - LocalResult::Ambiguous(early, late) => { - let early_offset = FixedOffset::east(early.offset()); - let late_offset = FixedOffset::east(late.offset()); + None => Err(ChronoError::new(ChronoErrorKind::MissingDate)), + Some(LocalResult::Ambiguous(early, late)) => { + let early_offset = FixedOffset::east(early.offset())?; + let late_offset = FixedOffset::east(late.offset())?; - LocalResult::Ambiguous( + Ok(LocalResult::Ambiguous( DateTime::from_utc(d - early_offset, early_offset), DateTime::from_utc(d - late_offset, late_offset), - ) + )) } - LocalResult::Single(tt) => { - let offset = FixedOffset::east(tt.offset()); - LocalResult::Single(DateTime::from_utc(d - offset, offset)) + Some(LocalResult::Single(tt)) => { + let offset = FixedOffset::east(tt.offset())?; + Ok(LocalResult::Single(DateTime::from_utc(d - offset, offset))) } } } diff --git a/src/offset/local/windows.rs b/src/offset/local/windows.rs index b4c0ee675f..de47ff485c 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -17,14 +17,19 @@ use winapi::um::minwinbase::SYSTEMTIME; use winapi::um::timezoneapi::*; use super::{FixedOffset, Local}; -use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; +use crate::error::{ChronoError, ChronoErrorKind}; +use crate::offset::LocalResult; +use crate::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; -pub(super) fn now() -> DateTime { - tm_to_datetime(Timespec::now().local()) +pub(super) fn now() -> Result, ChronoError> { + tm_to_datetime(Timespec::now()?.local()?) } /// Converts a local `NaiveDateTime` to the `time::Timespec`. -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult> { +pub(super) fn naive_to_local( + d: &NaiveDateTime, + local: bool, +) -> Result>, ChronoError> { let tm = Tm { tm_sec: d.second() as i32, tm_min: d.minute() as i32, @@ -43,38 +48,38 @@ pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult utc_tm_to_time(&tm), - true => local_tm_to_time(&tm), + false => utc_tm_to_time(&tm)?, + true => local_tm_to_time(&tm)?, }, nsec: tm.tm_nsec, }; // Adjust for leap seconds - let mut tm = spec.local(); + let mut tm = spec.local()?; assert_eq!(tm.tm_nsec, 0); tm.tm_nsec = d.nanosecond() as i32; // #TODO - there should be ambiguous cases, investigate? - LocalResult::Single(tm_to_datetime(tm)) + Ok(LocalResult::Single(tm_to_datetime(tm)?)) } /// Converts a `time::Tm` struct into the timezone-aware `DateTime`. -fn tm_to_datetime(mut tm: Tm) -> DateTime { +fn tm_to_datetime(mut tm: Tm) -> Result, ChronoError> { if tm.tm_sec >= 60 { tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000; tm.tm_sec = 59; } - let date = NaiveDate::from_ymd(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32); + let date = NaiveDate::from_ymd(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32)?; let time = NaiveTime::from_hms_nano( tm.tm_hour as u32, tm.tm_min as u32, tm.tm_sec as u32, tm.tm_nsec as u32, - ); + )?; - let offset = FixedOffset::east(tm.tm_utcoff); - DateTime::from_utc(date.and_time(time) - offset, offset) + let offset = FixedOffset::east(tm.tm_utcoff)?; + Ok(DateTime::from_utc(date.and_time(time) - offset, offset)) } /// A record specifying a time value in seconds and nanoseconds, where @@ -89,14 +94,15 @@ struct Timespec { impl Timespec { /// Constructs a timespec representing the current time in UTC. - fn now() -> Timespec { - let st = - SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); - Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 } + fn now() -> Result { + let st = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|_| ChronoErrorKind::SystemTimeBeforeEpoch)?; + Ok(Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 }) } /// Converts this timespec into the system's local time. - fn local(self) -> Tm { + fn local(self) -> Result { let mut tm = Tm { tm_sec: 0, tm_min: 0, @@ -110,9 +116,9 @@ impl Timespec { tm_utcoff: 0, tm_nsec: 0, }; - time_to_local_tm(self.sec, &mut tm); + time_to_local_tm(self.sec, &mut tm)?; tm.tm_nsec = self.nsec; - tm + Ok(tm) } } @@ -228,13 +234,12 @@ fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { macro_rules! call { ($name:ident($($arg:expr),*)) => { if $name($($arg),*) == 0 { - panic!(concat!(stringify!($name), " failed with: {}"), - io::Error::last_os_error()); + return Err(ChronoError::new(ChronoErrorKind::SystemError(io::Error::last_os_error()))) } } } -fn time_to_local_tm(sec: i64, tm: &mut Tm) { +fn time_to_local_tm(sec: i64, tm: &mut Tm) -> Result<(), ChronoError> { let ft = time_to_file_time(sec); unsafe { let mut utc = mem::zeroed(); @@ -253,25 +258,26 @@ fn time_to_local_tm(sec: i64, tm: &mut Tm) { // check if it non standard tm.tm_utcoff = (local_sec - sec) as i32; tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { 0 } else { 1 }; + Ok(()) } } -fn utc_tm_to_time(tm: &Tm) -> i64 { +fn utc_tm_to_time(tm: &Tm) -> Result { unsafe { let mut ft = mem::zeroed(); let sys_time = tm_to_system_time(tm); call!(SystemTimeToFileTime(&sys_time, &mut ft)); - file_time_to_unix_seconds(&ft) + Ok(file_time_to_unix_seconds(&ft)) } } -fn local_tm_to_time(tm: &Tm) -> i64 { +fn local_tm_to_time(tm: &Tm) -> Result { unsafe { let mut ft = mem::zeroed(); let mut utc = mem::zeroed(); let mut sys_time = tm_to_system_time(tm); call!(TzSpecificLocalTimeToSystemTime(0 as *mut _, &mut sys_time, &mut utc)); call!(SystemTimeToFileTime(&utc, &mut ft)); - file_time_to_unix_seconds(&ft) + Ok(file_time_to_unix_seconds(&ft)) } } diff --git a/src/offset/mod.rs b/src/offset/mod.rs index eb89680ae9..74150f55e5 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -20,10 +20,10 @@ use core::fmt; +use crate::error::ChronoErrorKind; use crate::format::{parse, ParseResult, Parsed, StrftimeItems}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; -use crate::Weekday; -use crate::{Date, DateTime}; +use crate::{ChronoError, Date, DateTime, Weekday}; mod fixed; pub use self::fixed::FixedOffset; @@ -39,9 +39,6 @@ pub use self::utc::Utc; /// The conversion result from the local time to the timezone-aware datetime types. #[derive(Clone, PartialEq, Debug, Copy, Eq, Hash)] pub enum LocalResult { - /// Given local time representation is invalid. - /// This can occur when, for example, the positive timezone transition. - None, /// Given local time representation has a single unique result. Single(T), /// Given local time representation has multiple results and thus ambiguous. @@ -50,38 +47,50 @@ pub enum LocalResult { } impl LocalResult { - /// Returns `Some` only when the conversion result is unique, or `None` otherwise. - pub fn single(self) -> Option { + /// Returns the single value that this local result corresponds to or + /// `Err(ChronoError)` if the result is ambiguous. + /// + /// # Errors + /// + /// Returns `Err(ChronoError)` in case the value is not + /// [LocalResult::Single]. + pub fn single(self) -> Result { match self { - LocalResult::Single(t) => Some(t), - _ => None, + LocalResult::Single(value) => Ok(value), + _ => Err(ChronoError::new(ChronoErrorKind::AmbiguousDate)), } } - /// Returns `Some` for the earliest possible conversion result, or `None` if none. - pub fn earliest(self) -> Option { + /// Returns the date corresponding to the earliest date in the local result. + pub fn earliest(self) -> T { match self { - LocalResult::Single(t) | LocalResult::Ambiguous(t, _) => Some(t), - _ => None, + LocalResult::Single(t) | LocalResult::Ambiguous(t, _) => t, } } - /// Returns `Some` for the latest possible conversion result, or `None` if none. - pub fn latest(self) -> Option { + /// Returns the date corresponding to the latest date in the local result. + pub fn latest(self) -> T { match self { - LocalResult::Single(t) | LocalResult::Ambiguous(_, t) => Some(t), - _ => None, + LocalResult::Single(t) | LocalResult::Ambiguous(_, t) => t, } } /// Maps a `LocalResult` into `LocalResult` with given function. pub fn map U>(self, mut f: F) -> LocalResult { match self { - LocalResult::None => LocalResult::None, LocalResult::Single(v) => LocalResult::Single(f(v)), LocalResult::Ambiguous(min, max) => LocalResult::Ambiguous(f(min), f(max)), } } + + /// Maps a `LocalResult` into `LocalResult` fallibly with given + /// function. + pub fn try_map Result>(self, mut f: F) -> Result, E> { + match self { + LocalResult::Single(v) => Ok(LocalResult::Single(f(v)?)), + LocalResult::Ambiguous(min, max) => Ok(LocalResult::Ambiguous(f(min)?, f(max)?)), + } + } } impl LocalResult> { @@ -90,13 +99,8 @@ impl LocalResult> { /// /// Propagates any error. Ambiguous result would be discarded. #[inline] - pub fn and_time(self, time: NaiveTime) -> LocalResult> { - match self { - LocalResult::Single(d) => { - d.and_time(time).map_or(LocalResult::None, LocalResult::Single) - } - _ => LocalResult::None, - } + pub fn and_time(self, time: NaiveTime) -> Result, ChronoError> { + self.single()?.and_time(time) } /// Makes a new `DateTime` from the current date, hour, minute and second. @@ -104,89 +108,64 @@ impl LocalResult> { /// /// Propagates any error. Ambiguous result would be discarded. #[inline] - pub fn and_hms_opt(self, hour: u32, min: u32, sec: u32) -> LocalResult> { - match self { - LocalResult::Single(d) => { - d.and_hms_opt(hour, min, sec).map_or(LocalResult::None, LocalResult::Single) - } - _ => LocalResult::None, - } + pub fn and_hms(self, hour: u32, min: u32, sec: u32) -> Result, ChronoError> { + self.single()?.and_hms(hour, min, sec) } /// Makes a new `DateTime` from the current date, hour, minute, second and millisecond. /// The millisecond part can exceed 1,000 in order to represent the leap second. /// The offset in the current date is preserved. /// - /// Propagates any error. Ambiguous result would be discarded. + /// Propagates any error. Errors on ambiguous results. #[inline] - pub fn and_hms_milli_opt( + pub fn and_hms_milli( self, hour: u32, min: u32, sec: u32, milli: u32, - ) -> LocalResult> { - match self { - LocalResult::Single(d) => d - .and_hms_milli_opt(hour, min, sec, milli) - .map_or(LocalResult::None, LocalResult::Single), - _ => LocalResult::None, - } + ) -> Result, ChronoError> { + self.single()?.and_hms_milli(hour, min, sec, milli) } /// Makes a new `DateTime` from the current date, hour, minute, second and microsecond. /// The microsecond part can exceed 1,000,000 in order to represent the leap second. /// The offset in the current date is preserved. /// - /// Propagates any error. Ambiguous result would be discarded. + /// Propagates any error. Errors on ambiguous results. #[inline] - pub fn and_hms_micro_opt( + pub fn and_hms_micro( self, hour: u32, min: u32, sec: u32, micro: u32, - ) -> LocalResult> { - match self { - LocalResult::Single(d) => d - .and_hms_micro_opt(hour, min, sec, micro) - .map_or(LocalResult::None, LocalResult::Single), - _ => LocalResult::None, - } + ) -> Result, ChronoError> { + self.single()?.and_hms_micro(hour, min, sec, micro) } /// Makes a new `DateTime` from the current date, hour, minute, second and nanosecond. /// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second. /// The offset in the current date is preserved. /// - /// Propagates any error. Ambiguous result would be discarded. + /// Propagates any error. Errors on ambiguous results. #[inline] - pub fn and_hms_nano_opt( + pub fn and_hms_nano( self, hour: u32, min: u32, sec: u32, nano: u32, - ) -> LocalResult> { - match self { - LocalResult::Single(d) => d - .and_hms_nano_opt(hour, min, sec, nano) - .map_or(LocalResult::None, LocalResult::Single), - _ => LocalResult::None, - } + ) -> Result, ChronoError> { + self.single()?.and_hms_nano(hour, min, sec, nano) } } -impl LocalResult { +#[cfg(test)] +impl LocalResult { /// Returns the single unique conversion result, or panics accordingly. pub fn unwrap(self) -> T { - match self { - LocalResult::None => panic!("No such local time"), - LocalResult::Single(t) => t, - LocalResult::Ambiguous(t1, t2) => { - panic!("Ambiguous local time, ranging from {:?} to {:?}", t1, t2) - } - } + self.single().unwrap() } } @@ -206,46 +185,29 @@ pub trait TimeZone: Sized + Clone { /// The original `TimeZone` value can be recovered via `TimeZone::from_offset`. type Offset: Offset; - /// Makes a new `Date` from year, month, day and the current time zone. - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// Makes a new `Date` from year, month, day and the current time zone. This + /// assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. /// - /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), - /// but it will propagate to the `DateTime` values constructed via this date. + /// The time zone normally does not affect the date (unless it is between + /// UTC-24 and UTC+24), but it will propagate to the `DateTime` values + /// constructed via this date. /// - /// Panics on the out-of-range date, invalid month and/or day. + /// Returns `Err(ChronoError)` on the out-of-range date, invalid month + /// and/or day. /// /// # Example /// /// ``` /// use chrono::{Utc, TimeZone}; /// - /// assert_eq!(Utc.ymd(2015, 5, 15).to_string(), "2015-05-15UTC"); + /// assert_eq!(Utc.ymd(2015, 5, 15)?.single()?.to_string(), "2015-05-15UTC"); + /// assert_eq!(Utc.ymd(2015, 5, 15)?.single()?.to_string(), "2015-05-15UTC"); + /// assert!(Utc.ymd(2000, 0, 0).is_err()); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - fn ymd(&self, year: i32, month: u32, day: u32) -> Date { - self.ymd_opt(year, month, day).unwrap() - } - - /// Makes a new `Date` from year, month, day and the current time zone. - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. - /// - /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), - /// but it will propagate to the `DateTime` values constructed via this date. - /// - /// Returns `None` on the out-of-range date, invalid month and/or day. - /// - /// # Example - /// - /// ``` - /// use chrono::{Utc, LocalResult, TimeZone}; - /// - /// assert_eq!(Utc.ymd_opt(2015, 5, 15).unwrap().to_string(), "2015-05-15UTC"); - /// assert_eq!(Utc.ymd_opt(2000, 0, 0), LocalResult::None); - /// ``` - fn ymd_opt(&self, year: i32, month: u32, day: u32) -> LocalResult> { - match NaiveDate::from_ymd_opt(year, month, day) { - Some(d) => self.from_local_date(&d), - None => LocalResult::None, - } + fn ymd(&self, year: i32, month: u32, day: u32) -> Result>, ChronoError> { + let d = NaiveDate::from_ymd(year, month, day)?; + self.from_local_date(&d) } /// Makes a new `Date` from year, day of year (DOY or "ordinal") and the current time zone. @@ -254,142 +216,91 @@ pub trait TimeZone: Sized + Clone { /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), /// but it will propagate to the `DateTime` values constructed via this date. /// - /// Panics on the out-of-range date and/or invalid DOY. + /// Returns `Err(ChronoError)` on the out-of-range date and/or invalid DOY. /// /// # Example /// /// ``` - /// use chrono::{Utc, TimeZone}; + /// use chrono::{ChronoError, Utc, TimeZone}; /// - /// assert_eq!(Utc.yo(2015, 135).to_string(), "2015-05-15UTC"); + /// assert_eq!(Utc.yo(2015, 135)?.single()?.to_string(), "2015-05-15UTC"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - fn yo(&self, year: i32, ordinal: u32) -> Date { - self.yo_opt(year, ordinal).unwrap() - } - - /// Makes a new `Date` from year, day of year (DOY or "ordinal") and the current time zone. - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. - /// - /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), - /// but it will propagate to the `DateTime` values constructed via this date. - /// - /// Returns `None` on the out-of-range date and/or invalid DOY. - fn yo_opt(&self, year: i32, ordinal: u32) -> LocalResult> { - match NaiveDate::from_yo_opt(year, ordinal) { - Some(d) => self.from_local_date(&d), - None => LocalResult::None, - } + fn yo(&self, year: i32, ordinal: u32) -> Result>, ChronoError> { + let d = NaiveDate::from_yo(year, ordinal)?; + self.from_local_date(&d) } - /// Makes a new `Date` from ISO week date (year and week number), day of the week (DOW) and - /// the current time zone. - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. - /// The resulting `Date` may have a different year from the input year. + /// Makes a new `Date` from ISO week date (year and week number), day of the + /// week (DOW) and the current time zone. This assumes the proleptic + /// Gregorian calendar, with the year 0 being 1 BCE. The resulting `Date` + /// may have a different year from the input year. /// - /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), - /// but it will propagate to the `DateTime` values constructed via this date. + /// The time zone normally does not affect the date (unless it is between + /// UTC-24 and UTC+24), but it will propagate to the `DateTime` values + /// constructed via this date. /// - /// Panics on the out-of-range date and/or invalid week number. + /// Returns `Err(ChronoError)` on the out-of-range date and/or invalid week + /// number. /// /// # Example /// /// ``` /// use chrono::{Utc, Weekday, TimeZone}; /// - /// assert_eq!(Utc.isoywd(2015, 20, Weekday::Fri).to_string(), "2015-05-15UTC"); + /// assert_eq!(Utc.isoywd(2015, 20, Weekday::Fri)?.single()?.to_string(), "2015-05-15UTC"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - fn isoywd(&self, year: i32, week: u32, weekday: Weekday) -> Date { - self.isoywd_opt(year, week, weekday).unwrap() - } - - /// Makes a new `Date` from ISO week date (year and week number), day of the week (DOW) and - /// the current time zone. - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. - /// The resulting `Date` may have a different year from the input year. - /// - /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), - /// but it will propagate to the `DateTime` values constructed via this date. - /// - /// Returns `None` on the out-of-range date and/or invalid week number. - fn isoywd_opt(&self, year: i32, week: u32, weekday: Weekday) -> LocalResult> { - match NaiveDate::from_isoywd_opt(year, week, weekday) { - Some(d) => self.from_local_date(&d), - None => LocalResult::None, - } + fn isoywd( + &self, + year: i32, + week: u32, + weekday: Weekday, + ) -> Result>, ChronoError> { + let d = NaiveDate::from_isoywd(year, week, weekday)?; + self.from_local_date(&d) } /// Makes a new `DateTime` from the number of non-leap seconds - /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp") - /// and the number of nanoseconds since the last whole non-leap second. + /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp") and the number + /// of nanoseconds since the last whole non-leap second. /// - /// Panics on the out-of-range number of seconds and/or invalid nanosecond, - /// for a non-panicking version see [`timestamp_opt`](#method.timestamp_opt). + /// Returns `Err(ChronoError)` on out-of-range number of seconds and/or + /// invalid nanosecond, otherwise always returns [`LocalResult::Single`]. /// /// # Example /// /// ``` /// use chrono::{Utc, TimeZone}; /// - /// assert_eq!(Utc.timestamp(1431648000, 0).to_string(), "2015-05-15 00:00:00 UTC"); + /// assert_eq!(Utc.timestamp(1431648000, 0)?.to_string(), "2015-05-15 00:00:00 UTC"); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - fn timestamp(&self, secs: i64, nsecs: u32) -> DateTime { - self.timestamp_opt(secs, nsecs).unwrap() + fn timestamp(&self, secs: i64, nsecs: u32) -> Result, ChronoError> { + let dt = NaiveDateTime::from_timestamp(secs, nsecs)?; + self.from_utc_datetime(&dt) } - /// Makes a new `DateTime` from the number of non-leap seconds - /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp") - /// and the number of nanoseconds since the last whole non-leap second. - /// - /// Returns `LocalResult::None` on out-of-range number of seconds and/or - /// invalid nanosecond, otherwise always returns `LocalResult::Single`. - fn timestamp_opt(&self, secs: i64, nsecs: u32) -> LocalResult> { - match NaiveDateTime::from_timestamp_opt(secs, nsecs) { - Some(dt) => LocalResult::Single(self.from_utc_datetime(&dt)), - None => LocalResult::None, - } - } - - /// Makes a new `DateTime` from the number of non-leap milliseconds - /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). + /// Makes a new `DateTime` from the number of non-leap milliseconds since + /// January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). /// - /// Panics on out-of-range number of milliseconds for a non-panicking - /// version see [`timestamp_millis_opt`](#method.timestamp_millis_opt). + /// Returns `Err(ChronoError)` on out-of-range number of milliseconds and/or + /// invalid nanosecond. /// /// # Example /// /// ``` /// use chrono::{Utc, TimeZone}; - /// - /// assert_eq!(Utc.timestamp_millis(1431648000).timestamp(), 1431648); - /// ``` - fn timestamp_millis(&self, millis: i64) -> DateTime { - self.timestamp_millis_opt(millis).unwrap() - } - - /// Makes a new `DateTime` from the number of non-leap milliseconds - /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). - /// - /// - /// Returns `LocalResult::None` on out-of-range number of milliseconds - /// and/or invalid nanosecond, otherwise always returns - /// `LocalResult::Single`. - /// - /// # Example - /// - /// ``` - /// use chrono::{Utc, TimeZone, LocalResult}; - /// match Utc.timestamp_millis_opt(1431648000) { - /// LocalResult::Single(dt) => assert_eq!(dt.timestamp(), 1431648), - /// _ => panic!("Incorrect timestamp_millis"), - /// }; + /// assert_eq!(Utc.timestamp_millis(1431648000)?.timestamp(), 1431648); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - fn timestamp_millis_opt(&self, millis: i64) -> LocalResult> { + fn timestamp_millis(&self, millis: i64) -> Result, ChronoError> { let (mut secs, mut millis) = (millis / 1000, millis % 1000); if millis < 0 { secs -= 1; millis += 1000; } - self.timestamp_opt(secs, millis as u32 * 1_000_000) + self.timestamp(secs, millis as u32 * 1_000_000) } /// Makes a new `DateTime` from the number of non-leap nanoseconds @@ -403,15 +314,16 @@ pub trait TimeZone: Sized + Clone { /// ``` /// use chrono::{Utc, TimeZone}; /// - /// assert_eq!(Utc.timestamp_nanos(1431648000000000).timestamp(), 1431648); + /// assert_eq!(Utc.timestamp_nanos(1431648000000000)?.timestamp(), 1431648); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` - fn timestamp_nanos(&self, nanos: i64) -> DateTime { + fn timestamp_nanos(&self, nanos: i64) -> Result, ChronoError> { let (mut secs, mut nanos) = (nanos / 1_000_000_000, nanos % 1_000_000_000); if nanos < 0 { secs -= 1; nanos += 1_000_000_000; } - self.timestamp_opt(secs, nanos as u32).unwrap() + self.timestamp(secs, nanos as u32) } /// Parses a string with the specified format string and returns a @@ -435,45 +347,79 @@ pub trait TimeZone: Sized + Clone { fn from_offset(offset: &Self::Offset) -> Self; /// Creates the offset(s) for given local `NaiveDate` if possible. - fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult; + fn offset_from_local_date( + &self, + local: &NaiveDate, + ) -> Result, ChronoError>; /// Creates the offset(s) for given local `NaiveDateTime` if possible. - fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult; + fn offset_from_local_datetime( + &self, + local: &NaiveDateTime, + ) -> Result, ChronoError>; /// Converts the local `NaiveDate` to the timezone-aware `Date` if possible. #[allow(clippy::wrong_self_convention)] - fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { - self.offset_from_local_date(local).map(|offset| { - // since FixedOffset is within +/- 1 day, the date is never affected - Date::from_utc(*local, offset) - }) + fn from_local_date(&self, local: &NaiveDate) -> Result>, ChronoError> { + let offset = self.offset_from_local_date(local)?; + let offset = offset.map(|offset| Date::from_utc(*local, offset)); + Ok(offset) } /// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible. #[allow(clippy::wrong_self_convention)] - fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult> { - self.offset_from_local_datetime(local) - .map(|offset| DateTime::from_utc(*local - offset.fix(), offset)) + fn from_local_datetime( + &self, + local: &NaiveDateTime, + ) -> Result>, ChronoError> { + let offset = self.offset_from_local_datetime(local)?; + let offset = offset.map(|offset| DateTime::from_utc(*local - offset.fix(), offset)); + Ok(offset) } /// Creates the offset for given UTC `NaiveDate`. This cannot fail. - fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset; + fn offset_from_utc_date(&self, utc: &NaiveDate) -> Result; + + /// Creates the offset for given UTC `NaiveDateTime`. This cannot fail. + fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Result; + + /// Converts the UTC `NaiveDate` to the local time. + /// The UTC is continuous and thus this cannot fail (but can give the duplicate local time). + #[allow(clippy::wrong_self_convention)] + fn from_utc_date(&self, utc: &NaiveDate) -> Result, ChronoError> { + Ok(Date::from_utc(*utc, self.offset_from_utc_date(utc)?)) + } + + /// Converts the UTC `NaiveDateTime` to the local time. + /// The UTC is continuous and thus this cannot fail (but can give the duplicate local time). + #[allow(clippy::wrong_self_convention)] + fn from_utc_datetime(&self, utc: &NaiveDateTime) -> Result, ChronoError> { + Ok(DateTime::from_utc(*utc, self.offset_from_utc_datetime(utc)?)) + } +} + +/// A time zone that is fixed. It is distinguished from [TimeZone] by allowing +/// for infallible operations since there is no need to access system +/// information to figure out which timezone is being used. +pub trait FixedTimeZone: TimeZone { + /// Creates the offset for given UTC `NaiveDate`. This cannot fail. + fn offset_from_utc_date_fixed(&self, utc: &NaiveDate) -> Self::Offset; /// Creates the offset for given UTC `NaiveDateTime`. This cannot fail. - fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset; + fn offset_from_utc_datetime_fixed(&self, utc: &NaiveDateTime) -> Self::Offset; /// Converts the UTC `NaiveDate` to the local time. /// The UTC is continuous and thus this cannot fail (but can give the duplicate local time). #[allow(clippy::wrong_self_convention)] - fn from_utc_date(&self, utc: &NaiveDate) -> Date { - Date::from_utc(*utc, self.offset_from_utc_date(utc)) + fn from_utc_date_fixed(&self, utc: &NaiveDate) -> Date { + Date::from_utc(*utc, self.offset_from_utc_date_fixed(utc)) } /// Converts the UTC `NaiveDateTime` to the local time. /// The UTC is continuous and thus this cannot fail (but can give the duplicate local time). #[allow(clippy::wrong_self_convention)] - fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime { - DateTime::from_utc(*utc, self.offset_from_utc_datetime(utc)) + fn from_utc_datetime_fixed(&self, utc: &NaiveDateTime) -> DateTime { + DateTime::from_utc(*utc, self.offset_from_utc_datetime_fixed(utc)) } } @@ -483,21 +429,21 @@ mod tests { #[test] fn test_negative_millis() { - let dt = Utc.timestamp_millis(-1000); + let dt = Utc.timestamp_millis(-1000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:59 UTC"); - let dt = Utc.timestamp_millis(-7000); + let dt = Utc.timestamp_millis(-7000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:53 UTC"); - let dt = Utc.timestamp_millis(-7001); + let dt = Utc.timestamp_millis(-7001).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:52.999 UTC"); - let dt = Utc.timestamp_millis(-7003); + let dt = Utc.timestamp_millis(-7003).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:52.997 UTC"); - let dt = Utc.timestamp_millis(-999); + let dt = Utc.timestamp_millis(-999).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:59.001 UTC"); - let dt = Utc.timestamp_millis(-1); + let dt = Utc.timestamp_millis(-1).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:59.999 UTC"); - let dt = Utc.timestamp_millis(-60000); + let dt = Utc.timestamp_millis(-60000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:00 UTC"); - let dt = Utc.timestamp_millis(-3600000); + let dt = Utc.timestamp_millis(-3600000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:00:00 UTC"); for (millis, expected) in &[ @@ -505,33 +451,29 @@ mod tests { (-7001, "1969-12-31 23:59:52.999 UTC"), (-7003, "1969-12-31 23:59:52.997 UTC"), ] { - match Utc.timestamp_millis_opt(*millis) { - LocalResult::Single(dt) => { - assert_eq!(dt.to_string(), *expected); - } - e => panic!("Got {:?} instead of an okay answer", e), - } + let dt = Utc.timestamp_millis(*millis).unwrap(); + assert_eq!(dt.to_string(), *expected); } } #[test] fn test_negative_nanos() { - let dt = Utc.timestamp_nanos(-1_000_000_000); + let dt = Utc.timestamp_nanos(-1_000_000_000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:59 UTC"); - let dt = Utc.timestamp_nanos(-999_999_999); + let dt = Utc.timestamp_nanos(-999_999_999).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:59.000000001 UTC"); - let dt = Utc.timestamp_nanos(-1); + let dt = Utc.timestamp_nanos(-1).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:59.999999999 UTC"); - let dt = Utc.timestamp_nanos(-60_000_000_000); + let dt = Utc.timestamp_nanos(-60_000_000_000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:00 UTC"); - let dt = Utc.timestamp_nanos(-3_600_000_000_000); + let dt = Utc.timestamp_nanos(-3_600_000_000_000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:00:00 UTC"); } #[test] fn test_nanos_never_panics() { - Utc.timestamp_nanos(i64::max_value()); - Utc.timestamp_nanos(i64::default()); - Utc.timestamp_nanos(i64::min_value()); + Utc.timestamp_nanos(i64::max_value()).unwrap(); + Utc.timestamp_nanos(i64::default()).unwrap(); + Utc.timestamp_nanos(i64::min_value()).unwrap(); } } diff --git a/src/offset/utc.rs b/src/offset/utc.rs index d38bfade51..6199b5e683 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -17,10 +17,10 @@ use std::time::{SystemTime, UNIX_EPOCH}; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; -use super::{FixedOffset, LocalResult, Offset, TimeZone}; +use super::{FixedOffset, FixedTimeZone, Offset, TimeZone}; use crate::naive::{NaiveDate, NaiveDateTime}; #[cfg(feature = "clock")] -use crate::{Date, DateTime}; +use crate::{ChronoError, Date, DateTime, LocalResult}; /// The UTC time zone. This is the most efficient time zone when you don't need the local time. /// It is also used as an offset (which is also a dummy type). @@ -34,10 +34,11 @@ use crate::{Date, DateTime}; /// ``` /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc}; /// -/// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc); +/// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0)?, Utc); /// -/// assert_eq!(Utc.timestamp(61, 0), dt); -/// assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 1, 1), dt); +/// assert_eq!(Utc.timestamp(61, 0)?, dt); +/// assert_eq!(Utc.ymd(1970, 1, 1)?.and_hms(0, 1, 1)?, dt); +/// # Ok::<_, chrono::ChronoError>(()) /// ``` #[derive(Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -47,8 +48,8 @@ pub struct Utc; #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] impl Utc { /// Returns a `Date` which corresponds to the current date. - pub fn today() -> Date { - Utc::now().date() + pub fn today() -> Result, ChronoError> { + Ok(Utc::now()?.date()) } /// Returns a `DateTime` which corresponds to the current date and time. @@ -57,11 +58,11 @@ impl Utc { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - pub fn now() -> DateTime { + pub fn now() -> Result, ChronoError> { let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); - let naive = NaiveDateTime::from_timestamp(now.as_secs() as i64, now.subsec_nanos() as u32); - DateTime::from_utc(naive, Utc) + let naive = NaiveDateTime::from_timestamp(now.as_secs() as i64, now.subsec_nanos() as u32)?; + Ok(DateTime::from_utc(naive, Utc)) } /// Returns a `DateTime` which corresponds to the current date and time. @@ -70,37 +71,52 @@ impl Utc { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] - pub fn now() -> DateTime { + pub fn now() -> Result, ChronoError> { let now = js_sys::Date::new_0(); - DateTime::::from(now) + Ok(DateTime::::from(now)) } } impl TimeZone for Utc { - type Offset = Utc; + type Offset = Self; - fn from_offset(_state: &Utc) -> Utc { - Utc + fn from_offset(_: &Self) -> Self { + Self } - fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult { - LocalResult::Single(Utc) + fn offset_from_local_date(&self, _: &NaiveDate) -> Result, ChronoError> { + Ok(LocalResult::Single(Self)) } - fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult { - LocalResult::Single(Utc) + + fn offset_from_local_datetime( + &self, + _: &NaiveDateTime, + ) -> Result, ChronoError> { + Ok(LocalResult::Single(Self)) + } + + fn offset_from_utc_date(&self, _: &NaiveDate) -> Result { + Ok(Self) } - fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Utc { - Utc + fn offset_from_utc_datetime(&self, _: &NaiveDateTime) -> Result { + Ok(Self) } - fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Utc { - Utc +} + +impl FixedTimeZone for Utc { + fn offset_from_utc_date_fixed(&self, _: &NaiveDate) -> Self::Offset { + Self + } + + fn offset_from_utc_datetime_fixed(&self, _: &NaiveDateTime) -> Self::Offset { + Self } } impl Offset for Utc { fn fix(&self) -> FixedOffset { - FixedOffset::east(0) + FixedOffset::UTC } } diff --git a/src/round.rs b/src/round.rs index 7cbcc46454..62d6d4c141 100644 --- a/src/round.rs +++ b/src/round.rs @@ -25,9 +25,10 @@ pub trait SubsecRound { /// # Example /// ``` rust /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// let dt = Utc.ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?; /// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` fn round_subsecs(self, digits: u16) -> Self; @@ -37,9 +38,10 @@ pub trait SubsecRound { /// # Example /// ``` rust /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// let dt = Utc.ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?; /// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` fn trunc_subsecs(self, digits: u16) -> Self; } @@ -112,7 +114,7 @@ pub trait DurationRound: Sized { /// # Example /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// let dt = Utc.ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?; /// assert_eq!( /// dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(), /// "2018-01-11 12:00:00.150 UTC" @@ -121,6 +123,7 @@ pub trait DurationRound: Sized { /// dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), /// "2018-01-12 00:00:00 UTC" /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` fn duration_round(self, duration: TimeDelta) -> Result; @@ -129,7 +132,7 @@ pub trait DurationRound: Sized { /// # Example /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// let dt = Utc.ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?; /// assert_eq!( /// dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), /// "2018-01-11 12:00:00.150 UTC" @@ -138,6 +141,7 @@ pub trait DurationRound: Sized { /// dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), /// "2018-01-11 00:00:00 UTC" /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` fn duration_trunc(self, duration: TimeDelta) -> Result; } @@ -244,12 +248,13 @@ pub enum RoundingError { /// /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.ymd(1970, 12, 12).and_hms(0, 0, 0); + /// let dt = Utc.ymd(1970, 12, 12)?.and_hms(0, 0, 0)?; /// /// assert_eq!( /// dt.duration_round(TimeDelta::days(365)), /// Err(RoundingError::DurationExceedsTimestamp), /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` DurationExceedsTimestamp, @@ -257,12 +262,13 @@ pub enum RoundingError { /// /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.ymd(2260, 12, 31).and_hms_nano(23, 59, 59, 1_75_500_000); + /// let dt = Utc.ymd(2260, 12, 31)?.and_hms_nano(23, 59, 59, 1_75_500_000)?; /// /// assert_eq!( /// dt.duration_round(TimeDelta::days(300 * 365)), /// Err(RoundingError::DurationExceedsLimit) /// ); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` DurationExceedsLimit, @@ -270,9 +276,10 @@ pub enum RoundingError { /// /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.ymd(2300, 12, 12).and_hms(0, 0, 0); + /// let dt = Utc.ymd(2300, 12, 12)?.and_hms(0, 0, 0)?; /// /// assert_eq!(dt.duration_round(TimeDelta::days(1)), Err(RoundingError::TimestampExceedsLimit),); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` TimestampExceedsLimit, } @@ -310,8 +317,8 @@ mod tests { #[test] fn test_round_subsecs() { - let pst = FixedOffset::east(8 * 60 * 60); - let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 84_660_684); + let pst = FixedOffset::east(8 * 60 * 60).unwrap(); + let dt = pst.ymd(2018, 1, 11).unwrap().and_hms_nano(10, 5, 13, 84_660_684).unwrap(); assert_eq!(dt.round_subsecs(10), dt); assert_eq!(dt.round_subsecs(9), dt); @@ -327,7 +334,7 @@ mod tests { assert_eq!(dt.round_subsecs(0).nanosecond(), 0); assert_eq!(dt.round_subsecs(0).second(), 13); - let dt = Utc.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000); + let dt = Utc.ymd(2018, 1, 11).unwrap().and_hms_nano(10, 5, 27, 750_500_000).unwrap(); assert_eq!(dt.round_subsecs(9), dt); assert_eq!(dt.round_subsecs(4), dt); assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000); @@ -340,7 +347,7 @@ mod tests { #[test] fn test_round_leap_nanos() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000); + let dt = Utc.ymd(2016, 12, 31).unwrap().and_hms_nano(23, 59, 59, 1_750_500_000).unwrap(); assert_eq!(dt.round_subsecs(9), dt); assert_eq!(dt.round_subsecs(4), dt); assert_eq!(dt.round_subsecs(2).nanosecond(), 1_750_000_000); @@ -353,8 +360,8 @@ mod tests { #[test] fn test_trunc_subsecs() { - let pst = FixedOffset::east(8 * 60 * 60); - let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 84_660_684); + let pst = FixedOffset::east(8 * 60 * 60).unwrap(); + let dt = pst.ymd(2018, 1, 11).unwrap().and_hms_nano(10, 5, 13, 84_660_684).unwrap(); assert_eq!(dt.trunc_subsecs(10), dt); assert_eq!(dt.trunc_subsecs(9), dt); @@ -370,7 +377,7 @@ mod tests { assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0); assert_eq!(dt.trunc_subsecs(0).second(), 13); - let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000); + let dt = pst.ymd(2018, 1, 11).unwrap().and_hms_nano(10, 5, 27, 750_500_000).unwrap(); assert_eq!(dt.trunc_subsecs(9), dt); assert_eq!(dt.trunc_subsecs(4), dt); assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000); @@ -383,7 +390,7 @@ mod tests { #[test] fn test_trunc_leap_nanos() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000); + let dt = Utc.ymd(2016, 12, 31).unwrap().and_hms_nano(23, 59, 59, 1_750_500_000).unwrap(); assert_eq!(dt.trunc_subsecs(9), dt); assert_eq!(dt.trunc_subsecs(4), dt); assert_eq!(dt.trunc_subsecs(2).nanosecond(), 1_750_000_000); @@ -396,7 +403,7 @@ mod tests { #[test] fn test_duration_round() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000); + let dt = Utc.ymd(2016, 12, 31).unwrap().and_hms_nano(23, 59, 59, 175_500_000).unwrap(); assert_eq!( dt.duration_round(TimeDelta::zero()).unwrap().to_string(), @@ -409,13 +416,13 @@ mod tests { ); // round up - let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0); + let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 30, 0).unwrap(); assert_eq!( dt.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); + let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 29, 999).unwrap(); assert_eq!( dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" @@ -439,7 +446,8 @@ mod tests { ); // timezone east - let dt = FixedOffset::east(3600).ymd(2020, 10, 27).and_hms(15, 0, 0); + let dt = + FixedOffset::east(3600).unwrap().ymd(2020, 10, 27).unwrap().and_hms(15, 0, 0).unwrap(); assert_eq!( dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), "2020-10-28 00:00:00 +01:00" @@ -450,7 +458,8 @@ mod tests { ); // timezone west - let dt = FixedOffset::west(3600).ymd(2020, 10, 27).and_hms(15, 0, 0); + let dt = + FixedOffset::west(3600).unwrap().ymd(2020, 10, 27).unwrap().and_hms(15, 0, 0).unwrap(); assert_eq!( dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), "2020-10-28 00:00:00 -01:00" @@ -463,7 +472,12 @@ mod tests { #[test] fn test_duration_round_naive() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000).naive_utc(); + let dt = Utc + .ymd(2016, 12, 31) + .unwrap() + .and_hms_nano(23, 59, 59, 175_500_000) + .unwrap() + .naive_utc(); assert_eq!( dt.duration_round(TimeDelta::zero()).unwrap().to_string(), @@ -476,13 +490,13 @@ mod tests { ); // round up - let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0).naive_utc(); + let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 30, 0).unwrap().naive_utc(); assert_eq!( dt.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(); + let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 29, 999).unwrap().naive_utc(); assert_eq!( dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00" @@ -508,7 +522,7 @@ mod tests { #[test] fn test_duration_round_pre_epoch() { - let dt = Utc.ymd(1969, 12, 12).and_hms(12, 12, 12); + let dt = Utc.ymd(1969, 12, 12).unwrap().and_hms(12, 12, 12).unwrap(); assert_eq!( dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(), "1969-12-12 12:10:00 UTC" @@ -517,7 +531,7 @@ mod tests { #[test] fn test_duration_trunc() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000); + let dt = Utc.ymd(2016, 12, 31).unwrap().and_hms_nano(23, 59, 59, 175_500_000).unwrap(); assert_eq!( dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), @@ -525,13 +539,13 @@ mod tests { ); // would round up - let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0); + let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 30, 0).unwrap(); assert_eq!( dt.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); + let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 29, 999).unwrap(); assert_eq!( dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00 UTC" @@ -554,7 +568,8 @@ mod tests { ); // timezone east - let dt = FixedOffset::east(3600).ymd(2020, 10, 27).and_hms(15, 0, 0); + let dt = + FixedOffset::east(3600).and_then(|o| o.ymd(2020, 10, 27)?.and_hms(15, 0, 0)).unwrap(); assert_eq!( dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), "2020-10-27 00:00:00 +01:00" @@ -565,7 +580,8 @@ mod tests { ); // timezone west - let dt = FixedOffset::west(3600).ymd(2020, 10, 27).and_hms(15, 0, 0); + let dt = + FixedOffset::west(3600).and_then(|o| o.ymd(2020, 10, 27)?.and_hms(15, 0, 0)).unwrap(); assert_eq!( dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), "2020-10-27 00:00:00 -01:00" @@ -578,7 +594,12 @@ mod tests { #[test] fn test_duration_trunc_naive() { - let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000).naive_utc(); + let dt = Utc + .ymd(2016, 12, 31) + .unwrap() + .and_hms_nano(23, 59, 59, 175_500_000) + .unwrap() + .naive_utc(); assert_eq!( dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), @@ -586,13 +607,13 @@ mod tests { ); // would round up - let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0).naive_utc(); + let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 30, 0).unwrap().naive_utc(); assert_eq!( dt.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(); + let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 29, 999).unwrap().naive_utc(); assert_eq!( dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), "2012-12-12 18:20:00" @@ -617,7 +638,7 @@ mod tests { #[test] fn test_duration_trunc_pre_epoch() { - let dt = Utc.ymd(1969, 12, 12).and_hms(12, 12, 12); + let dt = Utc.ymd(1969, 12, 12).unwrap().and_hms(12, 12, 12).unwrap(); assert_eq!( dt.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 7d82f82a71..f177b6c11f 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,4 +1,4 @@ -use crate::{IsoWeek, Weekday}; +use crate::{ChronoError, IsoWeek, Weekday}; /// The common set of methods for date component. pub trait Datelike: Sized { @@ -56,37 +56,37 @@ pub trait Datelike: Sized { /// Makes a new value with the year number changed. /// /// Returns `None` when the resulting value would be invalid. - fn with_year(&self, year: i32) -> Option; + fn with_year(&self, year: i32) -> Result; /// Makes a new value with the month number (starting from 1) changed. /// /// Returns `None` when the resulting value would be invalid. - fn with_month(&self, month: u32) -> Option; + fn with_month(&self, month: u32) -> Result; /// Makes a new value with the month number (starting from 0) changed. /// /// Returns `None` when the resulting value would be invalid. - fn with_month0(&self, month0: u32) -> Option; + fn with_month0(&self, month0: u32) -> Result; /// Makes a new value with the day of month (starting from 1) changed. /// /// Returns `None` when the resulting value would be invalid. - fn with_day(&self, day: u32) -> Option; + fn with_day(&self, day: u32) -> Result; /// Makes a new value with the day of month (starting from 0) changed. /// /// Returns `None` when the resulting value would be invalid. - fn with_day0(&self, day0: u32) -> Option; + fn with_day0(&self, day0: u32) -> Result; /// Makes a new value with the day of year (starting from 1) changed. /// /// Returns `None` when the resulting value would be invalid. - fn with_ordinal(&self, ordinal: u32) -> Option; + fn with_ordinal(&self, ordinal: u32) -> Result; /// Makes a new value with the day of year (starting from 0) changed. /// /// Returns `None` when the resulting value would be invalid. - fn with_ordinal0(&self, ordinal0: u32) -> Option; + fn with_ordinal0(&self, ordinal0: u32) -> Result; /// Counts the days in the proleptic Gregorian calendar, with January 1, Year 1 (CE) as day 1. /// @@ -95,10 +95,11 @@ pub trait Datelike: Sized { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd(1970, 1, 1).num_days_from_ce(), 719_163); - /// assert_eq!(NaiveDate::from_ymd(2, 1, 1).num_days_from_ce(), 366); - /// assert_eq!(NaiveDate::from_ymd(1, 1, 1).num_days_from_ce(), 1); - /// assert_eq!(NaiveDate::from_ymd(0, 1, 1).num_days_from_ce(), -365); + /// assert_eq!(NaiveDate::from_ymd(1970, 1, 1)?.num_days_from_ce(), 719_163); + /// assert_eq!(NaiveDate::from_ymd(2, 1, 1)?.num_days_from_ce(), 366); + /// assert_eq!(NaiveDate::from_ymd(1, 1, 1)?.num_days_from_ce(), 1); + /// assert_eq!(NaiveDate::from_ymd(0, 1, 1)?.num_days_from_ce(), -365); + /// # Ok::<_, chrono::ChronoError>(()) /// ``` fn num_days_from_ce(&self) -> i32 { // See test_num_days_from_ce_against_alternative_impl below for a more straightforward @@ -149,26 +150,26 @@ pub trait Timelike: Sized { /// Makes a new value with the hour number changed. /// /// Returns `None` when the resulting value would be invalid. - fn with_hour(&self, hour: u32) -> Option; + fn with_hour(&self, hour: u32) -> Result; /// Makes a new value with the minute number changed. /// /// Returns `None` when the resulting value would be invalid. - fn with_minute(&self, min: u32) -> Option; + fn with_minute(&self, min: u32) -> Result; /// Makes a new value with the second number changed. /// /// Returns `None` when the resulting value would be invalid. /// As with the [`second`](#tymethod.second) method, /// the input range is restricted to 0 through 59. - fn with_second(&self, sec: u32) -> Option; + fn with_second(&self, sec: u32) -> Result; /// Makes a new value with nanoseconds since the whole non-leap second changed. /// /// Returns `None` when the resulting value would be invalid. /// As with the [`nanosecond`](#tymethod.nanosecond) method, /// the input range can exceed 1,000,000,000 for leap seconds. - fn with_nanosecond(&self, nano: u32) -> Option; + fn with_nanosecond(&self, nano: u32) -> Result; /// Returns the number of non-leap seconds past the last midnight. #[inline] @@ -222,7 +223,7 @@ mod tests { use num_iter::range_inclusive; for year in range_inclusive(NaiveDate::MIN.year(), NaiveDate::MAX.year()) { - let jan1_year = NaiveDate::from_ymd(year, 1, 1); + let jan1_year = NaiveDate::from_ymd(year, 1, 1).unwrap(); assert_eq!( jan1_year.num_days_from_ce(), num_days_from_ce(&jan1_year), diff --git a/tests/wasm.rs b/tests/wasm.rs index bcec43fb9f..d1f67ae450 100644 --- a/tests/wasm.rs +++ b/tests/wasm.rs @@ -10,7 +10,7 @@ use self::wasm_bindgen_test::*; #[wasm_bindgen_test] fn now() { let utc: DateTime = Utc::now(); - let local: DateTime = Local::now(); + let local: DateTime = Local::now().unwrap(); // Ensure time set by the test script is correct let now = env!("NOW"); @@ -57,7 +57,7 @@ fn from_is_exact() { #[wasm_bindgen_test] fn local_from_local_datetime() { - let now = Local::now(); + let now = Local::now().unwrap(); let ndt = now.naive_local(); let res = match Local.from_local_datetime(&ndt).single() { Some(v) => v,