diff --git a/README.md b/README.md index 5fe189e404..afe65820be 100644 --- a/README.md +++ b/README.md @@ -47,9 +47,9 @@ Consider using `NaiveDateTime` with the implicit TAI (International Atomic Time) if you want. Chrono inherently does not support an inaccurate or partial date and time representation. -Any operation that can be ambiguous will return `None` in such cases. +Any operation that can be ambiguous will return `Err(chrono::Error)` in such cases. For example, "a month later" of 2014-01-30 is not well-defined -and consequently `Utc.ymd_opt(2014, 1, 30).unwrap().with_month(2)` returns `None`. +and consequently `Utc.ymd(2014, 1, 30).with_month(2)` returns `Err(chrono::Error)`. Non ISO week handling is not yet supported. For now you can use the [chrono_ext](https://crates.io/crates/chrono_ext) diff --git a/benches/chrono.rs b/benches/chrono.rs index e825b5f4b3..dcacb796c2 100644 --- a/benches/chrono.rs +++ b/benches/chrono.rs @@ -35,28 +35,18 @@ fn bench_datetime_from_str(c: &mut Criterion) { } fn bench_datetime_to_rfc2822(c: &mut Criterion) { - let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap(); - let dt = pst - .from_local_datetime( - &NaiveDate::from_ymd_opt(2018, 1, 11) - .unwrap() - .and_hms_nano_opt(10, 5, 13, 84_660_000) - .unwrap(), - ) - .unwrap(); + let pst = FixedOffset::east(8 * 60 * 60).unwrap(); + let dt = pst.from_local_datetime( + &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_000)? + ); 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_opt(8 * 60 * 60).unwrap(); - let dt = pst - .from_local_datetime( - &NaiveDate::from_ymd_opt(2018, 1, 11) - .unwrap() - .and_hms_nano_opt(10, 5, 13, 84_660_000) - .unwrap(), - ) - .unwrap(); + let pst = FixedOffset::east(8 * 60 * 60).unwrap(); + let dt = pst.from_local_datetime( + &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_000)? + ); c.bench_function("bench_datetime_to_rfc3339", |b| b.iter(|| black_box(dt).to_rfc3339())); } @@ -112,7 +102,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_opt(*year, 1, 1).unwrap(); + 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 4af7d2ecc5..e311edb5bc 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.with_ymd_and_hms(2019, 1, 1, 0, 0, 0).unwrap(); + let _ = Utc.ymd(2019, 1, 1).and_hms(0, 0, 0); } diff --git a/src/date.rs b/src/date.rs index ea9a9f4bd0..a874b54ee0 100644 --- a/src/date.rs +++ b/src/date.rs @@ -20,8 +20,7 @@ use crate::format::{DelayedFormat, Item, StrftimeItems}; use crate::naive::{IsoWeek, NaiveDate, NaiveTime}; use crate::offset::{TimeZone, Utc}; use crate::time_delta::TimeDelta; -use crate::DateTime; -use crate::{Datelike, Weekday}; +use crate::{DateTime, Datelike, Error, Weekday}; /// ISO 8601 calendar date with time zone. /// @@ -84,145 +83,108 @@ impl Date { /// Makes a new `DateTime` from the current date and given `NaiveTime`. /// The offset in the current date is preserved. /// - /// Panics on invalid datetime. + /// Returns `Err(Error)` on invalid datetime. #[inline] - pub fn and_time(&self, time: NaiveTime) -> Option> { + pub fn and_time(&self, time: NaiveTime) -> Result, Error> { let localdt = self.naive_local().and_time(time); - self.timezone().from_local_datetime(&localdt).single() + self.timezone().from_local_datetime(&localdt)?.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. - #[deprecated(since = "0.4.23", note = "Use and_hms_opt() instead")] + /// Returns `Err(Error)` 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, Error> { + 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. - #[deprecated(since = "0.4.23", note = "Use and_hms_milli_opt() instead")] + /// Returns `Err(Error)` 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. - #[deprecated(since = "0.4.23", note = "Use and_hms_micro_opt() instead")] - #[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, Error> { + 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(Error)` 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. - #[deprecated(since = "0.4.23", note = "Use and_hms_nano_opt() instead")] - #[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, Error> { + 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(Error)` 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)) + ) -> Result, Error> { + let time = NaiveTime::from_hms_nano(hour, min, sec, nano)?; + self.and_time(time) } /// Makes a new `Date` for the next date. /// - /// Panics when `self` is the last representable date. - #[deprecated(since = "0.4.23", note = "Use succ_opt() instead")] - #[inline] - pub fn succ(&self) -> Date { - self.succ_opt().expect("out of bound") - } - - /// Makes a new `Date` for the next date. + /// Returns `Err(Error)` when `self` is the last representable date. /// - /// Returns `None` 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())) - } - - /// Makes a new `Date` for the prior date. + /// ``` + /// use chrono::prelude::*; /// - /// Panics when `self` is the first representable date. - #[deprecated(since = "0.4.23", note = "Use pred_opt() instead")] + /// assert_eq!(Utc.ymd(2022, 09, 12)?.single()?.succ()?, Utc.ymd(2022, 09, 13)?.single()?); + /// + /// assert!(Date::::MAX_UTC.succ().is_err()); + /// Ok::<_, Error>(()) + /// ``` #[inline] - pub fn pred(&self) -> Date { - self.pred_opt().expect("out of bound") + pub fn succ(&self) -> Result, Error> { + let date = self.date.succ()?; + Ok(Date::from_utc(date, self.offset.clone())) } /// Makes a new `Date` for the prior date. /// - /// Returns `None` when `self` is the first representable date. + /// Returns `Err(Error)` when `self` is the first representable date. + /// + /// ``` + /// use chrono::prelude::*; + /// + /// assert_eq!(Utc.ymd(2022, 09, 12)?.single()?.succ()?, Utc.ymd(2022, 09, 13)?.single()?); + /// + /// assert!(Date::::MIN_UTC.pred().is_err()); + /// Ok::<_, Error>(()) + /// ``` #[inline] - pub fn pred_opt(&self) -> Option> { - self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone())) + pub fn pred(&self) -> Result, Error> { + let date = self.date.pred()?; + Ok(Date::from_utc(date, self.offset.clone())) } /// Retrieves an associated offset from UTC. @@ -240,26 +202,26 @@ 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, Error> { tz.from_utc_date(&self.date) } /// Adds given `Duration` to the current date. /// - /// Returns `None` when it will result in overflow. + /// Returns `Err(Error)` 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 { let date = self.date.checked_add_signed(rhs)?; - Some(Date { date, offset: self.offset }) + Ok(Self { date, offset: self.offset }) } /// Subtracts given `Duration` from the current date. /// - /// Returns `None` when it will result in overflow. + /// Returns `Err(Error)` 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 { let date = self.date.checked_sub_signed(rhs)?; - Some(Date { date, offset: self.offset }) + Ok(Self { date, offset: self.offset }) } /// Subtracts another `Date` from the current date. @@ -290,7 +252,15 @@ impl Date { /// Returns the number of whole years from the given `base` until `self`. pub fn years_since(&self, base: Self) -> Option { - self.date.years_since(base.date) + let mut years = self.year() - base.year(); + if (self.month(), self.day()) < (base.month(), base.day()) { + years -= 1; + } + + match years >= 0 { + true => Some(years as u32), + false => None, + } } /// The minimum possible `Date`. @@ -300,11 +270,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, Error> 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 @@ -326,6 +297,16 @@ where /// Formats the date with the specified format string. /// See the [`crate::format::strftime`] module /// on the supported escape sequences. + /// + /// # Example + /// ```rust + /// use chrono::prelude::*; + /// + /// 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::Error>(()) + /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] @@ -409,37 +390,37 @@ impl Datelike for Date { } #[inline] - fn with_year(&self, year: i32) -> Option> { + fn with_year(&self, year: i32) -> Result, Error> { map_local(self, |date| date.with_year(year)) } #[inline] - fn with_month(&self, month: u32) -> Option> { + fn with_month(&self, month: u32) -> Result, Error> { map_local(self, |date| date.with_month(month)) } #[inline] - fn with_month0(&self, month0: u32) -> Option> { + fn with_month0(&self, month0: u32) -> Result, Error> { map_local(self, |date| date.with_month0(month0)) } #[inline] - fn with_day(&self, day: u32) -> Option> { + fn with_day(&self, day: u32) -> Result, Error> { map_local(self, |date| date.with_day(day)) } #[inline] - fn with_day0(&self, day0: u32) -> Option> { + fn with_day0(&self, day0: u32) -> Result, Error> { map_local(self, |date| date.with_day0(day0)) } #[inline] - fn with_ordinal(&self, ordinal: u32) -> Option> { + fn with_ordinal(&self, ordinal: u32) -> Result, Error> { map_local(self, |date| date.with_ordinal(ordinal)) } #[inline] - fn with_ordinal0(&self, ordinal0: u32) -> Option> { + fn with_ordinal0(&self, ordinal0: u32) -> Result, Error> { map_local(self, |date| date.with_ordinal0(ordinal0)) } } @@ -563,36 +544,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_opt(2000, 1, 1).unwrap(); + 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_opt(60 * 60).unwrap(); - 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_timezone(&timezone).unwrap(); + let date_add = date_add.with_timezone(&timezone).unwrap(); assert_eq!(date_add, date + TimeDelta::days(5)); - let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap(); - let date = date.with_timezone(&timezone); - let date_add = date_add.with_timezone(&timezone); + let timezone = FixedOffset::west(2 * 60 * 60).unwrap(); + let date = date.with_timezone(&timezone).unwrap(); + let date_add = date_add.with_timezone(&timezone).unwrap(); assert_eq!(date_add, date + TimeDelta::days(5)); } @@ -600,9 +583,9 @@ mod tests { #[test] #[cfg(feature = "clock")] fn test_date_add_assign_local() { - let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(); + 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); @@ -611,22 +594,22 @@ mod tests { #[test] fn test_date_sub_assign() { - let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(); + 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_opt(60 * 60).unwrap(); - 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_timezone(&timezone).unwrap(); + let date_sub = date_sub.with_timezone(&timezone).unwrap(); assert_eq!(date_sub, date - TimeDelta::days(5)); - let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap(); - let date = date.with_timezone(&timezone); - let date_sub = date_sub.with_timezone(&timezone); + let timezone = FixedOffset::west(2 * 60 * 60).unwrap(); + let date = date.with_timezone(&timezone).unwrap(); + let date_sub = date_sub.with_timezone(&timezone).unwrap(); assert_eq!(date_sub, date - TimeDelta::days(5)); } @@ -634,9 +617,9 @@ mod tests { #[test] #[cfg(feature = "clock")] fn test_date_sub_assign_local() { - let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(); + 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 8f84ab1bf3..94a5ba58d1 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -11,7 +11,8 @@ use alloc::string::{String, ToString}; #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::cmp::Ordering; -use core::fmt::Write; +#[cfg(feature = "clock")] +use core::convert::TryFrom; use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::{fmt, hash, str}; #[cfg(feature = "std")] @@ -26,15 +27,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, Parsed, StrftimeItems}; 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}; -#[allow(deprecated)] -use crate::Date; -use crate::{Datelike, Months, TimeDelta, Timelike, Weekday}; +use crate::offset::{FixedOffset, FixedTimeZone, Offset, TimeZone, Utc}; +use crate::{Date, Datelike, Error, Months, TimeDelta, Timelike, Weekday}; /// documented at re-export site #[cfg(feature = "serde")] @@ -102,8 +101,9 @@ impl DateTime { /// ``` /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc}; /// - /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp_opt(61, 0).unwrap(), Utc); - /// assert_eq!(Utc.timestamp_opt(61, 0).unwrap(), dt); + /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0)?, Utc); + /// assert_eq!(Utc.timestamp(61, 0)?, dt); + /// # Ok::<_, chrono::Error>(()) /// ``` // // note: this constructor is purposely not named to `new` to discourage the direct usage. @@ -122,19 +122,20 @@ impl DateTime { /// use chrono::naive::NaiveDate; /// use chrono::offset::{Utc, FixedOffset}; /// - /// let naivedatetime_utc = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(2, 0, 0).unwrap(); + /// 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_opt(8 * 60 * 60).unwrap(); - /// let naivedatetime_east = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(10, 0, 0).unwrap(); + /// let timezone_east = FixedOffset::east_opt(8 * 60 * 60).unwrap()?; + /// let naivedatetime_east = NaiveDate::from_ymd(2000, 1, 12)?.unwrap().and_hms(10, 0, 0).unwrap()?; /// let datetime_east = DateTime::::from_local(naivedatetime_east, timezone_east); /// - /// let timezone_west = FixedOffset::west_opt(7 * 60 * 60).unwrap(); - /// let naivedatetime_west = NaiveDate::from_ymd_opt(2000, 1, 11).unwrap().and_hms_opt(19, 0, 0).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { @@ -148,6 +149,18 @@ impl DateTime { /// Unless you are immediately planning on turning this into a `DateTime` /// with the same Timezone you should use the /// [`date_naive`](DateTime::date_naive) method. + /// + /// ``` + /// use chrono::prelude::*; + /// + /// 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)?); + /// # Ok::<_, chrono::Error>(()) + /// ``` #[inline] #[deprecated(since = "0.4.23", note = "Use `date_naive()` instead")] #[allow(deprecated)] @@ -163,14 +176,14 @@ impl DateTime { /// ``` /// use chrono::prelude::*; /// - /// let date: DateTime = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap(); - /// let other: DateTime = FixedOffset::east_opt(23).unwrap().with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn date_naive(&self) -> NaiveDate { - let local = self.naive_local(); - NaiveDate::from_ymd_opt(local.year(), local.month(), local.day()).unwrap() + self.naive_local().date() } /// Retrieves a time component. @@ -199,11 +212,12 @@ impl DateTime { /// ``` /// use chrono::{Utc, TimeZone, NaiveDate}; /// - /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap(); + /// let dt = Utc.ymd(1970, 1, 1)?.and_hms_milli(0, 0, 1, 444)?; /// assert_eq!(dt.timestamp_millis(), 1_444); /// - /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_milli_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn timestamp_millis(&self) -> i64 { @@ -222,11 +236,12 @@ impl DateTime { /// ``` /// use chrono::{Utc, TimeZone, NaiveDate}; /// - /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_micro_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap(); + /// let dt = Utc.ymd(1970, 1, 1)?.and_hms_micro(0, 0, 1, 444)?; /// assert_eq!(dt.timestamp_micros(), 1_000_444); /// - /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_micro_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn timestamp_micros(&self) -> i64 { @@ -245,11 +260,12 @@ impl DateTime { /// ``` /// use chrono::{Utc, TimeZone, NaiveDate}; /// - /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_nano_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap(); + /// 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 = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn timestamp_nanos(&self) -> i64 { @@ -301,74 +317,70 @@ 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, Error> { 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(crate) 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. + /// Returns `Err(Error)` 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 { 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. /// - /// Returns `None` when it will result in overflow, or if the + /// Returns `Err(Error)` when it will result in overflow, or if the /// 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 { + 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. + /// Returns `Err(Error)` 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 { 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. /// - /// Returns `None` when it will result in overflow, or if the + /// Returns `Err(Error)` when it will result in overflow, or if the /// 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 { + self.naive_local().checked_sub_months(rhs)?.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.naive_local() - .checked_add_days(days)? - .and_local_timezone(TimeZone::from_offset(&self.offset)) - .single() + /// Returns `Err(Error)` if the resulting date would be out of range. + pub fn checked_add_days(self, days: Days) -> Result { + self.datetime.checked_add_days(days)?.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.naive_local() - .checked_sub_days(days)? - .and_local_timezone(TimeZone::from_offset(&self.offset)) - .single() + /// Returns `Err(Error)` if the resulting date would be out of range. + pub fn checked_sub_days(self, days: Days) -> Result { + self.datetime.checked_sub_days(days)?.and_local_timezone(TimeZone::from_offset(&self.offset)) } /// Subtracts another `DateTime` from the current date and time. @@ -415,7 +427,7 @@ impl DateTime { impl Default for DateTime { fn default() -> Self { - Utc.from_utc_datetime(&NaiveDateTime::default()) + Utc.from_utc_datetime_fixed(&NaiveDateTime::default()) } } @@ -423,13 +435,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_opt(0).unwrap().from_utc_datetime(&NaiveDateTime::default()) + FixedOffset::UTC.from_utc_datetime_fixed(&NaiveDateTime::default()) } } @@ -440,19 +453,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_opt(0).unwrap()) + 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 = Error; + /// 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) } } @@ -463,20 +478,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 = Error; + /// 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) } } @@ -489,7 +506,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) } } @@ -502,16 +519,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_opt(0).unwrap()) + 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, Error> 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 { @@ -523,19 +541,17 @@ impl DateTime { /// RFC 2822 is the internet message standard that specifies the representation of times in HTTP /// and email headers. /// - /// The RFC 2822 standard allows arbitrary intermixed whitespace. - /// See [RFC 2822 Appendix A.5] - /// /// ``` /// # use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate}; /// assert_eq!( - /// DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(), - /// FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap() + /// 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>(()) /// ``` /// /// [RFC 2822 Appendix A.5]: https://www.rfc-editor.org/rfc/rfc2822#appendix-A.5 - pub fn parse_from_rfc2822(s: &str) -> ParseResult> { + pub fn parse_from_rfc2822(s: &str) -> Result, Error> { const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC2822)]; let mut parsed = Parsed::new(); parse(&mut parsed, s, ITEMS.iter())?; @@ -555,7 +571,7 @@ impl DateTime { /// instances (rather than periods, ranges, dates, or times). Some valid ISO 8601 values are /// also simultaneously valid RFC 3339 values, but not all RFC 3339 values are valid ISO 8601 /// values (or the other way around). - pub fn parse_from_rfc3339(s: &str) -> ParseResult> { + pub fn parse_from_rfc3339(s: &str) -> Result, Error> { const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC3339)]; let mut parsed = Parsed::new(); parse(&mut parsed, s, ITEMS.iter())?; @@ -572,16 +588,30 @@ impl DateTime { /// See the [`format::strftime` module](./format/strftime/index.html) for supported format /// sequences. /// + /// See also [`TimeZone::datetime_from_str`] which gives a local + /// [`DateTime`] on specific time zone. + /// + /// Note that this method *requires a timezone* in the string. See + /// [`NaiveDateTime::parse_from_str`] + /// for a version that does not require a timezone in the to-be-parsed str. + /// + /// See also [`TimeZone::datetime_from_str`] which gives a local + /// [`DateTime`] on specific time zone. + /// + /// Note that this method *requires a timezone* in the string. See + /// [`NaiveDateTime::parse_from_str`] + /// for a version that does not require a timezone in the to-be-parsed str. + /// /// # Example /// /// ```rust /// use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate}; /// - /// 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_opt(0).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(1983, 4, 13).unwrap().and_hms_milli_opt(12, 9, 14, 274).unwrap()).unwrap())); + /// 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> { + pub fn parse_from_str(s: &str, fmt: &str) -> Result, Error> { let mut parsed = Parsed::new(); parse(&mut parsed, s, StrftimeItems::new(fmt))?; parsed.to_datetime() @@ -597,7 +627,7 @@ impl DateTime { /// /// RFC 2822 is the internet message standard that specifies the representation of times in HTTP /// and email headers. - pub fn parse_from_rfc2822(s: &str) -> ParseResult> { + pub fn parse_from_rfc2822(s: &str) -> Result, Error> { DateTime::::parse_from_rfc2822(s).map(|result| result.into()) } @@ -615,7 +645,7 @@ impl DateTime { /// instances (rather than periods, ranges, dates, or times). Some valid ISO 8601 values are /// also simultaneously valid RFC 3339 values, but not all RFC 3339 values are valid ISO 8601 /// values (or the other way around). - pub fn parse_from_rfc3339(s: &str) -> ParseResult> { + pub fn parse_from_rfc3339(s: &str) -> Result, Error> { DateTime::::parse_from_rfc3339(s).map(|result| result.into()) } @@ -639,7 +669,7 @@ impl DateTime { /// "1983 Apr 13 12:09:14.274 +0100", "%Y %b %d %H:%M:%S%.3f %z"); /// assert_eq!(dt, Ok(Utc.ymd(1983, 4, 13).and_hms_milli(11, 9, 14, 274))); /// ``` - pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult> { + pub fn parse_from_str(s: &str, fmt: &str) -> Result, Error> { DateTime::::parse_from_str(s, fmt).map(|result| result.into()) } } @@ -678,8 +708,8 @@ where /// # Examples /// /// ```rust - /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(18, 30, 9, 453_829).unwrap().and_local_timezone(Utc).unwrap(); + /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc}; + /// 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), @@ -687,10 +717,11 @@ where /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), /// "2018-01-26T18:30:09Z"); /// - /// let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap(); - /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(10, 30, 9, 453_829).unwrap()).unwrap(); + /// 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::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -757,9 +788,10 @@ where /// ```rust /// use chrono::prelude::*; /// - /// let date_time: DateTime = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap(); + /// 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::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -847,37 +879,37 @@ impl Datelike for DateTime { } #[inline] - fn with_year(&self, year: i32) -> Option> { + fn with_year(&self, year: i32) -> Result, Error> { map_local(self, |datetime| datetime.with_year(year)) } #[inline] - fn with_month(&self, month: u32) -> Option> { + fn with_month(&self, month: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_month(month)) } #[inline] - fn with_month0(&self, month0: u32) -> Option> { + fn with_month0(&self, month0: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_month0(month0)) } #[inline] - fn with_day(&self, day: u32) -> Option> { + fn with_day(&self, day: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_day(day)) } #[inline] - fn with_day0(&self, day0: u32) -> Option> { + fn with_day0(&self, day0: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_day0(day0)) } #[inline] - fn with_ordinal(&self, ordinal: u32) -> Option> { + fn with_ordinal(&self, ordinal: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_ordinal(ordinal)) } #[inline] - fn with_ordinal0(&self, ordinal0: u32) -> Option> { + fn with_ordinal0(&self, ordinal0: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_ordinal0(ordinal0)) } } @@ -901,22 +933,22 @@ impl Timelike for DateTime { } #[inline] - fn with_hour(&self, hour: u32) -> Option> { + fn with_hour(&self, hour: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_hour(hour)) } #[inline] - fn with_minute(&self, min: u32) -> Option> { + fn with_minute(&self, min: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_minute(min)) } #[inline] - fn with_second(&self, sec: u32) -> Option> { + fn with_second(&self, sec: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_second(sec)) } #[inline] - fn with_nanosecond(&self, nano: u32) -> Option> { + fn with_nanosecond(&self, nano: u32) -> Result, Error> { map_local(self, |datetime| datetime.with_nanosecond(nano)) } } @@ -941,13 +973,14 @@ impl PartialOrd> for DateTime { /// ``` /// use chrono::prelude::*; /// - /// let earlier = Utc.with_ymd_and_hms(2015, 5, 15, 2, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(1 * 3600).unwrap()); - /// let later = Utc.with_ymd_and_hms(2015, 5, 15, 3, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(5 * 3600).unwrap()); + /// 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::Error>(()) /// ``` fn partial_cmp(&self, other: &DateTime) -> Option { self.datetime.partial_cmp(&other.datetime) @@ -981,7 +1014,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(); } } @@ -1008,7 +1041,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(); } } @@ -1058,7 +1091,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.naive_local().fmt(f)?; - f.write_char(' ')?; + f.write_str(" ")?; self.offset.fmt(f) } } @@ -1075,10 +1108,11 @@ where /// "2012- 12-12T12: 12:12Z".parse::>(); /// ``` impl str::FromStr for DateTime { - type Err = ParseError; + type Err = Error; - fn from_str(s: &str) -> ParseResult> { - s.parse::>().map(|dt| dt.with_timezone(&Utc)) + fn from_str(s: &str) -> Result, Error> { + let dt = s.parse::>()?; + dt.with_timezone(&Utc).map_err(|_| Error::ParsingOutOfRange) } } @@ -1096,10 +1130,11 @@ impl str::FromStr for DateTime { #[cfg(feature = "clock")] #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] impl str::FromStr for DateTime { - type Err = ParseError; + type Err = Error; - fn from_str(s: &str) -> ParseResult> { - s.parse::>().map(|dt| dt.with_timezone(&Local)) + fn from_str(s: &str) -> Result, Error> { + let dt = s.parse::>()?; + dt.with_timezone(&Local).map_err(|_| Error::ParsingOutOfRange) } } @@ -1120,7 +1155,9 @@ impl From for DateTime { } } }; - Utc.timestamp_opt(sec, nsec).unwrap() + + // TODO: remove this conversion since it can panic or can we make it not panic? + Utc.timestamp(sec, nsec).unwrap() } } @@ -1128,7 +1165,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() } } @@ -1162,9 +1200,11 @@ impl From> for SystemTime { not(any(target_os = "emscripten", target_os = "wasi")) ))) )] -impl From for DateTime { - fn from(date: js_sys::Date) -> DateTime { - DateTime::::from(&date) +impl std::convert::TryFrom for DateTime { + type Error = Error; + + fn try_from(date: js_sys::Date) -> Result { + DateTime::::try_from(&date) } } @@ -1181,9 +1221,11 @@ impl From for DateTime { not(any(target_os = "emscripten", target_os = "wasi")) ))) )] -impl From<&js_sys::Date> for DateTime { - fn from(date: &js_sys::Date) -> DateTime { - Utc.timestamp_millis_opt(date.get_time() as i64).unwrap() +impl std::convert::TryFrom<&js_sys::Date> for DateTime { + type Error = Error; + + fn try_from(date: &js_sys::Date) -> Result { + Utc.timestamp_millis(date.get_time() as i64) } } @@ -1227,27 +1269,29 @@ where #[test] fn test_add_sub_months() { - let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); - assert_eq!(utc_dt + Months::new(15), Utc.with_ymd_and_hms(2019, 12, 5, 23, 58, 0).unwrap()); + 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.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap(); - assert_eq!(utc_dt + Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap()); - assert_eq!(utc_dt + Months::new(2), Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap()); + 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.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); - assert_eq!(utc_dt - Months::new(15), Utc.with_ymd_and_hms(2017, 6, 5, 23, 58, 0).unwrap()); + 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.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap(); - assert_eq!(utc_dt - Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap()); - assert_eq!(utc_dt - Months::new(2), Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap()); + 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.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); - let cdt_dt = FixedOffset::west_opt(5 * 60 * 60) + 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() - .with_ymd_and_hms(2018, 9, 5, 18, 58, 0) + .and_hms(18, 58, 0) .unwrap(); let utc_dt2: DateTime = cdt_dt.into(); assert_eq!(utc_dt, utc_dt2); @@ -1261,20 +1305,20 @@ where E: ::core::fmt::Debug, { assert_eq!( - to_string_utc(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).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_opt(3660).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() + &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_opt(3650).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() + &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()) @@ -1299,25 +1343,27 @@ fn test_decodable_json( assert_eq!( norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()), - norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap())) + 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.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap())) + 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_opt(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() + 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_opt(60 * 60 + 23 * 60) + FixedOffset::east(60 * 60 + 23 * 60) + .unwrap() + .ymd(2014, 7, 24) .unwrap() - .with_ymd_and_hms(2014, 7, 24, 13, 57, 6) + .and_hms(13, 57, 6) .unwrap() )) ); @@ -1326,11 +1372,11 @@ fn test_decodable_json( // the conversion didn't change the instant itself assert_eq!( local_from_str(r#""2014-07-24T12:34:06Z""#).expect("local shouuld parse"), - Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() + 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.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() + 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 5a428119ce..9f5167fe53 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 = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap(); +/// 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: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap(), + /// 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(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap()); +/// 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(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap()), + /// 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 = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap(); +/// 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: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap(), + /// 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(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap()); +/// 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(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap()), + /// 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 = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap(); +/// 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: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap(), + /// 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(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap()); +/// 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(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap()), + /// 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.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(); +/// 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.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(), + /// 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.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()); +/// 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.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()), + /// 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.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap(); + 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 5d893e0858..d0b80774a5 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1,681 +1,186 @@ use std::time::{SystemTime, UNIX_EPOCH}; use super::DateTime; +use crate::NaiveTime; #[cfg(feature = "clock")] use crate::offset::Local; use crate::offset::{FixedOffset, TimeZone, Utc}; #[cfg(feature = "clock")] use crate::Datelike; -use crate::{ - naive::{NaiveDate, NaiveTime}, - TimeDelta, -}; -use crate::{Days, LocalResult, Months, NaiveDateTime}; - -#[derive(Clone)] -struct DstTester; - -impl DstTester { - fn winter_offset() -> FixedOffset { - FixedOffset::east_opt(8 * 60 * 60).unwrap() - } - fn summer_offset() -> FixedOffset { - FixedOffset::east_opt(9 * 60 * 60).unwrap() - } - - const TO_WINTER_MONTH_DAY: (u32, u32) = (4, 15); - const TO_SUMMER_MONTH_DAY: (u32, u32) = (9, 15); - - fn transition_start_local() -> NaiveTime { - NaiveTime::from_hms_opt(2, 0, 0).unwrap() - } -} - -impl TimeZone for DstTester { - type Offset = FixedOffset; - - fn from_offset(_: &Self::Offset) -> Self { - DstTester - } - - fn offset_from_local_date(&self, _: &NaiveDate) -> crate::LocalResult { - unimplemented!() - } - - fn offset_from_local_datetime( - &self, - local: &NaiveDateTime, - ) -> crate::LocalResult { - let local_to_winter_transition_start = NaiveDate::from_ymd_opt( - local.year(), - DstTester::TO_WINTER_MONTH_DAY.0, - DstTester::TO_WINTER_MONTH_DAY.1, - ) - .unwrap() - .and_time(DstTester::transition_start_local()); - - let local_to_winter_transition_end = NaiveDate::from_ymd_opt( - local.year(), - DstTester::TO_WINTER_MONTH_DAY.0, - DstTester::TO_WINTER_MONTH_DAY.1, - ) - .unwrap() - .and_time(DstTester::transition_start_local() - TimeDelta::hours(1)); - - let local_to_summer_transition_start = NaiveDate::from_ymd_opt( - local.year(), - DstTester::TO_SUMMER_MONTH_DAY.0, - DstTester::TO_SUMMER_MONTH_DAY.1, - ) - .unwrap() - .and_time(DstTester::transition_start_local()); - - let local_to_summer_transition_end = NaiveDate::from_ymd_opt( - local.year(), - DstTester::TO_SUMMER_MONTH_DAY.0, - DstTester::TO_SUMMER_MONTH_DAY.1, - ) - .unwrap() - .and_time(DstTester::transition_start_local() + TimeDelta::hours(1)); - - if *local < local_to_winter_transition_end || *local >= local_to_summer_transition_end { - LocalResult::Single(DstTester::summer_offset()) - } else if *local >= local_to_winter_transition_start - && *local < local_to_summer_transition_start - { - LocalResult::Single(DstTester::winter_offset()) - } else if *local >= local_to_winter_transition_end - && *local < local_to_winter_transition_start - { - LocalResult::Ambiguous(DstTester::winter_offset(), DstTester::summer_offset()) - } else if *local >= local_to_summer_transition_start - && *local < local_to_summer_transition_end - { - LocalResult::None - } else { - panic!("Unexpected local time {}", local) - } - } - - fn offset_from_utc_date(&self, _: &NaiveDate) -> Self::Offset { - unimplemented!() - } - - fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset { - let utc_to_winter_transition = NaiveDate::from_ymd_opt( - utc.year(), - DstTester::TO_WINTER_MONTH_DAY.0, - DstTester::TO_WINTER_MONTH_DAY.1, - ) - .unwrap() - .and_time(DstTester::transition_start_local()) - - DstTester::summer_offset(); - - let utc_to_summer_transition = NaiveDate::from_ymd_opt( - utc.year(), - DstTester::TO_SUMMER_MONTH_DAY.0, - DstTester::TO_SUMMER_MONTH_DAY.1, - ) - .unwrap() - .and_time(DstTester::transition_start_local()) - - DstTester::winter_offset(); - - if *utc < utc_to_winter_transition || *utc >= utc_to_summer_transition { - DstTester::summer_offset() - } else if *utc >= utc_to_winter_transition && *utc < utc_to_summer_transition { - DstTester::winter_offset() - } else { - panic!("Unexpected utc time {}", utc) - } - } -} - -#[test] -fn test_datetime_add_days() { - let est = FixedOffset::west_opt(5 * 60 * 60).unwrap(); - let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap(); - - assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Days::new(5)), - "2014-05-11 07:08:09 -05:00" - ); - assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Days::new(5)), - "2014-05-11 07:08:09 +09:00" - ); - - assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Days::new(35)), - "2014-06-10 07:08:09 -05:00" - ); - assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Days::new(35)), - "2014-06-10 07:08:09 +09:00" - ); - - assert_eq!( - format!("{}", DstTester.with_ymd_and_hms(2014, 4, 6, 7, 8, 9).unwrap() + Days::new(5)), - "2014-04-11 07:08:09 +09:00" - ); - assert_eq!( - format!("{}", DstTester.with_ymd_and_hms(2014, 4, 6, 7, 8, 9).unwrap() + Days::new(10)), - "2014-04-16 07:08:09 +08:00" - ); - - assert_eq!( - format!("{}", DstTester.with_ymd_and_hms(2014, 9, 6, 7, 8, 9).unwrap() + Days::new(5)), - "2014-09-11 07:08:09 +08:00" - ); - assert_eq!( - format!("{}", DstTester.with_ymd_and_hms(2014, 9, 6, 7, 8, 9).unwrap() + Days::new(10)), - "2014-09-16 07:08:09 +09:00" - ); -} - -#[test] -fn test_datetime_sub_days() { - let est = FixedOffset::west_opt(5 * 60 * 60).unwrap(); - let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap(); - - assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(5)), - "2014-05-01 07:08:09 -05:00" - ); - assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(5)), - "2014-05-01 07:08:09 +09:00" - ); +use crate::TimeDelta; +use crate::NaiveDate; - assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(35)), - "2014-04-01 07:08:09 -05:00" - ); - assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(35)), - "2014-04-01 07:08:09 +09:00" - ); -} - -#[test] -fn test_datetime_add_months() { - let est = FixedOffset::west_opt(5 * 60 * 60).unwrap(); - let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap(); - - assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Months::new(1)), - "2014-06-06 07:08:09 -05:00" - ); - assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Months::new(1)), - "2014-06-06 07:08:09 +09:00" - ); - - assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Months::new(5)), - "2014-10-06 07:08:09 -05:00" - ); - assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Months::new(5)), - "2014-10-06 07:08:09 +09:00" - ); -} - -#[test] -fn test_datetime_sub_months() { - let est = FixedOffset::west_opt(5 * 60 * 60).unwrap(); - let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap(); - - assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Months::new(1)), - "2014-04-06 07:08:09 -05:00" - ); - assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Months::new(1)), - "2014-04-06 07:08:09 +09:00" - ); - - assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Months::new(5)), - "2013-12-06 07:08:09 -05:00" - ); - assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Months::new(5)), - "2013-12-06 07:08:09 +09:00" - ); -} - -// local helper function to easily create a DateTime -fn ymdhms( - fixedoffset: &FixedOffset, - year: i32, - month: u32, - day: u32, - hour: u32, - min: u32, - sec: u32, -) -> DateTime { - fixedoffset.with_ymd_and_hms(year, month, day, hour, min, sec).unwrap() -} - -// local helper function to easily create a DateTime -fn ymdhms_milli( - fixedoffset: &FixedOffset, - year: i32, - month: u32, - day: u32, - hour: u32, - min: u32, - sec: u32, - milli: i64, -) -> DateTime { - fixedoffset - .with_ymd_and_hms(year, month, day, hour, min, sec) - .unwrap() - .checked_add_signed(TimeDelta::milliseconds(milli)) - .unwrap() -} - -// local helper function to easily create a DateTime -fn ymdhms_micro( - fixedoffset: &FixedOffset, - year: i32, - month: u32, - day: u32, - hour: u32, - min: u32, - sec: u32, - micro: i64, -) -> DateTime { - fixedoffset - .with_ymd_and_hms(year, month, day, hour, min, sec) - .unwrap() - .checked_add_signed(TimeDelta::microseconds(micro)) - .unwrap() -} - -// local helper function to easily create a DateTime -fn ymdhms_nano( - fixedoffset: &FixedOffset, - year: i32, - month: u32, - day: u32, - hour: u32, - min: u32, - sec: u32, - nano: i64, -) -> DateTime { - fixedoffset - .with_ymd_and_hms(year, month, day, hour, min, sec) - .unwrap() - .checked_add_signed(TimeDelta::nanoseconds(nano)) - .unwrap() -} - -// local helper function to easily create a DateTime -fn ymdhms_utc(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> DateTime { - Utc.with_ymd_and_hms(year, month, day, hour, min, sec).unwrap() -} - -// local helper function to easily create a DateTime -fn ymdhms_milli_utc( - year: i32, - month: u32, - day: u32, - hour: u32, - min: u32, - sec: u32, - milli: i64, -) -> DateTime { - Utc.with_ymd_and_hms(year, month, day, hour, min, sec) - .unwrap() - .checked_add_signed(TimeDelta::milliseconds(milli)) - .unwrap() +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_opt(5 * 60 * 60).unwrap(); - let edt = FixedOffset::west_opt(4 * 60 * 60).unwrap(); - let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap(); + 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.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()), + format!("{}", Utc.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), "2014-05-06 07:08:09 UTC" ); assert_eq!( - format!("{}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()), + 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.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()), + 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.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()), + format!("{:?}", Utc.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), "2014-05-06T07:08:09Z" ); assert_eq!( - format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()), + format!("{:?}", edt.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), "2014-05-06T07:08:09-04:00" ); assert_eq!( - format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()), + 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.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()), + format!("{:?}", Utc.ymd(2014, 5, 6).unwrap().and_hms(0, 0, 0).unwrap()), "2014-05-06T00:00:00Z" ); assert_eq!( - format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()), + format!("{:?}", edt.ymd(2014, 5, 6).unwrap().and_hms(0, 0, 0).unwrap()), "2014-05-06T00:00:00-04:00" ); assert_eq!( - format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()), + format!("{:?}", kst.ymd(2014, 5, 6).unwrap().and_hms(0, 0, 0).unwrap()), "2014-05-06T00:00:00+09:00" ); assert_eq!( - format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()), + format!("{:?}", Utc.ymd(2014, 5, 6).unwrap().and_hms(23, 59, 59).unwrap()), "2014-05-06T23:59:59Z" ); assert_eq!( - format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()), + format!("{:?}", edt.ymd(2014, 5, 6).unwrap().and_hms(23, 59, 59).unwrap()), "2014-05-06T23:59:59-04:00" ); assert_eq!( - format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()), + format!("{:?}", kst.ymd(2014, 5, 6).unwrap().and_hms(23, 59, 59).unwrap()), "2014-05-06T23:59:59+09:00" ); - let dt = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap(); - assert_eq!(dt, edt.with_ymd_and_hms(2014, 5, 6, 3, 8, 9).unwrap()); + 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 + TimeDelta::seconds(3600 + 60 + 1), - Utc.with_ymd_and_hms(2014, 5, 6, 8, 9, 10).unwrap() + Utc.ymd(2014, 5, 6).unwrap().and_hms(8, 9, 10).unwrap() ); assert_eq!( - dt.signed_duration_since(edt.with_ymd_and_hms(2014, 5, 6, 10, 11, 12).unwrap()), + 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.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset(), Utc); - assert_eq!(*edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset(), edt); - assert!(*edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().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_opt(5 * 60 * 60).unwrap(); - let d = tz.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap(); - assert_eq!(d.time(), NaiveTime::from_hms_opt(7, 8, 9).unwrap()); - assert_eq!(d.date_naive(), NaiveDate::from_ymd_opt(2014, 5, 6).unwrap()); - - let tz = FixedOffset::east_opt(4 * 60 * 60).unwrap(); - let d = tz.with_ymd_and_hms(2016, 5, 4, 3, 2, 1).unwrap(); - assert_eq!(d.time(), NaiveTime::from_hms_opt(3, 2, 1).unwrap()); - assert_eq!(d.date_naive(), NaiveDate::from_ymd_opt(2016, 5, 4).unwrap()); - - let tz = FixedOffset::west_opt(13 * 60 * 60).unwrap(); - let d = tz.with_ymd_and_hms(2017, 8, 9, 12, 34, 56).unwrap(); - assert_eq!(d.time(), NaiveTime::from_hms_opt(12, 34, 56).unwrap()); - assert_eq!(d.date_naive(), NaiveDate::from_ymd_opt(2017, 8, 9).unwrap()); - - let utc_d = Utc.with_ymd_and_hms(2017, 8, 9, 12, 34, 56).unwrap(); + 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() { - let edt = FixedOffset::east_opt(5 * 60 * 60).unwrap(); - - // timezone 0 +fn test_datetime_rfc2822_and_rfc3339() { + let edt = FixedOffset::east(5 * 60 * 60).unwrap(); assert_eq!( - Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc2822(), + Utc.ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap().to_rfc2822(), "Wed, 18 Feb 2015 23:16:09 +0000" ); - // timezone +05 - assert_eq!( - edt.from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 16, 9, 150) - .unwrap() - ) - .unwrap() - .to_rfc2822(), - "Wed, 18 Feb 2015 23:16:09 +0500" - ); - // seconds 60 - assert_eq!( - edt.from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_micro_opt(23, 59, 59, 1_234_567) - .unwrap() - ) - .unwrap() - .to_rfc2822(), - "Wed, 18 Feb 2015 23:59:60 +0500" - ); - - assert_eq!( - DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"), - Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()) - ); - assert_eq!( - DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000"), - Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()) - ); - assert_eq!( - ymdhms_milli(&edt, 2015, 2, 18, 23, 59, 58, 1_234_567).to_rfc2822(), - "Thu, 19 Feb 2015 00:20:32 +0500" - ); assert_eq!( - DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:58 +0500"), - Ok(ymdhms(&edt, 2015, 2, 18, 23, 59, 58)) - ); - assert_ne!( - DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:58 +0500"), - Ok(ymdhms_milli(&edt, 2015, 2, 18, 23, 59, 58, 500)) - ); - - // many varying whitespace intermixed - assert_eq!( - DateTime::::parse_from_rfc2822( - "\t\t\tWed,\n\t\t18 \r\n\t\tFeb \u{3000} 2015\r\n\t\t\t23:59:58 \t+0500" - ), - Ok(ymdhms(&edt, 2015, 2, 18, 23, 59, 58)) - ); - // example from RFC 2822 Appendix A.5. - assert_eq!( - DateTime::::parse_from_rfc2822( - "Thu,\n\t13\n Feb\n 1969\n 23:32\n -0330 (Newfoundland Time)" - ), - Ok( - ymdhms( - &FixedOffset::east_opt(-3 * 60 * 60 - 30 * 60).unwrap(), - 1969, 2, 13, 23, 32, 0, - ) - ) - ); - // example from RFC 2822 Appendix A.5. without trailing " (Newfoundland Time)" - assert_eq!( - DateTime::::parse_from_rfc2822( - "Thu,\n\t13\n Feb\n 1969\n 23:32\n -0330" - ), - Ok( - ymdhms(&FixedOffset::east_opt(-3 * 60 * 60 - 30 * 60).unwrap(), 1969, 2, 13, 23, 32, 0,) - ) - ); - - // bad year - assert!(DateTime::::parse_from_rfc2822("31 DEC 262143 23:59 -2359").is_err()); - // wrong format - assert!( - DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +00:00").is_err() - ); - // full name day of week - assert!(DateTime::::parse_from_rfc2822("Wednesday, 18 Feb 2015 23:16:09 +0000") - .is_err()); - // full name day of week - assert!(DateTime::::parse_from_rfc2822("Wednesday 18 Feb 2015 23:16:09 +0000") - .is_err()); - // wrong day of week separator '.' - assert!(DateTime::::parse_from_rfc2822("Wed. 18 Feb 2015 23:16:09 +0000").is_err()); - // *trailing* space causes failure - assert!( - DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000 ").is_err() - ); -} - -#[test] -fn test_datetime_rfc3339() { - let edt5 = FixedOffset::east_opt(5 * 60 * 60).unwrap(); - let edt0 = FixedOffset::east_opt(0).unwrap(); - - // timezone 0 - assert_eq!( - Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc3339(), + Utc.ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap().to_rfc3339(), "2015-02-18T23:16:09+00:00" ); - // timezone +05 assert_eq!( - edt5.from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 16, 9, 150) - .unwrap() - ) - .unwrap() - .to_rfc3339(), - "2015-02-18T23:16:09.150+05:00" + 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!(ymdhms_utc(2015, 2, 18, 23, 16, 9).to_rfc3339(), "2015-02-18T23:16:09+00:00"); assert_eq!( - ymdhms_milli(&edt5, 2015, 2, 18, 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!( - ymdhms_micro(&edt5, 2015, 2, 18, 23, 59, 59, 1_234_567).to_rfc3339(), - "2015-02-19T00:00:00.234567+05:00" - ); - assert_eq!( - DateTime::::parse_from_rfc3339("2015-02-18T23:59:59.123+05:00"), - Ok(ymdhms_micro(&edt5, 2015, 2, 18, 23, 59, 59, 123_000)) - ); - assert_eq!( - DateTime::::parse_from_rfc3339("2015-02-18T23:59:59.123456+05:00"), - Ok(ymdhms_micro(&edt5, 2015, 2, 18, 23, 59, 59, 123_456)) - ); - assert_eq!( - DateTime::::parse_from_rfc3339("2015-02-18T23:59:59.123456789+05:00"), - Ok(ymdhms_nano(&edt5, 2015, 2, 18, 23, 59, 59, 123_456_789)) + 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!( - DateTime::::parse_from_rfc3339("2015-02-18T23:16:09Z"), - Ok(ymdhms(&edt0, 2015, 2, 18, 23, 16, 9)) + 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!( - ymdhms_micro(&edt5, 2015, 2, 18, 23, 59, 59, 1_234_567).to_rfc3339(), - "2015-02-19T00:00:00.234567+05:00" - ); - assert_eq!( - ymdhms_milli(&edt5, 2015, 2, 18, 23, 16, 9, 150).to_rfc3339(), - "2015-02-18T23:16:09.150+05:00" + DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"), + Ok(FixedOffset::east(0).unwrap().ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap()) ); assert_eq!( - DateTime::::parse_from_rfc3339("2015-02-18T00:00:00.234567+05:00"), - Ok(ymdhms_micro(&edt5, 2015, 2, 18, 0, 0, 0, 234_567)) + DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000"), + 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(ymdhms(&edt0, 2015, 2, 18, 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(edt5 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 59, 59, 1_000) - .unwrap() - ) - .unwrap()) + 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(edt5 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_micro_opt(23, 59, 59, 1_234_567) - .unwrap() - ) - .unwrap()) - ); - assert_eq!(ymdhms_utc(2015, 2, 18, 23, 16, 9).to_rfc3339(), "2015-02-18T23:16:09+00:00"); - - assert!( - DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567 +05:00").is_err() - ); - assert!( - DateTime::::parse_from_rfc3339("2015-02-18T23:059:60.234567+05:00").is_err() - ); - assert!( - DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00PST").is_err() - ); - assert!(DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567+PST").is_err()); - assert!(DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567PST").is_err()); - assert!(DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567+0500").is_err()); - assert!( - DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00:00").is_err() - ); - assert!( - DateTime::::parse_from_rfc3339("2015-02-18 23:59:60.234567+05:00").is_err() - ); - assert!( - DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567:+05:00").is_err() - ); - assert!( - DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00 ").is_err() - ); - assert!( - DateTime::::parse_from_rfc3339(" 2015-02-18T23:59:60.234567+05:00").is_err() - ); - assert!( - DateTime::::parse_from_rfc3339("2015- 02-18T23:59:60.234567+05:00").is_err() - ); - assert!( - DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567A+05:00").is_err() + 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_opt(8 * 60 * 60).unwrap(); - let dt = pst - .from_local_datetime( - &NaiveDate::from_ymd_opt(2018, 1, 11) - .unwrap() - .and_hms_nano_opt(10, 5, 13, 84_660_000) - .unwrap(), - ) - .unwrap(); + 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"); @@ -697,7 +202,7 @@ fn test_rfc3339_opts() { #[should_panic] fn test_rfc3339_opts_nonexhaustive() { use crate::SecondsFormat; - let dt = Utc.with_ymd_and_hms(1999, 10, 9, 1, 2, 3).unwrap(); + let dt = Utc.ymd(1999, 10, 9).unwrap().and_hms(1, 2, 3).unwrap(); dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true); } @@ -705,97 +210,53 @@ fn test_rfc3339_opts_nonexhaustive() { fn test_datetime_from_str() { assert_eq!( "2015-02-18T23:16:9.15Z".parse::>(), - Ok(FixedOffset::east_opt(0) + Ok(FixedOffset::east(0) .unwrap() - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 16, 9, 150) - .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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 16, 9, 150) - .unwrap() - ) - .unwrap()) + 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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 16, 9, 150) - .unwrap() - ) - .unwrap()) + 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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 16, 9, 150) - .unwrap() - ) - .unwrap()) + 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_opt(0) + Ok(FixedOffset::east(0) + .unwrap() + .ymd(2015, 2, 18) .unwrap() - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 16, 9, 150) - .unwrap() - ) + .and_hms_milli(23, 16, 9, 150) .unwrap()) ); assert_eq!( "2015-2-18T13:16:9.15-10:00".parse::>(), - Ok(FixedOffset::west_opt(10 * 3600) + Ok(FixedOffset::west(10 * 3600) .unwrap() - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(13, 16, 9, 150) - .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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 16, 9, 150) - .unwrap() - ) - .unwrap()) + 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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2015, 2, 18) - .unwrap() - .and_hms_milli_opt(23, 16, 9, 150) - .unwrap() - ) - .unwrap()) + 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()); @@ -803,106 +264,13 @@ fn test_datetime_from_str() { } #[test] -fn test_parse_datetime_utc() { - // valid cases - let valid = [ - "2001-02-03T04:05:06Z", - "2001-02-03T04:05:06+0000", - "2001-02-03T04:05:06-00:00", - "2001-02-03T04:05:06-00 00", - "2001-02-03T04:05:06-01:00", - "2001-02-03T04:05:06-01: 00", - "2001-02-03T04:05:06-01 :00", - "2001-02-03T04:05:06-01 : 00", - "2012-12-12T12:12:12Z", - "2015-02-18T23:16:09.153Z", - "2015-2-18T23:16:09.153Z", - "+2015-2-18T23:16:09.153Z", - "-77-02-18T23:16:09Z", - "+82701-05-6T15:9:60.898989898989Z", - ]; - for &s in &valid { - eprintln!("test_parse_datetime_utc valid {:?}", s); - let d = match s.parse::>() { - Ok(d) => d, - Err(e) => panic!("parsing `{}` has failed: {}", s, e), - }; - let s_ = format!("{:?}", d); - // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same - let d_ = match s_.parse::>() { - Ok(d) => d, - Err(e) => { - panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e) - } - }; - assert!( - d == d_, - "`{}` is parsed into `{:?}`, but reparsed result \ - `{:?}` does not match", - s, - d, - d_ - ); - } - - // some invalid cases - // since `ParseErrorKind` is private, all we can do is to check if there was an error - let invalid = [ - "", // empty - "Z", // missing data - "15Z", // missing data - "15:8:9Z", // missing date - "15-8-9Z", // missing time or date - "Fri, 09 Aug 2013 23:54:35 GMT", // valid datetime, wrong format - "Sat Jun 30 23:59:60 2012", // valid datetime, wrong format - "1441497364.649", // valid datetime, wrong format - "+1441497364.649", // valid datetime, wrong format - "+1441497364", // valid datetime, wrong format - "+1441497364Z", // valid datetime, wrong format - "2014/02/03 04:05:06Z", // valid datetime, wrong format - "2001-02-03T04:05:0600:00", // valid datetime, timezone too close - "2015-15-15T15:15:15Z", // invalid datetime - "2012-12-12T12:12:12x", // invalid timezone - "2012-123-12T12:12:12Z", // invalid month - "2012-12-77T12:12:12Z", // invalid day - "2012-12-12T26:12:12Z", // invalid hour - "2012-12-12T12:61:12Z", // invalid minute - "2012-12-12T12:12:62Z", // invalid second - "2012-12-12 T12:12:12Z", // space after date - "2012-12-12t12:12:12Z", // wrong divider 't' - "2012-12-12T12:12:12ZZ", // trailing literal 'Z' - "+802701-12-12T12:12:12Z", // invalid year (out of bounds) - "+ 2012-12-12T12:12:12Z", // invalid space before year - "2012 -12-12T12:12:12Z", // space after year - "2012 -12-12T12:12:12Z", // multi space after year - "2012- 12-12T12:12:12Z", // space after year divider - "2012- 12-12T12:12:12Z", // multi space after year divider - "2012-12-12T 12:12:12Z", // space after date-time divider - "2012-12-12T12 :12:12Z", // space after hour - "2012-12-12T12 :12:12Z", // multi space after hour - "2012-12-12T12: 12:12Z", // space before minute - "2012-12-12T12: 12:12Z", // multi space before minute - "2012-12-12T12 : 12:12Z", // space space before and after hour-minute divider - "2012-12-12T12:12:12Z ", // trailing space - " 2012-12-12T12:12:12Z", // leading space - "2001-02-03T04:05:06-01 : 00", // invalid timezone spacing - "2001-02-03T04:05:06-01 : :00", // invalid timezone spacing - " +82701 - 05 - 6 T 15 : 9 : 60.898989898989 Z", // valid datetime, wrong format - ]; - for &s in invalid.iter() { - eprintln!("test_parse_datetime_utc invalid {:?}", s); - assert!(s.parse::>().is_err()); - } -} - -#[test] -fn test_utc_datetime_from_str() { - let edt = FixedOffset::east_opt(570 * 60).unwrap(); - let edt0 = FixedOffset::east_opt(0).unwrap(); - let wdt = FixedOffset::west_opt(10 * 3600).unwrap(); +fn test_datetime_parse_from_str() { + 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(&edt, 2014, 5, 7, 12, 34, 56)) + Ok(ymdhms(2014, 5, 7, 12, 34, 56, 570 * 60)) ); // ignore offset assert!(DateTime::::parse_from_str("20140507000000", "%Y%m%d%H%M%S").is_err()); // no offset assert!(DateTime::::parse_from_str( @@ -912,592 +280,7 @@ fn test_utc_datetime_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.with_ymd_and_hms(2013, 8, 9, 23, 54, 35).unwrap()) - ); - - assert_eq!( - "2015-02-18T23:16:9.15Z".parse::>(), - Ok(ymdhms_milli(&edt0, 2015, 2, 18, 23, 16, 9, 150)) - ); - assert_eq!( - "2015-02-18T23:16:9.15Z".parse::>(), - Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)), - ); - assert_eq!( - "2015-02-18T23:16:9.15 UTC".parse::>(), - Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)) - ); - assert_eq!( - "2015-02-18T23:16:9.15UTC".parse::>(), - Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)) - ); - - assert_eq!( - "2015-2-18T23:16:9.15Z".parse::>(), - Ok(ymdhms_milli(&edt0, 2015, 2, 18, 23, 16, 9, 150)) - ); - assert_eq!( - "2015-2-18T13:16:9.15-10:00".parse::>(), - Ok(ymdhms_milli(&wdt, 2015, 2, 18, 13, 16, 9, 150)) - ); - assert!("2015-2-18T23:16:9.15".parse::>().is_err()); - - assert_eq!( - "2015-2-18T23:16:9.15Z".parse::>(), - Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)) - ); - assert_eq!( - "2015-2-18T13:16:9.15-10:00".parse::>(), - Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)) - ); - assert!("2015-2-18T23:16:9.15".parse::>().is_err()); - - // no test for `DateTime`, we cannot verify that much. -} - -#[test] -fn test_utc_datetime_from_str_with_spaces() { - let dt = ymdhms_utc(2013, 8, 9, 23, 54, 35); - // with varying spaces - should succeed - assert_eq!(Utc.datetime_from_str(" Aug 09 2013 23:54:35", " %b %d %Y %H:%M:%S"), Ok(dt),); - assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35 ", "%b %d %Y %H:%M:%S "), Ok(dt),); - assert_eq!(Utc.datetime_from_str(" Aug 09 2013 23:54:35 ", " %b %d %Y %H:%M:%S "), Ok(dt),); - assert_eq!(Utc.datetime_from_str(" Aug 09 2013 23:54:35", " %b %d %Y %H:%M:%S"), Ok(dt),); - assert_eq!(Utc.datetime_from_str(" Aug 09 2013 23:54:35", " %b %d %Y %H:%M:%S"), Ok(dt),); - assert_eq!( - Utc.datetime_from_str("\n\tAug 09 2013 23:54:35 ", "\n\t%b %d %Y %H:%M:%S "), - Ok(dt), - ); - assert_eq!(Utc.datetime_from_str("\tAug 09 2013 23:54:35\t", "\t%b %d %Y %H:%M:%S\t"), Ok(dt),); - assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S"), Ok(dt),); - assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S"), Ok(dt),); - assert_eq!(Utc.datetime_from_str("Aug 09 2013\t23:54:35", "%b %d %Y\t%H:%M:%S"), Ok(dt),); - assert_eq!(Utc.datetime_from_str("Aug 09 2013\t\t23:54:35", "%b %d %Y\t\t%H:%M:%S"), Ok(dt),); - // with varying spaces - should fail - // leading whitespace in format - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35", " %b %d %Y %H:%M:%S").is_err()); - // trailing whitespace in format - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S ").is_err()); - // extra mid-string whitespace in format - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S").is_err()); - // mismatched leading whitespace - assert!(Utc.datetime_from_str("\tAug 09 2013 23:54:35", "\n%b %d %Y %H:%M:%S").is_err()); - // mismatched trailing whitespace - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35 ", "%b %d %Y %H:%M:%S\n").is_err()); - // mismatched mid-string whitespace - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y\t%H:%M:%S").is_err()); - // trailing whitespace in format - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S ").is_err()); - // trailing whitespace (newline) in format - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S\n").is_err()); - // leading space in data - assert!(Utc.datetime_from_str(" Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S").is_err()); - // trailing space in data - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35 ", "%b %d %Y %H:%M:%S").is_err()); - // trailing tab in data - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35\t", "%b %d %Y %H:%M:%S").is_err()); - // mismatched newlines - assert!(Utc.datetime_from_str("\nAug 09 2013 23:54:35", "%b %d %Y %H:%M:%S\n").is_err()); - // trailing literal in data - assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35 !!!", "%b %d %Y %H:%M:%S ").is_err()); -} - -#[test] -fn test_datetime_parse_from_str() { - let dt = ymdhms(&FixedOffset::east_opt(-9 * 60 * 60).unwrap(), 2013, 8, 9, 23, 54, 35); - - // timezone variations - - // - // %Z - // - // wrong timezone format - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900", - "%b %d %Y %H:%M:%S %Z" - ) - .is_err()); - // bad timezone data? - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 PST", - "%b %d %Y %H:%M:%S %Z" - ) - .is_err()); - // bad timezone data - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 XXXXX", - "%b %d %Y %H:%M:%S %Z" - ) - .is_err()); - - // - // %z - // - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900", - "%b %d %Y %H:%M:%S %z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 00", - "%b %d %Y %H:%M:%S %z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00", - "%b %d %Y %H:%M:%S %z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 : 00", - "%b %d %Y %H:%M:%S %z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 --0900", - "%b %d %Y %H:%M:%S -%z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 +-0900", - "%b %d %Y %H:%M:%S +%z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00 ", - "%b %d %Y %H:%M:%S %z " - ), - Ok(dt), - ); - // trailing newline after timezone - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00\n", - "%b %d %Y %H:%M:%S %z" - ) - .is_err()); - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00\n", - "%b %d %Y %H:%M:%S %z " - ) - .is_err()); - // trailing colon - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:", - "%b %d %Y %H:%M:%S %z" - ) - .is_err()); - // trailing colon with space - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00: ", - "%b %d %Y %H:%M:%S %z " - ) - .is_err()); - // trailing colon, mismatch space - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:", - "%b %d %Y %H:%M:%S %z " - ) - .is_err()); - // wrong timezone data - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09", - "%b %d %Y %H:%M:%S %z" - ) - .is_err()); - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09::00", - "%b %d %Y %H:%M:%S %z" - ) - .is_err()); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900::", - "%b %d %Y %H:%M:%S %z::" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:00", - "%b %d %Y %H:%M:%S %z:00" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:00 ", - "%b %d %Y %H:%M:%S %z:00 " - ), - Ok(dt), - ); - - // - // %:z - // - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00", - "%b %d %Y %H:%M:%S %:z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900", - "%b %d %Y %H:%M:%S %:z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 00", - "%b %d %Y %H:%M:%S %:z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 : 00", - "%b %d %Y %H:%M:%S %:z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 : 00:", - "%b %d %Y %H:%M:%S %:z:" - ), - Ok(dt), - ); - // wrong timezone data - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09", - "%b %d %Y %H:%M:%S %:z" - ) - .is_err()); - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09::00", - "%b %d %Y %H:%M:%S %:z" - ) - .is_err()); - // timezone data hs too many colons - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:", - "%b %d %Y %H:%M:%S %:z" - ) - .is_err()); - // timezone data hs too many colons - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00::", - "%b %d %Y %H:%M:%S %:z" - ) - .is_err()); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00::", - "%b %d %Y %H:%M:%S %:z::" - ), - Ok(dt), - ); - - // - // %:::z - // - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900", - "%b %d %Y %H:%M:%S %::z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00", - "%b %d %Y %H:%M:%S %::z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 : 00", - "%b %d %Y %H:%M:%S %::z" - ), - Ok(dt), - ); - // mismatching colon expectations - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:00", - "%b %d %Y %H:%M:%S %::z" - ) - .is_err()); - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09::00", - "%b %d %Y %H:%M:%S %::z" - ) - .is_err()); - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09::00", - "%b %d %Y %H:%M:%S %:z" - ) - .is_err()); - // wrong timezone data - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09", - "%b %d %Y %H:%M:%S %::z" - ) - .is_err()); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09001234", - "%b %d %Y %H:%M:%S %::z1234" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:001234", - "%b %d %Y %H:%M:%S %::z1234" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900 ", - "%b %d %Y %H:%M:%S %::z " - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900\t\n", - "%b %d %Y %H:%M:%S %::z\t\n" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900:", - "%b %d %Y %H:%M:%S %::z:" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 :-0900:0", - "%b %d %Y %H:%M:%S :%::z:0" - ), - Ok(dt), - ); - // mismatching colons and spaces - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 :-0900: ", - "%b %d %Y %H:%M:%S :%::z::" - ) - .is_err()); - // mismatching colons expectations - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:00", - "%b %d %Y %H:%M:%S %::z" - ) - .is_err()); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 -0900: 23:54:35", - "%b %d %Y %::z: %H:%M:%S" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 :-0900:0 23:54:35", - "%b %d %Y :%::z:0 %H:%M:%S" - ), - Ok(dt), - ); - // mismatching colons expectations mid-string - assert!(DateTime::::parse_from_str( - "Aug 09 2013 :-0900: 23:54:35", - "%b %d %Y :%::z %H:%M:%S" - ) - .is_err()); - // mismatching colons expectations, before end - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:00 ", - "%b %d %Y %H:%M:%S %::z " - ) - .is_err()); - - // - // %:::z - // - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00", - "%b %d %Y %H:%M:%S %:::z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900", - "%b %d %Y %H:%M:%S %:::z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900 ", - "%b %d %Y %H:%M:%S %:::z " - ), - Ok(dt), - ); - // wrong timezone data - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09", - "%b %d %Y %H:%M:%S %:::z" - ) - .is_err()); - - // - // %::::z - // - // too many colons - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900", - "%b %d %Y %H:%M:%S %::::z" - ) - .is_err()); - // too many colons - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00", - "%b %d %Y %H:%M:%S %::::z" - ) - .is_err()); - // too many colons - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:", - "%b %d %Y %H:%M:%S %::::z" - ) - .is_err()); - // too many colons - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00:00", - "%b %d %Y %H:%M:%S %::::z" - ) - .is_err()); - - // - // %#z - // - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00", - "%b %d %Y %H:%M:%S %#z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900", - "%b %d %Y %H:%M:%S %#z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:00 ", - "%b %d %Y %H:%M:%S %#z " - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900 ", - "%b %d %Y %H:%M:%S %#z " - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09", - "%b %d %Y %H:%M:%S %#z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -0900", - "%b %d %Y %H:%M:%S %#z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09:", - "%b %d %Y %H:%M:%S %#z" - ), - Ok(dt), - ); - assert!(DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09: ", - "%b %d %Y %H:%M:%S %#z " - ) - .is_err()); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35+-09", - "%b %d %Y %H:%M:%S+%#z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35--09", - "%b %d %Y %H:%M:%S-%#z" - ), - Ok(dt), - ); - assert!(DateTime::::parse_from_str( - "Aug 09 2013 -09:00 23:54:35", - "%b %d %Y %#z%H:%M:%S" - ) - .is_err()); - assert!(DateTime::::parse_from_str( - "Aug 09 2013 -0900 23:54:35", - "%b %d %Y %#z%H:%M:%S" - ) - .is_err()); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 -090023:54:35", - "%b %d %Y %#z%H:%M:%S" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 -09:0023:54:35", - "%b %d %Y %#z%H:%M:%S" - ), - Ok(dt), - ); - // timezone with partial minutes adjacent hours - assert_ne!( - DateTime::::parse_from_str("Aug 09 2013 -09023:54:35", "%b %d %Y %#z%H:%M:%S"), - Ok(dt), + Ok(Utc.ymd(2013, 8, 9).unwrap().and_hms(23, 54, 35).unwrap()) ); // bad timezone data assert!(DateTime::::parse_from_str( @@ -1539,20 +322,20 @@ fn test_datetime_parse_from_str() { #[test] fn test_to_string_round_trip() { - let dt = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap(); + 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_opt(3600).unwrap()); + 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_opt(0).unwrap()); + 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(); } @@ -1560,15 +343,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); } @@ -1589,14 +372,7 @@ fn test_datetime_is_send() { #[test] fn test_subsecond_part() { - let datetime = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2014, 7, 8) - .unwrap() - .and_hms_nano_opt(9, 10, 11, 1234567) - .unwrap(), - ) - .unwrap(); + 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()); @@ -1608,67 +384,42 @@ fn test_subsecond_part() { fn test_from_system_time() { use std::time::Duration; - let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap(); + 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.from_local_datetime( - &NaiveDate::from_ymd_opt(2001, 9, 9) - .unwrap() - .and_hms_nano_opt(1, 46, 39, nanos) - .unwrap() - ) - .unwrap() + 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.from_local_datetime( - &NaiveDate::from_ymd_opt(1938, 4, 24).unwrap().and_hms_nano_opt(22, 13, 20, 1).unwrap() - ) - .unwrap() + 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.from_local_datetime( - &NaiveDate::from_ymd_opt(2001, 9, 9) - .unwrap() - .and_hms_nano_opt(1, 46, 39, nanos) - .unwrap() - ) - .unwrap() - ), + 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.from_local_datetime( - &NaiveDate::from_ymd_opt(1938, 4, 24) - .unwrap() - .and_hms_nano_opt(22, 13, 20, 1) - .unwrap() - ) - .unwrap() - ), + 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_opt(32400).unwrap())), + SystemTime::from(epoch.with_fixed_timezone(&FixedOffset::east(32400).unwrap())), UNIX_EPOCH ); assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::west_opt(28800).unwrap())), + SystemTime::from(epoch.with_fixed_timezone(&FixedOffset::west(28800).unwrap())), UNIX_EPOCH ); } @@ -1676,80 +427,59 @@ fn test_from_system_time() { #[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.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap(); + 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.from_local_datetime( - &NaiveDate::from_ymd_opt(2001, 9, 9) - .unwrap() - .and_hms_nano_opt(1, 46, 39, nanos) - .unwrap() - ) - .unwrap() + 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.from_local_datetime( - &NaiveDate::from_ymd_opt(1938, 4, 24) - .unwrap() - .and_hms_nano_opt(22, 13, 20, 1_000) - .unwrap() - ) - .unwrap() + 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.from_local_datetime( - &NaiveDate::from_ymd_opt(2001, 9, 9) - .unwrap() - .and_hms_nano_opt(1, 46, 39, nanos) - .unwrap() - ) - .unwrap() - ), + 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.from_local_datetime( - &NaiveDate::from_ymd_opt(1938, 4, 24) - .unwrap() - .and_hms_nano_opt(22, 13, 20, 1_000) - .unwrap() - ) - .unwrap() - ), + 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_opt(32400).unwrap())), + SystemTime::try_from(epoch.with_fixed_timezone(&FixedOffset::east(32400).unwrap())) + .unwrap(), UNIX_EPOCH ); assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::west_opt(28800).unwrap())), + SystemTime::try_from(epoch.with_fixed_timezone(&FixedOffset::west(28800).unwrap())) + .unwrap(), UNIX_EPOCH ); } #[test] fn test_datetime_format_alignment() { - let datetime = Utc.with_ymd_and_hms(2007, 1, 2, 0, 0, 0).unwrap(); + let datetime = Utc.ymd(2007, 1, 2).unwrap().unwrap(); // Item::Literal let percent = datetime.format("%%"); @@ -1780,24 +510,21 @@ fn test_datetime_format_alignment() { #[test] fn test_datetime_from_local() { // 2000-01-12T02:00:00Z - let naivedatetime_utc = - NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(2, 0, 0).unwrap(); + 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_opt(8 * 60 * 60).unwrap(); - let naivedatetime_east = - NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(10, 0, 0).unwrap(); + 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_opt(7 * 60 * 60).unwrap(); - let naivedatetime_west = - NaiveDate::from_ymd_opt(2000, 1, 11).unwrap().and_hms_opt(19, 0, 0).unwrap(); + 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] @@ -1807,37 +534,37 @@ fn test_years_elapsed() { // This is always at least one year because 1 year = 52.1775 weeks. let one_year_ago = - Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); + Utc::today().unwrap() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); // A bit more than 2 years. let two_year_ago = - Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); + Utc::today().unwrap() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); - assert_eq!(Utc::now().date_naive().years_since(one_year_ago), Some(1)); - assert_eq!(Utc::now().date_naive().years_since(two_year_ago), Some(2)); + 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::now().date_naive() + TimeDelta::weeks(12); - assert_eq!(Utc::now().date_naive().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_opt(2000, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); + 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_opt(60 * 60).unwrap(); - 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_opt(2 * 60 * 60).unwrap(); - 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)); } @@ -1845,10 +572,10 @@ fn test_datetime_add_assign() { #[test] #[cfg(feature = "clock")] fn test_datetime_add_assign_local() { - let naivedatetime = NaiveDate::from_ymd_opt(2022, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); + 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 { @@ -1859,22 +586,22 @@ fn test_datetime_add_assign_local() { #[test] fn test_datetime_sub_assign() { - let naivedatetime = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(12, 0, 0).unwrap(); + 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_opt(60 * 60).unwrap(); - 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_opt(2 * 60 * 60).unwrap(); - 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)); } @@ -1882,10 +609,10 @@ fn test_datetime_sub_assign() { #[test] #[cfg(feature = "clock")] fn test_datetime_sub_assign_local() { - let naivedatetime = NaiveDate::from_ymd_opt(2022, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); + 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..ebda37e6d6 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,186 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +use core::{fmt, num::{TryFromIntError, ParseIntError}, str::Utf8Error}; +use std::time::SystemTimeError; + +/// Chrono error +#[derive(Debug, PartialEq)] +pub enum Error { + /// Invalid date + InvalidDate, + /// Invalid time + InvalidTime, + /// Invalid date time + InvalidDateTime, + /// Invalid time zone + InvalidTimeZone, + /// Ambigious date + AmbiguousDate, + /// Missing date + #[cfg(all(unix, feature = "clock"))] + MissingDate, + #[cfg(all(windows, feature = "clock"))] + SystemTimeBeforeEpoch, + #[cfg(all(windows, feature = "clock"))] + SystemError(std::io::Error), + + /// Given field is out of permitted range. + ParsingOutOfRange, + + /// There is no possible date and time value with given set of fields. + /// + /// This does not include the out-of-range conditions, which are trivially invalid. + /// It includes the case that there are one or more fields that are inconsistent to each other. + ParsingImpossible, + + /// Given set of fields is not enough to make a requested date and time value. + /// + /// Note that there *may* be a case that given fields constrain the possible values so much + /// that there is a unique possible value. Chrono only tries to be correct for + /// most useful sets of fields however, as such constraint solving can be expensive. + ParsingNotEnough, + + /// The input string has some invalid character sequence for given formatting items. + ParsingInvalid, + + /// The input string has been prematurely ended. + ParsingTooShort, + + /// All formatting items have been read but there is a remaining input. + ParsingTooLong, + + /// There was an error on the formatting string, or there were non-supported formating items. + ParsingBadFormat, + + /// Date time error + DateTime(&'static str), + /// Local time type search error + FindLocalTimeType(&'static str), + /// Local time type error + LocalTimeType(&'static str), + /// Invalid slice for integer conversion + InvalidSlice(&'static str), + /// Invalid Tzif file + InvalidTzFile(&'static str), + /// Invalid TZ string + InvalidTzString(&'static str), + /// I/O error + Io(std::io::ErrorKind), + /// Out of range error + OutOfRange(&'static str), + /// Integer parsing error + ParseInt(ParseIntError), + /// Date time projection error + ProjectDateTime(&'static str), + /// System time error + SystemTime, + /// Time zone error + TimeZone(&'static str), + /// Transition rule error + TransitionRule(&'static str), + /// Unsupported Tzif file + UnsupportedTzFile(&'static str), + /// Unsupported TZ string + UnsupportedTzString(&'static str), + /// UTF-8 error + Utf8(Utf8Error), + + /// Error when tryint to convert from int + TryFromIntError(TryFromIntError), + + /// Unexpected end of file + UnexpectedEOF, + + /// Invalid data + InvalidData, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::InvalidDate => write!(f, "invalid date"), + Error::InvalidTime => write!(f, "invalid time"), + Error::InvalidDateTime => write!(f, "invalid date time"), + Error::InvalidTimeZone => write!(f, "invalid time zone"), + Error::AmbiguousDate => write!(f, "tried to operate over ambiguous date"), + #[cfg(all(unix, feature = "clock"))] + Error::MissingDate => write!(f, "missing date"), + #[cfg(all(windows, feature = "clock"))] + Error::SystemTimeBeforeEpoch => write!(f, "system time before Unix epoch"), + #[cfg(all(windows, feature = "clock"))] + + Error::SystemError(error) => write!(f, "system error: {}", error), + Error::ParsingOutOfRange => write!(f, "input is out of range"), + Error::ParsingImpossible => write!(f, "no possible date and time matching input"), + Error::ParsingNotEnough => write!(f, "input is not enough for unique date and time"), + Error::ParsingInvalid => write!(f, "input contains invalid characters"), + Error::ParsingTooShort => write!(f, "premature end of input"), + Error::ParsingTooLong => write!(f, "trailing input"), + Error::ParsingBadFormat => write!(f, "bad or unsupported format string"), + + Error::DateTime(error) => write!(f, "invalid date time: {}", error), + Error::FindLocalTimeType(error) => error.fmt(f), + Error::LocalTimeType(error) => write!(f, "invalid local time type: {}", error), + Error::InvalidSlice(error) => error.fmt(f), + Error::InvalidTzString(error) => write!(f, "invalid TZ string: {}", error), + Error::InvalidTzFile(error) => error.fmt(f), + Error::Io(error) => error.fmt(f), + Error::OutOfRange(error) => error.fmt(f), + Error::ParseInt(error) => error.fmt(f), + Error::ProjectDateTime(error) => error.fmt(f), + Error::SystemTime => write!(f, "opposite direction of system time"), + Error::TransitionRule(error) => write!(f, "invalid transition rule: {}", error), + Error::TimeZone(error) => write!(f, "invalid time zone: {}", error), + Error::UnsupportedTzFile(error) => error.fmt(f), + Error::UnsupportedTzString(error) => write!(f, "unsupported TZ string: {}", error), + Error::Utf8(error) => error.fmt(f), + + Error::TryFromIntError(error) => error.fmt(f), + + Error::UnexpectedEOF => write!(f, "unexpected end of file"), + Error::InvalidData => write!(f, "invalid data"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + #[cfg(all(windows, feature = "clock"))] + ErrorKind::SystemError(error) => Some(error), + _ => None, + } + } +} + +impl From for Error { + fn from(error: TryFromIntError) -> Self { + Error::TryFromIntError(error) + } +} + +impl From for Error { + fn from(error: std::io::Error) -> Self { + Error::Io(error.kind()) + } +} + +impl From for Error { + fn from(error: ParseIntError) -> Self { + Error::ParseInt(error) + } +} + +impl From for Error { + fn from(_: SystemTimeError) -> Self { + Error::SystemTime + } +} + +impl From for Error { + fn from(error: Utf8Error) -> Self { + Error::Utf8(error) + } +} \ No newline at end of file diff --git a/src/format/mod.rs b/src/format/mod.rs index 3985215dd1..0bc145cf43 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.with_ymd_and_hms(2020, 11, 10, 0, 1, 32).unwrap(); +//! 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")] @@ -42,8 +42,6 @@ use core::borrow::Borrow; use core::fmt; use core::fmt::Write; use core::str::FromStr; -#[cfg(any(feature = "std", test))] -use std::error::Error; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::naive::{NaiveDate, NaiveTime}; @@ -344,85 +342,6 @@ macro_rules! internal_fix { }; } -/// An error from the `parse` function. -#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] -pub struct ParseError(ParseErrorKind); - -impl ParseError { - /// The category of parse error - pub const fn kind(&self) -> ParseErrorKind { - self.0 - } -} - -/// The category of parse error -#[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] -pub enum ParseErrorKind { - /// Given field is out of permitted range. - OutOfRange, - - /// There is no possible date and time value with given set of fields. - /// - /// This does not include the out-of-range conditions, which are trivially invalid. - /// It includes the case that there are one or more fields that are inconsistent to each other. - Impossible, - - /// Given set of fields is not enough to make a requested date and time value. - /// - /// Note that there *may* be a case that given fields constrain the possible values so much - /// that there is a unique possible value. Chrono only tries to be correct for - /// most useful sets of fields however, as such constraint solving can be expensive. - NotEnough, - - /// The input string has some invalid character sequence for given formatting items. - Invalid, - - /// The input string has been prematurely ended. - TooShort, - - /// All formatting items have been read but there is a remaining input. - TooLong, - - /// There was an error on the formatting string, or there were non-supported formating items. - BadFormat, -} - -/// Same as `Result`. -pub type ParseResult = Result; - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.0 { - ParseErrorKind::OutOfRange => write!(f, "input is out of range"), - ParseErrorKind::Impossible => write!(f, "no possible date and time matching input"), - ParseErrorKind::NotEnough => write!(f, "input is not enough for unique date and time"), - ParseErrorKind::Invalid => write!(f, "input contains invalid characters"), - ParseErrorKind::TooShort => write!(f, "premature end of input"), - ParseErrorKind::TooLong => write!(f, "trailing input"), - ParseErrorKind::BadFormat => write!(f, "bad or unsupported format string"), - } - } -} - -#[cfg(any(feature = "std", test))] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl Error for ParseError { - #[allow(deprecated)] - fn description(&self) -> &str { - "parser error, see to_string() for details" - } -} - -// to be used in this module and submodules -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); -const TOO_SHORT: ParseError = ParseError(ParseErrorKind::TooShort); -const TOO_LONG: ParseError = ParseError(ParseErrorKind::TooLong); -const BAD_FORMAT: ParseError = ParseError(ParseErrorKind::BadFormat); - #[cfg(any(feature = "alloc", feature = "std", test))] struct Locales { short_months: &'static [&'static str], diff --git a/src/format/parse.rs b/src/format/parse.rs index 91673af9a4..541bc1b165 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -12,11 +12,9 @@ use core::usize; use super::scan; use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric, Pad, Parsed}; -use super::{ParseError, ParseErrorKind, ParseResult}; -use super::{BAD_FORMAT, INVALID, NOT_ENOUGH, OUT_OF_RANGE, TOO_LONG, TOO_SHORT}; -use crate::{DateTime, FixedOffset, Weekday}; +use crate::{Error, DateTime, FixedOffset, Weekday}; -fn set_weekday_with_num_days_from_sunday(p: &mut Parsed, v: i64) -> ParseResult<()> { +fn set_weekday_with_num_days_from_sunday(p: &mut Parsed, v: i64) -> Result<(), Error> { p.set_weekday(match v { 0 => Weekday::Sun, 1 => Weekday::Mon, @@ -25,11 +23,11 @@ fn set_weekday_with_num_days_from_sunday(p: &mut Parsed, v: i64) -> ParseResult< 4 => Weekday::Thu, 5 => Weekday::Fri, 6 => Weekday::Sat, - _ => return Err(OUT_OF_RANGE), + _ => return Err(Error::ParsingOutOfRange), }) } -fn set_weekday_with_number_from_monday(p: &mut Parsed, v: i64) -> ParseResult<()> { +fn set_weekday_with_number_from_monday(p: &mut Parsed, v: i64) -> Result<(), Error> { p.set_weekday(match v { 1 => Weekday::Mon, 2 => Weekday::Tue, @@ -38,7 +36,7 @@ fn set_weekday_with_number_from_monday(p: &mut Parsed, v: i64) -> ParseResult<() 5 => Weekday::Fri, 6 => Weekday::Sat, 7 => Weekday::Sun, - _ => return Err(OUT_OF_RANGE), + _ => return Err(Error::ParsingOutOfRange), }) } @@ -46,7 +44,7 @@ fn set_weekday_with_number_from_monday(p: &mut Parsed, v: i64) -> ParseResult<() /// e.g. `Fri, 21 Nov 1997 09:55:06 -0600` /// /// This function allows arbitrary intermixed whitespace per RFC 2822 appendix A.5 -fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a str, ())> { +fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> Result<(&'a str, ()), Error> { macro_rules! try_consume { ($e:expr) => {{ let (s_, v) = $e?; @@ -108,7 +106,7 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st if let Ok((s_, weekday)) = scan::short_weekday(s) { if !s_.starts_with(',') { - return Err(INVALID); + return Err(Error::ParsingInvalid); } s = &s_[1..]; parsed.set_weekday(weekday)?; @@ -161,7 +159,7 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st Ok((s, ())) } -fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a str, ())> { +fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> Result<(&'a str, ()), Error> { macro_rules! try_consume { ($e:expr) => {{ let (s_, v) = $e?; @@ -205,8 +203,8 @@ fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st s = match s.as_bytes().first() { Some(&b't') | Some(&b'T') => &s[1..], - Some(_) => return Err(INVALID), - None => return Err(TOO_SHORT), + Some(_) => return Err(Error::ParsingInvalid), + None => return Err(Error::ParsingTooShort), }; parsed.set_hour(try_consume!(scan::number(s, 2, 2)))?; @@ -221,7 +219,7 @@ fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st let offset = try_consume!(scan::timezone_offset_zulu(s, |s| scan::char(s, b':'))); if offset <= -86_400 || offset >= 86_400 { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } parsed.set_offset(i64::from(offset))?; @@ -244,7 +242,7 @@ fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st /// so one can prepend any number of zeroes before numbers. /// /// - (Still) obeying the intrinsic parsing width. This allows, for example, parsing `HHMMSS`. -pub fn parse<'a, I, B>(parsed: &mut Parsed, s: &str, items: I) -> ParseResult<()> +pub fn parse<'a, I, B>(parsed: &mut Parsed, s: &str, items: I) -> Result<(), Error> where I: Iterator, B: Borrow>, @@ -256,7 +254,7 @@ fn parse_internal<'a, 'b, I, B>( parsed: &mut Parsed, mut s: &'b str, items: I, -) -> Result<&'b str, (&'b str, ParseError)> +) -> Result<&'b str, (&'b str, Error)> where I: Iterator, B: Borrow>, @@ -277,10 +275,10 @@ where match *item.borrow() { Item::Literal(prefix) => { if s.len() < prefix.len() { - return Err((s, TOO_SHORT)); + return Err((s, Error::ParsingTooShort)); } if !s.starts_with(prefix) { - return Err((s, INVALID)); + return Err((s, Error::ParsingInvalid)); } s = &s[prefix.len()..]; } @@ -288,10 +286,10 @@ where #[cfg(any(feature = "alloc", feature = "std", test))] Item::OwnedLiteral(ref prefix) => { if s.len() < prefix.len() { - return Err((s, TOO_SHORT)); + return Err((s, Error::ParsingTooShort)); } if !s.starts_with(&prefix[..]) { - return Err((s, INVALID)); + return Err((s, Error::ParsingInvalid)); } s = &s[prefix.len()..]; } @@ -301,11 +299,11 @@ where let actual = match s.chars().next() { Some(c) => c, None => { - return Err((s, TOO_SHORT)); + return Err((s, Error::ParsingTooShort)); } }; if expect != actual { - return Err((s, INVALID)); + return Err((s, Error::ParsingInvalid)); } // advance `s` forward 1 char s = scan::s_next(s); @@ -318,11 +316,11 @@ where let actual = match s.chars().next() { Some(c) => c, None => { - return Err((s, TOO_SHORT)); + return Err((s, Error::ParsingTooShort)); } }; if expect != actual { - return Err((s, INVALID)); + return Err((s, Error::ParsingInvalid)); } // advance `s` forward 1 char s = scan::s_next(s); @@ -331,7 +329,7 @@ where Item::Numeric(ref spec, ref _pad) => { use super::Numeric::*; - type Setter = fn(&mut Parsed, i64) -> ParseResult<()>; + type Setter = fn(&mut Parsed, i64) -> Result<(), Error>; let (width, signed, set): (usize, bool, Setter) = match *spec { Year => (4, true, Parsed::set_year), @@ -362,7 +360,7 @@ where let v = if signed { if s.starts_with('-') { let v = try_consume!(scan::number(&s[1..], 1, usize::MAX)); - 0i64.checked_sub(v).ok_or((s, OUT_OF_RANGE))? + 0i64.checked_sub(v).ok_or((s, Error::ParsingOutOfRange))? } else if s.starts_with('+') { try_consume!(scan::number(&s[1..], 1, usize::MAX)) } else { @@ -401,12 +399,12 @@ where &LowerAmPm | &UpperAmPm => { if s.len() < 2 { - return Err((s, TOO_SHORT)); + return Err((s, Error::ParsingTooShort)); } let ampm = match (s.as_bytes()[0] | 32, s.as_bytes()[1] | 32) { (b'a', b'm') => false, (b'p', b'm') => true, - _ => return Err((s, INVALID)), + _ => return Err((s, Error::ParsingInvalid)), }; parsed.set_ampm(ampm).map_err(|e| (s, e))?; s = &s[2..]; @@ -421,7 +419,7 @@ where &Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => { if s.len() < 3 { - return Err((s, TOO_SHORT)); + return Err((s, Error::ParsingTooShort)); } let nano = try_consume!(scan::nanosecond_fixed(s, 3)); parsed.set_nanosecond(nano).map_err(|e| (s, e))?; @@ -429,7 +427,7 @@ where &Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => { if s.len() < 6 { - return Err((s, TOO_SHORT)); + return Err((s, Error::ParsingTooShort)); } let nano = try_consume!(scan::nanosecond_fixed(s, 6)); parsed.set_nanosecond(nano).map_err(|e| (s, e))?; @@ -437,7 +435,7 @@ where &Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => { if s.len() < 9 { - return Err((s, TOO_SHORT)); + return Err((s, Error::ParsingTooShort)); } let nano = try_consume!(scan::nanosecond_fixed(s, 9)); parsed.set_nanosecond(nano).map_err(|e| (s, e))?; @@ -481,14 +479,14 @@ where } Item::Error => { - return Err((s, BAD_FORMAT)); + return Err((s, Error::ParsingBadFormat)); } } } // if there are trailling chars, it is an error if !s.is_empty() { - Err((s, TOO_LONG)) + Err((s, Error::ParsingTooLong)) } else { Ok(s) } @@ -504,9 +502,9 @@ where /// "2000-01-02 03:04:05Z".parse::>(); /// ``` impl str::FromStr for DateTime { - type Err = ParseError; + type Err = Error; - fn from_str(s: &str) -> ParseResult> { + fn from_str(s: &str) -> Result, Error> { const DATE_ITEMS: &[Item<'static>] = &[ Item::Numeric(Numeric::Year, Pad::Zero), Item::Literal("-"), @@ -526,15 +524,15 @@ impl str::FromStr for DateTime { let mut parsed = Parsed::new(); match parse_internal(&mut parsed, s, DATE_ITEMS.iter()) { - Err((remainder, e)) if e.0 == ParseErrorKind::TooLong => { + Err((remainder, e)) if e == Error::ParsingTooLong => { if remainder.starts_with('T') || remainder.starts_with(' ') { parse(&mut parsed, &remainder[1..], TIME_ITEMS.iter())?; } else { - return Err(INVALID); + return Err(Error::ParsingInvalid); } } Err((_s, e)) => return Err(e), - Ok(_) => return Err(NOT_ENOUGH), + Ok(_) => return Err(Error::ParsingNotEnough), }; parsed.to_datetime() } @@ -546,7 +544,7 @@ fn test_parse() { use super::*; // workaround for Rust issue #22255 - fn parse_all(s: &str, items: &[Item]) -> ParseResult { + fn parse_all(s: &str, items: &[Item]) -> Result { let mut parsed = Parsed::new(); parse(&mut parsed, s, items.iter())?; Ok(parsed) @@ -555,7 +553,7 @@ fn test_parse() { macro_rules! check { ($fmt:expr, $items:expr; $err:tt) => ( eprintln!("test_parse: format {:?}", $fmt); - assert_eq!(parse_all($fmt, &$items), Err($err)) + assert_eq!(parse_all($fmt, &$items), Err(Error::$err)) ); ($fmt:expr, $items:expr; $($k:ident: $v:expr),*) => ({ eprintln!("test_parse: format {:?}", $fmt); @@ -569,41 +567,41 @@ fn test_parse() { // empty string check!("", []; ); - check!(" ", []; TOO_LONG); - check!("a", []; TOO_LONG); - check!("abc", []; TOO_LONG); - check!("🤠", []; TOO_LONG); + check!(" ", []; ParsingTooLong); + check!("a", []; ParsingTooLong); + check!("abc", []; ParsingTooLong); + check!("🤠", []; ParsingTooLong); // whitespaces check!("", [sp!("")]; ); check!(" ", [sp!(" ")]; ); check!(" ", [sp!(" ")]; ); check!(" ", [sp!(" ")]; ); - check!(" ", [sp!("")]; TOO_LONG); - check!(" ", [sp!(" ")]; TOO_LONG); - check!(" ", [sp!(" ")]; TOO_LONG); - check!(" ", [sp!(" ")]; TOO_LONG); - check!("", [sp!(" ")]; TOO_SHORT); - check!(" ", [sp!(" ")]; TOO_SHORT); - check!(" ", [sp!(" ")]; TOO_SHORT); - check!(" ", [sp!(" "), sp!(" ")]; TOO_SHORT); - check!(" ", [sp!(" "), sp!(" ")]; TOO_SHORT); + check!(" ", [sp!("")]; ParsingTooLong); + check!(" ", [sp!(" ")]; ParsingTooLong); + check!(" ", [sp!(" ")]; ParsingTooLong); + check!(" ", [sp!(" ")]; ParsingTooLong); + check!("", [sp!(" ")]; ParsingTooShort); + check!(" ", [sp!(" ")]; ParsingTooShort); + check!(" ", [sp!(" ")]; ParsingTooShort); + check!(" ", [sp!(" "), sp!(" ")]; ParsingTooShort); + check!(" ", [sp!(" "), sp!(" ")]; ParsingTooShort); check!(" ", [sp!(" "), sp!(" ")]; ); check!(" ", [sp!(" "), sp!(" ")]; ); check!(" ", [sp!(" "), sp!(" ")]; ); check!(" ", [sp!(" "), sp!(" "), sp!(" ")]; ); - check!("\t", [sp!("")]; TOO_LONG); - check!(" \n\r \n", [sp!("")]; TOO_LONG); + check!("\t", [sp!("")]; ParsingTooLong); + check!(" \n\r \n", [sp!("")]; ParsingTooLong); check!("\t", [sp!("\t")]; ); - check!("\t", [sp!(" ")]; INVALID); - check!(" ", [sp!("\t")]; INVALID); + check!("\t", [sp!(" ")]; ParsingInvalid); + check!(" ", [sp!("\t")]; ParsingInvalid); check!("\t\r", [sp!("\t\r")]; ); check!("\t\r ", [sp!("\t\r ")]; ); check!("\t \r", [sp!("\t \r")]; ); check!(" \t\r", [sp!(" \t\r")]; ); check!(" \n\r \n", [sp!(" \n\r \n")]; ); - check!(" \t\n", [sp!(" \t")]; TOO_LONG); - check!(" \n\t", [sp!(" \t\n")]; INVALID); + check!(" \t\n", [sp!(" \t")]; ParsingTooLong); + check!(" \n\t", [sp!(" \t\n")]; ParsingInvalid); check!("\u{2002}", [sp!("\u{2002}")]; ); // most unicode whitespace characters check!( @@ -618,33 +616,33 @@ fn test_parse() { sp!("\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{3000}") ]; ); - check!("a", [sp!("")]; TOO_LONG); - check!("a", [sp!(" ")]; INVALID); + check!("a", [sp!("")]; ParsingTooLong); + check!("a", [sp!(" ")]; ParsingInvalid); // a Space containing a literal can match a literal, but this should not be done check!("a", [sp!("a")]; ); - check!("abc", [sp!("")]; TOO_LONG); - check!("abc", [sp!(" ")]; INVALID); - check!(" abc", [sp!("")]; TOO_LONG); - check!(" abc", [sp!(" ")]; TOO_LONG); + check!("abc", [sp!("")]; ParsingTooLong); + check!("abc", [sp!(" ")]; ParsingInvalid); + check!(" abc", [sp!("")]; ParsingTooLong); + check!(" abc", [sp!(" ")]; ParsingTooLong); // `\u{0363}` is combining diacritic mark "COMBINING LATIN SMALL LETTER A" // literal check!("", [lit!("")]; ); - check!("", [lit!("a")]; TOO_SHORT); - check!(" ", [lit!("a")]; INVALID); + check!("", [lit!("a")]; ParsingTooShort); + check!(" ", [lit!("a")]; ParsingInvalid); check!("a", [lit!("a")]; ); // a Literal may contain whitespace and match whitespace, but this should not be done check!(" ", [lit!(" ")]; ); - check!("aa", [lit!("a")]; TOO_LONG); - check!("🤠", [lit!("a")]; INVALID); - check!("A", [lit!("a")]; INVALID); - check!("a", [lit!("z")]; INVALID); - check!("a", [lit!("🤠")]; TOO_SHORT); - check!("a", [lit!("\u{0363}a")]; TOO_SHORT); - check!("\u{0363}a", [lit!("a")]; INVALID); + check!("aa", [lit!("a")]; ParsingTooLong); + check!("🤠", [lit!("a")]; ParsingInvalid); + check!("A", [lit!("a")]; ParsingInvalid); + check!("a", [lit!("z")]; ParsingInvalid); + check!("a", [lit!("🤠")]; ParsingTooShort); + check!("a", [lit!("\u{0363}a")]; ParsingTooShort); + check!("\u{0363}a", [lit!("a")]; ParsingInvalid); check!("\u{0363}a", [lit!("\u{0363}a")]; ); - check!("a", [lit!("ab")]; TOO_SHORT); + check!("a", [lit!("ab")]; ParsingTooShort); check!("xy", [lit!("xy")]; ); check!("xy", [lit!("x"), lit!("y")]; ); check!("1", [lit!("1")]; ); @@ -664,9 +662,9 @@ fn test_parse() { check!("xyz", [lit!("xy"), lit!("z")]; ); check!("xyz", [lit!("x"), lit!("y"), lit!("z")]; ); // - check!("x y", [lit!("x"), lit!("y")]; INVALID); + check!("x y", [lit!("x"), lit!("y")]; ParsingInvalid); check!("xy", [lit!("x"), sp!(""), lit!("y")]; ); - check!("x y", [lit!("x"), sp!(""), lit!("y")]; INVALID); + check!("x y", [lit!("x"), sp!(""), lit!("y")]; ParsingInvalid); check!("x y", [lit!("x"), sp!(" "), lit!("y")]; ); // whitespaces + literals @@ -680,32 +678,32 @@ fn test_parse() { // numeric check!("1987", [num!(Year)]; year: 1987); - check!("1987 ", [num!(Year)]; TOO_LONG); - check!("0x12", [num!(Year)]; TOO_LONG); // `0` is parsed - check!("x123", [num!(Year)]; INVALID); - check!("o123", [num!(Year)]; INVALID); + check!("1987 ", [num!(Year)]; ParsingTooLong); + check!("0x12", [num!(Year)]; ParsingTooLong); // `0` is parsed + check!("x123", [num!(Year)]; ParsingInvalid); + check!("o123", [num!(Year)]; ParsingInvalid); check!("2015", [num!(Year)]; year: 2015); check!("0000", [num!(Year)]; year: 0); check!("9999", [num!(Year)]; year: 9999); - check!(" \t987", [num!(Year)]; INVALID); + check!(" \t987", [num!(Year)]; ParsingInvalid); check!(" \t987", [sp!(" \t"), num!(Year)]; year: 987); check!(" \t987🤠", [sp!(" \t"), num!(Year), lit!("🤠")]; year: 987); check!("987🤠", [num!(Year), lit!("🤠")]; year: 987); check!("5", [num!(Year)]; year: 5); - check!("5\0", [num!(Year)]; TOO_LONG); - check!("\x005", [num!(Year)]; INVALID); - check!("", [num!(Year)]; TOO_SHORT); + check!("5\0", [num!(Year)]; ParsingTooLong); + check!("\x005", [num!(Year)]; ParsingInvalid); + check!("", [num!(Year)]; ParsingTooShort); check!("12345", [num!(Year), lit!("5")]; year: 1234); check!("12345", [nums!(Year), lit!("5")]; year: 1234); check!("12345", [num0!(Year), lit!("5")]; year: 1234); check!("12341234", [num!(Year), num!(Year)]; year: 1234); - check!("1234 1234", [num!(Year), num!(Year)]; INVALID); + check!("1234 1234", [num!(Year), num!(Year)]; ParsingInvalid); check!("1234 1234", [num!(Year), sp!(" "), num!(Year)]; year: 1234); - check!("1234 1235", [num!(Year), num!(Year)]; INVALID); - check!("1234 1234", [num!(Year), lit!("x"), num!(Year)]; INVALID); + check!("1234 1235", [num!(Year), num!(Year)]; ParsingInvalid); + check!("1234 1234", [num!(Year), lit!("x"), num!(Year)]; ParsingInvalid); check!("1234x1234", [num!(Year), lit!("x"), num!(Year)]; year: 1234); - check!("1234 x 1234", [num!(Year), lit!("x"), num!(Year)]; INVALID); - check!("1234xx1234", [num!(Year), lit!("x"), num!(Year)]; INVALID); + check!("1234 x 1234", [num!(Year), lit!("x"), num!(Year)]; ParsingInvalid); + check!("1234xx1234", [num!(Year), lit!("x"), num!(Year)]; ParsingInvalid); check!("1234xx1234", [num!(Year), lit!("xx"), num!(Year)]; year: 1234); check!("1234 x 1234", [num!(Year), sp!(" "), lit!("x"), sp!(" "), num!(Year)]; year: 1234); check!("1234 x 1235", [num!(Year), sp!(" "), lit!("x"), sp!(" "), lit!("1235")]; year: 1234); @@ -717,46 +715,46 @@ fn test_parse() { check!("+0042", [num!(Year)]; year: 42); check!("-42195", [num!(Year)]; year: -42195); check!("+42195", [num!(Year)]; year: 42195); - check!(" -42195", [num!(Year)]; INVALID); - check!(" +42195", [num!(Year)]; INVALID); - check!(" -42195", [num!(Year)]; INVALID); - check!(" +42195", [num!(Year)]; INVALID); - check!("-42195 ", [num!(Year)]; TOO_LONG); - check!("+42195 ", [num!(Year)]; TOO_LONG); - check!(" - 42", [num!(Year)]; INVALID); - check!(" + 42", [num!(Year)]; INVALID); + check!(" -42195", [num!(Year)]; ParsingInvalid); + check!(" +42195", [num!(Year)]; ParsingInvalid); + check!(" -42195", [num!(Year)]; ParsingInvalid); + check!(" +42195", [num!(Year)]; ParsingInvalid); + check!("-42195 ", [num!(Year)]; ParsingTooLong); + check!("+42195 ", [num!(Year)]; ParsingTooLong); + check!(" - 42", [num!(Year)]; ParsingInvalid); + check!(" + 42", [num!(Year)]; ParsingInvalid); check!(" -42195", [sp!(" "), num!(Year)]; year: -42195); check!(" +42195", [sp!(" "), num!(Year)]; year: 42195); - check!(" - 42", [sp!(" "), num!(Year)]; INVALID); - check!(" + 42", [sp!(" "), num!(Year)]; INVALID); - check!("-", [num!(Year)]; TOO_SHORT); - check!("+", [num!(Year)]; TOO_SHORT); + check!(" - 42", [sp!(" "), num!(Year)]; ParsingInvalid); + check!(" + 42", [sp!(" "), num!(Year)]; ParsingInvalid); + check!("-", [num!(Year)]; ParsingTooShort); + check!("+", [num!(Year)]; ParsingTooShort); // unsigned numeric check!("345", [num!(Ordinal)]; ordinal: 345); - check!("+345", [num!(Ordinal)]; INVALID); - check!("-345", [num!(Ordinal)]; INVALID); - check!(" 345", [num!(Ordinal)]; INVALID); - check!("345 ", [num!(Ordinal)]; TOO_LONG); + check!("+345", [num!(Ordinal)]; ParsingInvalid); + check!("-345", [num!(Ordinal)]; ParsingInvalid); + check!(" 345", [num!(Ordinal)]; ParsingInvalid); + check!("345 ", [num!(Ordinal)]; ParsingTooLong); check!(" 345", [sp!(" "), num!(Ordinal)]; ordinal: 345); check!("345 ", [num!(Ordinal), sp!(" ")]; ordinal: 345); check!("345🤠 ", [num!(Ordinal), lit!("🤠"), sp!(" ")]; ordinal: 345); - check!("345🤠", [num!(Ordinal)]; TOO_LONG); - check!("\u{0363}345", [num!(Ordinal)]; INVALID); - check!(" +345", [num!(Ordinal)]; INVALID); - check!(" -345", [num!(Ordinal)]; INVALID); + check!("345🤠", [num!(Ordinal)]; ParsingTooLong); + check!("\u{0363}345", [num!(Ordinal)]; ParsingInvalid); + check!(" +345", [num!(Ordinal)]; ParsingInvalid); + check!(" -345", [num!(Ordinal)]; ParsingInvalid); check!("\t345", [sp!("\t"), num!(Ordinal)]; ordinal: 345); - check!(" +345", [sp!(" "), num!(Ordinal)]; INVALID); - check!(" -345", [sp!(" "), num!(Ordinal)]; INVALID); + check!(" +345", [sp!(" "), num!(Ordinal)]; ParsingInvalid); + check!(" -345", [sp!(" "), num!(Ordinal)]; ParsingInvalid); // various numeric fields - check!("1234 5678", [num!(Year), num!(IsoYear)]; INVALID); + check!("1234 5678", [num!(Year), num!(IsoYear)]; ParsingInvalid); check!("1234 5678", [num!(Year), sp!(" "), num!(IsoYear)]; year: 1234, isoyear: 5678); check!("12 34 56 78", [num!(YearDiv100), num!(YearMod100), num!(IsoYearDiv100), num!(IsoYearMod100)]; - INVALID); + ParsingInvalid); check!("12 34🤠56 78", [num!(YearDiv100), sp!(" "), num!(YearMod100), lit!("🤠"), num!(IsoYearDiv100), sp!(" "), num!(IsoYearMod100)]; @@ -779,33 +777,33 @@ fn test_parse() { check!("Apr", [fix!(ShortMonthName)]; month: 4); check!("APR", [fix!(ShortMonthName)]; month: 4); check!("ApR", [fix!(ShortMonthName)]; month: 4); - check!("\u{0363}APR", [fix!(ShortMonthName)]; INVALID); - check!("April", [fix!(ShortMonthName)]; TOO_LONG); // `Apr` is parsed - check!("A", [fix!(ShortMonthName)]; TOO_SHORT); - check!("Sol", [fix!(ShortMonthName)]; INVALID); + check!("\u{0363}APR", [fix!(ShortMonthName)]; ParsingInvalid); + check!("April", [fix!(ShortMonthName)]; ParsingTooLong); // `Apr` is parsed + check!("A", [fix!(ShortMonthName)]; ParsingTooShort); + check!("Sol", [fix!(ShortMonthName)]; ParsingInvalid); check!("Apr", [fix!(LongMonthName)]; month: 4); - check!("Apri", [fix!(LongMonthName)]; TOO_LONG); // `Apr` is parsed + check!("Apri", [fix!(LongMonthName)]; ParsingTooLong); // `Apr` is parsed check!("April", [fix!(LongMonthName)]; month: 4); - check!("Aprill", [fix!(LongMonthName)]; TOO_LONG); + check!("Aprill", [fix!(LongMonthName)]; ParsingTooLong); check!("Aprill", [fix!(LongMonthName), lit!("l")]; month: 4); check!("Aprl", [fix!(LongMonthName), lit!("l")]; month: 4); - check!("April", [fix!(LongMonthName), lit!("il")]; TOO_SHORT); // do not backtrack + check!("April", [fix!(LongMonthName), lit!("il")]; ParsingTooShort); // do not backtrack check!("thu", [fix!(ShortWeekdayName)]; weekday: Weekday::Thu); check!("Thu", [fix!(ShortWeekdayName)]; weekday: Weekday::Thu); check!("THU", [fix!(ShortWeekdayName)]; weekday: Weekday::Thu); check!("tHu", [fix!(ShortWeekdayName)]; weekday: Weekday::Thu); - check!("Thursday", [fix!(ShortWeekdayName)]; TOO_LONG); // `Thu` is parsed - check!("T", [fix!(ShortWeekdayName)]; TOO_SHORT); - check!("The", [fix!(ShortWeekdayName)]; INVALID); - check!("Nop", [fix!(ShortWeekdayName)]; INVALID); + check!("Thursday", [fix!(ShortWeekdayName)]; ParsingTooLong); // `Thu` is parsed + check!("T", [fix!(ShortWeekdayName)]; ParsingTooShort); + check!("The", [fix!(ShortWeekdayName)]; ParsingInvalid); + check!("Nop", [fix!(ShortWeekdayName)]; ParsingInvalid); check!("Thu", [fix!(LongWeekdayName)]; weekday: Weekday::Thu); - check!("Thur", [fix!(LongWeekdayName)]; TOO_LONG); // `Thu` is parsed - check!("Thurs", [fix!(LongWeekdayName)]; TOO_LONG); // ditto + check!("Thur", [fix!(LongWeekdayName)]; ParsingTooLong); // `Thu` is parsed + check!("Thurs", [fix!(LongWeekdayName)]; ParsingTooLong); // ditto check!("Thursday", [fix!(LongWeekdayName)]; weekday: Weekday::Thu); - check!("Thursdays", [fix!(LongWeekdayName)]; TOO_LONG); + check!("Thursdays", [fix!(LongWeekdayName)]; ParsingTooLong); check!("Thursdays", [fix!(LongWeekdayName), lit!("s")]; weekday: Weekday::Thu); check!("Thus", [fix!(LongWeekdayName), lit!("s")]; weekday: Weekday::Thu); - check!("Thursday", [fix!(LongWeekdayName), lit!("rsday")]; TOO_SHORT); // do not backtrack + check!("Thursday", [fix!(LongWeekdayName), lit!("rsday")]; ParsingTooShort); // do not backtrack // fixed: am/pm check!("am", [fix!(LowerAmPm)]; hour_div_12: 0); @@ -820,22 +818,22 @@ fn test_parse() { check!(" Am", [sp!(" "), fix!(LowerAmPm)]; hour_div_12: 0); check!("Am🤠", [fix!(LowerAmPm), lit!("🤠")]; hour_div_12: 0); check!("🤠Am", [lit!("🤠"), fix!(LowerAmPm)]; hour_div_12: 0); - check!("\u{0363}am", [fix!(LowerAmPm)]; INVALID); - check!("\u{0360}am", [fix!(LowerAmPm)]; INVALID); - check!(" Am", [fix!(LowerAmPm)]; INVALID); - check!("Am ", [fix!(LowerAmPm)]; TOO_LONG); - check!("a.m.", [fix!(LowerAmPm)]; INVALID); - check!("A.M.", [fix!(LowerAmPm)]; INVALID); - check!("ame", [fix!(LowerAmPm)]; TOO_LONG); // `am` is parsed - check!("a", [fix!(LowerAmPm)]; TOO_SHORT); - check!("p", [fix!(LowerAmPm)]; TOO_SHORT); - check!("x", [fix!(LowerAmPm)]; TOO_SHORT); - check!("xx", [fix!(LowerAmPm)]; INVALID); - check!("", [fix!(LowerAmPm)]; TOO_SHORT); + check!("\u{0363}am", [fix!(LowerAmPm)]; ParsingInvalid); + check!("\u{0360}am", [fix!(LowerAmPm)]; ParsingInvalid); + check!(" Am", [fix!(LowerAmPm)]; ParsingInvalid); + check!("Am ", [fix!(LowerAmPm)]; ParsingTooLong); + check!("a.m.", [fix!(LowerAmPm)]; ParsingInvalid); + check!("A.M.", [fix!(LowerAmPm)]; ParsingInvalid); + check!("ame", [fix!(LowerAmPm)]; ParsingTooLong); // `am` is parsed + check!("a", [fix!(LowerAmPm)]; ParsingTooShort); + check!("p", [fix!(LowerAmPm)]; ParsingTooShort); + check!("x", [fix!(LowerAmPm)]; ParsingTooShort); + check!("xx", [fix!(LowerAmPm)]; ParsingInvalid); + check!("", [fix!(LowerAmPm)]; ParsingTooShort); // fixed: dot plus nanoseconds check!("", [fix!(Nanosecond)]; ); // no field set, but not an error - check!("4", [fix!(Nanosecond)]; TOO_LONG); // never consumes `4` + check!("4", [fix!(Nanosecond)]; ParsingTooLong); // never consumes `4` check!("4", [fix!(Nanosecond), num!(Second)]; second: 4); check!(".0", [fix!(Nanosecond)]; nanosecond: 0); check!(".4", [fix!(Nanosecond)]; nanosecond: 400_000_000); @@ -857,91 +855,91 @@ fn test_parse() { check!(".000000000547", [fix!(Nanosecond)]; nanosecond: 0); check!(".0000000009999999999999999999999999", [fix!(Nanosecond)]; nanosecond: 0); check!(".4🤠", [fix!(Nanosecond), lit!("🤠")]; nanosecond: 400_000_000); - check!(".", [fix!(Nanosecond)]; TOO_SHORT); - check!(".4x", [fix!(Nanosecond)]; TOO_LONG); - check!(". 4", [fix!(Nanosecond)]; INVALID); - check!(" .4", [fix!(Nanosecond)]; TOO_LONG); // no automatic trimming + check!(".", [fix!(Nanosecond)]; ParsingTooShort); + check!(".4x", [fix!(Nanosecond)]; ParsingTooLong); + check!(". 4", [fix!(Nanosecond)]; ParsingInvalid); + check!(" .4", [fix!(Nanosecond)]; ParsingTooLong); // no automatic trimming // fixed: nanoseconds without the dot - check!("", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); - check!("0", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); - check!("4", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); - check!("42", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); + check!("", [internal_fix!(Nanosecond3NoDot)]; ParsingTooShort); + check!("0", [internal_fix!(Nanosecond3NoDot)]; ParsingTooShort); + check!("4", [internal_fix!(Nanosecond3NoDot)]; ParsingTooShort); + check!("42", [internal_fix!(Nanosecond3NoDot)]; ParsingTooShort); check!("421", [internal_fix!(Nanosecond3NoDot)]; nanosecond: 421_000_000); - check!("4210", [internal_fix!(Nanosecond3NoDot)]; TOO_LONG); + check!("4210", [internal_fix!(Nanosecond3NoDot)]; ParsingTooLong); check!("42143", [internal_fix!(Nanosecond3NoDot), num!(Second)]; nanosecond: 421_000_000, second: 43); check!("421🤠", [internal_fix!(Nanosecond3NoDot), lit!("🤠")]; nanosecond: 421_000_000); check!("🤠421", [lit!("🤠"), internal_fix!(Nanosecond3NoDot)]; nanosecond: 421_000_000); - check!("42195", [internal_fix!(Nanosecond3NoDot)]; TOO_LONG); - check!("123456789", [internal_fix!(Nanosecond3NoDot)]; TOO_LONG); - check!("4x", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); - check!(" 4", [internal_fix!(Nanosecond3NoDot)]; INVALID); - check!(".421", [internal_fix!(Nanosecond3NoDot)]; INVALID); - - check!("", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); - check!("0", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); - check!("1234", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); - check!("12345", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); + check!("42195", [internal_fix!(Nanosecond3NoDot)]; ParsingTooLong); + check!("123456789", [internal_fix!(Nanosecond3NoDot)]; ParsingTooLong); + check!("4x", [internal_fix!(Nanosecond3NoDot)]; ParsingTooShort); + check!(" 4", [internal_fix!(Nanosecond3NoDot)]; ParsingInvalid); + check!(".421", [internal_fix!(Nanosecond3NoDot)]; ParsingInvalid); + + check!("", [internal_fix!(Nanosecond6NoDot)]; ParsingTooShort); + check!("0", [internal_fix!(Nanosecond6NoDot)]; ParsingTooShort); + check!("1234", [internal_fix!(Nanosecond6NoDot)]; ParsingTooShort); + check!("12345", [internal_fix!(Nanosecond6NoDot)]; ParsingTooShort); check!("421950", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 421_950_000); check!("000003", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 3000); check!("000000", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 0); - check!("1234567", [internal_fix!(Nanosecond6NoDot)]; TOO_LONG); - check!("123456789", [internal_fix!(Nanosecond6NoDot)]; TOO_LONG); - check!("4x", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); - check!(" 4", [internal_fix!(Nanosecond6NoDot)]; INVALID); - check!(".42100", [internal_fix!(Nanosecond6NoDot)]; INVALID); - - check!("", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT); - check!("42195", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT); - check!("12345678", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT); + check!("1234567", [internal_fix!(Nanosecond6NoDot)]; ParsingTooLong); + check!("123456789", [internal_fix!(Nanosecond6NoDot)]; ParsingTooLong); + check!("4x", [internal_fix!(Nanosecond6NoDot)]; ParsingTooShort); + check!(" 4", [internal_fix!(Nanosecond6NoDot)]; ParsingInvalid); + check!(".42100", [internal_fix!(Nanosecond6NoDot)]; ParsingInvalid); + + check!("", [internal_fix!(Nanosecond9NoDot)]; ParsingTooShort); + check!("42195", [internal_fix!(Nanosecond9NoDot)]; ParsingTooShort); + check!("12345678", [internal_fix!(Nanosecond9NoDot)]; ParsingTooShort); check!("421950803", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 421_950_803); check!("000000003", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 3); check!("42195080354", [internal_fix!(Nanosecond9NoDot), num!(Second)]; nanosecond: 421_950_803, second: 54); // don't skip digits that come after the 9 - check!("1234567890", [internal_fix!(Nanosecond9NoDot)]; TOO_LONG); + check!("1234567890", [internal_fix!(Nanosecond9NoDot)]; ParsingTooLong); check!("000000000", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 0); - check!("00000000x", [internal_fix!(Nanosecond9NoDot)]; INVALID); - check!(" 4", [internal_fix!(Nanosecond9NoDot)]; INVALID); - check!(".42100000", [internal_fix!(Nanosecond9NoDot)]; INVALID); + check!("00000000x", [internal_fix!(Nanosecond9NoDot)]; ParsingInvalid); + check!(" 4", [internal_fix!(Nanosecond9NoDot)]; ParsingInvalid); + check!(".42100000", [internal_fix!(Nanosecond9NoDot)]; ParsingInvalid); // fixed: timezone offsets // TimezoneOffset - check!("1", [fix!(TimezoneOffset)]; INVALID); - check!("12", [fix!(TimezoneOffset)]; INVALID); - check!("123", [fix!(TimezoneOffset)]; INVALID); - check!("1234", [fix!(TimezoneOffset)]; INVALID); - check!("12345", [fix!(TimezoneOffset)]; INVALID); - check!("123456", [fix!(TimezoneOffset)]; INVALID); - check!("1234567", [fix!(TimezoneOffset)]; INVALID); - check!("+1", [fix!(TimezoneOffset)]; TOO_SHORT); - check!("+12", [fix!(TimezoneOffset)]; TOO_SHORT); - check!("+123", [fix!(TimezoneOffset)]; TOO_SHORT); + check!("1", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("12", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("123", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("1234", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("12345", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("123456", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("1234567", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+1", [fix!(TimezoneOffset)]; ParsingTooShort); + check!("+12", [fix!(TimezoneOffset)]; ParsingTooShort); + check!("+123", [fix!(TimezoneOffset)]; ParsingTooShort); check!("+1234", [fix!(TimezoneOffset)]; offset: 45_240); - check!("+12345", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+123456", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+1234567", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+12345678", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+12:", [fix!(TimezoneOffset)]; TOO_SHORT); - check!("+12:3", [fix!(TimezoneOffset)]; TOO_SHORT); + check!("+12345", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+123456", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+1234567", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+12345678", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+12:", [fix!(TimezoneOffset)]; ParsingTooShort); + check!("+12:3", [fix!(TimezoneOffset)]; ParsingTooShort); check!("+12:34", [fix!(TimezoneOffset)]; offset: 45_240); check!("-12:34", [fix!(TimezoneOffset)]; offset: -45_240); - check!("+12:34:", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+12:34:5", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+12:34:56", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+12:34:56:", [fix!(TimezoneOffset)]; TOO_LONG); + check!("+12:34:", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+12:34:5", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+12:34:56", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+12:34:56:", [fix!(TimezoneOffset)]; ParsingTooLong); check!("+12 34", [fix!(TimezoneOffset)]; offset: 45_240); - check!("+12 34", [fix!(TimezoneOffset)]; INVALID); - check!("12:34", [fix!(TimezoneOffset)]; INVALID); - check!("12:34:56", [fix!(TimezoneOffset)]; INVALID); - check!("+12::34", [fix!(TimezoneOffset)]; INVALID); - check!("+12: :34", [fix!(TimezoneOffset)]; INVALID); - check!("+12:::34", [fix!(TimezoneOffset)]; INVALID); - check!("+12::::34", [fix!(TimezoneOffset)]; INVALID); - check!("+12::34", [fix!(TimezoneOffset)]; INVALID); - check!("+12:34:56", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+12:3456", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+1234:56", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+1234:567", [fix!(TimezoneOffset)]; TOO_LONG); + check!("+12 34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("12:34:56", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+12::34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+12: :34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+12:::34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+12::::34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+12::34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+12:34:56", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+12:3456", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+1234:56", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+1234:567", [fix!(TimezoneOffset)]; ParsingTooLong); check!("+00:00", [fix!(TimezoneOffset)]; offset: 0); check!("-00:00", [fix!(TimezoneOffset)]; offset: 0); check!("+00:01", [fix!(TimezoneOffset)]; offset: 60); @@ -952,212 +950,212 @@ fn test_parse() { check!("-24:00", [fix!(TimezoneOffset)]; offset: -86_400); check!("+99:59", [fix!(TimezoneOffset)]; offset: 359_940); check!("-99:59", [fix!(TimezoneOffset)]; offset: -359_940); - check!("+00:60", [fix!(TimezoneOffset)]; OUT_OF_RANGE); - check!("+00:99", [fix!(TimezoneOffset)]; OUT_OF_RANGE); - check!("#12:34", [fix!(TimezoneOffset)]; INVALID); - check!("+12:34 ", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+12 34 ", [fix!(TimezoneOffset)]; TOO_LONG); + check!("+00:60", [fix!(TimezoneOffset)]; ParsingOutOfRange); + check!("+00:99", [fix!(TimezoneOffset)]; ParsingOutOfRange); + check!("#12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+12:34 ", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+12 34 ", [fix!(TimezoneOffset)]; ParsingTooLong); check!(" +12:34", [fix!(TimezoneOffset)]; offset: 45_240); check!(" -12:34", [fix!(TimezoneOffset)]; offset: -45_240); - check!(" +12:34", [fix!(TimezoneOffset)]; INVALID); - check!(" -12:34", [fix!(TimezoneOffset)]; INVALID); - check!("\t -12:34", [fix!(TimezoneOffset)]; INVALID); + check!(" +12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!(" -12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("\t -12:34", [fix!(TimezoneOffset)]; ParsingInvalid); check!("-12: 34", [fix!(TimezoneOffset)]; offset: -45_240); check!("-12 :34", [fix!(TimezoneOffset)]; offset: -45_240); check!("-12 : 34", [fix!(TimezoneOffset)]; offset: -45_240); - check!("-12 : 34", [fix!(TimezoneOffset)]; INVALID); - check!("-12 : 34", [fix!(TimezoneOffset)]; INVALID); - check!("-12: 34", [fix!(TimezoneOffset)]; INVALID); - check!("-12 :34", [fix!(TimezoneOffset)]; INVALID); - check!("-12 : 34", [fix!(TimezoneOffset)]; INVALID); - check!("12:34 ", [fix!(TimezoneOffset)]; INVALID); - check!(" 12:34", [fix!(TimezoneOffset)]; INVALID); - check!("", [fix!(TimezoneOffset)]; TOO_SHORT); - check!("+", [fix!(TimezoneOffset)]; TOO_SHORT); + check!("-12 : 34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("-12 : 34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("-12: 34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("-12 :34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("-12 : 34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("12:34 ", [fix!(TimezoneOffset)]; ParsingInvalid); + check!(" 12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("", [fix!(TimezoneOffset)]; ParsingTooShort); + check!("+", [fix!(TimezoneOffset)]; ParsingTooShort); check!("+12345", [fix!(TimezoneOffset), num!(Day)]; offset: 45_240, day: 5); check!("+12:345", [fix!(TimezoneOffset), num!(Day)]; offset: 45_240, day: 5); check!("+12:34:", [fix!(TimezoneOffset), lit!(":")]; offset: 45_240); - check!("Z12:34", [fix!(TimezoneOffset)]; INVALID); - check!("X12:34", [fix!(TimezoneOffset)]; INVALID); - check!("Z+12:34", [fix!(TimezoneOffset)]; INVALID); - check!("X+12:34", [fix!(TimezoneOffset)]; INVALID); - check!("🤠+12:34", [fix!(TimezoneOffset)]; INVALID); - check!("+12:34🤠", [fix!(TimezoneOffset)]; TOO_LONG); - check!("+12:🤠34", [fix!(TimezoneOffset)]; INVALID); + check!("Z12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("X12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("Z+12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("X+12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("🤠+12:34", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+12:34🤠", [fix!(TimezoneOffset)]; ParsingTooLong); + check!("+12:🤠34", [fix!(TimezoneOffset)]; ParsingInvalid); check!("+12:34🤠", [fix!(TimezoneOffset), lit!("🤠")]; offset: 45_240); check!("🤠+12:34", [lit!("🤠"), fix!(TimezoneOffset)]; offset: 45_240); - check!("Z", [fix!(TimezoneOffset)]; INVALID); - check!("A", [fix!(TimezoneOffset)]; INVALID); - check!("PST", [fix!(TimezoneOffset)]; INVALID); - check!("#Z", [fix!(TimezoneOffset)]; INVALID); - check!(":Z", [fix!(TimezoneOffset)]; INVALID); - check!("+Z", [fix!(TimezoneOffset)]; TOO_SHORT); - check!("+:Z", [fix!(TimezoneOffset)]; INVALID); - check!("+Z:", [fix!(TimezoneOffset)]; INVALID); - check!("z", [fix!(TimezoneOffset)]; INVALID); - check!(" :Z", [fix!(TimezoneOffset)]; INVALID); - check!(" Z", [fix!(TimezoneOffset)]; INVALID); - check!(" z", [fix!(TimezoneOffset)]; INVALID); + check!("Z", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("A", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("PST", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("#Z", [fix!(TimezoneOffset)]; ParsingInvalid); + check!(":Z", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+Z", [fix!(TimezoneOffset)]; ParsingTooShort); + check!("+:Z", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("+Z:", [fix!(TimezoneOffset)]; ParsingInvalid); + check!("z", [fix!(TimezoneOffset)]; ParsingInvalid); + check!(" :Z", [fix!(TimezoneOffset)]; ParsingInvalid); + check!(" Z", [fix!(TimezoneOffset)]; ParsingInvalid); + check!(" z", [fix!(TimezoneOffset)]; ParsingInvalid); // TimezoneOffsetColon - check!("1", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12", [fix!(TimezoneOffsetColon)]; INVALID); - check!("123", [fix!(TimezoneOffsetColon)]; INVALID); - check!("1234", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12345", [fix!(TimezoneOffsetColon)]; INVALID); - check!("123456", [fix!(TimezoneOffsetColon)]; INVALID); - check!("1234567", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12345678", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+1", [fix!(TimezoneOffsetColon)]; TOO_SHORT); - check!("+12", [fix!(TimezoneOffsetColon)]; TOO_SHORT); - check!("+123", [fix!(TimezoneOffsetColon)]; TOO_SHORT); + check!("1", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("123", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("1234", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12345", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("123456", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("1234567", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12345678", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+1", [fix!(TimezoneOffsetColon)]; ParsingTooShort); + check!("+12", [fix!(TimezoneOffsetColon)]; ParsingTooShort); + check!("+123", [fix!(TimezoneOffsetColon)]; ParsingTooShort); check!("+1234", [fix!(TimezoneOffsetColon)]; offset: 45_240); check!("-1234", [fix!(TimezoneOffsetColon)]; offset: -45_240); - check!("+12345", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+123456", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+1234567", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+12345678", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("1:", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12:", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12:3", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12:34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12:34:", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12:34:5", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12:34:56", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+1:", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+12:", [fix!(TimezoneOffsetColon)]; TOO_SHORT); - check!("+12:3", [fix!(TimezoneOffsetColon)]; TOO_SHORT); + check!("+12345", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+123456", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+1234567", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+12345678", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("1:", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12:", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12:3", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12:34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12:34:", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12:34:5", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12:34:56", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+1:", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+12:", [fix!(TimezoneOffsetColon)]; ParsingTooShort); + check!("+12:3", [fix!(TimezoneOffsetColon)]; ParsingTooShort); check!("+12:34", [fix!(TimezoneOffsetColon)]; offset: 45_240); check!("-12:34", [fix!(TimezoneOffsetColon)]; offset: -45_240); - check!("+12:34:", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+12:34:5", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+12:34:56", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+12:34:56:", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+12:34:56:7", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+12:34:56:78", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+12:3456", [fix!(TimezoneOffsetColon)]; TOO_LONG); - check!("+1234:56", [fix!(TimezoneOffsetColon)]; TOO_LONG); + check!("+12:34:", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+12:34:5", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+12:34:56", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+12:34:56:", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+12:34:56:7", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+12:34:56:78", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+12:3456", [fix!(TimezoneOffsetColon)]; ParsingTooLong); + check!("+1234:56", [fix!(TimezoneOffsetColon)]; ParsingTooLong); check!("+12 34", [fix!(TimezoneOffsetColon)]; offset: 45_240); check!("+12: 34", [fix!(TimezoneOffsetColon)]; offset: 45_240); check!("+12 :34", [fix!(TimezoneOffsetColon)]; offset: 45_240); check!("+12 : 34", [fix!(TimezoneOffsetColon)]; offset: 45_240); - check!("+12 : 34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+12 : 34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+12 : 34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+12::34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+12: :34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+12:::34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+12::::34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+12::34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("#1234", [fix!(TimezoneOffsetColon)]; INVALID); - check!("#12:34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+12:34 ", [fix!(TimezoneOffsetColon)]; TOO_LONG); + check!("+12 : 34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+12 : 34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+12 : 34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+12::34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+12: :34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+12:::34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+12::::34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+12::34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("#1234", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("#12:34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+12:34 ", [fix!(TimezoneOffsetColon)]; ParsingTooLong); check!(" +12:34", [fix!(TimezoneOffsetColon)]; offset: 45_240); check!("\t+12:34", [fix!(TimezoneOffsetColon)]; offset: 45_240); - check!("\t\t+12:34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("12:34 ", [fix!(TimezoneOffsetColon)]; INVALID); - check!(" 12:34", [fix!(TimezoneOffsetColon)]; INVALID); - check!("", [fix!(TimezoneOffsetColon)]; TOO_SHORT); - check!("+", [fix!(TimezoneOffsetColon)]; TOO_SHORT); - check!(":", [fix!(TimezoneOffsetColon)]; INVALID); + check!("\t\t+12:34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("12:34 ", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!(" 12:34", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("", [fix!(TimezoneOffsetColon)]; ParsingTooShort); + check!("+", [fix!(TimezoneOffsetColon)]; ParsingTooShort); + check!(":", [fix!(TimezoneOffsetColon)]; ParsingInvalid); check!("+12345", [fix!(TimezoneOffsetColon), num!(Day)]; offset: 45_240, day: 5); check!("+12:345", [fix!(TimezoneOffsetColon), num!(Day)]; offset: 45_240, day: 5); check!("+12:34:", [fix!(TimezoneOffsetColon), lit!(":")]; offset: 45_240); - check!("Z", [fix!(TimezoneOffsetColon)]; INVALID); - check!("A", [fix!(TimezoneOffsetColon)]; INVALID); - check!("PST", [fix!(TimezoneOffsetColon)]; INVALID); - check!("#Z", [fix!(TimezoneOffsetColon)]; INVALID); - check!(":Z", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+Z", [fix!(TimezoneOffsetColon)]; TOO_SHORT); - check!("+:Z", [fix!(TimezoneOffsetColon)]; INVALID); - check!("+Z:", [fix!(TimezoneOffsetColon)]; INVALID); - check!("z", [fix!(TimezoneOffsetColon)]; INVALID); - check!(" :Z", [fix!(TimezoneOffsetColon)]; INVALID); - check!(" Z", [fix!(TimezoneOffsetColon)]; INVALID); - check!(" z", [fix!(TimezoneOffsetColon)]; INVALID); + check!("Z", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("A", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("PST", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("#Z", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!(":Z", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+Z", [fix!(TimezoneOffsetColon)]; ParsingTooShort); + check!("+:Z", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("+Z:", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!("z", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!(" :Z", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!(" Z", [fix!(TimezoneOffsetColon)]; ParsingInvalid); + check!(" z", [fix!(TimezoneOffsetColon)]; ParsingInvalid); // testing `TimezoneOffsetColon` also tests same path as `TimezoneOffsetDoubleColon` // and `TimezoneOffsetTripleColon` for function `parse_internal`. // No need for separate tests for `TimezoneOffsetDoubleColon` and // `TimezoneOffsetTripleColon`. // TimezoneOffsetZ - check!("1", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12", [fix!(TimezoneOffsetZ)]; INVALID); - check!("123", [fix!(TimezoneOffsetZ)]; INVALID); - check!("1234", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12345", [fix!(TimezoneOffsetZ)]; INVALID); - check!("123456", [fix!(TimezoneOffsetZ)]; INVALID); - check!("1234567", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12345678", [fix!(TimezoneOffsetZ)]; INVALID); - check!("+1", [fix!(TimezoneOffsetZ)]; TOO_SHORT); - check!("+12", [fix!(TimezoneOffsetZ)]; TOO_SHORT); - check!("+123", [fix!(TimezoneOffsetZ)]; TOO_SHORT); + check!("1", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("123", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("1234", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12345", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("123456", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("1234567", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12345678", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("+1", [fix!(TimezoneOffsetZ)]; ParsingTooShort); + check!("+12", [fix!(TimezoneOffsetZ)]; ParsingTooShort); + check!("+123", [fix!(TimezoneOffsetZ)]; ParsingTooShort); check!("+1234", [fix!(TimezoneOffsetZ)]; offset: 45_240); check!("-1234", [fix!(TimezoneOffsetZ)]; offset: -45_240); - check!("+12345", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+123456", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+1234567", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+12345678", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("1:", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12:", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12:3", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12:34", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12:34:", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12:34:5", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12:34:56", [fix!(TimezoneOffsetZ)]; INVALID); - check!("+1:", [fix!(TimezoneOffsetZ)]; INVALID); - check!("+12:", [fix!(TimezoneOffsetZ)]; TOO_SHORT); - check!("+12:3", [fix!(TimezoneOffsetZ)]; TOO_SHORT); + check!("+12345", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+123456", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+1234567", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+12345678", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("1:", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12:", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12:3", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12:34", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12:34:", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12:34:5", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12:34:56", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("+1:", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("+12:", [fix!(TimezoneOffsetZ)]; ParsingTooShort); + check!("+12:3", [fix!(TimezoneOffsetZ)]; ParsingTooShort); check!("+12:34", [fix!(TimezoneOffsetZ)]; offset: 45_240); check!("-12:34", [fix!(TimezoneOffsetZ)]; offset: -45_240); - check!("+12:34:", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+12:34:5", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+12:34:56", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+12:34:56:", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+12:34:56:7", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+12:34:56:78", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+12::34", [fix!(TimezoneOffsetZ)]; INVALID); - check!("+12:3456", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+1234:56", [fix!(TimezoneOffsetZ)]; TOO_LONG); + check!("+12:34:", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+12:34:5", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+12:34:56", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+12:34:56:", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+12:34:56:7", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+12:34:56:78", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+12::34", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("+12:3456", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+1234:56", [fix!(TimezoneOffsetZ)]; ParsingTooLong); check!("+12 34", [fix!(TimezoneOffsetZ)]; offset: 45_240); - check!("+12 34", [fix!(TimezoneOffsetZ)]; INVALID); + check!("+12 34", [fix!(TimezoneOffsetZ)]; ParsingInvalid); check!("+12: 34", [fix!(TimezoneOffsetZ)]; offset: 45_240); check!("+12 :34", [fix!(TimezoneOffsetZ)]; offset: 45_240); check!("+12 : 34", [fix!(TimezoneOffsetZ)]; offset: 45_240); - check!("+12 : 34", [fix!(TimezoneOffsetZ)]; INVALID); - check!("+12 : 34", [fix!(TimezoneOffsetZ)]; INVALID); - check!("+12 : 34", [fix!(TimezoneOffsetZ)]; INVALID); - check!("12:34 ", [fix!(TimezoneOffsetZ)]; INVALID); - check!(" 12:34", [fix!(TimezoneOffsetZ)]; INVALID); - check!("+12:34 ", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("+12 34 ", [fix!(TimezoneOffsetZ)]; TOO_LONG); + check!("+12 : 34", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("+12 : 34", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("+12 : 34", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("12:34 ", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!(" 12:34", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("+12:34 ", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("+12 34 ", [fix!(TimezoneOffsetZ)]; ParsingTooLong); check!(" +12:34", [fix!(TimezoneOffsetZ)]; offset: 45_240); check!("+12345", [fix!(TimezoneOffsetZ), num!(Day)]; offset: 45_240, day: 5); check!("+12:345", [fix!(TimezoneOffsetZ), num!(Day)]; offset: 45_240, day: 5); check!("+12:34:", [fix!(TimezoneOffsetZ), lit!(":")]; offset: 45_240); - check!("Z12:34", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("X12:34", [fix!(TimezoneOffsetZ)]; INVALID); + check!("Z12:34", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("X12:34", [fix!(TimezoneOffsetZ)]; ParsingInvalid); check!("Z", [fix!(TimezoneOffsetZ)]; offset: 0); check!("z", [fix!(TimezoneOffsetZ)]; offset: 0); check!(" Z", [fix!(TimezoneOffsetZ)]; offset: 0); check!(" z", [fix!(TimezoneOffsetZ)]; offset: 0); - check!("\u{0363}Z", [fix!(TimezoneOffsetZ)]; INVALID); - check!("Z ", [fix!(TimezoneOffsetZ)]; TOO_LONG); - check!("A", [fix!(TimezoneOffsetZ)]; INVALID); - check!("PST", [fix!(TimezoneOffsetZ)]; INVALID); - check!("#Z", [fix!(TimezoneOffsetZ)]; INVALID); - check!(":Z", [fix!(TimezoneOffsetZ)]; INVALID); - check!(":z", [fix!(TimezoneOffsetZ)]; INVALID); - check!("+Z", [fix!(TimezoneOffsetZ)]; TOO_SHORT); - check!("-Z", [fix!(TimezoneOffsetZ)]; TOO_SHORT); - check!("+A", [fix!(TimezoneOffsetZ)]; TOO_SHORT); - check!("+🙃", [fix!(TimezoneOffsetZ)]; INVALID); - check!("+Z:", [fix!(TimezoneOffsetZ)]; INVALID); - check!(" :Z", [fix!(TimezoneOffsetZ)]; INVALID); - check!(" +Z", [fix!(TimezoneOffsetZ)]; TOO_SHORT); - check!(" -Z", [fix!(TimezoneOffsetZ)]; TOO_SHORT); - check!("+:Z", [fix!(TimezoneOffsetZ)]; INVALID); - check!("Y", [fix!(TimezoneOffsetZ)]; INVALID); + check!("\u{0363}Z", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("Z ", [fix!(TimezoneOffsetZ)]; ParsingTooLong); + check!("A", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("PST", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("#Z", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!(":Z", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!(":z", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("+Z", [fix!(TimezoneOffsetZ)]; ParsingTooShort); + check!("-Z", [fix!(TimezoneOffsetZ)]; ParsingTooShort); + check!("+A", [fix!(TimezoneOffsetZ)]; ParsingTooShort); + check!("+🙃", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("+Z:", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!(" :Z", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!(" +Z", [fix!(TimezoneOffsetZ)]; ParsingTooShort); + check!(" -Z", [fix!(TimezoneOffsetZ)]; ParsingTooShort); + check!("+:Z", [fix!(TimezoneOffsetZ)]; ParsingInvalid); + check!("Y", [fix!(TimezoneOffsetZ)]; ParsingInvalid); check!("Zulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 0); check!("zulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 0); check!("+1234ulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 45_240); @@ -1167,91 +1165,91 @@ fn test_parse() { // No need for separate tests for `TimezoneOffsetColonZ`. // TimezoneOffsetPermissive - check!("1", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("123", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("1234", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12345", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("123456", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("1234567", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12345678", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+1", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT); + check!("1", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("123", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("1234", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12345", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("123456", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("1234567", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12345678", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+1", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooShort); check!("+12", [internal_fix!(TimezoneOffsetPermissive)]; offset: 43_200); - check!("+123", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT); + check!("+123", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooShort); check!("+1234", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240); check!("-1234", [internal_fix!(TimezoneOffsetPermissive)]; offset: -45_240); - check!("+12345", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("+123456", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("+1234567", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("+12345678", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("1:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12:3", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12:34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12:34:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12:34:5", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12:34:56", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+1:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); + check!("+12345", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("+123456", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("+1234567", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("+12345678", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("1:", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12:", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12:3", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12:34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12:34:", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12:34:5", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12:34:56", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+1:", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); check!("+12:", [internal_fix!(TimezoneOffsetPermissive)]; offset: 43_200); - check!("+12:3", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT); + check!("+12:3", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooShort); check!("+12:34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240); check!("-12:34", [internal_fix!(TimezoneOffsetPermissive)]; offset: -45_240); - check!("+12:34:", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("+12:34:5", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("+12:34:56", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("+12:34:56:", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("+12:34:56:7", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("+12:34:56:78", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); + check!("+12:34:", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("+12:34:5", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("+12:34:56", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("+12:34:56:", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("+12:34:56:7", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("+12:34:56:78", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); check!("+12 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240); - check!("+12 34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); + check!("+12 34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); check!("+12 :34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240); check!("+12: 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240); check!("+12 : 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240); - check!("+12 :34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12: 34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12 : 34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12::34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12 ::34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12: :34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12:: 34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12 ::34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12: :34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12:: 34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12:::34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12::::34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("12:34 ", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!(" 12:34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12:34 ", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); + check!("+12 :34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12: 34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12 : 34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12::34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12 ::34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12: :34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12:: 34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12 ::34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12: :34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12:: 34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12:::34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12::::34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("12:34 ", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!(" 12:34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12:34 ", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); check!(" +12:34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240); check!("+12345", [internal_fix!(TimezoneOffsetPermissive), num!(Day)]; offset: 45_240, day: 5); check!("+12:345", [internal_fix!(TimezoneOffsetPermissive), num!(Day)]; offset: 45_240, day: 5); check!("+12:34:", [internal_fix!(TimezoneOffsetPermissive), lit!(":")]; offset: 45_240); - check!("🤠+12:34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+12:34🤠", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("+12:🤠34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); + check!("🤠+12:34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+12:34🤠", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("+12:🤠34", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); check!("+12:34🤠", [internal_fix!(TimezoneOffsetPermissive), lit!("🤠")]; offset: 45_240); check!("🤠+12:34", [lit!("🤠"), internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240); check!("Z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0); - check!("A", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("PST", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); + check!("A", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("PST", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); check!("z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0); check!(" Z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0); check!(" z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0); - check!("Z ", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG); - check!("#Z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!(":Z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!(":z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+Z", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT); - check!("-Z", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT); - check!("+A", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT); - check!("+PST", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+🙃", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("+Z:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!(" :Z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!(" +Z", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT); - check!(" -Z", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT); - check!("+:Z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - check!("Y", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); + check!("Z ", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooLong); + check!("#Z", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!(":Z", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!(":z", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+Z", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooShort); + check!("-Z", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooShort); + check!("+A", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooShort); + check!("+PST", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+🙃", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("+Z:", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!(" :Z", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!(" +Z", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooShort); + check!(" -Z", [internal_fix!(TimezoneOffsetPermissive)]; ParsingTooShort); + check!("+:Z", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); + check!("Y", [internal_fix!(TimezoneOffsetPermissive)]; ParsingInvalid); // TimezoneName check!("CEST", [fix!(TimezoneName)]; ); @@ -1259,9 +1257,9 @@ fn test_parse() { check!("XXXXXXXX", [fix!(TimezoneName)]; ); // not a real timezone name check!("!!!!", [fix!(TimezoneName)]; ); // not a real timezone name! check!("CEST 5", [fix!(TimezoneName), lit!(" "), num!(Day)]; day: 5); - check!("CEST ", [fix!(TimezoneName)]; TOO_LONG); - check!(" CEST", [fix!(TimezoneName)]; TOO_LONG); - check!("CE ST", [fix!(TimezoneName)]; TOO_LONG); + check!("CEST ", [fix!(TimezoneName)]; ParsingTooLong); + check!(" CEST", [fix!(TimezoneName)]; ParsingTooLong); + check!("CE ST", [fix!(TimezoneName)]; ParsingTooLong); // some practical examples check!("2015-02-04T14:37:05+09:00", @@ -1340,47 +1338,15 @@ fn test_parse() { #[cfg(test)] #[test] fn test_rfc2822() { - use super::NOT_ENOUGH; use super::*; use crate::offset::FixedOffset; use crate::DateTime; - // Test data - (input, Ok(expected result after parse and format) or Err(error code)) - let testdates = [ - ("Tue, 20 Jan 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // normal case - ("Fri, 2 Jan 2015 17:35:20 -0800", Ok("Fri, 02 Jan 2015 17:35:20 -0800")), // folding whitespace - ("Fri, 02 Jan 2015 17:35:20 -0800", Ok("Fri, 02 Jan 2015 17:35:20 -0800")), // leading zero - ("Tue, 20 Jan 2015 17:35:20 -0800 (UTC)", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // trailing comment - ("Tue, 20 Jan 2015 17:35:20 -0800 (UTC)", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // intermixed arbitrary whitespace - ("Tue, 20 Jan 2015\t17:35:20\t-0800\t\t(UTC)", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // intermixed arbitrary whitespace - ( - r"Tue, 20 Jan 2015 17:35:20 -0800 ( (UTC ) (\( (a)\(( \t ) ) \\( \) ))", - Ok("Tue, 20 Jan 2015 17:35:20 -0800"), - ), // complex trailing comment - (r"Tue, 20 Jan 2015 17:35:20 -0800 (UTC\)", Err(TOO_LONG)), // incorrect comment, not enough closing parentheses - ( - "Tue, 20 Jan 2015 17:35:20 -0800 (UTC)\t \r\n(Anothercomment)", - Ok("Tue, 20 Jan 2015 17:35:20 -0800"), - ), // multiple comments - ("Tue, 20 Jan 2015 17:35:20 -0800 (UTC) ", Err(TOO_LONG)), // trailing whitespace after comment - ("20 Jan 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // no day of week - ("20 JAN 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // upper case month - ("Tue, 20 Jan 2015 17:35 -0800", Ok("Tue, 20 Jan 2015 17:35:00 -0800")), // no second - ("11 Sep 2001 09:45:00 EST", Ok("Tue, 11 Sep 2001 09:45:00 -0500")), - ("30 Feb 2015 17:35:20 -0800", Err(OUT_OF_RANGE)), // bad day of month - ("Tue, 20 Jan 2015", Err(TOO_SHORT)), // omitted fields - ("Tue, 20 Avr 2015 17:35:20 -0800", Err(INVALID)), // bad month name - ("Tue, 20 Jan 2015 25:35:20 -0800", Err(OUT_OF_RANGE)), // bad hour - ("Tue, 20 Jan 2015 7:35:20 -0800", Err(INVALID)), // bad # of digits in hour - ("Tue, 20 Jan 2015 17:65:20 -0800", Err(OUT_OF_RANGE)), // bad minute - ("Tue, 20 Jan 2015 17:35:90 -0800", Err(OUT_OF_RANGE)), // bad second - ("Tue, 20 Jan 2015 17:35:20 -0890", Err(OUT_OF_RANGE)), // bad offset - ("6 Jun 1944 04:00:00Z", Err(INVALID)), // bad offset (zulu not allowed) - ("Tue, 20 Jan 2015 17:35:20 HAS", Err(NOT_ENOUGH)), // bad named time zone - ("Tue, 20 Jan 2015😈17:35:20 -0800", Err(INVALID)), // bad character! - ]; + fn rfc(date: &str) -> Result { + rfc2822_to_datetime(date).map(|s| fmt_rfc2822_datetime(s)) + } - fn rfc2822_to_datetime(date: &str) -> ParseResult> { + fn rfc2822_to_datetime(date: &str) -> Result, Error> { let mut parsed = Parsed::new(); parse(&mut parsed, date, [Item::Fixed(Fixed::RFC2822)].iter())?; parsed.to_datetime() @@ -1390,22 +1356,32 @@ fn test_rfc2822() { dt.format_with_items([Item::Fixed(Fixed::RFC2822)].iter()).to_string() } - // Test against test data above - for &(date, checkdate) in testdates.iter() { - let d = rfc2822_to_datetime(date); // parse a date - let dt = match d { - // did we get a value? - Ok(dt) => Ok(fmt_rfc2822_datetime(dt)), // yes, go on - Err(e) => Err(e), // otherwise keep an error for the comparison - }; - if dt != checkdate.map(|s| s.to_string()) { - // check for expected result - panic!( - "Date conversion failed for {}\nReceived: {:?}\nExpected: {:?}", - date, dt, checkdate - ); - } - } + // Test data + assert_eq!(rfc("Tue, 20 Jan 2015 17:35:20 -0800").unwrap(), "Tue, 20 Jan 2015 17:35:20 -0800"); // normal case + assert_eq!(rfc("Fri, 2 Jan 2015 17:35:20 -0800").unwrap(), "Fri, 02 Jan 2015 17:35:20 -0800"); // folding whitespace + assert_eq!(rfc("Fri, 02 Jan 2015 17:35:20 -0800").unwrap(), "Fri, 02 Jan 2015 17:35:20 -0800"); // leading zero + assert_eq!(rfc("Tue, 20 Jan 2015 17:35:20 -0800 (UTC)").unwrap(), "Tue, 20 Jan 2015 17:35:20 -0800"); // trailing comment + assert_eq!(rfc("Tue, 20 Jan 2015 17:35:20 -0800 (UTC)").unwrap(), "Tue, 20 Jan 2015 17:35:20 -0800"); // intermixed arbitrary whitespace + assert_eq!(rfc("Tue, 20 Jan 2015\t17:35:20\t-0800\t\t(UTC)").unwrap(), "Tue, 20 Jan 2015 17:35:20 -0800"); // intermixed arbitrary whitespace + assert_eq!(rfc(r"Tue, 20 Jan 2015 17:35:20 -0800 ( (UTC ) (\( (a)\(( \t ) ) \\( \) ))").unwrap(), "Tue, 20 Jan 2015 17:35:20 -0800"); // complex trailing comment + assert_eq!(rfc(r"Tue, 20 Jan 2015 17:35:20 -0800 (UTC\)").unwrap_err(), Error::ParsingTooLong); // incorrect comment, not enough closing parentheses + assert_eq!(rfc("Tue, 20 Jan 2015 17:35:20 -0800 (UTC)\t \r\n(Anothercomment)").unwrap(), "Tue, 20 Jan 2015 17:35:20 -0800"); // multiple comments + assert_eq!(rfc("Tue, 20 Jan 2015 17:35:20 -0800 (UTC) ").unwrap_err(), Error::ParsingTooLong); // trailing whitespace after comment + assert_eq!(rfc("20 Jan 2015 17:35:20 -0800").unwrap(), "Tue, 20 Jan 2015 17:35:20 -0800"); // no day of week + assert_eq!(rfc("20 JAN 2015 17:35:20 -0800").unwrap(), "Tue, 20 Jan 2015 17:35:20 -0800"); // upper case month + assert_eq!(rfc("Tue, 20 Jan 2015 17:35 -0800").unwrap(), "Tue, 20 Jan 2015 17:35:00 -0800"); // no second + assert_eq!(rfc("11 Sep 2001 09:45:00 EST").unwrap(), "Tue, 11 Sep 2001 09:45:00 -0500"); + assert_eq!(rfc("30 Feb 2015 17:35:20 -0800").unwrap_err(), Error::ParsingOutOfRange); // bad day of month + assert_eq!(rfc("Tue, 20 Jan 2015").unwrap_err(), Error::ParsingTooShort); // omitted fields + assert_eq!(rfc("Tue, 20 Avr 2015 17:35:20 -0800").unwrap_err(), Error::ParsingInvalid); // bad month name + assert_eq!(rfc("Tue, 20 Jan 2015 25:35:20 -0800").unwrap_err(), Error::ParsingOutOfRange); // bad hour + assert_eq!(rfc("Tue, 20 Jan 2015 7:35:20 -0800").unwrap_err(), Error::ParsingInvalid); // bad # of digits in hour + assert_eq!(rfc("Tue, 20 Jan 2015 17:65:20 -0800").unwrap_err(), Error::ParsingOutOfRange); // bad minute + assert_eq!(rfc("Tue, 20 Jan 2015 17:35:90 -0800").unwrap_err(), Error::ParsingOutOfRange); // bad second + assert_eq!(rfc("Tue, 20 Jan 2015 17:35:20 -0890").unwrap_err(), Error::ParsingOutOfRange); // bad offset + assert_eq!(rfc("6 Jun 1944 04:00:00Z").unwrap_err(), Error::ParsingInvalid); // bad offset (zulu not allowed) + assert_eq!(rfc("Tue, 20 Jan 2015 17:35:20 HAS").unwrap_err(), Error::ParsingNotEnough);// bad named time zone + assert_eq!(rfc("Tue, 20 Jan 2015😈17:35:20 -0800").unwrap_err(), Error::ParsingInvalid); // bad character! } #[cfg(test)] @@ -1416,7 +1392,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.with_ymd_and_hms(1994, 11, 6, 8, 49, 37).unwrap(); + 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); @@ -1427,19 +1403,28 @@ fn parse_rfc850() { // Check that the rest of the weekdays parse correctly (this test originally failed because // Sunday parsed incorrectly). let testdates = [ - (Utc.with_ymd_and_hms(1994, 11, 7, 8, 49, 37).unwrap(), "Monday, 07-Nov-94 08:49:37 GMT"), - (Utc.with_ymd_and_hms(1994, 11, 8, 8, 49, 37).unwrap(), "Tuesday, 08-Nov-94 08:49:37 GMT"), ( - Utc.with_ymd_and_hms(1994, 11, 9, 8, 49, 37).unwrap(), + 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.with_ymd_and_hms(1994, 11, 10, 8, 49, 37).unwrap(), + Utc.ymd(1994, 11, 10).unwrap().and_hms(8, 49, 37).unwrap(), "Thursday, 10-Nov-94 08:49:37 GMT", ), - (Utc.with_ymd_and_hms(1994, 11, 11, 8, 49, 37).unwrap(), "Friday, 11-Nov-94 08:49:37 GMT"), ( - Utc.with_ymd_and_hms(1994, 11, 12, 8, 49, 37).unwrap(), + 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", ), ]; @@ -1456,38 +1441,11 @@ fn test_rfc3339() { use crate::offset::FixedOffset; use crate::DateTime; - // Test data - (input, Ok(expected result after parse and format) or Err(error code)) - let testdates = [ - ("2015-01-20T17:35:20-08:00", Ok("2015-01-20T17:35:20-08:00")), // normal case - ("1944-06-06T04:04:00Z", Ok("1944-06-06T04:04:00+00:00")), // D-day - ("2001-09-11T09:45:00-08:00", Ok("2001-09-11T09:45:00-08:00")), - ("2015-01-20T17:35:20.001-08:00", Ok("2015-01-20T17:35:20.001-08:00")), - ("2015-01-20T17:35:20.000031-08:00", Ok("2015-01-20T17:35:20.000031-08:00")), - ("2015-01-20T17:35:20.000000004-08:00", Ok("2015-01-20T17:35:20.000000004-08:00")), - ("2015-01-20T17:35:20.000000000452-08:00", Ok("2015-01-20T17:35:20-08:00")), // too small - ("2015-01-20 17:35:20.001-08:00", Err(INVALID)), // missing separator 'T' - ("2015/01/20T17:35:20.001-08:00", Err(INVALID)), // wrong separator char YMD - ("2015-01-20T17-35-20.001-08:00", Err(INVALID)), // wrong separator char HMS - ("99999-01-20T17:35:20-08:00", Err(INVALID)), // bad year value - ("-2000-01-20T17:35:20-08:00", Err(INVALID)), // bad year value - ("2015-02-30T17:35:20-08:00", Err(OUT_OF_RANGE)), // bad day of month value - ("2015-01-20T25:35:20-08:00", Err(OUT_OF_RANGE)), // bad hour value - ("2015-01-20T17:65:20-08:00", Err(OUT_OF_RANGE)), // bad minute value - ("2015-01-20T17:35:90-08:00", Err(OUT_OF_RANGE)), // bad second value - ("2015-01-20T17:35:20-24:00", Err(OUT_OF_RANGE)), // bad offset value - ("15-01-20T17:35:20-08:00", Err(INVALID)), // bad year format - ("15-01-20T17:35:20-08:00:00", Err(INVALID)), // bad year format, bad offset format - ("2015-01-20T17:35:20-0800", Err(INVALID)), // bad offset format - ("2015-01-20T17:35:20.001-08 : 00", Err(INVALID)), // bad offset format - ("2015-01-20T17:35:20-08:00:00", Err(TOO_LONG)), // bad offset format - ("2015-01-20T17:35:20-08:", Err(TOO_SHORT)), // bad offset format - ("2015-01-20T17:35:20-08", Err(TOO_SHORT)), // bad offset format - ("2015-01-20T", Err(TOO_SHORT)), // missing HMS - ("2015-01-20T00:00:1", Err(TOO_SHORT)), // missing complete S - ("2015-01-20T00:00:1-08:00", Err(INVALID)), // missing complete S - ]; + fn rfc(date: &str) -> Result { + rfc3339_to_datetime(date).map(|s| fmt_rfc3339_datetime(s)) + } - fn rfc3339_to_datetime(date: &str) -> ParseResult> { + fn rfc3339_to_datetime(date: &str) -> Result, Error> { let mut parsed = Parsed::new(); parse(&mut parsed, date, [Item::Fixed(Fixed::RFC3339)].iter())?; parsed.to_datetime() @@ -1497,21 +1455,33 @@ fn test_rfc3339() { dt.format_with_items([Item::Fixed(Fixed::RFC3339)].iter()).to_string() } - // Test against test data above - for &(date, checkdate) in testdates.iter() { - eprintln!("test_rfc3339: date {:?}, expect {:?}", date, checkdate); - let d = rfc3339_to_datetime(date); // parse a date - let dt = match d { - // did we get a value? - Ok(dt) => Ok(fmt_rfc3339_datetime(dt)), // yes, go on - Err(e) => Err(e), // otherwise keep an error for the comparison - }; - if dt != checkdate.map(|s| s.to_string()) { - // check for expected result - panic!( - "Date conversion failed for {}\nReceived: {:?}\nExpected: {:?}", - date, dt, checkdate - ); - } - } + // Test data + assert_eq!(rfc("2015-01-20T17:35:20-08:00").unwrap(), "2015-01-20T17:35:20-08:00"); // normal case + assert_eq!(rfc("1944-06-06T04:04:00Z").unwrap(), "1944-06-06T04:04:00+00:00"); // D-day + assert_eq!(rfc("2001-09-11T09:45:00-08:00").unwrap(), "2001-09-11T09:45:00-08:00"); + assert_eq!(rfc("2015-01-20T17:35:20.001-08:00").unwrap(), "2015-01-20T17:35:20.001-08:00"); + assert_eq!(rfc("2015-01-20T17:35:20.000031-08:00").unwrap(), "2015-01-20T17:35:20.000031-08:00"); + assert_eq!(rfc("2015-01-20T17:35:20.000000004-08:00").unwrap(), "2015-01-20T17:35:20.000000004-08:00"); + assert_eq!(rfc("2015-01-20T17:35:20.000000000452-08:00").unwrap(), "2015-01-20T17:35:20-08:00"); // too small + assert_eq!(rfc("2015-01-20 17:35:20.001-08:00").unwrap_err(), Error::ParsingInvalid); // missing separator 'T' + assert_eq!(rfc("2015/01/20T17:35:20.001-08:00").unwrap_err(), Error::ParsingInvalid); // wrong separator char YMD + assert_eq!(rfc("2015-01-20T17-35-20.001-08:00").unwrap_err(), Error::ParsingInvalid); // wrong separator char HMS + assert_eq!(rfc("99999-01-20T17:35:20-08:00").unwrap_err(), Error::ParsingInvalid); // bad year value + assert_eq!(rfc("-2000-01-20T17:35:20-08:00").unwrap_err(), Error::ParsingInvalid); // bad year value + assert_eq!(rfc("2015-02-30T17:35:20-08:00").unwrap_err(), Error::ParsingOutOfRange); // bad day of month value + assert_eq!(rfc("2015-01-20T25:35:20-08:00").unwrap_err(), Error::ParsingOutOfRange); // bad hour value + assert_eq!(rfc("2015-01-20T17:65:20-08:00").unwrap_err(), Error::ParsingOutOfRange); // bad minute value + assert_eq!(rfc("2015-01-20T17:35:90-08:00").unwrap_err(), Error::ParsingOutOfRange); // bad second value + assert_eq!(rfc("2015-01-20T17:35:20-24:00").unwrap_err(), Error::ParsingOutOfRange); // bad offset value + assert_eq!(rfc("15-01-20T17:35:20-08:00").unwrap_err(), Error::ParsingInvalid); // bad year format + assert_eq!(rfc("15-01-20T17:35:20-08:00:00").unwrap_err(), Error::ParsingInvalid); // bad year format, bad offset format + assert_eq!(rfc("2015-01-20T17:35:20-0800").unwrap_err(), Error::ParsingInvalid); // bad offset format + assert_eq!(rfc("2015-01-20T17:35:20.001-08 : 00").unwrap_err(), Error::ParsingInvalid); // bad offset format + assert_eq!(rfc("2015-01-20T17:35:20-08:00:00").unwrap_err(), Error::ParsingTooLong); // bad offset format + assert_eq!(rfc("2015-01-20T17:35:20-08:").unwrap_err(), Error::ParsingTooShort); // bad offset format + assert_eq!(rfc("2015-01-20T17:35:20-08").unwrap_err(), Error::ParsingTooShort); // bad offset format + assert_eq!(rfc("2015-01-20T").unwrap_err(), Error::ParsingTooShort); // missing HMS + assert_eq!(rfc("2015-01-20T00:00:1").unwrap_err(), Error::ParsingTooShort); // missing complete S + assert_eq!(rfc("2015-01-20T00:00:1-08:00").unwrap_err(), Error::ParsingInvalid); // missing complete S + } diff --git a/src/format/parsed.rs b/src/format/parsed.rs index 3235d32c97..eecbf8693d 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -8,10 +8,9 @@ use core::convert::TryFrom; 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::{DateTime, Datelike, TimeDelta, Timelike, Weekday}; +use crate::offset::{FixedOffset, Offset, TimeZone}; +use crate::{Error, DateTime, Datelike, TimeDelta, Timelike, Weekday}; /// Parsed parts of date and time. There are two classes of methods: /// @@ -108,12 +107,12 @@ pub struct Parsed { /// Checks if `old` is either empty or has the same value as `new` (i.e. "consistent"), /// and if it is empty, set `old` to `new` as well. #[inline] -fn set_if_consistent(old: &mut Option, new: T) -> ParseResult<()> { +fn set_if_consistent(old: &mut Option, new: T) -> Result<(), Error> { if let Some(ref old) = *old { if *old == new { Ok(()) } else { - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) } } else { *old = Some(new); @@ -129,113 +128,113 @@ impl Parsed { /// Tries to set the [`year`](#structfield.year) field from given value. #[inline] - pub fn set_year(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_year(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value. #[inline] - pub fn set_year_div_100(&mut self, value: i64) -> ParseResult<()> { + pub fn set_year_div_100(&mut self, value: i64) -> Result<(), Error> { if value < 0 { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } - set_if_consistent(&mut self.year_div_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + set_if_consistent(&mut self.year_div_100, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value. #[inline] - pub fn set_year_mod_100(&mut self, value: i64) -> ParseResult<()> { + pub fn set_year_mod_100(&mut self, value: i64) -> Result<(), Error> { if value < 0 { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } - set_if_consistent(&mut self.year_mod_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + set_if_consistent(&mut self.year_mod_100, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`isoyear`](#structfield.isoyear) field from given value. #[inline] - pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_isoyear(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value. #[inline] - pub fn set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()> { + pub fn set_isoyear_div_100(&mut self, value: i64) -> Result<(), Error> { if value < 0 { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } set_if_consistent( &mut self.isoyear_div_100, - i32::try_from(value).map_err(|_| OUT_OF_RANGE)?, + i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?, ) } /// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value. #[inline] - pub fn set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()> { + pub fn set_isoyear_mod_100(&mut self, value: i64) -> Result<(), Error> { if value < 0 { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } set_if_consistent( &mut self.isoyear_mod_100, - i32::try_from(value).map_err(|_| OUT_OF_RANGE)?, + i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?, ) } /// Tries to set the [`month`](#structfield.month) field from given value. #[inline] - pub fn set_month(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.month, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_month(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.month, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value. #[inline] - pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.week_from_sun, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_week_from_sun(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.week_from_sun, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value. #[inline] - pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.week_from_mon, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_week_from_mon(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.week_from_mon, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`isoweek`](#structfield.isoweek) field from given value. #[inline] - pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.isoweek, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_isoweek(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.isoweek, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`weekday`](#structfield.weekday) field from given value. #[inline] - pub fn set_weekday(&mut self, value: Weekday) -> ParseResult<()> { + pub fn set_weekday(&mut self, value: Weekday) -> Result<(), Error> { set_if_consistent(&mut self.weekday, value) } /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value. #[inline] - pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.ordinal, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_ordinal(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.ordinal, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`day`](#structfield.day) field from given value. #[inline] - pub fn set_day(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.day, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_day(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.day, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value. /// (`false` for AM, `true` for PM) #[inline] - pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> { + pub fn set_ampm(&mut self, value: bool) -> Result<(), Error> { set_if_consistent(&mut self.hour_div_12, u32::from(value)) } /// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from /// given hour number in 12-hour clocks. #[inline] - pub fn set_hour12(&mut self, value: i64) -> ParseResult<()> { + pub fn set_hour12(&mut self, value: i64) -> Result<(), Error> { if !(1..=12).contains(&value) { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } set_if_consistent(&mut self.hour_mod_12, value as u32 % 12) } @@ -243,8 +242,8 @@ impl Parsed { /// Tries to set both [`hour_div_12`](#structfield.hour_div_12) and /// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value. #[inline] - pub fn set_hour(&mut self, value: i64) -> ParseResult<()> { - let v = u32::try_from(value).map_err(|_| OUT_OF_RANGE)?; + pub fn set_hour(&mut self, value: i64) -> Result<(), Error> { + let v = u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?; set_if_consistent(&mut self.hour_div_12, v / 12)?; set_if_consistent(&mut self.hour_mod_12, v % 12)?; Ok(()) @@ -252,32 +251,32 @@ impl Parsed { /// Tries to set the [`minute`](#structfield.minute) field from given value. #[inline] - pub fn set_minute(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.minute, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_minute(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.minute, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`second`](#structfield.second) field from given value. #[inline] - pub fn set_second(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.second, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_second(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.second, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value. #[inline] - pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.nanosecond, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_nanosecond(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.nanosecond, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Tries to set the [`timestamp`](#structfield.timestamp) field from given value. #[inline] - pub fn set_timestamp(&mut self, value: i64) -> ParseResult<()> { + pub fn set_timestamp(&mut self, value: i64) -> Result<(), Error> { set_if_consistent(&mut self.timestamp, value) } /// Tries to set the [`offset`](#structfield.offset) field from given value. #[inline] - pub fn set_offset(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) + pub fn set_offset(&mut self, value: i64) -> Result<(), Error> { + set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Returns a parsed naive date out of given fields. @@ -291,12 +290,12 @@ impl Parsed { /// /// Gregorian year and ISO week date year can have their century number (`*_div_100`) omitted, /// the two-digit year is used to guess the century number then. - pub fn to_naive_date(&self) -> ParseResult { + pub fn to_naive_date(&self) -> Result { fn resolve_year( y: Option, q: Option, r: Option, - ) -> ParseResult> { + ) -> Result, Error> { match (y, q, r) { // if there is no further information, simply return the given full year. // this is a common case, so let's avoid division here. @@ -308,13 +307,13 @@ impl Parsed { // we should filter a negative full year first. (Some(y), q, r @ Some(0..=99)) | (Some(y), q, r @ None) => { if y < 0 { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } let (q_, r_) = div_rem(y, 100); if q.unwrap_or(q_) == q_ && r.unwrap_or(r_) == r_ { Ok(Some(y)) } else { - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) } } @@ -322,10 +321,10 @@ impl Parsed { // reconstruct the full year. make sure that the result is always positive. (None, Some(q), Some(r @ 0..=99)) => { if q < 0 { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } let y = q.checked_mul(100).and_then(|v| v.checked_add(r)); - Ok(Some(y.ok_or(OUT_OF_RANGE)?)) + Ok(Some(y.ok_or(Error::ParsingOutOfRange)?)) } // we only have modulo. try to interpret a modulo as a conventional two-digit year. @@ -333,8 +332,8 @@ impl Parsed { (None, None, Some(r @ 0..=99)) => Ok(Some(r + if r < 70 { 2000 } else { 1900 })), // otherwise it is an out-of-bound or insufficient condition. - (None, Some(_), None) => Err(NOT_ENOUGH), - (_, _, Some(_)) => Err(OUT_OF_RANGE), + (None, Some(_), None) => Err(Error::ParsingNotEnough), + (_, _, Some(_)) => Err(Error::ParsingOutOfRange), } } @@ -394,13 +393,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(|_| Error::ParsingOutOfRange)?; (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(|_| Error::ParsingOutOfRange)?; (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date) } @@ -410,7 +409,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(|_| Error::ParsingOutOfRange)?; let firstweek = match newyear.weekday() { Weekday::Sun => 0, Weekday::Mon => 6, @@ -423,16 +422,15 @@ impl Parsed { // `firstweek+1`-th day of January is the beginning of the week 1. if week_from_sun > 53 { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } // can it overflow? let ndays = firstweek + (week_from_sun as i32 - 1) * 7 + weekday.num_days_from_sunday() as i32; let date = newyear - .checked_add_signed(TimeDelta::days(i64::from(ndays))) - .ok_or(OUT_OF_RANGE)?; + .checked_add_signed(TimeDelta::days(i64::from(ndays)))?; if date.year() != year { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } // early exit for correct error (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date) @@ -444,7 +442,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(|_| Error::ParsingOutOfRange)?; let firstweek = match newyear.weekday() { Weekday::Sun => 1, Weekday::Mon => 0, @@ -457,16 +455,14 @@ impl Parsed { // `firstweek+1`-th day of January is the beginning of the week 1. if week_from_mon > 53 { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } // can it overflow? let ndays = firstweek + (week_from_mon as i32 - 1) * 7 + weekday.num_days_from_monday() as i32; - let date = newyear - .checked_add_signed(TimeDelta::days(i64::from(ndays))) - .ok_or(OUT_OF_RANGE)?; + let date = newyear.checked_add_signed(TimeDelta::days(i64::from(ndays)))?; if date.year() != year { - return Err(OUT_OF_RANGE); + return Err(Error::ParsingOutOfRange); } // early exit for correct error (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date) @@ -474,18 +470,18 @@ 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(|_| Error::ParsingOutOfRange)?; (verify_ymd(date) && verify_ordinal(date), date) } - (_, _, _) => return Err(NOT_ENOUGH), + (_, _, _) => return Err(Error::ParsingNotEnough), }; if verified { Ok(parsed_date) } else { - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) } } @@ -498,39 +494,39 @@ impl Parsed { /// - Hour, minute, second, nanosecond. /// /// It is able to handle leap seconds when given second is 60. - pub fn to_naive_time(&self) -> ParseResult { + pub fn to_naive_time(&self) -> Result { let hour_div_12 = match self.hour_div_12 { Some(v @ 0..=1) => v, - Some(_) => return Err(OUT_OF_RANGE), - None => return Err(NOT_ENOUGH), + Some(_) => return Err(Error::ParsingOutOfRange), + None => return Err(Error::ParsingNotEnough), }; let hour_mod_12 = match self.hour_mod_12 { Some(v @ 0..=11) => v, - Some(_) => return Err(OUT_OF_RANGE), - None => return Err(NOT_ENOUGH), + Some(_) => return Err(Error::ParsingOutOfRange), + None => return Err(Error::ParsingNotEnough), }; let hour = hour_div_12 * 12 + hour_mod_12; let minute = match self.minute { Some(v @ 0..=59) => v, - Some(_) => return Err(OUT_OF_RANGE), - None => return Err(NOT_ENOUGH), + Some(_) => return Err(Error::ParsingOutOfRange), + None => return Err(Error::ParsingNotEnough), }; // we allow omitting seconds or nanoseconds, but they should be in the range. let (second, mut nano) = match self.second.unwrap_or(0) { v @ 0..=59 => (v, 0), 60 => (59, 1_000_000_000), - _ => return Err(OUT_OF_RANGE), + _ => return Err(Error::ParsingOutOfRange), }; nano += match self.nanosecond { Some(v @ 0..=999_999_999) if self.second.is_some() => v, - Some(0..=999_999_999) => return Err(NOT_ENOUGH), // second is missing - Some(_) => return Err(OUT_OF_RANGE), + Some(0..=999_999_999) => return Err(Error::ParsingNotEnough), // second is missing + Some(_) => return Err(Error::ParsingOutOfRange), 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(|_| Error::ParsingOutOfRange) } /// Returns a parsed naive date and time out of given fields, @@ -540,81 +536,73 @@ impl Parsed { /// This method is able to determine the combined date and time /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field. /// Either way those fields have to be consistent to each other. - pub fn to_naive_datetime_with_offset(&self, offset: i32) -> ParseResult { - let date = self.to_naive_date(); - let time = self.to_naive_time(); - if let (Ok(date), Ok(time)) = (date, time) { - let datetime = date.and_time(time); - - // verify the timestamp field if any - // the following is safe, `timestamp` is very limited in range - let timestamp = datetime.timestamp() - i64::from(offset); - if let Some(given_timestamp) = self.timestamp { - // if `datetime` represents a leap second, it might be off by one second. - if given_timestamp != timestamp - && !(datetime.nanosecond() >= 1_000_000_000 && given_timestamp == timestamp + 1) - { - return Err(IMPOSSIBLE); - } - } - - Ok(datetime) - } else if let Some(timestamp) = self.timestamp { - use super::ParseError as PE; - use super::ParseErrorKind::{Impossible, OutOfRange}; - - // if date and time is problematic already, there is no point proceeding. - // we at least try to give a correct error though. - match (date, time) { - (Err(PE(OutOfRange)), _) | (_, Err(PE(OutOfRange))) => return Err(OUT_OF_RANGE), - (Err(PE(Impossible)), _) | (_, Err(PE(Impossible))) => return Err(IMPOSSIBLE), - (_, _) => {} // one of them is insufficient - } - - // 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)?; - - // fill year, ordinal, hour, minute and second fields from timestamp. - // if existing fields are consistent, this will allow the full date/time reconstruction. - let mut parsed = self.clone(); - if parsed.second == Some(60) { - // `datetime.second()` cannot be 60, so this is the only case for a leap second. - match datetime.second() { - // it's okay, just do not try to overwrite the existing field. - 59 => {} - // `datetime` is known to be off by one second. - 0 => { - datetime -= TimeDelta::seconds(1); + pub fn to_naive_datetime_with_offset(&self, offset: i32) -> Result { + match (self.to_naive_date(), self.to_naive_time()) { + // Both are unproblematic + (Ok(date), Ok(time)) => { + let datetime = date.and_time(time); + + // verify the timestamp field if any + // the following is safe, `timestamp` is very limited in range + let timestamp = datetime.timestamp() - i64::from(offset); + if let Some(given_timestamp) = self.timestamp { + // if `datetime` represents a leap second, it might be off by one second. + if given_timestamp != timestamp + && !(datetime.nanosecond() >= 1_000_000_000 && given_timestamp == timestamp + 1) + { + return Err(Error::ParsingImpossible); } - // otherwise it is impossible. - _ => return Err(IMPOSSIBLE), } - // ...and we have the correct candidates for other fields. - } else { - parsed.set_second(i64::from(datetime.second()))?; - } - parsed.set_year(i64::from(datetime.year()))?; - parsed.set_ordinal(i64::from(datetime.ordinal()))?; // more efficient than ymd - parsed.set_hour(i64::from(datetime.hour()))?; - parsed.set_minute(i64::from(datetime.minute()))?; - - // validate other fields (e.g. week) and return - let date = parsed.to_naive_date()?; - let time = parsed.to_naive_time()?; - Ok(date.and_time(time)) - } else { - // reproduce the previous error(s) - date?; - time?; - unreachable!() + + Ok(datetime) + }, + // If either is problematic, return their error + (Err(e), _) => Err(e), + (_, Err(e)) => Err(e), + // Unclear condition for reconstruction of date and time fields from timestamp + // (_,_) => { + // let ts = match self.timestamp { + // None => Error::ParsingOutOfRange + // } + // checked_add(i64::from(offset)).ok_or(Error::ParsingOutOfRange)?; + // let mut datetime = NaiveDateTime::from_timestamp(ts, 0).map_err(|_| Error::ParsingOutOfRange)?; + + // // fill year, ordinal, hour, minute and second fields from timestamp. + // // if existing fields are consistent, this will allow the full date/time reconstruction. + // let mut parsed = self.clone(); + // if parsed.second == Some(60) { + // // `datetime.second()` cannot be 60, so this is the only case for a leap second. + // match datetime.second() { + // // it's okay, just do not try to overwrite the existing field. + // 59 => {} + // // `datetime` is known to be off by one second. + // 0 => { + // datetime -= TimeDelta::seconds(1); + // } + // // otherwise it is impossible. + // _ => return Err(Error::ParsingImpossible), + // } + // // ...and we have the correct candidates for other fields. + // } else { + // parsed.set_second(i64::from(datetime.second()))?; + // } + // parsed.set_year(i64::from(datetime.year()))?; + // parsed.set_ordinal(i64::from(datetime.ordinal()))?; // more efficient than ymd + // parsed.set_hour(i64::from(datetime.hour()))?; + // parsed.set_minute(i64::from(datetime.minute()))?; + + // // validate other fields (e.g. week) and return + // let date = parsed.to_naive_date()?; + // let time = parsed.to_naive_time()?; + // Ok(date.and_time(time)) + // } } } /// 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) + pub fn to_fixed_offset(&self) -> Result { + let offset = self.offset.ok_or(Error::ParsingOutOfRange)?; + FixedOffset::east(offset).map_err(|_| Error::ParsingOutOfRange) } /// Returns a parsed timezone-aware date and time out of given fields. @@ -623,21 +611,16 @@ impl Parsed { /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field, /// plus a time zone offset. /// Either way those fields have to be consistent to each other. - pub fn to_datetime(&self) -> ParseResult> { - let offset = self.offset.ok_or(NOT_ENOUGH)?; + pub fn to_datetime(&self) -> Result, Error> { + let offset = self.offset.ok_or(Error::ParsingNotEnough)?; 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(|_| Error::ParsingOutOfRange)?; // this is used to prevent an overflow when calling FixedOffset::from_local_datetime - datetime - .checked_sub_signed(TimeDelta::seconds(i64::from(offset.local_minus_utc()))) - .ok_or(OUT_OF_RANGE)?; - - match offset.from_local_datetime(&datetime) { - LocalResult::None => Err(IMPOSSIBLE), - LocalResult::Single(t) => Ok(t), - LocalResult::Ambiguous(..) => Err(NOT_ENOUGH), - } + // TODO: is this still needed? + datetime.checked_sub_signed(TimeDelta::seconds(i64::from(offset.local_minus_utc())))?; + + offset.from_local_datetime(&datetime).and_then(|dt| dt.single()).map_err(|_| Error::ParsingOutOfRange) } /// Returns a parsed timezone-aware date and time out of given fields, @@ -649,16 +632,17 @@ impl Parsed { /// Either way those fields have to be consistent to each other. /// If parsed fields include an UTC offset, it also has to be consistent to /// [`offset`](#structfield.offset). - pub fn to_datetime_with_timezone(&self, tz: &Tz) -> ParseResult> { + pub fn to_datetime_with_timezone(&self, tz: &Tz) -> Result, Error> { // if we have `timestamp` specified, guess an offset from that. let mut guessed_offset = 0; if let Some(timestamp) = self.timestamp { // 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(|_| Error::ParsingOutOfRange)?; + guessed_offset = + tz.offset_from_utc_datetime(&dt).map_err(|_| Error::ParsingOutOfRange)?.fix().local_minus_utc(); } // checks if the given `DateTime` has a consistent `Offset` with given `self.offset`. @@ -673,51 +657,48 @@ 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(|_| Error::ParsingOutOfRange)?; + + if check_offset(&dt) { + Ok(dt) + } else { + Err(Error::ParsingImpossible) } } } #[cfg(test)] mod tests { - use super::super::{IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE}; use super::Parsed; use crate::naive::{NaiveDate, NaiveTime}; use crate::offset::{FixedOffset, TimeZone, Utc}; - use crate::Datelike; + use crate::{Datelike, Error}; 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* let mut p = Parsed::new(); assert_eq!(p.set_year(1987), Ok(())); - assert_eq!(p.set_year(1986), Err(IMPOSSIBLE)); - assert_eq!(p.set_year(1988), Err(IMPOSSIBLE)); + assert_eq!(p.set_year(1986), Err(Error::ParsingImpossible)); + assert_eq!(p.set_year(1988), Err(Error::ParsingImpossible)); assert_eq!(p.set_year(1987), Ok(())); assert_eq!(p.set_year_div_100(20), Ok(())); // independent to `year` - assert_eq!(p.set_year_div_100(21), Err(IMPOSSIBLE)); - assert_eq!(p.set_year_div_100(19), Err(IMPOSSIBLE)); + assert_eq!(p.set_year_div_100(21), Err(Error::ParsingImpossible)); + assert_eq!(p.set_year_div_100(19), Err(Error::ParsingImpossible)); assert_eq!(p.set_year_mod_100(37), Ok(())); // ditto - assert_eq!(p.set_year_mod_100(38), Err(IMPOSSIBLE)); - assert_eq!(p.set_year_mod_100(36), Err(IMPOSSIBLE)); + assert_eq!(p.set_year_mod_100(38), Err(Error::ParsingImpossible)); + assert_eq!(p.set_year_mod_100(36), Err(Error::ParsingImpossible)); let mut p = Parsed::new(); assert_eq!(p.set_year(0), Ok(())); @@ -725,54 +706,54 @@ mod tests { assert_eq!(p.set_year_mod_100(0), Ok(())); let mut p = Parsed::new(); - assert_eq!(p.set_year_div_100(-1), Err(OUT_OF_RANGE)); - assert_eq!(p.set_year_mod_100(-1), Err(OUT_OF_RANGE)); + assert_eq!(p.set_year_div_100(-1), Err(Error::ParsingOutOfRange)); + assert_eq!(p.set_year_mod_100(-1), Err(Error::ParsingOutOfRange)); assert_eq!(p.set_year(-1), Ok(())); - assert_eq!(p.set_year(-2), Err(IMPOSSIBLE)); - assert_eq!(p.set_year(0), Err(IMPOSSIBLE)); + assert_eq!(p.set_year(-2), Err(Error::ParsingImpossible)); + assert_eq!(p.set_year(0), Err(Error::ParsingImpossible)); let mut p = Parsed::new(); - assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(OUT_OF_RANGE)); + assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(Error::ParsingOutOfRange)); assert_eq!(p.set_year_div_100(8), Ok(())); - assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(OUT_OF_RANGE)); + assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(Error::ParsingOutOfRange)); // month, week*, isoweek, ordinal, day, minute, second, nanosecond, offset let mut p = Parsed::new(); assert_eq!(p.set_month(7), Ok(())); - assert_eq!(p.set_month(1), Err(IMPOSSIBLE)); - assert_eq!(p.set_month(6), Err(IMPOSSIBLE)); - assert_eq!(p.set_month(8), Err(IMPOSSIBLE)); - assert_eq!(p.set_month(12), Err(IMPOSSIBLE)); + assert_eq!(p.set_month(1), Err(Error::ParsingImpossible)); + assert_eq!(p.set_month(6), Err(Error::ParsingImpossible)); + assert_eq!(p.set_month(8), Err(Error::ParsingImpossible)); + assert_eq!(p.set_month(12), Err(Error::ParsingImpossible)); let mut p = Parsed::new(); assert_eq!(p.set_month(8), Ok(())); - assert_eq!(p.set_month(0x1_0000_0008), Err(OUT_OF_RANGE)); + assert_eq!(p.set_month(0x1_0000_0008), Err(Error::ParsingOutOfRange)); // hour let mut p = Parsed::new(); assert_eq!(p.set_hour(12), Ok(())); - assert_eq!(p.set_hour(11), Err(IMPOSSIBLE)); - assert_eq!(p.set_hour(13), Err(IMPOSSIBLE)); + assert_eq!(p.set_hour(11), Err(Error::ParsingImpossible)); + assert_eq!(p.set_hour(13), Err(Error::ParsingImpossible)); assert_eq!(p.set_hour(12), Ok(())); - assert_eq!(p.set_ampm(false), Err(IMPOSSIBLE)); + assert_eq!(p.set_ampm(false), Err(Error::ParsingImpossible)); assert_eq!(p.set_ampm(true), Ok(())); assert_eq!(p.set_hour12(12), Ok(())); - assert_eq!(p.set_hour12(0), Err(OUT_OF_RANGE)); // requires canonical representation - assert_eq!(p.set_hour12(1), Err(IMPOSSIBLE)); - assert_eq!(p.set_hour12(11), Err(IMPOSSIBLE)); + assert_eq!(p.set_hour12(0), Err(Error::ParsingOutOfRange)); // requires canonical representation + assert_eq!(p.set_hour12(1), Err(Error::ParsingImpossible)); + assert_eq!(p.set_hour12(11), Err(Error::ParsingImpossible)); let mut p = Parsed::new(); assert_eq!(p.set_ampm(true), Ok(())); assert_eq!(p.set_hour12(7), Ok(())); - assert_eq!(p.set_hour(7), Err(IMPOSSIBLE)); - assert_eq!(p.set_hour(18), Err(IMPOSSIBLE)); + assert_eq!(p.set_hour(7), Err(Error::ParsingImpossible)); + assert_eq!(p.set_hour(18), Err(Error::ParsingImpossible)); assert_eq!(p.set_hour(19), Ok(())); // timestamp let mut p = Parsed::new(); assert_eq!(p.set_timestamp(1_234_567_890), Ok(())); - assert_eq!(p.set_timestamp(1_234_567_889), Err(IMPOSSIBLE)); - assert_eq!(p.set_timestamp(1_234_567_891), Err(IMPOSSIBLE)); + assert_eq!(p.set_timestamp(1_234_567_889), Err(Error::ParsingImpossible)); + assert_eq!(p.set_timestamp(1_234_567_891), Err(Error::ParsingImpossible)); } #[test] @@ -783,182 +764,186 @@ mod tests { ) } - let ymd = |y, m, d| Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap()); - // 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, 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, 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!(), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year: 1984), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year: 1984, month: 1), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year: 1984, month: 1, day: 2), Ok(ymd!(1984, 1, 2))); + assert_eq!(parse!(year: 1984, day: 2), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year_div_100: 19), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 84), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 1), Err(Error::ParsingNotEnough)); + 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(Error::ParsingNotEnough)); + assert_eq!(parse!(year_div_100: 19, month: 1, day: 2), Err(Error::ParsingNotEnough)); + 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) + Err(Error::ParsingOutOfRange) ); assert_eq!( parse!(year_div_100: 19, year_mod_100: 83, month: 13, day: 1), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); 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), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); assert_eq!( parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 0), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); assert_eq!( parse!(year_div_100: 19, year_mod_100: 100, month: 1, day: 1), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); - 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: -1, year_mod_100: 42, month: 1, day: 1), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: -1, month: 1, day: 1), Err(Error::ParsingOutOfRange)); + 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(Error::ParsingOutOfRange)); 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, year_mod_100: (max_year + 1) % 100, month: 1, day: 1), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); // 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: 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: 83, month: 1, day: 1), Err(IMPOSSIBLE)); + 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(Error::ParsingImpossible)); + 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(Error::ParsingImpossible)); 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), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); assert_eq!( parse!(year: 1984, year_div_100: 18, year_mod_100: 184, month: 1, day: 1), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); assert_eq!( parse!(year: -1, year_div_100: 0, year_mod_100: -1, month: 1, day: 1), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); assert_eq!( parse!(year: -1, year_div_100: -1, year_mod_100: 99, month: 1, day: 1), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); - assert_eq!(parse!(year: -1, year_div_100: 0, month: 1, day: 1), Err(OUT_OF_RANGE)); - assert_eq!(parse!(year: -1, year_mod_100: 99, month: 1, day: 1), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: -1, year_div_100: 0, month: 1, day: 1), Err(Error::ParsingOutOfRange)); + assert_eq!(parse!(year: -1, year_mod_100: 99, month: 1, day: 1), Err(Error::ParsingOutOfRange)); // weekdates - assert_eq!(parse!(year: 2000, week_from_mon: 0), Err(NOT_ENOUGH)); - assert_eq!(parse!(year: 2000, week_from_sun: 0), Err(NOT_ENOUGH)); - 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_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: 2000, week_from_mon: 0), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year: 2000, week_from_sun: 0), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year: 2000, weekday: Sun), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Fri), Err(Error::ParsingOutOfRange)); + assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Fri), Err(Error::ParsingOutOfRange)); + 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(Error::ParsingOutOfRange)); + assert_eq!(parse!(year: 2000, week_from_sun: 0xffffffff, weekday: Mon), Err(Error::ParsingOutOfRange)); + assert_eq!(parse!(year: 2006, week_from_sun: 0, weekday: Sat), Err(Error::ParsingOutOfRange)); + 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), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); assert_eq!( parse!(year: 2000, week_from_mon: 2, week_from_sun: 2, weekday: Sun), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); // 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: 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, weekday: Thu), Err(NOT_ENOUGH)); + assert_eq!(parse!(isoyear: 2004, isoweek: 53), Err(Error::ParsingNotEnough)); + 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(Error::ParsingOutOfRange)); + assert_eq!(parse!(isoyear: 2005, isoweek: 0, weekday: Thu), Err(Error::ParsingOutOfRange)); + assert_eq!(parse!(isoyear: 2005, isoweek: 5, weekday: Thu), Ok(ymd!(2005, 2, 3))); + assert_eq!(parse!(isoyear: 2005, weekday: Thu), Err(Error::ParsingNotEnough)); // 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: 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: 366), Err(OUT_OF_RANGE)); - assert_eq!(parse!(year: 2100, ordinal: 0xffffffff), Err(OUT_OF_RANGE)); + assert_eq!(parse!(ordinal: 123), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(year: 2000, ordinal: 0), Err(Error::ParsingOutOfRange)); + 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(Error::ParsingOutOfRange)); + assert_eq!(parse!(year: 2000, ordinal: 0xffffffff), Err(Error::ParsingOutOfRange)); + assert_eq!(parse!(year: 2100, ordinal: 0), Err(Error::ParsingOutOfRange)); + 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(Error::ParsingOutOfRange)); + assert_eq!(parse!(year: 2100, ordinal: 0xffffffff), Err(Error::ParsingOutOfRange)); // more complex cases 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, week_from_sun: 52, week_from_mon: 52, weekday: Wed), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); // no ISO week date 2014-W53-3 assert_eq!( parse!(year: 2012, isoyear: 2015, isoweek: 1, week_from_sun: 52, week_from_mon: 52), - Err(NOT_ENOUGH) + Err(Error::ParsingNotEnough) ); // ambiguous (2014-12-29, 2014-12-30, 2014-12-31) - assert_eq!(parse!(year_div_100: 20, isoyear_mod_100: 15, ordinal: 366), Err(NOT_ENOUGH)); + assert_eq!(parse!(year_div_100: 20, isoyear_mod_100: 15, ordinal: 366), Err(Error::ParsingNotEnough)); // technically unique (2014-12-31) but Chrono gives up } @@ -970,50 +955,56 @@ mod tests { ) } - let hms = |h, m, s| Ok(NaiveTime::from_hms_opt(h, m, s).unwrap()); - let hmsn = |h, m, s, n| Ok(NaiveTime::from_hms_nano_opt(h, m, s, n).unwrap()); + 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!(), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(hour_div_12: 0), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1), Err(Error::ParsingNotEnough)); + 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_mod_12: 1, minute: 23), Err(Error::ParsingNotEnough)); assert_eq!( parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, nanosecond: 456_789_012), - Err(NOT_ENOUGH) + Err(Error::ParsingNotEnough) ); // out-of-range conditions - assert_eq!(parse!(hour_div_12: 2, hour_mod_12: 0, minute: 0), Err(OUT_OF_RANGE)); - assert_eq!(parse!(hour_div_12: 1, hour_mod_12: 12, minute: 0), Err(OUT_OF_RANGE)); - assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 60), Err(OUT_OF_RANGE)); + assert_eq!(parse!(hour_div_12: 2, hour_mod_12: 0, minute: 0), Err(Error::ParsingOutOfRange)); + assert_eq!(parse!(hour_div_12: 1, hour_mod_12: 12, minute: 0), Err(Error::ParsingOutOfRange)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 60), Err(Error::ParsingOutOfRange)); assert_eq!( parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 61), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); assert_eq!( parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 34, nanosecond: 1_000_000_000), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); // 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)) ); } @@ -1026,35 +1017,34 @@ mod tests { ($($k:ident: $v:expr),*) => (parse!(offset = 0; $($k: $v),*)) } - let ymdhms = |y, m, d, h, n, s| { - Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap()) - }; + 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| { - Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_nano_opt(h, n, s, nano).unwrap()) + 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!(), Err(Error::ParsingNotEnough)); 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 +1053,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, @@ -1071,7 +1061,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_419_999_999), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); assert_eq!( parse!(offset = 32400; @@ -1080,94 +1070,93 @@ 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_opt(1970, 1, 1).unwrap()); - let year_0_from_year_1970 = NaiveDate::from_ymd_opt(0, 1, 1) - .unwrap() - .signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()); - let min_days_from_year_1970 = - NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()); + 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_800), Err(IMPOSSIBLE)); + assert_eq!(parse!(second: 59, timestamp: 1_341_100_798), Err(Error::ParsingImpossible)); + 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(Error::ParsingImpossible)); 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: 1, timestamp: 1_341_100_800), Err(IMPOSSIBLE)); - assert_eq!(parse!(second: 60, timestamp: 1_341_100_801), Err(IMPOSSIBLE)); + 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(Error::ParsingImpossible)); + assert_eq!(parse!(second: 60, timestamp: 1_341_100_801), Err(Error::ParsingImpossible)); // leap seconds #2: full fields // we need to have separate tests for them since it uses another control flow. assert_eq!( parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, minute: 59, second: 59, timestamp: 1_341_100_798), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); 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, minute: 59, second: 59, timestamp: 1_341_100_800), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); 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, minute: 0, second: 1, timestamp: 1_341_100_800), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); assert_eq!( parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, minute: 59, second: 60, timestamp: 1_341_100_801), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); // error codes assert_eq!( parse!(year: 2015, month: 1, day: 20, weekday: Tue, hour_div_12: 2, hour_mod_12: 1, minute: 35, second: 20), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); // `hour_div_12` is out of range } @@ -1180,42 +1169,39 @@ mod tests { } let ymdhmsn = |y, m, d, h, n, s, nano, off| { - Ok(FixedOffset::east_opt(off) + FixedOffset::east(off) + .unwrap() + .ymd(y, m, d) + .unwrap() + .and_hms_nano(h, n, s, nano) .unwrap() - .from_local_datetime( - &NaiveDate::from_ymd_opt(y, m, d) - .unwrap() - .and_hms_nano_opt(h, n, s, nano) - .unwrap(), - ) - .unwrap()) }; - assert_eq!(parse!(offset: 0), Err(NOT_ENOUGH)); + assert_eq!(parse!(offset: 0), Err(Error::ParsingNotEnough)); assert_eq!( parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, nanosecond: 12_345_678), - Err(NOT_ENOUGH) + Err(Error::ParsingNotEnough) ); 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, minute: 26, second: 40, nanosecond: 12_345_678, offset: 86_400), - Err(OUT_OF_RANGE) + Err(Error::ParsingOutOfRange) ); // `FixedOffset` does not support such huge offset } @@ -1232,57 +1218,49 @@ 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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2014, 12, 31) - .unwrap() - .and_hms_nano_opt(4, 26, 40, 12_345_678) - .unwrap() - ) - .unwrap()) + Ok(Utc.ymd(2014, 12, 31).unwrap().and_hms_nano(4, 26, 40, 12_345_678).unwrap()) ); assert_eq!( parse!(Utc; year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1, minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400), - Err(IMPOSSIBLE) + Err(Error::ParsingImpossible) ); assert_eq!( - parse!(FixedOffset::east_opt(32400).unwrap(); + 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) + Err(Error::ParsingImpossible) ); assert_eq!( - parse!(FixedOffset::east_opt(32400).unwrap(); + 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_opt(32400) + Ok(FixedOffset::east(32400) .unwrap() - .from_local_datetime( - &NaiveDate::from_ymd_opt(2014, 12, 31) - .unwrap() - .and_hms_nano_opt(13, 26, 40, 12_345_678) - .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.with_ymd_and_hms(2014, 12, 31, 4, 26, 40).unwrap()) + 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!(Utc; timestamp: 1_420_000_000, offset: 32400), Err(Error::ParsingImpossible)); assert_eq!( - parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 0), - Err(IMPOSSIBLE) + parse!(FixedOffset::east(32400).unwrap(); timestamp: 1_420_000_000, offset: 0), + Err(Error::ParsingImpossible) ); assert_eq!( - parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 32400), - Ok(FixedOffset::east_opt(32400) + parse!(FixedOffset::east(32400).unwrap(); timestamp: 1_420_000_000, offset: 32400), + Ok(FixedOffset::east(32400) + .unwrap() + .ymd(2014, 12, 31) .unwrap() - .with_ymd_and_hms(2014, 12, 31, 13, 26, 40) + .and_hms(13, 26, 40) .unwrap()) ); diff --git a/src/format/scan.rs b/src/format/scan.rs index ffbf654b32..73f9e7f643 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -7,8 +7,7 @@ #![allow(deprecated)] -use super::{ParseResult, INVALID, OUT_OF_RANGE, TOO_SHORT}; -use crate::Weekday; +use crate::{Error, Weekday}; /// Returns true when two slices are equal case-insensitively (in ASCII). /// Assumes that the `pattern` is already converted to lower case. @@ -34,7 +33,7 @@ fn equals(s: &str, pattern: &str) -> bool { /// More than `max` digits are consumed up to the first `max` digits. /// Any number that does not fit in `i64` is an error. #[inline] -pub(super) fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> { +pub(super) fn number(s: &str, min: usize, max: usize) -> Result<(&str, i64), Error> { assert!(min <= max); // We are only interested in ascii numbers, so we can work with the `str` as bytes. We stop on @@ -42,7 +41,7 @@ pub(super) fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64) // UTF-8 character. let bytes = s.as_bytes(); if bytes.len() < min { - return Err(TOO_SHORT); + return Err(Error::ParsingTooShort); } let mut n = 0i64; @@ -50,7 +49,7 @@ pub(super) fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64) // cloned() = copied() if !c.is_ascii_digit() { if i < min { - return Err(INVALID); + return Err(Error::ParsingInvalid); } else { return Ok((&s[i..], n)); } @@ -58,7 +57,7 @@ pub(super) fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64) n = match n.checked_mul(10).and_then(|n| n.checked_add((c - b'0') as i64)) { Some(n) => n, - None => return Err(OUT_OF_RANGE), + None => return Err(Error::ParsingOutOfRange), }; } @@ -67,7 +66,7 @@ pub(super) fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64) /// Tries to consume at least one digits as a fractional second. /// Returns the number of whole nanoseconds (0--999,999,999). -pub(super) fn nanosecond(s: &str) -> ParseResult<(&str, i64)> { +pub(super) fn nanosecond(s: &str) -> Result<(&str, i64), Error> { // record the number of digits consumed for later scaling. let origlen = s.len(); let (s, v) = number(s, 1, 9)?; @@ -76,7 +75,7 @@ pub(super) fn nanosecond(s: &str) -> ParseResult<(&str, i64)> { // scale the number accordingly. static SCALE: [i64; 10] = [0, 100_000_000, 10_000_000, 1_000_000, 100_000, 10_000, 1_000, 100, 10, 1]; - let v = v.checked_mul(SCALE[consumed]).ok_or(OUT_OF_RANGE)?; + let v = v.checked_mul(SCALE[consumed]).ok_or(Error::ParsingOutOfRange)?; // if there are more than 9 digits, skip next digits. let s = s.trim_left_matches(|c: char| c.is_ascii_digit()); @@ -86,22 +85,22 @@ pub(super) fn nanosecond(s: &str) -> ParseResult<(&str, i64)> { /// Tries to consume a fixed number of digits as a fractional second. /// Returns the number of whole nanoseconds (0--999,999,999). -pub(super) fn nanosecond_fixed(s: &str, digits: usize) -> ParseResult<(&str, i64)> { +pub(super) fn nanosecond_fixed(s: &str, digits: usize) -> Result<(&str, i64), Error> { // record the number of digits consumed for later scaling. let (s, v) = number(s, digits, digits)?; // scale the number accordingly. static SCALE: [i64; 10] = [0, 100_000_000, 10_000_000, 1_000_000, 100_000, 10_000, 1_000, 100, 10, 1]; - let v = v.checked_mul(SCALE[digits]).ok_or(OUT_OF_RANGE)?; + let v = v.checked_mul(SCALE[digits]).ok_or(Error::ParsingOutOfRange)?; Ok((s, v)) } /// Tries to parse the month index (0 through 11) with the first three ASCII letters. -pub(super) fn short_month0(s: &str) -> ParseResult<(&str, u8)> { +pub(super) fn short_month0(s: &str) -> Result<(&str, u8), Error> { if s.len() < 3 { - return Err(TOO_SHORT); + return Err(Error::ParsingTooShort); } let buf = s.as_bytes(); let month0 = match (buf[0] | 32, buf[1] | 32, buf[2] | 32) { @@ -117,15 +116,15 @@ pub(super) fn short_month0(s: &str) -> ParseResult<(&str, u8)> { (b'o', b'c', b't') => 9, (b'n', b'o', b'v') => 10, (b'd', b'e', b'c') => 11, - _ => return Err(INVALID), + _ => return Err(Error::ParsingInvalid), }; Ok((&s[3..], month0)) } /// Tries to parse the weekday with the first three ASCII letters. -pub(super) fn short_weekday(s: &str) -> ParseResult<(&str, Weekday)> { +pub(super) fn short_weekday(s: &str) -> Result<(&str, Weekday), Error> { if s.len() < 3 { - return Err(TOO_SHORT); + return Err(Error::ParsingTooShort); } let buf = s.as_bytes(); let weekday = match (buf[0] | 32, buf[1] | 32, buf[2] | 32) { @@ -136,14 +135,14 @@ pub(super) fn short_weekday(s: &str) -> ParseResult<(&str, Weekday)> { (b'f', b'r', b'i') => Weekday::Fri, (b's', b'a', b't') => Weekday::Sat, (b's', b'u', b'n') => Weekday::Sun, - _ => return Err(INVALID), + _ => return Err(Error::ParsingInvalid), }; Ok((&s[3..], weekday)) } /// Tries to parse the month index (0 through 11) with short or long month names. /// It prefers long month names to short month names when both are possible. -pub(super) fn short_or_long_month0(s: &str) -> ParseResult<(&str, u8)> { +pub(super) fn short_or_long_month0(s: &str) -> Result<(&str, u8), Error> { // lowercased month names, minus first three chars static LONG_MONTH_SUFFIXES: [&str; 12] = ["uary", "ruary", "ch", "il", "", "e", "y", "ust", "tember", "ober", "ember", "ember"]; @@ -161,7 +160,7 @@ pub(super) fn short_or_long_month0(s: &str) -> ParseResult<(&str, u8)> { /// Tries to parse the weekday with short or long weekday names. /// It prefers long weekday names to short weekday names when both are possible. -pub(super) fn short_or_long_weekday(s: &str) -> ParseResult<(&str, Weekday)> { +pub(super) fn short_or_long_weekday(s: &str) -> Result<(&str, Weekday), Error> { // lowercased weekday names, minus first three chars static LONG_WEEKDAY_SUFFIXES: [&str; 7] = ["day", "sday", "nesday", "rsday", "day", "urday", "day"]; @@ -178,23 +177,23 @@ pub(super) fn short_or_long_weekday(s: &str) -> ParseResult<(&str, Weekday)> { } /// Tries to consume exactly one given character. -pub(super) fn char(s: &str, c1: u8) -> ParseResult<&str> { +pub(super) fn char(s: &str, c1: u8) -> Result<&str, Error> { match s.as_bytes().first() { Some(&c) if c == c1 => Ok(&s[1..]), - Some(_) => Err(INVALID), - None => Err(TOO_SHORT), + Some(_) => Err(Error::ParsingInvalid), + None => Err(Error::ParsingTooShort), } } /// Tries to consume one or more whitespace. -pub(super) fn space(s: &str) -> ParseResult<&str> { +pub(super) fn space(s: &str) -> Result<&str, Error> { let s_ = s.trim_left(); if s_.len() < s.len() { Ok(s_) } else if s.is_empty() { - Err(TOO_SHORT) + Err(Error::ParsingTooShort) } else { - Err(INVALID) + Err(Error::ParsingInvalid) } } @@ -229,7 +228,7 @@ fn next_is_whitespace(s: &str) -> bool { /// Consumes zero or one of these leading patterns: /// `":"`, `" "`, `" :"`, `": "`, or `" : "`. /// Always returns `Ok(s)`. -pub(super) fn maybe_colon_or_space(mut s: &str) -> ParseResult<&str> { +pub(super) fn maybe_colon_or_space(mut s: &str) -> Result<&str, Error> { if s.is_empty() { // nothing consumed return Ok(s); @@ -265,9 +264,9 @@ pub(super) fn maybe_colon_or_space(mut s: &str) -> ParseResult<&str> { /// /// The additional `colon` may be used to parse a mandatory or optional `:` /// between hours and minutes, and should return either a new suffix or `Err` when parsing fails. -pub(super) fn timezone_offset(s: &str, consume_colon: F) -> ParseResult<(&str, i32)> +pub(super) fn timezone_offset(s: &str, consume_colon: F) -> Result<(&str, i32), Error> where - F: FnMut(&str) -> ParseResult<&str>, + F: FnMut(&str) -> Result<&str, Error>, { timezone_offset_internal(s, consume_colon, false) } @@ -276,14 +275,14 @@ fn timezone_offset_internal( mut s: &str, mut consume_colon: F, allow_missing_minutes: bool, -) -> ParseResult<(&str, i32)> +) -> Result<(&str, i32), Error> where - F: FnMut(&str) -> ParseResult<&str>, + F: FnMut(&str) -> Result<&str, Error>, { - fn digits(s: &str) -> ParseResult<(u8, u8)> { + fn digits(s: &str) -> Result<(u8, u8), Error> { let b = s.as_bytes(); if b.len() < 2 { - Err(TOO_SHORT) + Err(Error::ParsingTooShort) } else { Ok((b[0], b[1])) } @@ -291,15 +290,15 @@ where let negative = match s.as_bytes().first() { Some(&b'+') => false, Some(&b'-') => true, - Some(_) => return Err(INVALID), - None => return Err(TOO_SHORT), + Some(_) => return Err(Error::ParsingInvalid), + None => return Err(Error::ParsingTooShort), }; s = &s[1..]; // hours (00--99) let hours = match digits(s)? { (h1 @ b'0'..=b'9', h2 @ b'0'..=b'9') => i32::from((h1 - b'0') * 10 + (h2 - b'0')), - _ => return Err(INVALID), + _ => return Err(Error::ParsingInvalid), }; s = &s[2..]; @@ -311,18 +310,18 @@ where let minutes = if let Ok(ds) = digits(s) { match ds { (m1 @ b'0'..=b'5', m2 @ b'0'..=b'9') => i32::from((m1 - b'0') * 10 + (m2 - b'0')), - (b'6'..=b'9', b'0'..=b'9') => return Err(OUT_OF_RANGE), - _ => return Err(INVALID), + (b'6'..=b'9', b'0'..=b'9') => return Err(Error::ParsingOutOfRange), + _ => return Err(Error::ParsingInvalid), } } else if allow_missing_minutes { 0 } else { - return Err(TOO_SHORT); + return Err(Error::ParsingTooShort); }; s = match s.len() { len if len >= 2 => &s[2..], len if len == 0 => s, - _ => return Err(TOO_SHORT), + _ => return Err(Error::ParsingTooShort), }; let seconds = hours * 3600 + minutes * 60; @@ -330,9 +329,9 @@ where } /// Same as `timezone_offset` but also allows for `z`/`Z` which is the same as `+00:00`. -pub(super) fn timezone_offset_zulu(s: &str, colon: F) -> ParseResult<(&str, i32)> +pub(super) fn timezone_offset_zulu(s: &str, colon: F) -> Result<(&str, i32), Error> where - F: FnMut(&str) -> ParseResult<&str>, + F: FnMut(&str) -> Result<&str, Error>, { let bytes = s.as_bytes(); match bytes.first() { @@ -342,10 +341,10 @@ where let (b, c) = (bytes[1], bytes[2]); match (b | 32, c | 32) { (b't', b'c') => Ok((&s[3..], 0)), - _ => Err(INVALID), + _ => Err(Error::ParsingInvalid), } } else { - Err(INVALID) + Err(Error::ParsingInvalid) } } _ => timezone_offset(s, colon), @@ -354,9 +353,9 @@ where /// Same as `timezone_offset` but also allows for `z`/`Z` which is the same as /// `+00:00`, and allows missing minutes entirely. -pub(super) fn timezone_offset_permissive(s: &str, colon: F) -> ParseResult<(&str, i32)> +pub(super) fn timezone_offset_permissive(s: &str, colon: F) -> Result<(&str, i32), Error> where - F: FnMut(&str) -> ParseResult<&str>, + F: FnMut(&str) -> Result<&str, Error>, { match s.as_bytes().first() { Some(&b'z') | Some(&b'Z') => Ok((&s[1..], 0)), @@ -364,9 +363,9 @@ where } } -/// Same as `timezone_offset` but also allows for RFC 2822 legacy timezones. -/// May return `None` which indicates an insufficient offset data (i.e. `-0000`). -pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option)> { +/// Same as `timezone_offset` but also allows for RFC 2822 legacy timezones. May +/// return `None` which indicates an insufficient offset data (i.e. `-0000`). +pub(super) fn timezone_offset_2822(s: &str) -> Result<(&str, Option), Error> { // tries to parse legacy time zone names let upto = s.as_bytes().iter().position(|c| !c.is_ascii_alphabetic()).unwrap_or(s.len()); if upto > 0 { @@ -395,14 +394,14 @@ pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option)> /// Tries to consume everything until next whitespace-like symbol. /// Does not provide any offset information from the consumed data. -pub(super) fn timezone_name_skip(s: &str) -> ParseResult<(&str, ())> { +pub(super) fn timezone_name_skip(s: &str) -> Result<(&str, ()), Error> { Ok((s.trim_left_matches(|c: char| !c.is_whitespace()), ())) } /// Tries to consume an RFC2822 comment including preceding ` `. /// /// Returns the remaining string after the closing parenthesis. -pub(super) fn comment_2822(s: &str) -> ParseResult<(&str, ())> { +pub(super) fn comment_2822(s: &str) -> Result<(&str, ()), Error> { use CommentState::*; let s = s.trim_start(); @@ -416,11 +415,11 @@ pub(super) fn comment_2822(s: &str) -> ParseResult<(&str, ())> { (Next(depth), b'(') => Next(depth + 1), (Next(depth), b')') => Next(depth - 1), (Next(depth), _) | (Escape(depth), _) => Next(depth), - _ => return Err(INVALID), + _ => return Err(Error::ParsingInvalid), }; } - Err(TOO_SHORT) + Err(Error::ParsingTooShort) } enum CommentState { @@ -433,10 +432,10 @@ enum CommentState { #[test] fn test_rfc2822_comments() { let testdata = [ - ("", Err(TOO_SHORT)), - (" ", Err(TOO_SHORT)), - ("x", Err(INVALID)), - ("(", Err(TOO_SHORT)), + ("", Err(Error::ParsingTooShort)), + (" ", Err(Error::ParsingTooShort)), + ("x", Err(Error::ParsingInvalid)), + ("(", Err(Error::ParsingTooShort)), ("()", Ok("")), (" \r\n\t()", Ok("")), ("() ", Ok(" ")), @@ -446,7 +445,7 @@ fn test_rfc2822_comments() { ("((()))", Ok("")), ("(x(x(x)x)x)", Ok("")), ("( x ( x ( x ) x ) x )", Ok("")), - (r"(\)", Err(TOO_SHORT)), + (r"(\)", Err(Error::ParsingTooShort)), (r"(\()", Ok("")), (r"(\))", Ok("")), (r"(\\)", Ok("")), @@ -466,13 +465,13 @@ fn test_rfc2822_comments() { #[test] fn test_space() { - assert_eq!(space(""), Err(TOO_SHORT)); + assert_eq!(space(""), Err(Error::ParsingTooShort)); assert_eq!(space(" "), Ok("")); assert_eq!(space(" \t"), Ok("")); assert_eq!(space(" \ta"), Ok("a")); assert_eq!(space(" \ta "), Ok("a ")); - assert_eq!(space("a"), Err(INVALID)); - assert_eq!(space("a "), Err(INVALID)); + assert_eq!(space("a"), Err(Error::ParsingInvalid)); + assert_eq!(space("a "), Err(Error::ParsingInvalid)); } #[test] diff --git a/src/format/strftime.rs b/src/format/strftime.rs index 5bfd1aa759..893010a426 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -634,14 +634,11 @@ fn test_strftime_docs() { use crate::NaiveDate; use crate::{DateTime, FixedOffset, TimeZone, Timelike, Utc}; - let dt = FixedOffset::east_opt(34200) + let dt = FixedOffset::east(34200) .unwrap() - .from_local_datetime( - &NaiveDate::from_ymd_opt(2001, 7, 8) - .unwrap() - .and_hms_nano_opt(0, 34, 59, 1_026_490_708) - .unwrap(), - ) + .ymd(2001, 7, 8) + .unwrap() + .and_hms_nano(0, 34, 59, 1_026_490_708) .unwrap(); // date specifiers @@ -707,19 +704,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() ); @@ -747,10 +744,11 @@ fn test_strftime_docs() { fn test_strftime_docs_localized() { use crate::{FixedOffset, NaiveDate}; - let dt = NaiveDate::from_ymd_opt(2001, 7, 8) - .and_then(|d| d.and_hms_nano_opt(0, 34, 59, 1_026_490_708)) + let dt = FixedOffset::east(34200) + .unwrap() + .ymd(2001, 7, 8) .unwrap() - .and_local_timezone(FixedOffset::east_opt(34200).unwrap()) + .and_hms_nano(0, 34, 59, 1_026_490_708) .unwrap(); // date specifiers @@ -778,7 +776,7 @@ fn test_strftime_docs_localized() { "dim 08 jui 2001 00:34:60 +09:30" ); - let nd = NaiveDate::from_ymd_opt(2001, 7, 8).unwrap(); + let nd = NaiveDate::from_ymd(2001, 7, 8).unwrap(); // date specifiers assert_eq!(nd.format_localized("%b", Locale::de_DE).to_string(), "Jul"); diff --git a/src/lib.rs b/src/lib.rs index 44303bde77..3dd2afe634 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::Error>(()) //! ``` //! //! Alternatively, you can create your own date and time. @@ -110,30 +111,29 @@ //! //! ```rust //! use chrono::prelude::*; -//! use chrono::offset::LocalResult; //! -//! let dt = Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap(); // `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_opt(9, 10, 11).unwrap()); +//! 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_opt(9, 10, 11).unwrap()); +//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue)?.and_hms(9, 10, 11)?); //! -//! let dt = NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(9, 10, 11, 12).unwrap().and_local_timezone(Utc).unwrap(); // `2014-07-08T09:10:11.012Z` -//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_micro_opt(9, 10, 11, 12_000).unwrap().and_local_timezone(Utc).unwrap()); -//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 12_000_000).unwrap().and_local_timezone(Utc).unwrap()); +//! 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.with_ymd_and_hms(2014, 7, 8, 21, 15, 33).unwrap())); -//! 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.from_local_datetime(&NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(9, 10, 11, 12).unwrap()).unwrap(); -//! let fixed_dt = FixedOffset::east_opt(9 * 3600).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(18, 10, 11, 12).unwrap()).unwrap(); +//! 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::Error>(()) //! ``` //! //! 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_opt(9*3600).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(21, 45, 59, 324310806).unwrap()).unwrap(); +//! 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_opt(9 * 3600).unwrap()); -//! assert_eq!(dt.with_timezone(&Utc), NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 45, 59, 324310806).unwrap().and_local_timezone(Utc).unwrap()); +//! 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)?); //! //! // 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.with_ymd_and_hms(2014, 11, 14, 8, 9, 10).unwrap(); -//! let dt2 = Utc.with_ymd_and_hms(2014, 11, 14, 10, 9, 8).unwrap(); +//! 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.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() + TimeDelta::seconds(1_000_000_000), -//! Utc.with_ymd_and_hms(2001, 9, 9, 1, 46, 40).unwrap()); -//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() - TimeDelta::seconds(1_000_000_000), -//! Utc.with_ymd_and_hms(1938, 4, 24, 22, 13, 20).unwrap()); +//! 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::Error>(()) //! ``` //! //! ### Formatting and Parsing @@ -206,8 +207,8 @@ //! use chrono::prelude::*; //! //! # #[cfg(feature = "unstable-locales")] -//! # fn test() { -//! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9).unwrap(); +//! # fn main() -> Result<(), chrono::Error> { +//! 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,11 @@ //! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z"); //! //! // Note that milli/nanoseconds are only printed if they are non-zero -//! let dt_nano = NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 0, 9, 1).unwrap().and_local_timezone(Utc).unwrap(); +//! 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"); -//! # } +//! # Ok(()) } //! # #[cfg(not(feature = "unstable-locales"))] -//! # fn test() {} -//! # if cfg!(feature = "unstable-locales") { -//! # test(); -//! # } +//! # fn main() {} //! ``` //! //! Parsing can be done with three methods: @@ -259,24 +257,24 @@ //! ```rust //! use chrono::prelude::*; //! -//! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9).unwrap(); -//! let fixed_dt = dt.with_timezone(&FixedOffset::east_opt(9*3600).unwrap()); +//! 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 +282,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) @@ -302,15 +301,16 @@ //! //! ```rust //! // We need the trait in scope to use Utc::timestamp(). -//! use chrono::{DateTime, FixedOffset, TimeZone, Utc}; +//! use chrono::{DateTime, FixedOffset, FixedOffset, 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 +321,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_opt(2014, 11, 28).unwrap().weekday(), Weekday::Fri); -//! assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None); -//! assert_eq!(NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_milli_opt(7, 8, 9, 10).unwrap().and_local_timezone(Utc).unwrap().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::Error>(()) //! ``` //! //! There is no timezone-aware `Time` due to the lack of usefulness and also the complexity. @@ -373,9 +373,9 @@ //! if you want. //! //! Chrono inherently does not support an inaccurate or partial date and time representation. -//! Any operation that can be ambiguous will return `None` in such cases. +//! Any operation that can be ambiguous will return `Err(chrono::Error)` in such cases. //! For example, "a month later" of 2014-01-30 is not well-defined -//! and consequently `Utc.ymd_opt(2014, 1, 30).unwrap().with_month(2)` returns `None`. +//! and consequently `Utc.ymd(2014, 1, 30)?.with_month(2)?` returns `Err(chrono::Error)`. //! //! Non ISO week handling is not yet supported. //! For now you can use the [chrono_ext](https://crates.io/crates/chrono_ext) @@ -411,6 +411,8 @@ pub mod prelude { #[doc(no_inline)] #[allow(deprecated)] pub use crate::Date; + #[doc(no_inline)] + pub use crate::Error; #[cfg(feature = "clock")] #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] #[doc(no_inline)] @@ -441,12 +443,14 @@ mod datetime; #[allow(deprecated)] pub use datetime::{DateTime, SecondsFormat, MAX_DATETIME, MIN_DATETIME}; +mod error; +pub use error::Error; + pub mod format; /// L10n locales. #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] pub use format::Locale; -pub use format::{ParseError, ParseResult}; pub mod naive; #[doc(no_inline)] diff --git a/src/month.rs b/src/month.rs index 7abf4eb196..b6d2d1428e 100644 --- a/src/month.rs +++ b/src/month.rs @@ -10,21 +10,27 @@ 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 std::convert::TryFrom; /// use chrono::prelude::*; -/// let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap(); +/// use std::convert::TryFrom; +/// 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)) +/// let month = Month::try_from(u8::try_from(date.month())?).ok(); +/// assert_eq!(month, Some(Month::October)); +/// # Ok::<_, Box>(()) /// ``` +/// /// Or from a Month to an integer usable by dates +/// /// ``` /// # use chrono::prelude::*; /// let month = Month::January; -/// let dt = Utc.with_ymd_and_hms(2019, month.number_from_month(), 28, 9, 10, 11).unwrap(); +/// 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::Error>(()) /// ``` /// Allows mapping from and to month, from 1-January to 12-December. /// Can be Serialized/Deserialized with serde @@ -319,11 +325,11 @@ mod tests { assert_eq!(Month::try_from(12), Ok(Month::December)); assert_eq!(Month::try_from(13), Err(OutOfRange::new())); - let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap(); - assert_eq!(Month::try_from(date.month() as u8).ok(), Some(Month::October)); + 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.with_ymd_and_hms(2019, month.number_from_month(), 28, 9, 10, 11).unwrap(); + 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 92739401a4..2b3a31d2d3 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -13,17 +13,13 @@ use num_integer::div_mod_floor; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; -/// L10n locales. -#[cfg(feature = "unstable-locales")] -use pure_rust_locales::Locale; - #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::DelayedFormat; -use crate::format::{parse, write_hundreds, ParseError, ParseResult, Parsed, StrftimeItems}; +use crate::format::{parse, write_hundreds, 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::{Datelike, Error, TimeDelta, Weekday}; use super::internals::{self, DateImpl, Mdf, Of, YearFlags}; use super::isoweek; @@ -70,9 +66,10 @@ impl NaiveWeek { /// ``` /// use chrono::{NaiveDate, Weekday}; /// - /// let date = NaiveDate::from_ymd_opt(2022, 4, 18).unwrap(); + /// let date = NaiveDate::from_ymd(2022, 4, 18)?; /// let week = date.week(Weekday::Mon); /// assert!(week.first_day() <= date); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] pub fn first_day(&self) -> NaiveDate { @@ -89,9 +86,10 @@ impl NaiveWeek { /// ``` /// use chrono::{NaiveDate, Weekday}; /// - /// let date = NaiveDate::from_ymd_opt(2022, 4, 18).unwrap(); + /// let date = NaiveDate::from_ymd(2022, 4, 18)?; /// let week = date.week(Weekday::Mon); /// assert!(week.last_day() >= date); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] pub fn last_day(&self) -> NaiveDate { @@ -107,10 +105,11 @@ impl NaiveWeek { /// ``` /// use chrono::{NaiveDate, Weekday}; /// - /// let date = NaiveDate::from_ymd_opt(2022, 4, 18).unwrap(); + /// let date = NaiveDate::from_ymd(2022, 4, 18)?; /// let week = date.week(Weekday::Mon); /// let days = week.days(); /// assert!(days.contains(&date)); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] pub fn days(&self) -> RangeInclusive { @@ -209,8 +208,8 @@ impl arbitrary::Arbitrary<'_> for NaiveDate { // we use a separate run-time test. #[test] fn test_date_bounds() { - let calculated_min = NaiveDate::from_ymd_opt(MIN_YEAR, 1, 1).unwrap(); - let calculated_max = NaiveDate::from_ymd_opt(MAX_YEAR, 12, 31).unwrap(); + let calculated_min = NaiveDate::from_ymd(MIN_YEAR, 1, 1).unwrap(); + let calculated_max = NaiveDate::from_ymd(MAX_YEAR, 12, 31).unwrap(); assert!( NaiveDate::MIN == calculated_min, "`NaiveDate::MIN` should have a year flag {:?}", @@ -237,119 +236,134 @@ impl NaiveDate { pub(crate) fn weeks_from(&self, day: Weekday) -> i32 { (self.ordinal() as i32 - self.weekday().num_days_from(day) as i32 + 6) / 7 } + /// 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(Error::ParsingOutOfRange) } } /// 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). - /// - /// Panics on the out-of-range date, invalid month and/or day. - #[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")] - 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). + /// 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. + /// Returns `Err(Error)` on the out-of-range date, invalid month + /// and/or day. /// /// # Example /// /// ``` - /// use chrono::NaiveDate; + /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let from_ymd_opt = NaiveDate::from_ymd_opt; + /// let d = NaiveDate::from_ymd(2015, 3, 14)?; + /// assert_eq!(d.year(), 2015); + /// assert_eq!(d.month(), 3); + /// assert_eq!(d.day(), 14); + /// assert_eq!(d.ordinal(), 73); // day of year + /// assert_eq!(d.iso_week().year(), 2015); + /// 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 /// - /// 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()); + /// let from_ymd = NaiveDate::from_ymd; + /// + /// 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::Error>(()) /// ``` - 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). - /// - /// Panics on the out-of-range date and/or invalid day of year. - #[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")] - 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). + /// 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. + /// Returns `Err(Error)` on the out-of-range date and/or invalid day + /// of year. /// /// # Example /// /// ``` - /// use chrono::NaiveDate; - /// - /// let from_yo_opt = NaiveDate::from_yo_opt; + /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// 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()); - /// ``` - pub fn from_yo_opt(year: i32, ordinal: u32) -> Option { + /// 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); + /// assert_eq!(d.day(), 14); + /// assert_eq!(d.iso_week().year(), 2015); + /// 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 + /// + /// 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::Error>(()) + /// ``` + 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. - /// - /// Panics on the out-of-range date and/or invalid week number. - #[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")] - 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. + /// 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. + /// Returns `Err(Error)` on the out-of-range date and/or invalid week + /// number. /// /// # Example /// /// ``` - /// use chrono::{NaiveDate, Weekday}; + /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let from_ymd = NaiveDate::from_ymd; - /// let from_isoywd_opt = NaiveDate::from_isoywd_opt; + /// let d = NaiveDate::from_isoywd(2015, 11, Weekday::Sat)?; /// - /// 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); + /// assert_eq!(d.iso_week().year(), 2015); + /// assert_eq!(d.iso_week().week(), 11); + /// assert_eq!(d.weekday(), Weekday::Sat); + /// assert_eq!(d.year(), 2015); + /// assert_eq!(d.month(), 3); + /// 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::Error>(()) + /// ``` + /// + /// Examples showcasing errors. /// - /// assert_eq!(from_isoywd_opt(400000, 10, Weekday::Fri), None); - /// assert_eq!(from_isoywd_opt(-400000, 10, Weekday::Sat), 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!(from_isoywd(400000, 10, Weekday::Fri).is_err()); + /// assert!(from_isoywd(-400000, 10, Weekday::Sat).is_err()); + /// # Ok::<_, chrono::Error>(()) /// ``` /// /// The year number of ISO week date may differ from that of the calendar date. @@ -357,23 +371,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::Error>(()) /// ``` - 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 { @@ -400,7 +415,7 @@ impl NaiveDate { } } } else { - None + Err(Error::InvalidDate) } } @@ -408,33 +423,56 @@ impl NaiveDate { /// January 1, 1 being day 1. /// /// Panics if the date is out of range. - #[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")] - #[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; + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// 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); + /// assert_eq!(d.day(), 14); + /// assert_eq!(d.ordinal(), 73); // day of year + /// assert_eq!(d.iso_week().year(), 2015); + /// assert_eq!(d.iso_week().week(), 11); + /// assert_eq!(d.weekday(), Weekday::Sat); + /// # Ok::<_, chrono::Error>(()) + /// ``` /// - /// let from_ndays_opt = NaiveDate::from_num_days_from_ce_opt; - /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + /// While not directly supported by Chrono, + /// it is easy to convert from the Julian day number + /// (January 1, 4713 BCE in the *Julian* calendar being Day 0) + /// to Gregorian with this method. + /// (Note that this panics when `jd` is out of range.) /// - /// 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); /// ``` - pub fn from_num_days_from_ce_opt(days: i32) -> Option { + /// use chrono::{NaiveDate, Error}; + /// + /// 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(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!(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::Error>(()) + /// ``` + #[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); @@ -442,46 +480,44 @@ 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)`. + /// 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. + /// Returns `Err(Error)` 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`. /// - /// `n` is 1-indexed. Passing `n=0` will cause a panic. - #[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")] - 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. + /// # Example /// /// ``` /// 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( + /// 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)?); + /// assert_eq!(NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)?, NaiveDate::from_ymd(2017, 3, 10)?); + /// # Ok::<_, chrono::Error>(()) + /// ``` + pub fn from_weekday_of_month( year: i32, month: u32, weekday: Weekday, n: u8, - ) -> Option { + ) -> Result { if n == 0 { - return None; + return Err(Error::InvalidDate); } - let first = NaiveDate::from_ymd_opt(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`. @@ -495,10 +531,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_opt(2015, 9, 5).unwrap())); - /// assert_eq!(parse_from_str("5sep2015", "%d%b%Y"), - /// Ok(NaiveDate::from_ymd_opt(2015, 9, 5).unwrap())); + /// 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. @@ -506,8 +543,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_opt(2014, 5, 17).unwrap())); + /// 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. @@ -526,7 +564,7 @@ impl NaiveDate { /// # let parse_from_str = NaiveDate::parse_from_str; /// assert!(parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err()); /// ``` - pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { + pub fn parse_from_str(s: &str, fmt: &str) -> Result { let mut parsed = Parsed::new(); parse(&mut parsed, s, StrftimeItems::new(fmt))?; parsed.to_naive_date() @@ -536,62 +574,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(Error)` if the resulting date would be out of range. /// /// ``` /// # use chrono::{NaiveDate, Months}; /// assert_eq!( - /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_add_months(Months::new(6)), - /// Some(NaiveDate::from_ymd_opt(2022, 8, 20).unwrap()) + /// NaiveDate::from_ymd(2022, 2, 20)?.checked_add_months(Months::new(6)), + /// Some(NaiveDate::from_ymd(2022, 8, 20)?) /// ); /// assert_eq!( - /// NaiveDate::from_ymd_opt(2022, 7, 31).unwrap().checked_add_months(Months::new(2)), - /// Some(NaiveDate::from_ymd_opt(2022, 9, 30).unwrap()) + /// NaiveDate::from_ymd(2022, 7, 31)?.checked_add_months(Months::new(2)), + /// Some(NaiveDate::from_ymd(2022, 9, 30)?) /// ); + /// # Ok::<_, chrono::Error>(()) /// ``` - 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)?; + 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(Error)` if the resulting date would be out of range. /// /// ``` - /// # use chrono::{NaiveDate, Months}; + /// use chrono::{NaiveDate, Months}; + /// /// assert_eq!( - /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_sub_months(Months::new(6)), - /// Some(NaiveDate::from_ymd_opt(2021, 8, 20).unwrap()) + /// NaiveDate::from_ymd(2022, 2, 20)?.checked_sub_months(Months::new(6)), + /// Some(NaiveDate::from_ymd(2021, 8, 20)?) /// ); /// - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap() - /// .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_none() /// ); + /// # Ok::<_, chrono::Error>(()) /// ``` - 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 = match i32::try_from(months.0)?.checked_neg() { + None => return Err(Error::InvalidDate), + Some(d) => d, + }; + + 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 @@ -599,7 +639,7 @@ impl NaiveDate { let year = if (years > 0 && years > (MAX_YEAR - self.year())) || (years < 0 && years < (MIN_YEAR - self.year())) { - return None; + return Err(Error::InvalidDate); } else { self.year() + years }; @@ -609,13 +649,13 @@ impl NaiveDate { let month = self.month() as i32 + left; let (year, month) = if month <= 0 { if year == MIN_YEAR { - return None; + return Err(Error::InvalidDate); } (year - 1, month + 12) } else if month > 12 { if year == MAX_YEAR { - return None; + return Err(Error::InvalidDate); } (year + 1, month - 12) @@ -635,58 +675,62 @@ impl NaiveDate { /// Add a duration in [`Days`] to the date /// - /// Returns `None` if the resulting date would be out of range. + /// Returns `Err(Error)` if the resulting date would be out of range. /// /// ``` - /// # use chrono::{NaiveDate, Days}; - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_add_days(Days::new(9)), - /// Some(NaiveDate::from_ymd_opt(2022, 3, 1).unwrap()) - /// ); + /// use chrono::{NaiveDate, Days}; + /// /// assert_eq!( - /// NaiveDate::from_ymd_opt(2022, 7, 31).unwrap().checked_add_days(Days::new(2)), - /// Some(NaiveDate::from_ymd_opt(2022, 8, 2).unwrap()) + /// NaiveDate::from_ymd(2022, 2, 20)?.checked_add_days(Days::new(9)), + /// Ok(NaiveDate::from_ymd(2022, 3, 1)?) /// ); /// assert_eq!( - /// NaiveDate::from_ymd_opt(2022, 7, 31).unwrap().checked_add_days(Days::new(1000000000000)), - /// None + /// NaiveDate::from_ymd(2022, 7, 31)?.checked_add_days(Days::new(2)), + /// Ok(NaiveDate::from_ymd(2022, 8, 2)?) /// ); + /// # Ok::<_, chrono::Error>(()) /// ``` - 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)?; + 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(Error)` if the resulting date would be out of range. /// /// ``` - /// # use chrono::{NaiveDate, Days}; - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_sub_days(Days::new(6)), - /// Some(NaiveDate::from_ymd_opt(2022, 2, 14).unwrap()) - /// ); + /// use chrono::{NaiveDate, Days}; + /// /// assert_eq!( - /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_sub_days(Days::new(1000000000000)), - /// None + /// NaiveDate::from_ymd(2022, 2, 20)?.checked_sub_days(Days::new(6)), + /// Ok(NaiveDate::from_ymd(2022, 2, 14)?) /// ); + /// # Ok::<_, chrono::Error>(()) /// ``` - 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 = match i64::try_from(days.0)?.checked_neg() { + None => return Err(Error::ParsingOutOfRange), + Some(d) => d, + }; + self.diff_days(d) } - fn diff_days(self, days: i64) -> Option { - let secs = days.checked_mul(86400)?; // 86400 seconds in one day + fn diff_days(self, days: i64) -> Result { + let secs = match days.checked_mul(86400) { + None => return Err(Error::ParsingOutOfRange), + Some(secs) => secs, + }; // 86400 seconds in one day if secs >= core::i64::MAX / 1000 || secs <= core::i64::MIN / 1000 { - return None; // See the `time` 0.1 crate. Outside these bounds, `TimeDelta::seconds` will panic + return Err(Error::ParsingOutOfRange); // See the `time` 0.1 crate. Outside these bounds, `TimeDelta::seconds` will panic } self.checked_add_signed(TimeDelta::seconds(secs)) } @@ -698,12 +742,13 @@ impl NaiveDate { /// ``` /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime}; /// - /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); - /// let t = NaiveTime::from_hms_milli_opt(12, 34, 56, 789).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime { @@ -716,76 +761,77 @@ impl NaiveDate { /// use `NaiveDate::and_hms_*` methods with a subsecond parameter instead. /// /// Panics on invalid hour, minute and/or second. - #[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")] - #[inline] - pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime { - self.and_hms_opt(hour, min, sec).expect("invalid 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; + /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; /// - /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); - /// 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()); + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; + /// + /// 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::Error>(()) /// ``` #[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)) + 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, second and millisecond. - /// - /// 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. - #[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")] - #[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` with the time set to midnight. + #[cfg(feature = "clock")] + 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. /// /// The millisecond part can exceed 1,000 - /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling) /// - /// Returns `None` on invalid hour, minute, second and/or millisecond. + /// Returns `Err(Error)` on invalid hour, minute, second and/or millisecond. /// /// # Example /// /// ``` - /// use chrono::NaiveDate; + /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; /// - /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); - /// 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 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); + /// + /// 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::Error>(()) /// ``` #[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. @@ -793,56 +839,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(Error)` on invalid hour, minute, second and/or microsecond. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; /// - /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); + /// 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); - /// ``` - #[deprecated(since = "0.4.23", note = "use `and_hms_micro_opt()` instead")] - #[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_opt(2015, 6, 3).unwrap(); - /// 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::Error>(()) /// ``` #[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. @@ -850,42 +880,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. - #[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")] - #[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. + /// Returns `Err(Error)` on invalid hour, minute, second and/or nanosecond. /// /// # Example /// /// ``` - /// use chrono::NaiveDate; + /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3)?; /// - /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); - /// 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 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); + /// + /// 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::Error>(()) /// ``` #[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. @@ -902,139 +930,139 @@ impl NaiveDate { /// Makes a new `NaiveDate` with the packed month-day-flags changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(Error)` 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(Error)` 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(Error::InvalidDate) } } /// Makes a new `NaiveDate` for the next calendar date. /// - /// Panics when `self` is the last representable date. - #[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")] - #[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. + /// Returns `Err(Error)` when `self` is the last representable date. /// /// # Example /// /// ``` /// use chrono::NaiveDate; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 6, 3).unwrap().succ_opt(), - /// Some(NaiveDate::from_ymd_opt(2015, 6, 4).unwrap())); - /// assert_eq!(NaiveDate::MAX.succ_opt(), None); - /// ``` - #[inline] - pub fn succ_opt(&self) -> Option { - self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1)) - } - - /// Makes a new `NaiveDate` for the previous calendar date. + /// 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)?); /// - /// Panics when `self` is the first representable date. - #[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")] + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3)?.succ()?, + /// NaiveDate::from_ymd(2015, 6, 4)?); + /// assert!(NaiveDate::MAX.succ().is_err()); + /// # Ok::<_, chrono::Error>(()) + /// ``` #[inline] - pub fn pred(&self) -> NaiveDate { - self.pred_opt().expect("out of bound") + 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. /// - /// Returns `None` when `self` is the first representable date. + /// Returns `Err(Error)` when `self` is the first representable date. /// /// # Example /// /// ``` /// use chrono::NaiveDate; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 6, 3).unwrap().pred_opt(), - /// Some(NaiveDate::from_ymd_opt(2015, 6, 2).unwrap())); - /// assert_eq!(NaiveDate::MIN.pred_opt(), None); + /// 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)?); + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3)?.pred()?, + /// NaiveDate::from_ymd(2015, 6, 2)?); + /// assert!(NaiveDate::MIN.pred().is_err()); + /// # Ok::<_, chrono::Error>(()) /// ``` #[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(Error)` when it will result in overflow. /// /// # Example /// /// ``` /// use chrono::{TimeDelta, NaiveDate}; /// - /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// let d = NaiveDate::from_ymd(2015, 9, 5)?; /// assert_eq!(d.checked_add_signed(TimeDelta::days(40)), - /// Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap())); + /// Ok(NaiveDate::from_ymd(2015, 10, 15).unwrap()?)); /// assert_eq!(d.checked_add_signed(TimeDelta::days(-40)), - /// Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap())); - /// 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); + /// Ok(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::Error>(()) /// ``` - pub fn checked_add_signed(self, rhs: TimeDelta) -> Option { + 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((cycle as i64).checked_add(rhs.num_days()).ok_or(Error::ParsingOutOfRange)?)?; let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097); year_div_400 += cycle_div_400y; let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); - NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?) + Self::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?) } /// Subtracts the `days` part of given `TimeDelta` from the current date. /// - /// Returns `None` when it will result in overflow. + /// Returns `Err(Error)` when it will result in overflow. /// /// # Example /// /// ``` /// use chrono::{TimeDelta, NaiveDate}; /// - /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// let d = NaiveDate::from_ymd(2015, 9, 5)?; /// assert_eq!(d.checked_sub_signed(TimeDelta::days(40)), - /// Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap())); + /// Ok(NaiveDate::from_ymd(2015, 7, 27)?)); /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-40)), - /// Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap())); - /// 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); + /// Ok(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::Error>(()) /// ``` - pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option { + 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((cycle as i64).checked_sub(rhs.num_days()).ok_or(Error::ParsingOutOfRange)?)?; let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097); year_div_400 += cycle_div_400y; let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); - NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?) + Self::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?) } /// Subtracts another `NaiveDate` from the current date. @@ -1051,13 +1079,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::Error>(()) /// ``` pub fn signed_duration_since(self, rhs: NaiveDate) -> TimeDelta { let year1 = self.year(); @@ -1097,9 +1126,10 @@ impl NaiveDate { /// use chrono::format::strftime::StrftimeItems; /// /// let fmt = StrftimeItems::new("%Y-%m-%d"); - /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// 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::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -1108,8 +1138,9 @@ impl NaiveDate { /// # use chrono::NaiveDate; /// # use chrono::format::strftime::StrftimeItems; /// # let fmt = StrftimeItems::new("%Y-%m-%d").clone(); - /// # let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// # let d = NaiveDate::from_ymd(2015, 9, 5)?; /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05"); + /// # Ok::<_, chrono::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -1141,18 +1172,20 @@ impl NaiveDate { /// ``` /// use chrono::NaiveDate; /// - /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// 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::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. /// /// ``` /// # use chrono::NaiveDate; - /// # let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// # 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::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -1200,23 +1233,24 @@ impl NaiveDate { /// # use chrono::NaiveDate; /// /// let expected = [ - /// NaiveDate::from_ymd_opt(2016, 2, 27).unwrap(), - /// NaiveDate::from_ymd_opt(2016, 2, 28).unwrap(), - /// NaiveDate::from_ymd_opt(2016, 2, 29).unwrap(), - /// NaiveDate::from_ymd_opt(2016, 3, 1).unwrap(), + /// 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_opt(2016, 2, 27).unwrap().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_opt(2016, 3, 1).unwrap().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::Error>(()) /// ``` #[inline] pub const fn iter_days(&self) -> NaiveDateDaysIterator { @@ -1231,23 +1265,24 @@ impl NaiveDate { /// # use chrono::NaiveDate; /// /// let expected = [ - /// NaiveDate::from_ymd_opt(2016, 2, 27).unwrap(), - /// NaiveDate::from_ymd_opt(2016, 3, 5).unwrap(), - /// NaiveDate::from_ymd_opt(2016, 3, 12).unwrap(), - /// NaiveDate::from_ymd_opt(2016, 3, 19).unwrap(), + /// 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_opt(2016, 2, 27).unwrap().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_opt(2016, 3, 19).unwrap().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::Error>(()) /// ``` #[inline] pub const fn iter_weeks(&self) -> NaiveDateWeeksIterator { @@ -1275,8 +1310,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().year(), 2015); - /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().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::Error>(()) /// ``` #[inline] fn year(&self) -> i32 { @@ -1292,8 +1328,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().month(), 9); - /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().month(), 3); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.month(), 9); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.month(), 3); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn month(&self) -> u32 { @@ -1309,8 +1346,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().month0(), 8); - /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().month0(), 2); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.month0(), 8); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.month0(), 2); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn month0(&self) -> u32 { @@ -1326,8 +1364,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().day(), 8); - /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().day(), 14); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.day(), 8); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.day(), 14); + /// # Ok::<_, chrono::Error>(()) /// ``` /// /// Combined with [`NaiveDate::pred`](#method.pred), @@ -1335,22 +1374,23 @@ impl Datelike for NaiveDate { /// (Note that this panics when `year` is out of range.) /// /// ``` - /// use chrono::{NaiveDate, Datelike}; + /// use chrono::{NaiveDate, Datelike, Error}; /// - /// 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_opt(y, m, 1).unwrap(); + /// 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::Error>(()) /// ``` #[inline] fn day(&self) -> u32 { @@ -1366,8 +1406,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().day0(), 7); - /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().day0(), 13); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.day0(), 7); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.day0(), 13); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn day0(&self) -> u32 { @@ -1383,8 +1424,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().ordinal(), 251); - /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().ordinal(), 74); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.ordinal(), 251); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.ordinal(), 74); + /// # Ok::<_, chrono::Error>(()) /// ``` /// /// Combined with [`NaiveDate::pred`](#method.pred), @@ -1392,21 +1434,22 @@ impl Datelike for NaiveDate { /// (Note that this panics when `year` is out of range.) /// /// ``` - /// use chrono::{NaiveDate, Datelike}; + /// use chrono::{NaiveDate, Datelike, Error}; /// - /// 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_opt(year + 1, 1, 1).unwrap(); + /// 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::Error>(()) /// ``` #[inline] fn ordinal(&self) -> u32 { @@ -1422,8 +1465,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().ordinal0(), 250); - /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().ordinal0(), 73); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.ordinal0(), 250); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.ordinal0(), 73); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn ordinal0(&self) -> u32 { @@ -1437,8 +1481,9 @@ impl Datelike for NaiveDate { /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().weekday(), Weekday::Tue); - /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().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::Error>(()) /// ``` #[inline] fn weekday(&self) -> Weekday { @@ -1452,28 +1497,29 @@ impl Datelike for NaiveDate { /// Makes a new `NaiveDate` with the year number changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Returns `Err(Error)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_year(2016), - /// Some(NaiveDate::from_ymd_opt(2016, 9, 8).unwrap())); - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_year(-308), - /// Some(NaiveDate::from_ymd_opt(-308, 9, 8).unwrap())); + /// 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::Error>(()) /// ``` /// - /// A leap day (February 29) is a good example that this method can return `None`. + /// A leap day (February 29) is a good example that this method can return + /// an error. /// /// ``` /// # use chrono::{NaiveDate, Datelike}; - /// assert!(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().with_year(2015).is_none()); - /// assert!(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().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::Error>(()) /// ``` #[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(); @@ -1486,125 +1532,126 @@ 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(Error)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month(10), - /// Some(NaiveDate::from_ymd_opt(2015, 10, 8).unwrap())); - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month(13), None); // no month 13 - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month0(9), - /// Some(NaiveDate::from_ymd_opt(2015, 10, 8).unwrap())); - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month0(12), None); // no month 13 - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day(30), - /// Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap())); - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day0(29), - /// Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap())); - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal(60), - /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap())); - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().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_opt(2016, 1, 1).unwrap().with_ordinal(60), - /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap())); - /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal(366), - /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap())); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.unwrap().with_ordinal(60)?, + /// NaiveDate::from_ymd(2016, 2, 29).unwrap()?); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.unwrap().with_ordinal(366)?, + /// NaiveDate::from_ymd(2016, 12, 31).unwrap()?); + /// # Ok::<_, chrono::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDate` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, Datelike}; /// - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal0(59), - /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap())); - /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().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_opt(2016, 1, 1).unwrap().with_ordinal0(59), - /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap())); - /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal0(365), - /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap())); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.unwrap().with_ordinal0(59)?, + /// NaiveDate::from_ymd(2016, 2, 29).unwrap()?); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.unwrap().with_ordinal0(365)?, + /// NaiveDate::from_ymd(2016, 12, 31).unwrap()?); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] - fn with_ordinal0(&self, ordinal0: u32) -> Option { + fn with_ordinal0(&self, ordinal0: u32) -> Result { self.with_of(self.of().with_ordinal(ordinal0 + 1)?) } } @@ -1622,14 +1669,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::Error>(()) /// ``` impl Add for NaiveDate { type Output = NaiveDate; @@ -1663,12 +1711,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::Error>(()) /// ``` fn add(self, months: Months) -> Self::Output { self.checked_add_months(months).unwrap() @@ -1691,9 +1740,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::Error>(()) /// ``` fn sub(self, months: Months) -> Self::Output { self.checked_sub_months(months).unwrap() @@ -1730,14 +1780,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::Error>(()) /// ``` impl Sub for NaiveDate { type Output = NaiveDate; @@ -1771,13 +1822,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::Error>(()) /// ``` impl Sub for NaiveDate { type Output = TimeDelta; @@ -1804,7 +1856,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_opt().unwrap(); + self.value = current.succ().ok()?; Some(current) } @@ -1822,7 +1874,7 @@ impl DoubleEndedIterator for NaiveDateDaysIterator { return None; } let current = self.value; - self.value = current.pred_opt().unwrap(); + self.value = current.pred().ok()?; Some(current) } } @@ -1877,17 +1929,19 @@ impl DoubleEndedIterator for NaiveDateWeeksIterator { /// ``` /// use chrono::NaiveDate; /// -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()), "2015-09-05"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( 0, 1, 1).unwrap()), "0000-01-01"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap()), "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::Error>(()) /// ``` /// /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. /// /// ``` /// # use chrono::NaiveDate; -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( -1, 1, 1).unwrap()), "-0001-01-01"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap()), "+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::Error>(()) /// ``` impl fmt::Debug for NaiveDate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1895,6 +1949,7 @@ impl fmt::Debug for NaiveDate { let year = self.year(); let mdf = self.mdf(); + if (0..=9999).contains(&year) { write_hundreds(f, (year / 100) as u8)?; write_hundreds(f, (year % 100) as u8)?; @@ -1920,17 +1975,19 @@ impl fmt::Debug for NaiveDate { /// ``` /// use chrono::NaiveDate; /// -/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()), "2015-09-05"); -/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt( 0, 1, 1).unwrap()), "0000-01-01"); -/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap()), "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::Error>(()) /// ``` /// /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. /// /// ``` /// # use chrono::NaiveDate; -/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt( -1, 1, 1).unwrap()), "-0001-01-01"); -/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap()), "+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::Error>(()) /// ``` impl fmt::Display for NaiveDate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1946,18 +2003,19 @@ impl fmt::Display for NaiveDate { /// ``` /// use chrono::NaiveDate; /// -/// let d = NaiveDate::from_ymd_opt(2015, 9, 18).unwrap(); -/// 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_opt(12345, 6, 7).unwrap(); -/// 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; + type Err = Error; - fn from_str(s: &str) -> ParseResult { + fn from_str(s: &str) -> Result { const ITEMS: &[Item<'static>] = &[ Item::Numeric(Numeric::Year, Pad::Zero), Item::Literal("-"), @@ -1980,11 +2038,12 @@ impl str::FromStr for NaiveDate { /// use chrono::NaiveDate; /// /// let default_date = NaiveDate::default(); -/// assert_eq!(default_date, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()); +/// assert_eq!(default_date, NaiveDate::from_ymd(1970, 1, 1)?); +/// # Ok::<_, chrono::Error>(()) /// ``` impl Default for NaiveDate { fn default() -> Self { - NaiveDate::from_ymd_opt(1970, 1, 1).unwrap() + NaiveDate::MIN } } @@ -1995,15 +2054,15 @@ where E: ::std::fmt::Debug, { assert_eq!( - to_string(&NaiveDate::from_ymd_opt(2014, 7, 24).unwrap()).ok(), + to_string(&NaiveDate::from_ymd(2014, 7, 24).unwrap()).ok(), Some(r#""2014-07-24""#.into()) ); assert_eq!( - to_string(&NaiveDate::from_ymd_opt(0, 1, 1).unwrap()).ok(), + to_string(&NaiveDate::from_ymd(0, 1, 1).unwrap()).ok(), Some(r#""0000-01-01""#.into()) ); assert_eq!( - to_string(&NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()).ok(), + 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())); @@ -2018,20 +2077,14 @@ where { use std::{i32, i64}; - assert_eq!( - from_str(r#""2016-07-08""#).ok(), - Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap()) - ); - assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap())); - assert_eq!(from_str(r#""+002016-07-08""#).ok(), NaiveDate::from_ymd_opt(2016, 7, 8)); - assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap())); - assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap())); - assert_eq!( - from_str(r#""-0001-12-31""#).ok(), - Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()) - ); - 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()); @@ -2131,7 +2184,7 @@ mod serde { // it is not self-describing. use bincode::{deserialize, serialize}; - let d = NaiveDate::from_ymd_opt(2014, 7, 24).unwrap(); + let d = NaiveDate::from_ymd(2014, 7, 24).unwrap(); let encoded = serialize(&d).unwrap(); let decoded: NaiveDate = deserialize(&encoded).unwrap(); assert_eq!(d, decoded); @@ -2141,98 +2194,93 @@ 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::time_delta::TimeDelta; - use crate::{Datelike, Weekday}; + use crate::{Datelike, Weekday, Error}; 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_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(0)), - Some(NaiveDate::from_ymd_opt(2022, 8, 3).unwrap()) - ); + 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_opt(2022, 8, 3) - .unwrap() - .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 exceeding `i32::MIN` - assert_eq!( - NaiveDate::from_ymd_opt(2022, 8, 3) - .unwrap() - .checked_sub_months(Months::new((i32::MIN as i64).abs() as u32 + 1)), - None - ); + // sub with months exceeindg `i32::MIN` + 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_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(2050 * 12)), - Some(NaiveDate::from_ymd_opt(-28, 8, 3).unwrap()) - ); + assert_eq!(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_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(6)), - Some(NaiveDate::from_ymd_opt(2023, 2, 3).unwrap()) - ); + 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_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(10)), - Some(NaiveDate::from_ymd_opt(2021, 10, 3).unwrap()) - ); + 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_opt(2022, 1, 29).unwrap().checked_add_months(Months::new(1)), - Some(NaiveDate::from_ymd_opt(2022, 2, 28).unwrap()) - ); + 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_opt(2022, 10, 29).unwrap().checked_add_months(Months::new(16)), - Some(NaiveDate::from_ymd_opt(2024, 2, 29).unwrap()) - ); + 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_opt(2022, 10, 31).unwrap().checked_add_months(Months::new(2)), - Some(NaiveDate::from_ymd_opt(2022, 12, 31).unwrap()) - ); + 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_opt(2022, 10, 31).unwrap().checked_sub_months(Months::new(10)), - Some(NaiveDate::from_ymd_opt(2021, 12, 31).unwrap()) - ); + 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_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(5)), - Some(NaiveDate::from_ymd_opt(2023, 1, 3).unwrap()) - ); + 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_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(7)), - Some(NaiveDate::from_ymd_opt(2022, 1, 3).unwrap()) - ); + assert_eq!(ymd!(2022, 8, 3).checked_sub_months(Months::new(7)), Ok(ymd!(2022, 1, 3))); } #[test] @@ -2241,20 +2289,20 @@ mod tests { for y in range_inclusive(NaiveDate::MIN.year(), NaiveDate::MAX.year()) { // even months - let d4 = NaiveDate::from_ymd_opt(y, 4, 4).unwrap(); - let d6 = NaiveDate::from_ymd_opt(y, 6, 6).unwrap(); - let d8 = NaiveDate::from_ymd_opt(y, 8, 8).unwrap(); - let d10 = NaiveDate::from_ymd_opt(y, 10, 10).unwrap(); - let d12 = NaiveDate::from_ymd_opt(y, 12, 12).unwrap(); + 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_opt(y, 5, 9).unwrap(); - let d95 = NaiveDate::from_ymd_opt(y, 9, 5).unwrap(); - let d711 = NaiveDate::from_ymd_opt(y, 7, 11).unwrap(); - let d117 = NaiveDate::from_ymd_opt(y, 11, 7).unwrap(); + 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_opt(y, 3, 1).unwrap().pred_opt().unwrap(); + let d30 = ymd!(y, 3, 1).pred().unwrap(); let weekday = d30.weekday(); let other_dates = [d4, d6, d8, d10, d12, d59, d95, d711, d117]; @@ -2264,77 +2312,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 ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); - - 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); + let from_yo = NaiveDate::from_yo; + let ymd = NaiveDate::from_ymd; + + 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 = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); - - 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] @@ -2352,8 +2399,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); @@ -2366,11 +2414,12 @@ 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_opt(w.year(), w.week(), d.weekday()); - assert_eq!(d, d_.unwrap()); + let d_ = NaiveDate::from_isoywd(w.year(), w.week(), d.weekday()).unwrap(); + assert_eq!(d, d_); } } } @@ -2379,111 +2428,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_opt(1, 1, 1).unwrap())); - assert_eq!(from_ndays_from_ce(2), Some(NaiveDate::from_ymd_opt(1, 1, 2).unwrap())); - assert_eq!(from_ndays_from_ce(31), Some(NaiveDate::from_ymd_opt(1, 1, 31).unwrap())); - assert_eq!(from_ndays_from_ce(32), Some(NaiveDate::from_ymd_opt(1, 2, 1).unwrap())); - assert_eq!(from_ndays_from_ce(59), Some(NaiveDate::from_ymd_opt(1, 2, 28).unwrap())); - assert_eq!(from_ndays_from_ce(60), Some(NaiveDate::from_ymd_opt(1, 3, 1).unwrap())); - assert_eq!(from_ndays_from_ce(365), Some(NaiveDate::from_ymd_opt(1, 12, 31).unwrap())); - assert_eq!(from_ndays_from_ce(365 + 1), Some(NaiveDate::from_ymd_opt(2, 1, 1).unwrap())); - assert_eq!( - from_ndays_from_ce(365 * 2 + 1), - Some(NaiveDate::from_ymd_opt(3, 1, 1).unwrap()) - ); - assert_eq!( - from_ndays_from_ce(365 * 3 + 1), - Some(NaiveDate::from_ymd_opt(4, 1, 1).unwrap()) - ); - assert_eq!( - from_ndays_from_ce(365 * 4 + 2), - Some(NaiveDate::from_ymd_opt(5, 1, 1).unwrap()) - ); - assert_eq!( - from_ndays_from_ce(146097 + 1), - Some(NaiveDate::from_ymd_opt(401, 1, 1).unwrap()) - ); - assert_eq!( - from_ndays_from_ce(146097 * 5 + 1), - Some(NaiveDate::from_ymd_opt(2001, 1, 1).unwrap()) - ); - assert_eq!(from_ndays_from_ce(719163), Some(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap())); - assert_eq!(from_ndays_from_ce(0), Some(NaiveDate::from_ymd_opt(0, 12, 31).unwrap())); // 1 BCE - assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap())); - assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap())); // 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_opt(2018, 8, 1).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Thu, 1), - Some(NaiveDate::from_ymd_opt(2018, 8, 2).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Sun, 1), - Some(NaiveDate::from_ymd_opt(2018, 8, 5).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Mon, 1), - Some(NaiveDate::from_ymd_opt(2018, 8, 6).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Tue, 1), - Some(NaiveDate::from_ymd_opt(2018, 8, 7).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Wed, 2), - Some(NaiveDate::from_ymd_opt(2018, 8, 8).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Sun, 2), - Some(NaiveDate::from_ymd_opt(2018, 8, 12).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Thu, 3), - Some(NaiveDate::from_ymd_opt(2018, 8, 16).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Thu, 4), - Some(NaiveDate::from_ymd_opt(2018, 8, 23).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Thu, 5), - Some(NaiveDate::from_ymd_opt(2018, 8, 30).unwrap()) - ); - assert_eq!( - ymwd(2018, 8, Weekday::Fri, 5), - Some(NaiveDate::from_ymd_opt(2018, 8, 31).unwrap()) - ); - 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_opt(year, month, day).unwrap(); + 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_opt(year, ordinal).unwrap(); + let d2 = NaiveDate::from_yo(year, ordinal).unwrap(); assert_eq!(d2.year(), year); assert_eq!(d2.month(), month); assert_eq!(d2.day(), day); @@ -2515,90 +2516,88 @@ mod tests { #[test] fn test_date_weekday() { - assert_eq!(NaiveDate::from_ymd_opt(1582, 10, 15).unwrap().weekday(), Weekday::Fri); + assert_eq!(ymd!(1582, 10, 15).weekday(), Weekday::Fri); // May 20, 1875 = ISO 8601 reference date - assert_eq!(NaiveDate::from_ymd_opt(1875, 5, 20).unwrap().weekday(), Weekday::Thu); - assert_eq!(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().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_opt(2000, 2, 29).unwrap(); - assert_eq!(d.with_year(-400), Some(NaiveDate::from_ymd_opt(-400, 2, 29).unwrap())); - assert_eq!(d.with_year(-100), None); - assert_eq!(d.with_year(1600), Some(NaiveDate::from_ymd_opt(1600, 2, 29).unwrap())); - assert_eq!(d.with_year(1900), None); - assert_eq!(d.with_year(2000), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap())); - assert_eq!(d.with_year(2001), None); - assert_eq!(d.with_year(2004), Some(NaiveDate::from_ymd_opt(2004, 2, 29).unwrap())); - assert_eq!(d.with_year(i32::MAX), None); - - let d = NaiveDate::from_ymd_opt(2000, 4, 30).unwrap(); - assert_eq!(d.with_month(0), None); - assert_eq!(d.with_month(1), Some(NaiveDate::from_ymd_opt(2000, 1, 30).unwrap())); - assert_eq!(d.with_month(2), None); - assert_eq!(d.with_month(3), Some(NaiveDate::from_ymd_opt(2000, 3, 30).unwrap())); - assert_eq!(d.with_month(4), Some(NaiveDate::from_ymd_opt(2000, 4, 30).unwrap())); - assert_eq!(d.with_month(12), Some(NaiveDate::from_ymd_opt(2000, 12, 30).unwrap())); - assert_eq!(d.with_month(13), None); - assert_eq!(d.with_month(u32::MAX), None); - - let d = NaiveDate::from_ymd_opt(2000, 2, 8).unwrap(); - assert_eq!(d.with_day(0), None); - assert_eq!(d.with_day(1), Some(NaiveDate::from_ymd_opt(2000, 2, 1).unwrap())); - assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap())); - assert_eq!(d.with_day(30), None); - assert_eq!(d.with_day(u32::MAX), None); - - let d = NaiveDate::from_ymd_opt(2000, 5, 5).unwrap(); - assert_eq!(d.with_ordinal(0), None); - assert_eq!(d.with_ordinal(1), Some(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap())); - assert_eq!(d.with_ordinal(60), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap())); - assert_eq!(d.with_ordinal(61), Some(NaiveDate::from_ymd_opt(2000, 3, 1).unwrap())); - assert_eq!(d.with_ordinal(366), Some(NaiveDate::from_ymd_opt(2000, 12, 31).unwrap())); - 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_opt(1, 1, 1).unwrap().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_opt(year, 1, 1).unwrap().num_days_from_ce(), - NaiveDate::from_ymd_opt(year - 1, 12, 31).unwrap().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 = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); - 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 = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); - 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_opt(y1, m1, d1).unwrap(); - let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd_opt(y, m, d).unwrap()); - assert_eq!(lhs.checked_add_signed(rhs), sum); - assert_eq!(lhs.checked_sub_signed(-rhs), sum); + let lhs = ymd!(y1, m1, d1); + let sum = ymd.map(|(y, m, d)| ymd!(y, m, d)); + assert_eq!(lhs.checked_add_signed(rhs).ok(), sum); + assert_eq!(lhs.checked_sub_signed(-rhs).ok(), sum); } check((2014, 1, 1), TimeDelta::zero(), Some((2014, 1, 1))); @@ -2625,8 +2624,8 @@ mod tests { #[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_opt(y1, m1, d1).unwrap(); - let rhs = NaiveDate::from_ymd_opt(y2, m2, d2).unwrap(); + 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); } @@ -2645,9 +2644,9 @@ 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_opt(y1, m1, d1).unwrap(); - let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd_opt(y, m, d).unwrap()); - assert_eq!(lhs.checked_add_days(rhs), sum); + let lhs = ymd!(y1, m1, d1); + let sum = ymd.map(|(y, m, d)| ymd!(y, m, d)); + assert_eq!(lhs.checked_add_days(rhs).ok(), sum); } check((2014, 1, 1), Days::new(0), Some((2014, 1, 1))); @@ -2671,8 +2670,8 @@ mod tests { #[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_opt(y1, m1, d1).unwrap(); - let rhs = NaiveDate::from_ymd_opt(y2, m2, d2).unwrap(); + let lhs = ymd!(y1, m1, d1); + let rhs = ymd!(y2, m2, d2); assert_eq!(lhs - diff, rhs); } @@ -2689,42 +2688,37 @@ mod tests { #[test] fn test_date_addassignment() { - let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); - 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 = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); - 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_opt(2012, 3, 4).unwrap()), "2012-03-04"); - assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(0, 3, 4).unwrap()), "0000-03-04"); - assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(-307, 3, 4).unwrap()), "-0307-03-04"); - assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(12345, 3, 4).unwrap()), "+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_opt(2012, 3, 4).unwrap().to_string(), "2012-03-04"); - assert_eq!(NaiveDate::from_ymd_opt(0, 3, 4).unwrap().to_string(), "0000-03-04"); - assert_eq!(NaiveDate::from_ymd_opt(-307, 3, 4).unwrap().to_string(), "-0307-03-04"); - assert_eq!(NaiveDate::from_ymd_opt(12345, 3, 4).unwrap().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_opt(1234, 5, 6).unwrap()), "1234-05-06"); - assert_eq!( - format!("{:30?}", NaiveDate::from_ymd_opt(12345, 6, 7).unwrap()), - "+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] @@ -2808,37 +2802,36 @@ mod tests { #[test] fn test_date_parse_from_str() { - let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); 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)) + NaiveDate::parse_from_str("2015-W06-1=2015-033", "%G-W%V-%u = %Y-%j"), + 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()); assert!(NaiveDate::parse_from_str("2014", "%Y").is_err()); // insufficient assert_eq!( - NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w").ok(), - NaiveDate::from_ymd_opt(2020, 1, 12), + NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w"), + NaiveDate::from_ymd(2020, 1, 12), ); assert_eq!( - NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w").ok(), - NaiveDate::from_ymd_opt(2019, 1, 13), + NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w"), + NaiveDate::from_ymd(2019, 1, 13), ); } #[test] fn test_date_format() { - let d = NaiveDate::from_ymd_opt(2012, 3, 4).unwrap(); + 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"); @@ -2851,59 +2844,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_opt(12345, 1, 1).unwrap().format("%Y").to_string(), - "+12345" - ); - assert_eq!(NaiveDate::from_ymd_opt(1234, 1, 1).unwrap().format("%Y").to_string(), "1234"); - assert_eq!(NaiveDate::from_ymd_opt(123, 1, 1).unwrap().format("%Y").to_string(), "0123"); - assert_eq!(NaiveDate::from_ymd_opt(12, 1, 1).unwrap().format("%Y").to_string(), "0012"); - assert_eq!(NaiveDate::from_ymd_opt(1, 1, 1).unwrap().format("%Y").to_string(), "0001"); - assert_eq!(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().format("%Y").to_string(), "0000"); - assert_eq!(NaiveDate::from_ymd_opt(-1, 1, 1).unwrap().format("%Y").to_string(), "-0001"); - assert_eq!(NaiveDate::from_ymd_opt(-12, 1, 1).unwrap().format("%Y").to_string(), "-0012"); - assert_eq!(NaiveDate::from_ymd_opt(-123, 1, 1).unwrap().format("%Y").to_string(), "-0123"); - assert_eq!(NaiveDate::from_ymd_opt(-1234, 1, 1).unwrap().format("%Y").to_string(), "-1234"); - assert_eq!( - NaiveDate::from_ymd_opt(-12345, 1, 1).unwrap().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_opt(2007, 12, 31).unwrap().format("%G,%g,%U,%W,%V").to_string(), - "2008,08,52,53,01" - ); - assert_eq!( - NaiveDate::from_ymd_opt(2010, 1, 3).unwrap().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_opt(262143, 12, 29).unwrap().iter_days().take(4).count(), 2); - assert_eq!( - NaiveDate::from_ymd_opt(-262144, 1, 3).unwrap().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_opt(262143, 12, 12).unwrap().iter_weeks().take(4).count(), - 2 - ); - assert_eq!( - NaiveDate::from_ymd_opt(-262144, 1, 15).unwrap().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_opt(2022, 5, 18).unwrap(); + 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"), @@ -2927,12 +2899,12 @@ mod tests { // tests per: https://github.com/chronotope/chrono/issues/961 // these internally use `weeks_from` via the parsing infrastructure assert_eq!( - NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w").ok(), - NaiveDate::from_ymd_opt(2020, 1, 12), + NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w"), + NaiveDate::from_ymd(2020, 1, 12), ); assert_eq!( - NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w").ok(), - NaiveDate::from_ymd_opt(2019, 1, 13), + NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w"), + NaiveDate::from_ymd(2019, 1, 13), ); // direct tests @@ -2956,17 +2928,17 @@ mod tests { Weekday::Sun, ] { assert_eq!( - NaiveDate::from_ymd_opt(*y, 1, 1).map(|d| d.weeks_from(*day)), - Some(if day == starts_on { 1 } else { 0 }) + NaiveDate::from_ymd(*y, 1, 1).map(|d| d.weeks_from(*day)), + Ok(if day == starts_on { 1 } else { 0 }) ); // last day must always be in week 52 or 53 assert!([52, 53] - .contains(&NaiveDate::from_ymd_opt(*y, 12, 31).unwrap().weeks_from(*day)),); + .contains(&NaiveDate::from_ymd(*y, 12, 31).unwrap().weeks_from(*day)),); } } - let base = NaiveDate::from_ymd_opt(2019, 1, 1).unwrap(); + let base = NaiveDate::from_ymd(2019, 1, 1).unwrap(); // 400 years covers all year types for day in &[ diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index c89f39f7c8..a006b38d61 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -1,5 +1,6 @@ // This is a part of Chrono. // See README.md and LICENSE.txt for details. +#![allow(dead_code)] //! ISO 8601 date and time without timezone. @@ -17,10 +18,10 @@ use rkyv::{Archive, Deserialize, Serialize}; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::DelayedFormat; -use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems}; +use crate::format::{parse, 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::{DateTime, Datelike, Error, Months, TimeDelta, TimeZone, Timelike, Weekday}; /// Tools to help serializing/deserializing `NaiveDateTime`s #[cfg(feature = "serde")] @@ -58,8 +59,9 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX; /// ``` /// use chrono::{NaiveDate, NaiveDateTime}; /// -/// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap(); +/// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8)?.and_hms(9, 10, 11)?; /// # let _ = dt; +/// # Ok::<_, chrono::Error>(()) /// ``` /// /// You can use typical [date-like](../trait.Datelike.html) and @@ -68,11 +70,12 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX; /// /// ``` /// # use chrono::{NaiveDate, NaiveDateTime}; -/// # let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap(); +/// # 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::Error>(()) /// ``` #[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -109,6 +112,9 @@ impl TimestampUnit { } impl NaiveDateTime { + pub(crate) const UNIX_EPOCH: NaiveDateTime = + NaiveDateTime { date: NaiveDate::MIN, 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`. @@ -118,43 +124,24 @@ impl NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime}; /// - /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); - /// let t = NaiveTime::from_hms_milli_opt(12, 34, 56, 789).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub const 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. - /// - /// 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.) - /// - /// Panics on the out-of-range number of seconds and/or invalid nanosecond. - #[deprecated(since = "0.4.23", note = "use `from_timestamp_opt()` instead")] - #[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") - } - /// Creates a new [NaiveDateTime] from milliseconds since the UNIX epoch. /// /// The UNIX epoch starts on midnight, January 1, 1970, UTC. /// - /// Returns `None` on an out-of-range number of milliseconds. + /// Returns `Err(Error)` on an out-of-range number of milliseconds. /// /// # Example /// @@ -172,7 +159,7 @@ impl NaiveDateTime { /// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis()); /// ``` #[inline] - pub fn from_timestamp_millis(millis: i64) -> Option { + pub fn from_timestamp_millis(millis: i64) -> Result { Self::from_timestamp_unit(millis, TimestampUnit::Millis) } @@ -180,7 +167,7 @@ impl NaiveDateTime { /// /// The UNIX epoch starts on midnight, January 1, 1970, UTC. /// - /// Returns `None` on an out-of-range number of microseconds. + /// Returns `Err(Error)` on an out-of-range number of microseconds. /// /// # Example /// @@ -198,21 +185,24 @@ impl NaiveDateTime { /// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros()); /// ``` #[inline] - pub fn from_timestamp_micros(micros: i64) -> Option { + pub fn from_timestamp_micros(micros: i64) -> Result { Self::from_timestamp_unit(micros, TimestampUnit::Micros) } - /// 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.) + /// 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 (more than 262 000 years away - /// from common era) and/or invalid nanosecond (2 seconds or more). + /// Returns `Err(Error)` on the out-of-range number of seconds and/or + /// invalid nanosecond. /// /// # Example /// @@ -220,26 +210,32 @@ impl NaiveDateTime { /// use chrono::{NaiveDateTime, NaiveDate}; /// use std::i64; /// - /// let from_timestamp_opt = NaiveDateTime::from_timestamp_opt; + /// 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)?); /// - /// 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()); + /// let from_timestamp = NaiveDateTime::from_timestamp; + /// + /// 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::Error>(()) /// ``` #[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_else(|| Error::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`. @@ -254,9 +250,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_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap())); + /// 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_opt(2015, 9, 5).unwrap().and_hms_micro_opt(13, 23, 45, 678_900).unwrap())); + /// Ok(NaiveDate::from_ymd(2015, 9, 5)?.and_hms_micro(13, 23, 45, 678_900)?)); + /// # Ok::<_, chrono::Error>(()) /// ``` /// /// Offset is ignored for the purpose of parsing. @@ -265,7 +262,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_opt(2014, 5, 17).unwrap().and_hms_opt(12, 34, 56).unwrap())); + /// Ok(NaiveDate::from_ymd(2014, 5, 17)?.and_hms(12, 34, 56)?)); + /// # Ok::<_, chrono::Error>(()) /// ``` /// /// [Leap seconds](./struct.NaiveTime.html#leap-second-handling) are correctly handled by @@ -276,7 +274,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_opt(2015, 7, 1).unwrap().and_hms_milli_opt(8, 59, 59, 1_123).unwrap())); + /// Ok(NaiveDate::from_ymd(2015, 7, 1)?.and_hms_milli(8, 59, 59, 1_123)?)); + /// # Ok::<_, chrono::Error>(()) /// ``` /// /// Missing seconds are assumed to be zero, @@ -286,12 +285,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_opt(1994, 9, 4).unwrap().and_hms_opt(7, 15, 0).unwrap())); + /// 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::Error>(()) /// ``` /// /// All parsed fields should be consistent to each other, otherwise it's an error. @@ -313,7 +313,7 @@ impl NaiveDateTime { /// assert!(parse_from_str("10000-09-09 01:46:39", fmt).is_err()); /// assert!(parse_from_str("+10000-09-09 01:46:39", fmt).is_ok()); ///``` - pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { + pub fn parse_from_str(s: &str, fmt: &str) -> Result { let mut parsed = Parsed::new(); parse(&mut parsed, s, StrftimeItems::new(fmt))?; parsed.to_naive_datetime_with_offset(0) // no offset adjustment @@ -326,8 +326,9 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap(); - /// assert_eq!(dt.date(), NaiveDate::from_ymd_opt(2016, 7, 8).unwrap()); + /// 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::Error>(()) /// ``` #[inline] pub const fn date(&self) -> NaiveDate { @@ -341,8 +342,9 @@ impl NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveTime}; /// - /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap(); - /// assert_eq!(dt.time(), NaiveTime::from_hms_opt(9, 10, 11).unwrap()); + /// 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::Error>(()) /// ``` #[inline] pub const fn time(&self) -> NaiveTime { @@ -359,17 +361,18 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 980).unwrap(); + /// 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_opt(2001, 9, 9).unwrap().and_hms_opt(1, 46, 40).unwrap(); + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.unwrap().and_hms(1, 46, 40).unwrap()?; /// assert_eq!(dt.timestamp(), 1_000_000_000); /// - /// let dt = NaiveDate::from_ymd_opt(1969, 12, 31).unwrap().and_hms_opt(23, 59, 59).unwrap(); + /// let dt = NaiveDate::from_ymd(1969, 12, 31)?.unwrap().and_hms(23, 59, 59).unwrap()?; /// assert_eq!(dt.timestamp(), -1); /// - /// let dt = NaiveDate::from_ymd_opt(-1, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); + /// let dt = NaiveDate::from_ymd(-1, 1, 1)?.and_hms(0, 0, 0)?; /// assert_eq!(dt.timestamp(), -62198755200); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] pub fn timestamp(&self) -> i64 { @@ -394,14 +397,15 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 444).unwrap(); + /// 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_opt(2001, 9, 9).unwrap().and_hms_milli_opt(1, 46, 40, 555).unwrap(); + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.unwrap().and_hms_milli_opt(1, 46, 40, 555).unwrap()?; /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); /// - /// let dt = NaiveDate::from_ymd_opt(1969, 12, 31).unwrap().and_hms_milli_opt(23, 59, 59, 100).unwrap(); + /// let dt = NaiveDate::from_ymd(1969, 12, 31)?.and_hms_milli(23, 59, 59, 100)?; /// assert_eq!(dt.timestamp_millis(), -900); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] pub fn timestamp_millis(&self) -> i64 { @@ -424,11 +428,12 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_micro_opt(0, 0, 1, 444).unwrap(); + /// 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_opt(2001, 9, 9).unwrap().and_hms_micro_opt(1, 46, 40, 555).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn timestamp_micros(&self) -> i64 { @@ -456,18 +461,19 @@ impl NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime}; /// - /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_nano_opt(0, 0, 1, 444).unwrap(); + /// 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_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 40, 555).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn timestamp_nanos(&self) -> i64 { @@ -485,11 +491,12 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 123_456_789).unwrap(); + /// 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_opt(2015, 7, 1).unwrap().and_hms_nano_opt(8, 59, 59, 1_234_567_890).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn timestamp_subsec_millis(&self) -> u32 { @@ -506,11 +513,12 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 123_456_789).unwrap(); + /// 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_opt(2015, 7, 1).unwrap().and_hms_nano_opt(8, 59, 59, 1_234_567_890).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn timestamp_subsec_micros(&self) -> u32 { @@ -527,11 +535,12 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 123_456_789).unwrap(); + /// 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_opt(2015, 7, 1).unwrap().and_hms_nano_opt(8, 59, 59, 1_234_567_890).unwrap(); + /// 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::Error>(()) /// ``` #[inline] pub fn timestamp_subsec_nanos(&self) -> u32 { @@ -545,39 +554,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(Error)` 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_opt(h, m, s).unwrap(); - /// 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_opt(3, 5, 7).unwrap())); + /// 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(NaiveDate::from_ymd(2016, 7, 9)?.and_hms(3, 5, 7)?)); /// - /// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap(); - /// assert_eq!(hmsm(3, 5, 7, 980).checked_add_signed(TimeDelta::milliseconds(450)), - /// Some(hmsm(3, 5, 8, 430))); + /// 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)?)); + /// # Ok::<_, chrono::Error>(()) /// ``` /// - /// Overflow returns `None`. + /// Overflow returns `Err(Error)`. /// /// ``` - /// # use chrono::{TimeDelta, NaiveDate}; - /// # let hms = |h, m, s| NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(h, m, s).unwrap(); - /// assert_eq!(hms(3, 5, 7).checked_add_signed(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_none()); + /// # Ok::<_, chrono::Error>(()) /// ``` /// /// Leap seconds are handled, @@ -586,40 +595,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_opt(h, m, s, milli).unwrap(); - /// let leap = hmsm(3, 5, 59, 1_300); + /// # let hmsm = |h, m, s, milli| Ok::<_, chrono::Error>(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))); + /// Some(hmsm(3, 5, 59, 1_300)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(-500)), - /// Some(hmsm(3, 5, 59, 800))); + /// Some(hmsm(3, 5, 59, 800)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(500)), - /// Some(hmsm(3, 5, 59, 1_800))); + /// Some(hmsm(3, 5, 59, 1_800)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(800)), - /// Some(hmsm(3, 6, 0, 100))); + /// Some(hmsm(3, 6, 0, 100)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(10)), - /// Some(hmsm(3, 6, 9, 300))); + /// Some(hmsm(3, 6, 9, 300)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(-10)), - /// Some(hmsm(3, 5, 50, 300))); + /// Some(hmsm(3, 5, 50, 300)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::days(1)), - /// Some(from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap())); + /// Some(from_ymd(2016, 7, 9)?.and_hms_milli(3, 5, 59, 300)?)); + /// # Ok::<_, chrono::Error>(()) /// ``` - pub fn checked_add_signed(self, rhs: TimeDelta) -> Option { + 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(Error::ParsingOutOfRange); } let date = self.date.checked_add_signed(TimeDelta::seconds(rhs))?; - Some(NaiveDateTime { date, time }) + Ok(Self { date, time }) } /// Adds given `Months` to the current date and time. /// - /// Returns `None` when it will result in overflow. - /// - /// Overflow returns `None`. + /// Returns `Err(Error)` when it will result in overflow. /// /// # Example /// @@ -628,19 +636,20 @@ impl NaiveDateTime { /// use chrono::{Months, NaiveDate, NaiveDateTime}; /// /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)? /// .checked_add_months(Months::new(1)), - /// Some(NaiveDate::from_ymd_opt(2014, 2, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()) + /// Ok(NaiveDate::from_ymd(2014, 2, 1)?.unwrap().and_hms(1, 0, 0).unwrap()?) /// ); /// - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() - /// .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::Error>(()) /// ``` - 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. @@ -650,77 +659,69 @@ 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(Error)` when it will result in overflow. /// /// # Example /// /// ``` /// use chrono::{TimeDelta, NaiveDate}; /// - /// let from_ymd = NaiveDate::from_ymd; - /// - /// let d = from_ymd(2016, 7, 8); - /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); - /// 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_opt(3, 5, 7).unwrap())); + /// let d = NaiveDate::from_ymd(2016, 7, 8)?; /// - /// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap(); - /// assert_eq!(hmsm(3, 5, 7, 450).checked_sub_signed(TimeDelta::milliseconds(670)), - /// Some(hmsm(3, 5, 6, 780))); - /// ``` + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::zero()), + /// Some(d.and_hms(3, 5, 7)?)); + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::seconds(1)), + /// Some(d.and_hms(3, 5, 6)?)); + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::seconds(-1)), + /// Some(d.and_hms(3, 5, 8)?)); + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::seconds(3600 + 60)), + /// Some(d.and_hms(2, 4, 7)?)); + /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::seconds(86_400)), + /// Some(NaiveDate::from_ymd(2016, 7, 7)?.and_hms(3, 5, 7)?)); /// - /// Overflow returns `None`. + /// assert_eq!(d.and_hms_milli(3, 5, 7, 450)?.checked_sub_signed(TimeDelta::milliseconds(670)), + /// Some(d.and_hms_milli(3, 5, 6, 780)?)); /// - /// ``` - /// # use chrono::{TimeDelta, NaiveDate}; - /// # let hms = |h, m, s| NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(h, m, s).unwrap(); - /// assert_eq!(hms(3, 5, 7).checked_sub_signed(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_none()); + /// # Ok::<_, chrono::Error>(()) /// ``` /// - /// Leap seconds are handled, - /// but the subtraction assumes that it is the only leap second happened. + /// Leap seconds are handled, but the subtraction assumes that it is the + /// only leap second happened. /// /// ``` /// # use chrono::{TimeDelta, NaiveDate}; /// # let from_ymd = NaiveDate::from_ymd; - /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap(); - /// let leap = hmsm(3, 5, 59, 1_300); + /// # let hmsm = |h, m, s, milli| Ok::<_, chrono::Error>(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))); + /// Some(hmsm(3, 5, 59, 1_300)?)); /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(200)), - /// Some(hmsm(3, 5, 59, 1_100))); + /// Some(hmsm(3, 5, 59, 1_100)?)); /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(500)), - /// Some(hmsm(3, 5, 59, 800))); + /// Some(hmsm(3, 5, 59, 800)?)); /// assert_eq!(leap.checked_sub_signed(TimeDelta::seconds(60)), - /// Some(hmsm(3, 5, 0, 300))); + /// Some(hmsm(3, 5, 0, 300)?)); /// assert_eq!(leap.checked_sub_signed(TimeDelta::days(1)), - /// Some(from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap())); + /// Some(from_ymd(2016, 7, 7)?.and_hms_milli(3, 6, 0, 300)?)); + /// # Ok::<_, chrono::Error>(()) /// ``` - pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option { + 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(Error::ParsingOutOfRange); } let date = self.date.checked_sub_signed(TimeDelta::seconds(rhs))?; - Some(NaiveDateTime { date, time }) + Ok(Self { date, time }) } /// Subtracts given `Months` from the current date and time. /// - /// Returns `None` when it will result in overflow. - /// - /// Overflow returns `None`. + /// Returns `Err(Error)` when it will result in overflow. /// /// # Example /// @@ -729,33 +730,34 @@ impl NaiveDateTime { /// use chrono::{Months, NaiveDate, NaiveDateTime}; /// /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)? /// .checked_sub_months(Months::new(1)), - /// Some(NaiveDate::from_ymd_opt(2013, 12, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()) + /// Some(NaiveDate::from_ymd(2013, 12, 1)?.unwrap().and_hms(1, 0, 0).unwrap()?) /// ); /// - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() - /// .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_none() /// ); + /// # Ok::<_, chrono::Error>(()) /// ``` - 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(Error)` 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` /// - /// 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(Error)` 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. @@ -774,14 +776,15 @@ impl NaiveDateTime { /// /// let from_ymd = NaiveDate::from_ymd; /// - /// let d = from_ymd(2016, 7, 8); - /// assert_eq!(d.and_hms_opt(3, 5, 7).unwrap().signed_duration_since(d.and_hms_opt(2, 4, 6).unwrap()), + /// 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_opt(0, 7, 6, 500).unwrap().signed_duration_since(d0.and_hms_opt(0, 0, 0).unwrap()), + /// 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::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that @@ -790,11 +793,12 @@ impl NaiveDateTime { /// ``` /// # use chrono::{TimeDelta, NaiveDate}; /// # let from_ymd = NaiveDate::from_ymd; - /// let leap = from_ymd(2015, 6, 30).and_hms_milli_opt(23, 59, 59, 1_500).unwrap(); - /// assert_eq!(leap.signed_duration_since(from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap()), + /// 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_opt(1, 0, 0).unwrap().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::Error>(()) /// ``` pub fn signed_duration_since(self, rhs: NaiveDateTime) -> TimeDelta { self.date.signed_duration_since(rhs.date) + self.time.signed_duration_since(rhs.time) @@ -813,9 +817,10 @@ impl NaiveDateTime { /// use chrono::format::strftime::StrftimeItems; /// /// let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S"); - /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap(); + /// 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::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -824,8 +829,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_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap(); + /// # 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::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -857,18 +863,20 @@ impl NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// - /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap(); + /// 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::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. /// /// ``` /// # use chrono::NaiveDate; - /// # let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap(); + /// # 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::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -892,10 +900,12 @@ impl NaiveDateTime { /// /// ``` /// use chrono::{NaiveDate, Utc}; - /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap().and_local_timezone(Utc).unwrap(); + /// let dt = NaiveDate::from_ymd(2015, 9, 5)?.and_hms(23, 56, 4)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timezone(), Utc); - pub fn and_local_timezone(&self, tz: Tz) -> LocalResult> { - tz.from_local_datetime(self) + /// # Ok::<_, chrono::Error>(()) + /// ``` + pub fn and_local_timezone(&self, tz: Tz) -> Result, Error> { + tz.from_local_datetime(self)?.single() } /// The minimum possible `NaiveDateTime`. @@ -907,7 +917,7 @@ impl NaiveDateTime { /// /// This is a private function used by [from_timestamp_millis] and [from_timestamp_micros]. #[inline] - fn from_timestamp_unit(value: i64, unit: TimestampUnit) -> Option { + fn from_timestamp_unit(value: i64, unit: TimestampUnit) -> Result { let (secs, subsecs) = (value / i64::from(unit.per_second()), value % i64::from(unit.per_second())); @@ -917,18 +927,24 @@ impl NaiveDateTime { // hence we subtract one from the seconds part, and we then add a whole second worth of nanos // to our nanos part. Due to the use of u32 datatype, it is more convenient to subtract // the absolute value of the subsec nanos from a whole second worth of nanos - let nsecs = u32::try_from(subsecs.abs()).ok()? * unit.nanos_per(); - NaiveDateTime::from_timestamp_opt( - secs.checked_sub(1)?, - NANOS_IN_SECOND.checked_sub(nsecs)?, + let nsecs = u32::try_from(subsecs.abs())? * unit.nanos_per(); + NaiveDateTime::from_timestamp( + match secs.checked_sub(1) { + None => return Err(Error::ParsingOutOfRange), + Some(secs) => secs, + }, + match NANOS_IN_SECOND.checked_sub(nsecs) { + None => return Err(Error::ParsingOutOfRange), + Some(nsecs) => nsecs, + }, ) } - Ordering::Equal => NaiveDateTime::from_timestamp_opt(secs, 0), + Ordering::Equal => NaiveDateTime::from_timestamp(secs, 0), Ordering::Greater => { // convert the subsec millis into nanosecond scale so they can be supplied // as the nanoseconds parameter - let nsecs = u32::try_from(subsecs).ok()? * unit.nanos_per(); - NaiveDateTime::from_timestamp_opt(secs, nsecs) + let nsecs = u32::try_from(subsecs)? * unit.nanos_per(); + NaiveDateTime::from_timestamp(secs, nsecs) } } } @@ -944,8 +960,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.year(), 2015); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn year(&self) -> i32 { @@ -963,8 +980,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.month(), 9); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn month(&self) -> u32 { @@ -982,8 +1000,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.month0(), 8); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn month0(&self) -> u32 { @@ -1001,8 +1020,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.day(), 25); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn day(&self) -> u32 { @@ -1020,8 +1040,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.day0(), 24); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn day0(&self) -> u32 { @@ -1039,8 +1060,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.ordinal(), 268); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn ordinal(&self) -> u32 { @@ -1058,8 +1080,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.ordinal0(), 267); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn ordinal0(&self) -> u32 { @@ -1075,8 +1098,9 @@ impl Datelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Weekday}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.weekday(), Weekday::Fri); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn weekday(&self) -> Weekday { @@ -1090,158 +1114,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(Error)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap(); - /// assert_eq!(dt.with_year(2016), Some(NaiveDate::from_ymd_opt(2016, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap())); - /// assert_eq!(dt.with_year(-308), Some(NaiveDate::from_ymd_opt(-308, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap())); + /// 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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().and_hms_opt(12, 34, 56).unwrap(); - /// assert_eq!(dt.with_month(10), Some(NaiveDate::from_ymd_opt(2015, 10, 30).unwrap().and_hms_opt(12, 34, 56).unwrap())); - /// 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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().and_hms_opt(12, 34, 56).unwrap(); - /// assert_eq!(dt.with_month0(9), Some(NaiveDate::from_ymd_opt(2015, 10, 30).unwrap().and_hms_opt(12, 34, 56).unwrap())); - /// 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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap(); - /// assert_eq!(dt.with_day(30), Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().and_hms_opt(12, 34, 56).unwrap())); - /// 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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap(); - /// assert_eq!(dt.with_day0(29), Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().and_hms_opt(12, 34, 56).unwrap())); - /// 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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap(); - /// assert_eq!(dt.with_ordinal(60), - /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap().and_hms_opt(12, 34, 56).unwrap())); - /// 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_opt(2016, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap(); - /// assert_eq!(dt.with_ordinal(60), - /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().and_hms_opt(12, 34, 56).unwrap())); - /// assert_eq!(dt.with_ordinal(366), - /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap().and_hms_opt(12, 34, 56).unwrap())); + /// 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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDateTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap(); - /// assert_eq!(dt.with_ordinal0(59), - /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap().and_hms_opt(12, 34, 56).unwrap())); - /// 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_opt(2016, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap(); - /// assert_eq!(dt.with_ordinal0(59), - /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().and_hms_opt(12, 34, 56).unwrap())); - /// assert_eq!(dt.with_ordinal0(365), - /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap().and_hms_opt(12, 34, 56).unwrap())); + /// 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::Error>(()) /// ``` #[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 }) } } @@ -1255,8 +1279,9 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.hour(), 12); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn hour(&self) -> u32 { @@ -1272,8 +1297,9 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.minute(), 34); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn minute(&self) -> u32 { @@ -1289,8 +1315,9 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap(); + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.second(), 56); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn second(&self) -> u32 { @@ -1308,8 +1335,9 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap(); + /// 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::Error>(()) /// ``` #[inline] fn nanosecond(&self) -> u32 { @@ -1318,7 +1346,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(Error)` when the resulting `NaiveDateTime` would be invalid. /// /// See also the [`NaiveTime::with_hour`] method. /// @@ -1327,19 +1355,21 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap(); - /// assert_eq!(dt.with_hour(7), - /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(7, 34, 56, 789).unwrap())); - /// 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::Error>(()) /// ``` #[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(Error)` when the resulting `NaiveDateTime` would be invalid. /// /// See also the /// [`NaiveTime::with_minute`] method. @@ -1349,62 +1379,64 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; /// - /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap(); - /// assert_eq!(dt.with_minute(45), - /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 45, 56, 789).unwrap())); - /// 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::Error>(()) /// ``` #[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(Error)` 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_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap(); - /// assert_eq!(dt.with_second(17), - /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 17, 789).unwrap())); - /// 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::Error>(()) /// ``` #[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(Error)` 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_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap(); - /// assert_eq!(dt.with_nanosecond(333_333_333), - /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_nano_opt(12, 34, 56, 333_333_333).unwrap())); - /// assert_eq!(dt.with_nanosecond(1_333_333_333), // leap second - /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_nano_opt(12, 34, 56, 1_333_333_333).unwrap())); - /// 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::Error>(()) /// ``` #[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 }) } } @@ -1423,21 +1455,20 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{TimeDelta, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; -/// -/// let d = from_ymd(2016, 7, 8); -/// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); -/// assert_eq!(hms(3, 5, 7) + TimeDelta::zero(), hms(3, 5, 7)); -/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(1), hms(3, 5, 8)); -/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(-1), hms(3, 5, 6)); -/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(3600 + 60), hms(4, 6, 7)); -/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(86_400), -/// from_ymd(2016, 7, 9).and_hms_opt(3, 5, 7).unwrap()); -/// assert_eq!(hms(3, 5, 7) + TimeDelta::days(365), -/// from_ymd(2017, 7, 8).and_hms_opt(3, 5, 7).unwrap()); +/// 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), +/// 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_opt(h, m, s, milli).unwrap(); -/// assert_eq!(hmsm(3, 5, 7, 980) + TimeDelta::milliseconds(450), hmsm(3, 5, 8, 430)); +/// 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)?); +/// # Ok::<_, chrono::Error>(()) /// ``` /// /// Leap seconds are handled, @@ -1446,16 +1477,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_opt(h, m, s, milli).unwrap(); -/// 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_opt(3, 5, 59, 300).unwrap()); +/// from_ymd(2016, 7, 9)?.and_hms_milli(3, 5, 59, 300)?); +/// # Ok::<_, chrono::Error>(()) /// ``` impl Add for NaiveDateTime { type Output = NaiveDateTime; @@ -1489,29 +1521,30 @@ impl Add for NaiveDateTime { /// use std::str::FromStr; /// /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + Months::new(1), - /// NaiveDate::from_ymd_opt(2014, 2, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + /// 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_opt(2014, 1, 1).unwrap().and_hms_opt(0, 2, 0).unwrap() + Months::new(11), - /// NaiveDate::from_ymd_opt(2014, 12, 1).unwrap().and_hms_opt(0, 2, 0).unwrap() + /// 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_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap() + Months::new(12), - /// NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap() + /// 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_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 4).unwrap() + Months::new(13), - /// NaiveDate::from_ymd_opt(2015, 2, 1).unwrap().and_hms_opt(0, 0, 4).unwrap() + /// 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_opt(2014, 1, 31).unwrap().and_hms_opt(0, 5, 0).unwrap() + Months::new(1), - /// NaiveDate::from_ymd_opt(2014, 2, 28).unwrap().and_hms_opt(0, 5, 0).unwrap() + /// 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_opt(2020, 1, 31).unwrap().and_hms_opt(6, 0, 0).unwrap() + Months::new(1), - /// NaiveDate::from_ymd_opt(2020, 2, 29).unwrap().and_hms_opt(6, 0, 0).unwrap() + /// 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::Error>(()) /// ``` fn add(self, rhs: Months) -> Self::Output { Self { date: self.date.checked_add_months(rhs).unwrap(), time: self.time } @@ -1536,19 +1569,20 @@ impl Add for NaiveDateTime { /// /// let from_ymd = NaiveDate::from_ymd; /// -/// let d = from_ymd(2016, 7, 8); -/// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); -/// assert_eq!(hms(3, 5, 7) - TimeDelta::zero(), hms(3, 5, 7)); -/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(1), hms(3, 5, 6)); -/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(-1), hms(3, 5, 8)); -/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(3600 + 60), hms(2, 4, 7)); -/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(86_400), -/// from_ymd(2016, 7, 7).and_hms_opt(3, 5, 7).unwrap()); -/// assert_eq!(hms(3, 5, 7) - TimeDelta::days(365), -/// from_ymd(2015, 7, 9).and_hms_opt(3, 5, 7).unwrap()); +/// 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)?); /// -/// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap(); -/// assert_eq!(hmsm(3, 5, 7, 450) - TimeDelta::milliseconds(670), hmsm(3, 5, 6, 780)); +/// 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)?); +/// # Ok::<_, chrono::Error>(()) /// ``` /// /// Leap seconds are handled, @@ -1557,14 +1591,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_opt(h, m, s, milli).unwrap(); -/// 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::Error>(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_opt(3, 6, 0, 300).unwrap()); +/// from_ymd(2016, 7, 7)?.and_hms_milli(3, 6, 0, 300)?); +/// # Ok::<_, chrono::Error>(()) /// ``` impl Sub for NaiveDateTime { type Output = NaiveDateTime; @@ -1595,17 +1630,18 @@ impl SubAssign for NaiveDateTime { /// use std::str::FromStr; /// /// assert_eq!( -/// NaiveDate::from_ymd_opt(2014, 01, 01).unwrap().and_hms_opt(01, 00, 00).unwrap() - Months::new(11), -/// NaiveDate::from_ymd_opt(2013, 02, 01).unwrap().and_hms_opt(01, 00, 00).unwrap() +/// 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_opt(2014, 01, 01).unwrap().and_hms_opt(00, 02, 00).unwrap() - Months::new(12), -/// NaiveDate::from_ymd_opt(2013, 01, 01).unwrap().and_hms_opt(00, 02, 00).unwrap() +/// NaiveDate::from_ymd(2014, 01, 01)?.unwrap().and_hms(00, 02, 00).unwrap()? - Months::new(12), +/// NaiveDate::from_ymd(2013, 01, 01)?.unwrap().and_hms(00, 02, 00).unwrap()? /// ); /// assert_eq!( -/// NaiveDate::from_ymd_opt(2014, 01, 01).unwrap().and_hms_opt(00, 00, 03).unwrap() - Months::new(13), -/// NaiveDate::from_ymd_opt(2012, 12, 01).unwrap().and_hms_opt(00, 00, 03).unwrap() +/// 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::Error>(()) /// ``` impl Sub for NaiveDateTime { type Output = NaiveDateTime; @@ -1631,15 +1667,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_opt(3, 5, 7).unwrap() - d.and_hms_opt(2, 4, 6).unwrap(), 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_opt(0, 7, 6, 500).unwrap() - d0.and_hms_opt(0, 0, 0).unwrap(), +/// 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::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that no other leap @@ -1647,12 +1682,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_opt(23, 59, 59, 1_500).unwrap(); -/// assert_eq!(leap - from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap(), +/// 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_opt(1, 0, 0).unwrap() - leap, +/// +/// assert_eq!(NaiveDate::from_ymd(2015, 7, 1)?.and_hms(1, 0, 0)? - leap, /// TimeDelta::seconds(3600) - TimeDelta::milliseconds(500)); +/// # Ok::<_, chrono::Error>(()) /// ``` impl Sub for NaiveDateTime { type Output = TimeDelta; @@ -1695,16 +1732,18 @@ impl Sub for NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// -/// let dt = NaiveDate::from_ymd_opt(2016, 11, 15).unwrap().and_hms_opt(7, 39, 24).unwrap(); +/// let dt = NaiveDate::from_ymd(2016, 11, 15)?.and_hms(7, 39, 24)?; /// assert_eq!(format!("{:?}", dt), "2016-11-15T07:39:24"); +/// # Ok::<_, chrono::Error>(()) /// ``` /// /// Leap seconds may also be used. /// /// ``` /// # use chrono::NaiveDate; -/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_500).unwrap(); +/// 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::Error>(()) /// ``` impl fmt::Debug for NaiveDateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1728,16 +1767,18 @@ impl fmt::Debug for NaiveDateTime { /// ``` /// use chrono::NaiveDate; /// -/// let dt = NaiveDate::from_ymd_opt(2016, 11, 15).unwrap().and_hms_opt(7, 39, 24).unwrap(); +/// 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::Error>(()) /// ``` /// /// Leap seconds may also be used. /// /// ``` /// # use chrono::NaiveDate; -/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_500).unwrap(); +/// 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::Error>(()) /// ``` impl fmt::Display for NaiveDateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1755,18 +1796,19 @@ impl fmt::Display for NaiveDateTime { /// ``` /// use chrono::{NaiveDateTime, NaiveDate}; /// -/// let dt = NaiveDate::from_ymd_opt(2015, 9, 18).unwrap().and_hms_opt(23, 56, 4).unwrap(); +/// 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_opt(12345, 6, 7).unwrap().and_hms_milli_opt(7, 59, 59, 1_500).unwrap(); // 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::Error>(()) /// ``` impl str::FromStr for NaiveDateTime { - type Err = ParseError; + type Err = Error; - fn from_str(s: &str) -> ParseResult { + fn from_str(s: &str) -> Result { const ITEMS: &[Item<'static>] = &[ Item::Numeric(Numeric::Year, Pad::Zero), Item::Space(""), @@ -1803,11 +1845,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::Error>(()) /// ``` impl Default for NaiveDateTime { fn default() -> Self { - NaiveDateTime::from_timestamp_opt(0, 0).unwrap() + NaiveDateTime::UNIX_EPOCH } } @@ -1818,37 +1861,30 @@ where E: ::std::fmt::Debug, { assert_eq!( - to_string( - &NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap() - ) - .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_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()) - .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_opt(0, 1, 1).unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap() - ) - .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_opt(-1, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 7).unwrap() - ) - .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_opt(0, 0, 0).unwrap()).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_opt(23, 59, 59, 1_999_999_999).unwrap()).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()) ); } @@ -1860,44 +1896,42 @@ where E: ::std::fmt::Debug, { assert_eq!( - from_str(r#""2016-07-08T09:10:48.090""#).ok(), - Some( - NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap() - ) + 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""#).ok(), - Some( - NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap() - ) + from_str(r#""2016-7-8T9:10:48.09""#).unwrap(), + + NaiveDate::from_ymd(2016, 7, 8).unwrap().unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap() + .unwrap() ); assert_eq!( - from_str(r#""2014-07-24T12:34:06""#).ok(), - Some(NaiveDate::from_ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()) + from_str(r#""2014-07-24T12:34:06""#).unwrap(), + NaiveDate::from_ymd(2014, 7, 24).unwrap().unwrap().and_hms(12, 34, 6).unwrap().unwrap() ); assert_eq!( - from_str(r#""0000-01-01T00:00:60""#).ok(), - Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap()) + from_str(r#""0000-01-01T00:00:60""#).unwrap(), + NaiveDate::from_ymd(0, 1, 1).unwrap().unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap().unwrap() ); assert_eq!( - from_str(r#""0-1-1T0:0:60""#).ok(), - Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap()) + from_str(r#""0-1-1T0:0:60""#).unwrap(), + NaiveDate::from_ymd(0, 1, 1).unwrap().unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap().unwrap() ); assert_eq!( - from_str(r#""-0001-12-31T23:59:59.000000007""#).ok(), - Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 7).unwrap()) + from_str(r#""-0001-12-31T23:59:59.000000007""#).unwrap(), + NaiveDate::from_ymd(-1, 12, 31).unwrap().unwrap().and_hms_nano_opt(23, 59, 59, 7).unwrap().unwrap() ); assert_eq!( - from_str(r#""-262144-01-01T00:00:00""#).ok(), - Some(NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap()) + from_str(r#""-262144-01-01T00:00:00""#).unwrap(), + NaiveDate::MIN.and_hms(0, 0, 0).unwrap() ); assert_eq!( - from_str(r#""+262143-12-31T23:59:60.999999999""#).ok(), - Some(NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) + 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_opt(23, 59, 59, 1_999_999_999).unwrap()) + 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 40695fa74b..5124ff8bd3 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_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap(); +/// 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_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap(), + /// 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_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap()); +/// 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_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap()), + /// 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_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap(); +/// 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_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap(), + /// 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_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap()); +/// 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_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap()), + /// 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_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap(); +/// 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_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap(), + /// 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_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap()); +/// 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_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap()), + /// 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_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap(); +/// 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_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap(), + /// 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_opt(2018, 5, 17).unwrap().and_hms_opt(02, 04, 59).unwrap()); +/// 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_opt(2018, 5, 17).unwrap().and_hms_opt(02, 04, 59).unwrap()), + /// 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::NaiveDate; use bincode::{deserialize, serialize}; - let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap(); + 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); @@ -1077,57 +1067,9 @@ fn test_serde_bincode_optional() { } let expected = - Test { one: Some(1), two: Some(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap()) }; + 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 c07c00f659..fb7c36d752 100644 --- a/src/naive/datetime/tests.rs +++ b/src/naive/datetime/tests.rs @@ -1,7 +1,6 @@ use super::NaiveDateTime; use crate::time_delta::TimeDelta; -use crate::NaiveDate; -use crate::{Datelike, FixedOffset, Utc}; +use crate::{Datelike, Error, FixedOffset, Utc, NaiveDate}; use std::i64; #[test] @@ -19,15 +18,15 @@ fn test_datetime_from_timestamp_millis() { for (timestamp_millis, formatted) in valid_map.iter().copied() { let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis); - assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis()); - assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), formatted); + assert_eq!(naive_datetime.as_ref().unwrap().timestamp_millis(), timestamp_millis); + assert_eq!(naive_datetime.as_ref().unwrap().format("%F %T%.9f").to_string(), formatted); } let invalid = [i64::MAX, i64::MIN]; for timestamp_millis in invalid.iter().copied() { let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis); - assert!(naive_datetime.is_none()); + assert!(naive_datetime.is_err()); } // Test that the result of `from_timestamp_millis` compares equal to @@ -36,7 +35,7 @@ fn test_datetime_from_timestamp_millis() { for secs in secs_test.iter().cloned() { assert_eq!( NaiveDateTime::from_timestamp_millis(secs * 1000), - NaiveDateTime::from_timestamp_opt(secs, 0) + NaiveDateTime::from_timestamp(secs, 0) ); } } @@ -56,141 +55,147 @@ fn test_datetime_from_timestamp_micros() { for (timestamp_micros, formatted) in valid_map.iter().copied() { let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros); - assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros()); - assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), formatted); + assert_eq!(naive_datetime.as_ref().unwrap().timestamp_micros(), timestamp_micros); + assert_eq!(naive_datetime.as_ref().unwrap().format("%F %T%.9f").to_string(), formatted); } let invalid = [i64::MAX, i64::MIN]; for timestamp_micros in invalid.iter().copied() { let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros); - assert!(naive_datetime.is_none()); + assert!(naive_datetime.is_err()); } // Test that the result of `from_timestamp_micros` compares equal to - // that of `from_timestamp_opt`. + // that of `from_timestamp`. let secs_test = [0, 1, 2, 1000, 1234, 12345678, -1, -2, -1000, -12345678]; for secs in secs_test.iter().copied() { assert_eq!( NaiveDateTime::from_timestamp_micros(secs * 1_000_000), - NaiveDateTime::from_timestamp_opt(secs, 0) + NaiveDateTime::from_timestamp(secs, 0) ); } } #[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_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); - 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::<_, Error>(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_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); - let sum = result.map(|(y, m, d, h, n, s)| { - NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap() - }); - 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.map(|(y, m, d, h, n, s)| { + NaiveDate::from_ymd(y, m, d).unwrap().and_hms(h, n, s).unwrap() + }); + 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_opt(0, 1, 1).unwrap()); - check((0, 1, 1, 0, 0, 0), max_days_from_year_0, Some((NaiveDate::MAX.year(), 12, 31, 0, 0, 0))); - check( + 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), None); - check((0, 1, 1, 0, 0, 0), TimeDelta::max_value(), None); + check!((0, 1, 1, 0, 0, 0), max_days_from_year_0 + TimeDelta::seconds(86_400), Err(Error::ParsingOutOfRange),); + check!((0, 1, 1, 0, 0, 0), TimeDelta::max_value(), Err(Error::ParsingOutOfRange),); let min_days_from_year_0 = - NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd_opt(0, 1, 1).unwrap()); - check((0, 1, 1, 0, 0, 0), min_days_from_year_0, Some((NaiveDate::MIN.year(), 1, 1, 0, 0, 0))); - check((0, 1, 1, 0, 0, 0), min_days_from_year_0 - TimeDelta::seconds(1), None); - check((0, 1, 1, 0, 0, 0), TimeDelta::min_value(), None); + 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(Error::ParsingOutOfRange),); + check!((0, 1, 1, 0, 0, 0), TimeDelta::min_value(), Err(Error::ParsingOutOfRange),); } #[test] fn test_datetime_sub() { - let ymdhms = - |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); + let ymdhms = |y, m, d, h, n, s| Ok::<_, Error>(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_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); - let mut date = ymdhms(2016, 10, 1, 10, 10, 10); + let ymdhms = |y, m, d, h, n, s| Ok::<_, Error>(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_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); - let mut date = ymdhms(2016, 10, 1, 10, 10, 10); + let ymdhms = |y, m, d, h, n, s| Ok::<_, Error>(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_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap().timestamp() + Ok::<_, Error>(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); + 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] @@ -276,26 +281,25 @@ fn test_datetime_from_str() { #[test] fn test_datetime_parse_from_str() { - let ymdhms = - |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap(); + let ymdhms = |y, m, d, h, n, s| Ok::<_, Error>(NaiveDate::from_ymd(y, m, d)?.and_hms(h, n, s)?); let ymdhmsn = |y, m, d, h, n, s, nano| { - NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_nano_opt(h, n, s, nano).unwrap() + Ok::<_, Error>(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!( // intermixed whitespace NaiveDateTime::parse_from_str("2015-W06-1 000000", "%G-W%V-%u%H%M%S").is_err() ); 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)) + NaiveDateTime::parse_from_str("2015-W06-1 000000", "%G-W%V-%u%H%M%S"), + 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", @@ -306,36 +310,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_opt(2010, 9, 8).unwrap().and_hms_milli_opt(7, 6, 54, 321).unwrap(); + 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_opt(2012, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap(); + 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. } @@ -343,7 +346,7 @@ fn test_datetime_format() { #[test] fn test_datetime_add_sub_invariant() { // issue #37 - let base = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); + let 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()); @@ -357,7 +360,7 @@ fn test_nanosecond_range() { let nanos = parsed.timestamp_nanos(); assert_eq!( parsed, - NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap() + NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap() ); let minimum = "1677-09-21T00:12:44.000000000"; @@ -365,18 +368,18 @@ fn test_nanosecond_range() { let nanos = parsed.timestamp_nanos(); assert_eq!( parsed, - NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap() + NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap() ); } #[test] fn test_and_timezone() { - let ndt = NaiveDate::from_ymd_opt(2022, 6, 15).unwrap().and_hms_opt(18, 59, 36).unwrap(); + 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_opt(4 * 3600).unwrap(); + 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/internals.rs b/src/naive/internals.rs index 3c33f4b91a..541c30ef92 100644 --- a/src/naive/internals.rs +++ b/src/naive/internals.rs @@ -20,7 +20,7 @@ use core::{fmt, i32}; use num_integer::{div_rem, mod_floor}; -use crate::Weekday; +use crate::{Error, Weekday}; /// The internal date representation. This also includes the packed `Mdf` value. pub(super) type DateImpl = i32; @@ -272,10 +272,10 @@ pub(super) struct Of(pub(crate) u32); impl Of { #[inline] - pub(super) fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Option { + pub(super) fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Result { match ordinal <= 366 { - true => Some(Of((ordinal << 4) | u32::from(flags))), - false => None, + true => Ok(Of((ordinal << 4) | u32::from(flags))), + false => Err(Error::InvalidDate), } } @@ -302,13 +302,13 @@ impl Of { } #[inline] - pub(super) fn with_ordinal(&self, ordinal: u32) -> Option { + pub(super) fn with_ordinal(&self, ordinal: u32) -> Result { if ordinal > 366 { - return None; + return Err(Error::ParsingOutOfRange); } let Of(of) = *self; - Some(Of((of & 0b1111) | (ordinal << 4))) + Ok(Of((of & 0b1111) | (ordinal << 4))) } #[inline] @@ -373,10 +373,10 @@ pub(super) struct Mdf(pub(super) u32); impl Mdf { #[inline] - pub(super) fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option { + pub(super) fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Result { match month <= 12 && day <= 31 { - true => Some(Mdf((month << 9) | (day << 4) | u32::from(flags))), - false => None, + true => Ok(Mdf((month << 9) | (day << 4) | u32::from(flags))), + false => Err(Error::InvalidDate), } } @@ -406,13 +406,13 @@ impl Mdf { } #[inline] - pub(super) fn with_month(&self, month: u32) -> Option { + pub(super) fn with_month(&self, month: u32) -> Result { if month > 12 { - return None; + return Err(Error::InvalidDate); } let Mdf(mdf) = *self; - Some(Mdf((mdf & 0b1_1111_1111) | (month << 9))) + Ok(Mdf((mdf & 0b1_1111_1111) | (month << 9))) } #[inline] @@ -422,13 +422,13 @@ impl Mdf { } #[inline] - pub(super) fn with_day(&self, day: u32) -> Option { + pub(super) fn with_day(&self, day: u32) -> Result { if day > 31 { - return None; + return Err(Error::InvalidDate); } let Mdf(mdf) = *self; - Some(Mdf((mdf & !0b1_1111_0000) | (day << 4))) + Ok(Mdf((mdf & !0b1_1111_0000) | (day << 4))) } #[inline] @@ -511,9 +511,9 @@ mod tests { fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) { for ordinal in range_inclusive(ordinal1, ordinal2) { let of = match Of::new(ordinal, flags) { - Some(of) => of, - None if !expected => continue, - None => panic!("Of::new({}, {:?}) returned None", ordinal, flags), + Ok(of) => of, + Err(..) if !expected => continue, + Err(..) => panic!("Of::new({}, {:?}) returned None", ordinal, flags), }; assert!( @@ -548,9 +548,9 @@ mod tests { for month in range_inclusive(month1, month2) { for day in range_inclusive(day1, day2) { let mdf = match Mdf::new(month, day, flags) { - Some(mdf) => mdf, - None if !expected => continue, - None => panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags), + Ok(mdf) => mdf, + Err(..) if !expected => continue, + Err(..) => panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags), }; assert!( @@ -652,9 +652,9 @@ mod tests { for ordinal in range_inclusive(0u32, 1024) { let of = match of.with_ordinal(ordinal) { - Some(of) => of, - None if ordinal > 366 => continue, - None => panic!("failed to create Of with ordinal {}", ordinal), + Ok(of) => of, + Err(..) if ordinal > 366 => continue, + Err(..) => panic!("failed to create Of with ordinal {}", ordinal), }; assert_eq!(of.valid(), Of::new(ordinal, flags).unwrap().valid()); @@ -708,8 +708,8 @@ mod tests { for month in range_inclusive(1u32, 12) { for day in range_inclusive(1u32, 31) { let mdf = match Mdf::new(month, day, flags) { - Some(mdf) => mdf, - None => continue, + Ok(mdf) => mdf, + Err(..) => continue, }; if mdf.valid() { @@ -728,9 +728,9 @@ mod tests { for month in range_inclusive(0u32, 16) { let mdf = match mdf.with_month(month) { - Some(mdf) => mdf, - None if month > 12 => continue, - None => panic!("failed to create Mdf with month {}", month), + Ok(mdf) => mdf, + Err(..) if month > 12 => continue, + Err(..) => panic!("failed to create Mdf with month {}", month), }; if mdf.valid() { @@ -741,9 +741,9 @@ mod tests { for day in range_inclusive(0u32, 1024) { let mdf = match mdf.with_day(day) { - Some(mdf) => mdf, - None if day > 31 => continue, - None => panic!("failed to create Mdf with month {}", month), + Ok(mdf) => mdf, + Err(..) if day > 31 => continue, + Err(..) => panic!("failed to create Mdf with month {}", month), }; if mdf.valid() { diff --git a/src/naive/isoweek.rs b/src/naive/isoweek.rs index 45c2a81ede..9ed2e1ac7b 100644 --- a/src/naive/isoweek.rs +++ b/src/naive/isoweek.rs @@ -58,8 +58,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::Error>(()) /// ``` /// /// This year number might not match the calendar year number. @@ -67,9 +68,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_opt(2014, 12, 29).unwrap()); + /// assert_eq!(d, NaiveDate::from_ymd(2014, 12, 29)?); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] pub const fn year(&self) -> i32 { @@ -85,8 +87,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::Error>(()) /// ``` #[inline] pub const fn week(&self) -> u32 { @@ -102,8 +105,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::Error>(()) /// ``` #[inline] pub const fn week0(&self) -> u32 { @@ -120,17 +124,19 @@ impl IsoWeek { /// ``` /// use chrono::{NaiveDate, Datelike}; /// -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().iso_week()), "2015-W36"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( 0, 1, 3).unwrap().iso_week()), "0000-W01"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap().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::Error>(()) /// ``` /// /// 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_opt( 0, 1, 2).unwrap().iso_week()), "-0001-W52"); -/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap().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::Error>(()) /// ``` impl fmt::Debug for IsoWeek { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -168,24 +174,24 @@ mod tests { #[test] fn test_iso_week_equivalence_for_first_week() { - let monday = NaiveDate::from_ymd_opt(2024, 12, 30).unwrap(); - let friday = NaiveDate::from_ymd_opt(2025, 1, 3).unwrap(); + let monday = NaiveDate::from_ymd(2024, 12, 30).unwrap(); + let friday = NaiveDate::from_ymd(2025, 1, 3).unwrap(); assert_eq!(monday.iso_week(), friday.iso_week()); } #[test] fn test_iso_week_equivalence_for_last_week() { - let monday = NaiveDate::from_ymd_opt(2026, 12, 28).unwrap(); - let friday = NaiveDate::from_ymd_opt(2027, 1, 1).unwrap(); + let monday = NaiveDate::from_ymd(2026, 12, 28).unwrap(); + let friday = NaiveDate::from_ymd(2027, 1, 1).unwrap(); assert_eq!(monday.iso_week(), friday.iso_week()); } #[test] fn test_iso_week_ordering_for_first_week() { - let monday = NaiveDate::from_ymd_opt(2024, 12, 30).unwrap(); - let friday = NaiveDate::from_ymd_opt(2025, 1, 3).unwrap(); + let monday = NaiveDate::from_ymd(2024, 12, 30).unwrap(); + let friday = NaiveDate::from_ymd(2025, 1, 3).unwrap(); assert!(monday.iso_week() >= friday.iso_week()); assert!(monday.iso_week() <= friday.iso_week()); @@ -193,8 +199,8 @@ mod tests { #[test] fn test_iso_week_ordering_for_last_week() { - let monday = NaiveDate::from_ymd_opt(2026, 12, 28).unwrap(); - let friday = NaiveDate::from_ymd_opt(2027, 1, 1).unwrap(); + let monday = NaiveDate::from_ymd(2026, 12, 28).unwrap(); + let friday = NaiveDate::from_ymd(2027, 1, 1).unwrap(); assert!(monday.iso_week() >= friday.iso_week()); assert!(monday.iso_week() <= friday.iso_week()); diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 2b7204f34a..b65637a475 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -14,9 +14,9 @@ use rkyv::{Archive, Deserialize, Serialize}; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::DelayedFormat; -use crate::format::{parse, write_hundreds, ParseError, ParseResult, Parsed, StrftimeItems}; +use crate::format::{parse, write_hundreds, Parsed, StrftimeItems}; use crate::format::{Fixed, Item, Numeric, Pad}; -use crate::{TimeDelta, Timelike}; +use crate::{Error, TimeDelta, Timelike}; #[cfg(feature = "serde")] mod serde; @@ -72,12 +72,13 @@ mod tests; /// ``` /// use chrono::{NaiveDate, NaiveTime, Utc, TimeZone}; /// -/// let t = NaiveTime::from_hms_milli_opt(8, 59, 59, 1_000).unwrap(); +/// let t = NaiveTime::from_hms_milli(8, 59, 59, 1_000).unwrap(); /// -/// let dt1 = NaiveDate::from_ymd_opt(2015, 7, 1).unwrap().and_hms_micro_opt(8, 59, 59, 1_000_000).unwrap(); +/// let dt1 = NaiveDate::from_ymd(2015, 7, 1)?.and_hms_micro(8, 59, 59, 1_000_000)?; /// -/// let dt2 = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_nano_opt(23, 59, 59, 1_000_000_000).unwrap().and_local_timezone(Utc).unwrap(); +/// let dt2 = Utc.ymd(2015, 6, 30)?.and_hms_nano(23, 59, 59, 1_000_000_000)?; /// # let _ = (t, dt1, dt2); +/// # Ok::<_, chrono::Error>(()) /// ``` /// /// Note that the leap second can happen anytime given an appropriate time zone; @@ -159,8 +160,9 @@ mod tests; /// ``` /// use chrono::{Utc, TimeZone, NaiveDate}; /// -/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap().and_local_timezone(Utc).unwrap(); +/// 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::Error>(()) /// ``` /// /// There are hypothetical leap seconds not on the minute boundary @@ -173,12 +175,12 @@ mod tests; /// ``` /// use chrono::{DateTime, Utc, TimeZone, NaiveDate}; /// -/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 56, 4, 1_000).unwrap().and_local_timezone(Utc).unwrap(); +/// 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.with_ymd_and_hms(2015, 6, 30, 23, 56, 5).unwrap(); +/// 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); +/// assert_eq!(DateTime::::parse_from_rfc3339("2015-06-30T23:56:05Z")?, dt); /// ``` /// /// Since Chrono alone cannot determine any existence of leap seconds, @@ -202,53 +204,44 @@ impl arbitrary::Arbitrary<'_> for NaiveTime { } impl NaiveTime { - /// 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. - /// - /// Panics on invalid hour, minute and/or second. - #[deprecated(since = "0.4.23", note = "use `from_hms_opt()` instead")] - #[inline] - pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime { - NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time") - } + /// 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_*_opt` 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. /// - /// Returns `None` on invalid hour, minute and/or second. + /// Returns `Err(Error)` on invalid hour, minute and/or second. /// /// # Example /// /// ``` - /// use chrono::NaiveTime; + /// use chrono::{NaiveTime, Timelike}; /// - /// let from_hms_opt = NaiveTime::from_hms_opt; + /// 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); /// - /// 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()); + /// let from_hms = NaiveTime::from_hms; + /// + /// 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::Error>(()) /// ``` #[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` from hour, minute, second and millisecond. - /// - /// 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. - #[deprecated(since = "0.4.23", note = "use `from_hms_milli_opt()` instead")] - #[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` 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. @@ -256,150 +249,146 @@ impl NaiveTime { /// 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. + /// Returns `Err(Error)` on invalid hour, minute, second and/or millisecond. /// /// # Example /// /// ``` - /// use chrono::NaiveTime; - /// - /// let from_hmsm_opt = NaiveTime::from_hms_milli_opt; + /// use chrono::{NaiveTime, Timelike}; /// - /// 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()); + /// 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); + /// + /// let from_hms_milli = NaiveTime::from_hms_milli; + /// + /// 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::Error>(()) /// ``` #[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(Error::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). - /// - /// Panics on invalid hour, minute, second and/or microsecond. - #[deprecated(since = "0.4.23", note = "use `from_hms_micro_opt()` instead")] - #[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). + /// 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. + /// Returns `Err(Error)` on invalid hour, minute, second and/or + /// microsecond. /// /// # Example /// /// ``` - /// use chrono::NaiveTime; - /// - /// let from_hmsu_opt = NaiveTime::from_hms_micro_opt; + /// use chrono::{NaiveTime, Timelike}; /// - /// 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()); + /// 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); + /// + /// let from_hms_micro = NaiveTime::from_hms_micro; + /// + /// 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::Error>(()) /// ``` #[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(Error::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. - #[deprecated(since = "0.4.23", note = "use `from_hms_nano_opt()` instead")] - #[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). - /// - /// Returns `None` on invalid hour, minute, second and/or nanosecond. + /// Returns `Err(Error)` on invalid hour, minute, second and/or + /// nanosecond. /// /// # Example /// /// ``` - /// use chrono::NaiveTime; - /// - /// let from_hmsn_opt = NaiveTime::from_hms_nano_opt; + /// use chrono::{NaiveTime, Timelike}; /// - /// 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()); + /// 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); + /// + /// let from_hms_nano = NaiveTime::from_hms_nano; + /// + /// 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::Error>(()) /// ``` #[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(Error::InvalidTime); } let secs = hour * 3600 + min * 60 + sec; - Some(NaiveTime { secs, frac: nano }) - } - - /// 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). - /// - /// Panics on invalid number of seconds and/or nanosecond. - #[deprecated(since = "0.4.23", note = "use `from_num_seconds_from_midnight_opt()` instead")] - #[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") + 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). /// - /// Returns `None` on invalid number of seconds and/or nanosecond. + /// Returns `Err(Error)` on invalid number of seconds and/or + /// nanosecond. /// /// # Example /// /// ``` - /// use chrono::NaiveTime; + /// use chrono::{NaiveTime, Timelike}; + /// + /// 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); /// - /// let from_nsecs_opt = NaiveTime::from_num_seconds_from_midnight_opt; + /// let from_num_seconds_from_midnight = NaiveTime::from_num_seconds_from_midnight; /// - /// 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::Error>(()) /// ``` #[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(Error::InvalidTime); } - Some(NaiveTime { secs, frac: nano }) + Ok(NaiveTime { secs, frac: nano }) } /// Parses a string with the specified format string and returns a new `NaiveTime`. @@ -413,10 +402,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_opt(23, 56, 4).unwrap())); - /// assert_eq!(parse_from_str("pm012345.6789", "%p%I%M%S%.f"), - /// Ok(NaiveTime::from_hms_micro_opt(13, 23, 45, 678_900).unwrap())); + /// 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. @@ -424,8 +414,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_opt(12, 34, 56).unwrap())); + /// 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 @@ -435,8 +426,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_opt(8, 59, 59, 1_123).unwrap())); + /// 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, @@ -445,13 +437,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_opt(7, 15, 0).unwrap())); + /// 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. @@ -463,7 +456,7 @@ impl NaiveTime { /// # let parse_from_str = NaiveTime::parse_from_str; /// assert!(parse_from_str("13:07 AM", "%H:%M %p").is_err()); /// ``` - pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { + pub fn parse_from_str(s: &str, fmt: &str) -> Result { let mut parsed = Parsed::new(); parse(&mut parsed, s, StrftimeItems::new(fmt))?; parsed.to_naive_time() @@ -481,12 +474,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::Error>(()) /// ``` pub fn overflowing_add_signed(&self, mut rhs: TimeDelta) -> (NaiveTime, i64) { let mut secs = self.secs; @@ -563,12 +557,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::Error>(()) /// ``` #[inline] pub fn overflowing_sub_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) { @@ -594,22 +589,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::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that @@ -619,16 +615,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::Error>(()) /// ``` pub fn signed_duration_since(self, rhs: NaiveTime) -> TimeDelta { // | | :leap| | | | | | | :leap| | @@ -675,9 +672,10 @@ impl NaiveTime { /// use chrono::format::strftime::StrftimeItems; /// /// let fmt = StrftimeItems::new("%H:%M:%S"); - /// let t = NaiveTime::from_hms_opt(23, 56, 4).unwrap(); + /// 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::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -686,8 +684,9 @@ impl NaiveTime { /// # use chrono::NaiveTime; /// # use chrono::format::strftime::StrftimeItems; /// # let fmt = StrftimeItems::new("%H:%M:%S").clone(); - /// # let t = NaiveTime::from_hms_opt(23, 56, 4).unwrap(); + /// # let t = NaiveTime::from_hms(23, 56, 4)?; /// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04"); + /// # Ok::<_, chrono::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -719,20 +718,22 @@ impl NaiveTime { /// ``` /// use chrono::NaiveTime; /// - /// let t = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); + /// 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::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. /// /// ``` /// # use chrono::NaiveTime; - /// # let t = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); + /// # 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::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -761,8 +762,9 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms_opt(0, 0, 0).unwrap().hour(), 0); - /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().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::Error>(()) /// ``` #[inline] fn hour(&self) -> u32 { @@ -776,8 +778,9 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms_opt(0, 0, 0).unwrap().minute(), 0); - /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().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::Error>(()) /// ``` #[inline] fn minute(&self) -> u32 { @@ -791,8 +794,9 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms_opt(0, 0, 0).unwrap().second(), 0); - /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().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::Error>(()) /// ``` /// /// This method never returns 60 even when it is a leap second. @@ -801,9 +805,10 @@ impl Timelike for NaiveTime { /// /// ``` /// # use chrono::{NaiveTime, Timelike}; - /// let leap = NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap(); + /// 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::Error>(()) /// ``` #[inline] fn second(&self) -> u32 { @@ -819,8 +824,9 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms_opt(0, 0, 0).unwrap().nanosecond(), 0); - /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().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::Error>(()) /// ``` /// /// Leap seconds may have seemingly out-of-range return values. @@ -829,9 +835,10 @@ impl Timelike for NaiveTime { /// /// ``` /// # use chrono::{NaiveTime, Timelike}; - /// let leap = NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap(); + /// 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::Error>(()) /// ``` #[inline] fn nanosecond(&self) -> u32 { @@ -840,106 +847,110 @@ impl Timelike for NaiveTime { /// Makes a new `NaiveTime` with the hour number changed. /// - /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// Returns `Err(Error)` when the resulting `NaiveTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); - /// assert_eq!(dt.with_hour(7), Some(NaiveTime::from_hms_nano_opt(7, 56, 4, 12_345_678).unwrap())); - /// 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::Error>(()) /// ``` #[inline] - fn with_hour(&self, hour: u32) -> Option { + fn with_hour(&self, hour: u32) -> Result { if hour >= 24 { - return None; + return Err(Error::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. /// - /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// Returns `Err(Error)` when the resulting `NaiveTime` would be invalid. /// /// # Example /// /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); - /// assert_eq!(dt.with_minute(45), Some(NaiveTime::from_hms_nano_opt(23, 45, 4, 12_345_678).unwrap())); - /// 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::Error>(()) /// ``` #[inline] - fn with_minute(&self, min: u32) -> Option { + fn with_minute(&self, min: u32) -> Result { if min >= 60 { - return None; + return Err(Error::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. /// - /// Returns `None` when the resulting `NaiveTime` would be invalid. - /// As with the [`second`](#method.second) method, - /// the input range is restricted to 0 through 59. + /// Returns `Err(Error)` when the resulting `NaiveTime` would be + /// invalid. As with the [`second`](#method.second) method, the input range + /// is restricted to 0 through 59. /// /// # Example /// /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); - /// assert_eq!(dt.with_second(17), Some(NaiveTime::from_hms_nano_opt(23, 56, 17, 12_345_678).unwrap())); - /// 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::Error>(()) /// ``` #[inline] - fn with_second(&self, sec: u32) -> Option { + fn with_second(&self, sec: u32) -> Result { if sec >= 60 { - return None; + return Err(Error::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. + /// Makes a new `NaiveTime` with nanoseconds since the whole non-leap second + /// changed. /// - /// Returns `None` when the resulting `NaiveTime` would be invalid. - /// As with the [`nanosecond`](#method.nanosecond) method, - /// the input range can exceed 1,000,000,000 for leap seconds. + /// Returns `Err(Error)` when the resulting `NaiveTime` would be + /// invalid. As with the [`nanosecond`](#method.nanosecond) method, the + /// input range can exceed 1,000,000,000 for leap seconds. /// /// # Example /// /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); - /// assert_eq!(dt.with_nanosecond(333_333_333), - /// Some(NaiveTime::from_hms_nano_opt(23, 56, 4, 333_333_333).unwrap())); - /// 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::Error>(()) /// ``` /// - /// Leap seconds can theoretically follow *any* whole second. - /// The following would be a proper leap second at the time zone offset of UTC-00:03:57 - /// (there are several historical examples comparable to this "non-sense" offset), - /// and therefore is allowed. + /// Leap seconds can theoretically follow *any* whole second. The following + /// would be a proper leap second at the time zone offset of UTC-00:03:57 + /// (there are several historical examples comparable to this "non-sense" + /// offset), and therefore is allowed. /// /// ``` /// # use chrono::{NaiveTime, Timelike}; - /// # let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); - /// assert_eq!(dt.with_nanosecond(1_333_333_333), - /// Some(NaiveTime::from_hms_nano_opt(23, 56, 4, 1_333_333_333).unwrap())); + /// # 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::Error>(()) /// ``` #[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(Error::InvalidTime); } - Some(NaiveTime { frac: nano, ..*self }) + Ok(NaiveTime { frac: nano, ..*self }) } /// Returns the number of non-leap seconds past the last midnight. @@ -949,12 +960,13 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms_opt(1, 2, 3).unwrap().num_seconds_from_midnight(), + /// assert_eq!(NaiveTime::from_hms(1, 2, 3)?.num_seconds_from_midnight(), /// 3723); - /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().num_seconds_from_midnight(), + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?.unwrap().num_seconds_from_midnight(), /// 86164); - /// assert_eq!(NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap().num_seconds_from_midnight(), + /// assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000)?.num_seconds_from_midnight(), /// 86399); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] fn num_seconds_from_midnight(&self) -> u32 { @@ -977,14 +989,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::Error>(()) /// ``` /// /// The addition wraps around. @@ -992,9 +1005,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::Error>(()) /// ``` /// /// Leap seconds are handled, but the addition assumes that it is the only leap second happened. @@ -1002,14 +1016,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::Error>(()) /// ``` impl Add for NaiveTime { type Output = NaiveTime; @@ -1043,12 +1058,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::Error>(()) /// ``` /// /// The subtraction wraps around. @@ -1056,8 +1072,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::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that it is the only leap second happened. @@ -1065,12 +1082,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::Error>(()) /// ``` impl Sub for NaiveTime { type Output = NaiveTime; @@ -1108,15 +1127,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::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that @@ -1125,13 +1145,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::Error>(()) /// ``` impl Sub for NaiveTime { type Output = TimeDelta; @@ -1158,17 +1179,19 @@ impl Sub for NaiveTime { /// ``` /// use chrono::NaiveTime; /// -/// assert_eq!(format!("{:?}", NaiveTime::from_hms_opt(23, 56, 4).unwrap()), "23:56:04"); -/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli_opt(23, 56, 4, 12).unwrap()), "23:56:04.012"); -/// assert_eq!(format!("{:?}", NaiveTime::from_hms_micro_opt(23, 56, 4, 1234).unwrap()), "23:56:04.001234"); -/// assert_eq!(format!("{:?}", NaiveTime::from_hms_nano_opt(23, 56, 4, 123456).unwrap()), "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::Error>(()) /// ``` /// /// Leap seconds may also be used. /// /// ``` /// # use chrono::NaiveTime; -/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli_opt(6, 59, 59, 1_500).unwrap()), "06:59:60.500"); +/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)?), "06:59:60.500"); +/// # Ok::<_, chrono::Error>(()) /// ``` impl fmt::Debug for NaiveTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1214,17 +1237,19 @@ impl fmt::Debug for NaiveTime { /// ``` /// use chrono::NaiveTime; /// -/// assert_eq!(format!("{}", NaiveTime::from_hms_opt(23, 56, 4).unwrap()), "23:56:04"); -/// assert_eq!(format!("{}", NaiveTime::from_hms_milli_opt(23, 56, 4, 12).unwrap()), "23:56:04.012"); -/// assert_eq!(format!("{}", NaiveTime::from_hms_micro_opt(23, 56, 4, 1234).unwrap()), "23:56:04.001234"); -/// assert_eq!(format!("{}", NaiveTime::from_hms_nano_opt(23, 56, 4, 123456).unwrap()), "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::Error>(()) /// ``` /// /// Leap seconds may also be used. /// /// ``` /// # use chrono::NaiveTime; -/// assert_eq!(format!("{}", NaiveTime::from_hms_milli_opt(6, 59, 59, 1_500).unwrap()), "06:59:60.500"); +/// assert_eq!(format!("{}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)?), "06:59:60.500"); +/// # Ok::<_, chrono::Error>(()) /// ``` impl fmt::Display for NaiveTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1240,21 +1265,22 @@ impl fmt::Display for NaiveTime { /// ``` /// use chrono::NaiveTime; /// -/// let t = NaiveTime::from_hms_opt(23, 56, 4).unwrap(); +/// let t = NaiveTime::from_hms(23, 56, 4)?; /// assert_eq!("23:56:04".parse::(), Ok(t)); /// -/// let t = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); +/// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).unwrap()?; /// assert_eq!("23:56:4.012345678".parse::(), Ok(t)); /// -/// let t = NaiveTime::from_hms_nano_opt(23, 59, 59, 1_234_567_890).unwrap(); // 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::Error>(()) /// ``` impl str::FromStr for NaiveTime { - type Err = ParseError; + type Err = Error; - fn from_str(s: &str) -> ParseResult { + fn from_str(s: &str) -> Result { const ITEMS: &[Item<'static>] = &[ Item::Numeric(Numeric::Hour, Pad::Zero), Item::Literal(":"), @@ -1278,11 +1304,12 @@ impl str::FromStr for NaiveTime { /// use chrono::NaiveTime; /// /// let default_time = NaiveTime::default(); -/// assert_eq!(default_time, NaiveTime::from_hms_opt(0, 0, 0).unwrap()); +/// assert_eq!(default_time, NaiveTime::from_hms(0, 0, 0)?); +/// # Ok::<_, chrono::Error>(()) /// ``` impl Default for NaiveTime { fn default() -> Self { - NaiveTime::from_hms_opt(0, 0, 0).unwrap() + NaiveTime::midnight() } } @@ -1293,35 +1320,35 @@ where E: ::std::fmt::Debug, { assert_eq!( - to_string(&NaiveTime::from_hms_opt(0, 0, 0).unwrap()).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_opt(0, 0, 0, 950).unwrap()).ok(), + 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_opt(0, 0, 59, 1_000).unwrap()).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_opt(0, 1, 2).unwrap()).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_opt(3, 5, 7, 98765432).unwrap()).ok(), + 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_opt(7, 8, 9).unwrap()).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_opt(12, 34, 56, 789).unwrap()).ok(), + 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_opt(23, 59, 59, 1_999_999_999).unwrap()).ok(), + to_string(&NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999).unwrap()).ok(), Some(r#""23:59:60.999999999""#.into()) ); } @@ -1332,37 +1359,37 @@ where F: Fn(&str) -> Result, E: ::std::fmt::Debug, { - assert_eq!(from_str(r#""00:00:00""#).ok(), Some(NaiveTime::from_hms_opt(0, 0, 0).unwrap())); - assert_eq!(from_str(r#""0:0:0""#).ok(), Some(NaiveTime::from_hms_opt(0, 0, 0).unwrap())); + 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""#).ok(), - Some(NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()) + 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""#).ok(), - Some(NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()) + 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""#).ok(), - Some(NaiveTime::from_hms_milli_opt(0, 0, 59, 1_000).unwrap()) + 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""#).ok(), Some(NaiveTime::from_hms_opt(0, 1, 2).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_opt(3, 5, 7, 98765432).unwrap()) + 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_opt(7, 8, 9).unwrap())); + 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_opt(12, 34, 56, 789).unwrap()) + from_str(r#""12:34:56.000789""#).unwrap(), + NaiveTime::from_hms_micro_opt(12, 34, 56, 789).unwrap().unwrap() ); assert_eq!( - from_str(r#""23:59:60.999999999""#).ok(), - Some(NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) + from_str(r#""23:59:60.999999999""#).unwrap(), + NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999).unwrap().unwrap() ); assert_eq!( - from_str(r#""23:59:60.9999999999997""#).ok(), // excess digits are ignored - Some(NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) + 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 c7394fb575..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_opt(3, 5, 7, 98765432).unwrap(); + 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 4aba43434b..55bebb4eb9 100644 --- a/src/naive/time/tests.rs +++ b/src/naive/time/tests.rs @@ -6,82 +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_opt(3, 5, 7, 0).unwrap()) + 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_opt(3, 5, 7, 777_000_000).unwrap()) + 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_opt(3, 5, 7, 1_999_000_000).unwrap()) + 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_opt(3, 5, 7, 0).unwrap()) + 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_opt(3, 5, 7, 333_000).unwrap()) + 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_opt(3, 5, 7, 777_777_000).unwrap()) + 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_opt(3, 5, 7, 1_999_999_000).unwrap()) + 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_opt(3, 5, 7).unwrap().hour(), 3); + assert_eq!(NaiveTime::from_hms(3, 5, 7).unwrap().hour(), 3); assert_eq!( - NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(0), - Some(NaiveTime::from_hms_opt(0, 5, 7).unwrap()) + NaiveTime::from_hms(3, 5, 7).unwrap().with_hour(0).unwrap(), + NaiveTime::from_hms(0, 5, 7).unwrap() ); assert_eq!( - NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(23), - Some(NaiveTime::from_hms_opt(23, 5, 7).unwrap()) + NaiveTime::from_hms(3, 5, 7).unwrap().with_hour(23).unwrap(), + NaiveTime::from_hms(23, 5, 7).unwrap() ); - assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(24), None); - assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(u32::MAX), None); + 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_opt(3, 5, 7).unwrap().minute(), 5); + assert_eq!(NaiveTime::from_hms(3, 5, 7).unwrap().minute(), 5); assert_eq!( - NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(0), - Some(NaiveTime::from_hms_opt(3, 0, 7).unwrap()) + NaiveTime::from_hms(3, 5, 7).unwrap().with_minute(0).unwrap(), + NaiveTime::from_hms(3, 0, 7).unwrap() ); assert_eq!( - NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(59), - Some(NaiveTime::from_hms_opt(3, 59, 7).unwrap()) + NaiveTime::from_hms(3, 5, 7).unwrap().with_minute(59).unwrap(), + NaiveTime::from_hms(3, 59, 7).unwrap() ); - assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(60), None); - assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(u32::MAX), None); + 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_opt(3, 5, 7).unwrap().second(), 7); + assert_eq!(NaiveTime::from_hms(3, 5, 7).unwrap().second(), 7); assert_eq!( - NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(0), - Some(NaiveTime::from_hms_opt(3, 5, 0).unwrap()) + NaiveTime::from_hms(3, 5, 7).unwrap().with_second(0).unwrap(), + NaiveTime::from_hms(3, 5, 0).unwrap() ); assert_eq!( - NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(59), - Some(NaiveTime::from_hms_opt(3, 5, 59).unwrap()) + NaiveTime::from_hms(3, 5, 7).unwrap().with_second(59).unwrap(), + NaiveTime::from_hms(3, 5, 59).unwrap() ); - assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(60), None); - assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(u32::MAX), None); + 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] @@ -93,16 +93,40 @@ fn test_time_add() { }}; } - let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap(); + let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli(h, m, s, ms).unwrap(); 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, 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)); @@ -111,12 +135,16 @@ fn test_time_add() { // 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), + TimeDelta::milliseconds(-9990), + hmsm(23, 59, 50, 10) + ); } #[test] fn test_time_overflowing_add() { - let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap(); + let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli(h, m, s, ms).unwrap(); assert_eq!( hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(11)), @@ -144,7 +172,7 @@ fn test_time_overflowing_add() { #[test] fn test_time_addassignment() { - let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap(); + let hms = |h, m, s| NaiveTime::from_hms(h, m, s).unwrap(); let mut time = hms(12, 12, 12); time += TimeDelta::hours(10); assert_eq!(time, hms(22, 12, 12)); @@ -154,7 +182,7 @@ fn test_time_addassignment() { #[test] fn test_time_subassignment() { - let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap(); + let hms = |h, m, s| NaiveTime::from_hms(h, m, s).unwrap(); let mut time = hms(12, 12, 12); time -= TimeDelta::hours(10); assert_eq!(time, hms(2, 12, 12)); @@ -172,11 +200,15 @@ fn test_time_sub() { }}; } - let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap(); + let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli(h, m, s, ms).unwrap(); check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), TimeDelta::zero()); check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), TimeDelta::milliseconds(300)); - check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), TimeDelta::seconds(3600 + 60 + 1)); + check!( + hmsm(3, 5, 7, 200), + hmsm(2, 4, 6, 200), + TimeDelta::seconds(3600 + 60 + 1) + ); check!( hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 300), @@ -185,44 +217,53 @@ fn test_time_sub() { // 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), + hmsm(3, 5, 6, 1_800), + TimeDelta::milliseconds(400) + ); + check!( + hmsm(3, 5, 7, 1_200), + hmsm(3, 5, 6, 1_800), + TimeDelta::milliseconds(1400) + ); + check!( + hmsm(3, 5, 7, 1_200), + hmsm(3, 5, 6, 800), + TimeDelta::milliseconds(1400) + ); // additional equality: `time1 + duration = time2` is equivalent to // `time2 - time1 = duration` IF AND ONLY IF `time2` represents a non-leap second. - assert_eq!(hmsm(3, 5, 6, 800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200)); - assert_eq!(hmsm(3, 5, 6, 1_800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200)); -} - -#[test] -fn test_time_fmt() { assert_eq!( - format!("{}", NaiveTime::from_hms_milli_opt(23, 59, 59, 999).unwrap()), - "23:59:59.999" + hmsm(3, 5, 6, 800) + TimeDelta::milliseconds(400), + hmsm(3, 5, 7, 200) ); assert_eq!( - format!("{}", NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap()), - "23:59:60" + hmsm(3, 5, 6, 1_800) + TimeDelta::milliseconds(400), + hmsm(3, 5, 7, 200) ); +} + +#[test] +fn test_time_fmt() { + 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_opt(23, 59, 59, 1_001).unwrap()), + format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_001).unwrap()), "23:59:60.001" ); assert_eq!( - format!("{}", NaiveTime::from_hms_micro_opt(0, 0, 0, 43210).unwrap()), + format!("{}", NaiveTime::from_hms_micro(0, 0, 0, 43210).unwrap()), "00:00:00.043210" ); assert_eq!( - format!("{}", NaiveTime::from_hms_nano_opt(0, 0, 0, 6543210).unwrap()), + 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_opt(3, 5, 7, 9).unwrap()), - "03:05:07.009" - ); + assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9).unwrap()), "03:05:07.009"); } #[test] @@ -327,27 +368,18 @@ fn test_date_from_str() { #[test] fn test_time_parse_from_str() { - let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap(); + let hms = |h, m, s| NaiveTime::from_hms(h, m, s); 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("12:59 \n\t PM", "%H:%M \n\t %P"), Ok(hms(12, 59, 0))); - assert_eq!(NaiveTime::parse_from_str("\t\t12:59\tPM\t", "\t\t%H:%M\t%P\t"), Ok(hms(12, 59, 0))); - assert_eq!( - NaiveTime::parse_from_str("\t\t1259\t\tPM\t", "\t\t%H%M\t\t%P\t"), - Ok(hms(12, 59, 0)) - ); - assert!(NaiveTime::parse_from_str("12:59 PM", "%H:%M\t%P").is_err()); - assert!(NaiveTime::parse_from_str("\t\t12:59 PM\t", "\t\t%H:%M\t%P\t").is_err()); - assert!(NaiveTime::parse_from_str("12:59 PM", "%H:%M %P").is_err()); + 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_opt(3, 5, 7, 98765432).unwrap(); + 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"); @@ -357,22 +389,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_opt(3, 5, 7, 432100).unwrap(); + 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_opt(3, 5, 7, 210).unwrap(); + 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_opt(3, 5, 7).unwrap(); + 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_opt(13, 57, 9).unwrap().format("%r").to_string(), "01:57:09 PM"); + assert_eq!(NaiveTime::from_hms(13, 57, 9).unwrap().format("%r").to_string(), "01:57:09 PM"); assert_eq!( - NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap().format("%X").to_string(), + 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 f38fad3202..e9792f77b8 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -10,11 +10,10 @@ use num_integer::div_mod_floor; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; -use super::{LocalResult, Offset, TimeZone}; +use super::{DateTime, Error, FixedTimeZone, Offset, TimeZone}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; 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,65 +28,49 @@ pub struct FixedOffset { } impl FixedOffset { - /// 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`. - #[deprecated(since = "0.4.23", note = "use `east_opt()` instead")] - pub fn east(secs: i32) -> FixedOffset { - FixedOffset::east_opt(secs).expect("FixedOffset::east out of bounds") - } + /// 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. + /// 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`. + /// Returns `Err(Error)` on the out-of-bound `secs`. /// /// # Example /// /// ``` /// use chrono::{FixedOffset, TimeZone}; /// let hour = 3600; - /// let datetime = FixedOffset::east_opt(5 * hour).unwrap().ymd_opt(2016, 11, 08).unwrap() - /// .and_hms_opt(0, 0, 0).unwrap(); - /// 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::Error>(()) /// ``` - 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(Error::InvalidTimeZone) } } /// 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`. - #[deprecated(since = "0.4.23", note = "use `west_opt()` instead")] - 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`. + /// Returns `Err(Error)` on the out-of-bound `secs`. /// /// # Example /// /// ``` /// use chrono::{FixedOffset, TimeZone}; /// let hour = 3600; - /// let datetime = FixedOffset::west_opt(5 * hour).unwrap().ymd_opt(2016, 11, 08).unwrap() - /// .and_hms_opt(0, 0, 0).unwrap(); - /// 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::Error>(()) /// ``` - 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(Error::InvalidTimeZone) } } @@ -107,21 +90,35 @@ 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, Error> { + Ok(LocalResult::Single(*self)) + } + + fn offset_from_local_datetime( + &self, + _: &NaiveDateTime, + ) -> Result, Error> { + Ok(LocalResult::Single(*self)) } - fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult { - 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 } } @@ -241,44 +238,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_opt(86399) - .unwrap() - .with_ymd_and_hms(2012, 2, 29, 5, 6, 7) - .unwrap() - ), - "2012-02-29T05:06:07+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_opt(86399) + FixedOffset::east(86399) + .unwrap() + .ymd(2012, 2, 29) .unwrap() - .with_ymd_and_hms(2012, 2, 29, 5, 6, 7) + .and_hms(5, 6, 7) .unwrap() ), - "2012-02-29T05:06:07+23:59:59".to_string() + "2012-02-29T05:06:07+23:59:59" ); assert_eq!( - format!( - "{:?}", - FixedOffset::west_opt(86399) - .unwrap() - .with_ymd_and_hms(2012, 3, 4, 5, 6, 7) - .unwrap() - ), - "2012-03-04T05:06:07-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_opt(86399) + FixedOffset::west(86399) + .unwrap() + .ymd(2012, 3, 4) .unwrap() - .with_ymd_and_hms(2012, 3, 4, 5, 6, 7) + .and_hms(5, 6, 7) .unwrap() ), - "2012-03-04T05:06:07-23:59:59".to_string() + "2012-03-04T05:06:07-23:59:59" ); } } diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 8a8721744a..0807a05173 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -7,10 +7,9 @@ use rkyv::{Archive, Deserialize, Serialize}; use super::fixed::FixedOffset; -use super::{LocalResult, TimeZone}; use crate::naive::{NaiveDate, NaiveDateTime}; -#[allow(deprecated)] -use crate::{Date, DateTime}; +use crate::offset::LocalResult; +use crate::{Date, DateTime, Error, 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 @@ -48,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::Error>(()) /// ``` #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -58,10 +58,8 @@ pub struct Local; impl Local { /// Returns a `Date` which corresponds to the current date. - #[deprecated(since = "0.4.23", note = "use `Local::now()` instead")] - #[allow(deprecated)] - pub fn today() -> Date { - Local::now().date() + pub fn today() -> Result, Error> { + Ok(Local::now()?.date()) } /// Returns a `DateTime` which corresponds to the current date and time. @@ -70,7 +68,7 @@ impl Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - pub fn now() -> DateTime { + pub fn now() -> Result, Error> { inner::now() } @@ -80,15 +78,13 @@ impl Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] - pub fn now() -> DateTime { + pub fn now() -> Result, Error> { use super::Utc; - let now: DateTime = super::Utc::now(); + let now: DateTime = super::Utc::now()?; // Workaround missing timezone logic in `time` crate - let offset = - FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) - .unwrap(); - DateTime::from_utc(now.naive_utc(), offset) + let offset = FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60)?; + Ok(DateTime::from_utc(now.naive_utc(), offset)) } } @@ -100,32 +96,35 @@ impl TimeZone for Local { } // they are easier to define in terms of the finished date and time unlike other offsets - #[allow(deprecated)] - 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, Error> { + 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, Error> { + Ok(self.from_local_datetime(local)?.map(|o| *o.offset())) } - #[allow(deprecated)] - 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 - #[allow(deprecated)] - fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { + fn from_local_date(&self, local: &NaiveDate) -> Result>, Error> { // 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_opt(0, 0, 0).unwrap()); - 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( @@ -133,14 +132,15 @@ 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>, Error> { let mut local = local.clone(); // Get the offset from the js runtime - let offset = - FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) - .unwrap(); + 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(LocalResult::Single(DateTime::from_utc(local, offset))) } #[cfg(not(all( @@ -148,14 +148,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>, Error> { inner::naive_to_local(local, true) } - #[allow(deprecated)] - fn from_utc_date(&self, utc: &NaiveDate) -> Date { - let midnight = self.from_utc_datetime(&utc.and_hms_opt(0, 0, 0).unwrap()); - Date::from_utc(*utc, *midnight.offset()) + fn from_utc_date(&self, utc: &NaiveDate) -> Result, Error> { + let midnight = self.from_utc_datetime(&utc.and_midnight())?; + Ok(Date::from_utc(*utc, *midnight.offset())) } #[cfg(all( @@ -163,12 +165,10 @@ 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, Error> { // Get the offset from the js runtime - let offset = - FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) - .unwrap(); - DateTime::from_utc(*utc, offset) + let offset = FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60)?; + Ok(DateTime::from_utc(*utc, offset)) } #[cfg(not(all( @@ -176,10 +176,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, Error> { + inner::naive_to_local(utc, false)?.single() } } @@ -187,13 +185,88 @@ impl TimeZone for Local { mod tests { use super::Local; use crate::offset::TimeZone; - use crate::{Datelike, TimeDelta, Utc}; + use crate::{Datelike, TimeDelta}; + #[cfg(unix)] + use crate::{NaiveDate, NaiveDateTime, Timelike}; + + #[cfg(unix)] + use std::{path, process}; + + #[cfg(unix)] + fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) { + let output = process::Command::new(path) + .arg("-d") + .arg(format!("{}-{:02}-{:02} {:02}:05:01", dt.year(), dt.month(), dt.day(), dt.hour())) + .arg("+%Y-%m-%d %H:%M:%S %:z") + .output() + .unwrap(); + + let date_command_str = String::from_utf8(output.stdout).unwrap(); + + // The below would be preferred. At this stage neither earliest() or latest() + // seems to be consistent with the output of the `date` command, so we simply + // compare both. + // let local = Local + // .from_local_datetime(&NaiveDate::from_ymd(year, month, day).and_hms(hour, 5, 1)) + // // looks like the "date" command always returns a given time when it is ambiguous + // .earliest(); + + // if let Some(local) = local { + // assert_eq!(format!("{}\n", local), date_command_str); + // } else { + // // we are in a "Spring forward gap" due to DST, and so date also returns "" + // assert_eq!("", date_command_str); + // } + + // 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 + 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] + #[cfg(unix)] + fn try_verify_against_date_command() { + let date_path = "/usr/bin/date"; + + if !path::Path::new(date_path).exists() { + // date command not found, skipping + // avoid running this on macOS, which has path /bin/date + // as the required CLI arguments are not present in the + // macOS build. + return; + } + + 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()) + || (2020..=2022).contains(&date.year()) + || (2073..=2077).contains(&date.year()) + { + verify_against_date_command_local(date_path, date); + } + + date += crate::TimeDelta::hours(1); + } + } #[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()); @@ -205,9 +278,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()); @@ -218,9 +291,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(), @@ -235,21 +308,21 @@ mod tests { #[test] fn test_local_date_sanity_check() { // issue #27 - assert_eq!(Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0).unwrap().day(), 28); + assert_eq!(Local.ymd(2999, 12, 28).unwrap().unwrap().day(), 28); } #[test] fn test_leap_second() { // issue #123 - let today = Utc::now().date_naive(); + let today = Local::today().unwrap(); - let dt = today.and_hms_milli_opt(1, 2, 59, 1000).unwrap(); + 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_opt(1, 2, 3, 1234).unwrap(); + 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/stub.rs b/src/offset/local/stub.rs index 9ececd3c22..ca2d97ef53 100644 --- a/src/offset/local/stub.rs +++ b/src/offset/local/stub.rs @@ -11,9 +11,11 @@ use std::time::{SystemTime, UNIX_EPOCH}; use super::{FixedOffset, Local}; -use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; +use crate::{ + DateTime, Datelike, Error, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike, +}; -pub(super) fn now() -> DateTime { +pub(super) fn now() -> Result, Error> { tm_to_datetime(Timespec::now().local()) } @@ -23,7 +25,10 @@ pub(super) fn now() -> DateTime { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult> { +pub(super) fn naive_to_local( + d: &NaiveDateTime, + local: bool, +) -> Result>, Error> { let tm = Tm { tm_sec: d.second() as i32, tm_min: d.minute() as i32, @@ -53,7 +58,7 @@ pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult LocalResult DateTime { +fn tm_to_datetime(mut tm: Tm) -> Result, Error> { if tm.tm_sec >= 60 { tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000; tm.tm_sec = 59; } - let date = NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1); + let date = NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1)?; 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_opt(tm.tm_utcoff).unwrap(); - 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 diff --git a/src/offset/local/tz_info/mod.rs b/src/offset/local/tz_info/mod.rs index bd2693b6bb..96e098e6a9 100644 --- a/src/offset/local/tz_info/mod.rs +++ b/src/offset/local/tz_info/mod.rs @@ -1,104 +1,12 @@ -#![deny(missing_docs)] #![allow(dead_code)] #![warn(unreachable_pub)] -use std::num::ParseIntError; -use std::str::Utf8Error; -use std::time::SystemTimeError; -use std::{error, fmt, io}; - mod timezone; pub(crate) use timezone::TimeZone; mod parser; mod rule; -/// Unified error type for everything in the crate -#[derive(Debug)] -pub(crate) enum Error { - /// Date time error - DateTime(&'static str), - /// Local time type search error - FindLocalTimeType(&'static str), - /// Local time type error - LocalTimeType(&'static str), - /// Invalid slice for integer conversion - InvalidSlice(&'static str), - /// Invalid Tzif file - InvalidTzFile(&'static str), - /// Invalid TZ string - InvalidTzString(&'static str), - /// I/O error - Io(io::Error), - /// Out of range error - OutOfRange(&'static str), - /// Integer parsing error - ParseInt(ParseIntError), - /// Date time projection error - ProjectDateTime(&'static str), - /// System time error - SystemTime(SystemTimeError), - /// Time zone error - TimeZone(&'static str), - /// Transition rule error - TransitionRule(&'static str), - /// Unsupported Tzif file - UnsupportedTzFile(&'static str), - /// Unsupported TZ string - UnsupportedTzString(&'static str), - /// UTF-8 error - Utf8(Utf8Error), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use Error::*; - match self { - DateTime(error) => write!(f, "invalid date time: {}", error), - FindLocalTimeType(error) => error.fmt(f), - LocalTimeType(error) => write!(f, "invalid local time type: {}", error), - InvalidSlice(error) => error.fmt(f), - InvalidTzString(error) => write!(f, "invalid TZ string: {}", error), - InvalidTzFile(error) => error.fmt(f), - Io(error) => error.fmt(f), - OutOfRange(error) => error.fmt(f), - ParseInt(error) => error.fmt(f), - ProjectDateTime(error) => error.fmt(f), - SystemTime(error) => error.fmt(f), - TransitionRule(error) => write!(f, "invalid transition rule: {}", error), - TimeZone(error) => write!(f, "invalid time zone: {}", error), - UnsupportedTzFile(error) => error.fmt(f), - UnsupportedTzString(error) => write!(f, "unsupported TZ string: {}", error), - Utf8(error) => error.fmt(f), - } - } -} - -impl error::Error for Error {} - -impl From for Error { - fn from(error: io::Error) -> Self { - Error::Io(error) - } -} - -impl From for Error { - fn from(error: ParseIntError) -> Self { - Error::ParseInt(error) - } -} - -impl From for Error { - fn from(error: SystemTimeError) -> Self { - Error::SystemTime(error) - } -} - -impl From for Error { - fn from(error: Utf8Error) -> Self { - Error::Utf8(error) - } -} // MSRV: 1.38 #[inline] diff --git a/src/offset/local/tz_info/parser.rs b/src/offset/local/tz_info/parser.rs index 5652a0ea95..ccc0089b4f 100644 --- a/src/offset/local/tz_info/parser.rs +++ b/src/offset/local/tz_info/parser.rs @@ -1,11 +1,10 @@ -use std::io::{self, ErrorKind}; use std::iter; use std::num::ParseIntError; use std::str::{self, FromStr}; use super::rule::TransitionRule; use super::timezone::{LeapSecond, LocalTimeType, TimeZone, Transition}; -use super::Error; +use crate::Error; #[allow(clippy::map_clone)] // MSRV: 1.36 pub(super) fn parse(bytes: &[u8]) -> Result { @@ -249,28 +248,28 @@ impl<'a> Cursor<'a> { } /// Read exactly `count` bytes, reducing remaining data and incrementing read count - pub(crate) fn read_exact(&mut self, count: usize) -> Result<&'a [u8], io::Error> { + pub(crate) fn read_exact(&mut self, count: usize) -> Result<&'a [u8], Error> { match (self.remaining.get(..count), self.remaining.get(count..)) { (Some(result), Some(remaining)) => { self.remaining = remaining; self.read_count += count; Ok(result) } - _ => Err(io::Error::from(ErrorKind::UnexpectedEof)), + _ => Err(Error::UnexpectedEOF), } } /// Read bytes and compare them to the provided tag - pub(crate) fn read_tag(&mut self, tag: &[u8]) -> Result<(), io::Error> { + pub(crate) fn read_tag(&mut self, tag: &[u8]) -> Result<(), Error> { if self.read_exact(tag.len())? == tag { Ok(()) } else { - Err(io::Error::from(ErrorKind::InvalidData)) + Err(Error::InvalidData) } } /// Read bytes if the remaining data is prefixed by the provided tag - pub(crate) fn read_optional_tag(&mut self, tag: &[u8]) -> Result { + pub(crate) fn read_optional_tag(&mut self, tag: &[u8]) -> Result { if self.remaining.starts_with(tag) { self.read_exact(tag.len())?; Ok(true) @@ -280,7 +279,7 @@ impl<'a> Cursor<'a> { } /// Read bytes as long as the provided predicate is true - pub(crate) fn read_while bool>(&mut self, f: F) -> Result<&'a [u8], io::Error> { + pub(crate) fn read_while bool>(&mut self, f: F) -> Result<&'a [u8], Error> { match self.remaining.iter().position(|x| !f(x)) { None => self.read_exact(self.remaining.len()), Some(position) => self.read_exact(position), @@ -294,7 +293,7 @@ impl<'a> Cursor<'a> { } /// Read bytes until the provided predicate is true - pub(crate) fn read_until bool>(&mut self, f: F) -> Result<&'a [u8], io::Error> { + pub(crate) fn read_until bool>(&mut self, f: F) -> Result<&'a [u8], Error> { match self.remaining.iter().position(f) { None => self.read_exact(self.remaining.len()), Some(position) => self.read_exact(position), diff --git a/src/offset/local/tz_info/rule.rs b/src/offset/local/tz_info/rule.rs index 7befddb5cf..7635eb732f 100644 --- a/src/offset/local/tz_info/rule.rs +++ b/src/offset/local/tz_info/rule.rs @@ -3,9 +3,11 @@ use std::cmp::Ordering; use super::parser::Cursor; use super::timezone::{LocalTimeType, SECONDS_PER_WEEK}; use super::{ - rem_euclid, Error, CUMUL_DAY_IN_MONTHS_NORMAL_YEAR, DAYS_PER_WEEK, DAY_IN_MONTHS_NORMAL_YEAR, + rem_euclid, CUMUL_DAY_IN_MONTHS_NORMAL_YEAR, DAYS_PER_WEEK, DAY_IN_MONTHS_NORMAL_YEAR, SECONDS_PER_DAY, }; +use crate::offset::LocalResult; +use crate::Error; /// Transition rule #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -84,10 +86,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 +234,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 +255,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 +263,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 +308,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))) } } } @@ -775,9 +777,9 @@ pub(crate) fn is_leap_year(year: i32) -> bool { #[cfg(test)] mod tests { use super::super::timezone::Transition; - use super::super::{Error, TimeZone}; + use super::super::TimeZone; use super::{AlternateTime, LocalTimeType, RuleDay, TransitionRule}; - use crate::matches; + use crate::{Error, matches}; #[test] fn test_quoted() -> Result<(), Error> { diff --git a/src/offset/local/tz_info/timezone.rs b/src/offset/local/tz_info/timezone.rs index 8572825a89..55710ecc6a 100644 --- a/src/offset/local/tz_info/timezone.rs +++ b/src/offset/local/tz_info/timezone.rs @@ -6,7 +6,8 @@ use std::path::{Path, PathBuf}; use std::{cmp::Ordering, fmt, str}; use super::rule::{AlternateTime, TransitionRule}; -use super::{parser, Error, DAYS_PER_WEEK, SECONDS_PER_DAY}; +use super::{parser, DAYS_PER_WEEK, SECONDS_PER_DAY}; +use crate::offset::{Error, LocalResult}; /// Time zone #[derive(Debug, Clone, Eq, PartialEq)] @@ -122,7 +123,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) } @@ -204,7 +205,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) { @@ -233,26 +234,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()))); } } } @@ -260,11 +261,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))); } } } @@ -281,7 +282,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]))) } } @@ -630,9 +631,8 @@ const SECONDS_PER_28_DAYS: i64 = SECONDS_PER_DAY * 28; #[cfg(test)] mod tests { - use super::super::Error; use super::{LeapSecond, LocalTimeType, TimeZone, TimeZoneName, Transition, TransitionRule}; - use crate::matches; + use crate::{matches, Error}; #[test] fn test_no_dst() -> Result<(), Error> { diff --git a/src/offset/local/unix.rs b/src/offset/local/unix.rs index 22114f21ef..c1fcc6c866 100644 --- a/src/offset/local/unix.rs +++ b/src/offset/local/unix.rs @@ -7,19 +7,28 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(dead_code)] use std::{cell::RefCell, collections::hash_map, env, fs, hash::Hasher, time::SystemTime}; use super::tz_info::TimeZone; use super::{DateTime, FixedOffset, Local, NaiveDateTime}; -use crate::{Datelike, LocalResult, Utc}; +use crate::offset::LocalResult; +use crate::{Datelike, Error, Utc}; -pub(super) fn now() -> DateTime { - let now = Utc::now().naive_utc(); - naive_to_local(&now, false).unwrap() +pub(super) fn now() -> Result, Error> { + let now = Utc::now()?.naive_utc(); + + match naive_to_local(&now, false)? { + LocalResult::Single(dt) => Ok(dt), + _ => Err(Error::AmbiguousDate), + } } -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult> { +pub(super) fn naive_to_local( + d: &NaiveDateTime, + local: bool, +) -> Result>, Error> { TZ_INFO.with(|maybe_cache| { maybe_cache.borrow_mut().get_or_insert_with(Cache::default).offset(*d, local) }) @@ -102,61 +111,26 @@ fn current_zone(var: Option<&str>) -> TimeZone { } impl Cache { - fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult> { - let now = SystemTime::now(); - - match now.duration_since(self.last_checked) { - // If the cache has been around for less than a second then we reuse it - // unconditionally. This is a reasonable tradeoff because the timezone - // generally won't be changing _that_ often, but if the time zone does - // change, it will reflect sufficiently quickly from an application - // user's perspective. - Ok(d) if d.as_secs() < 1 => (), - Ok(_) | Err(_) => { - let env_tz = env::var("TZ").ok(); - let env_ref = env_tz.as_deref(); - let new_source = Source::new(env_ref); - - let out_of_date = match (&self.source, &new_source) { - // change from env to file or file to env, must recreate the zone - (Source::Environment { .. }, Source::LocalTime { .. }) - | (Source::LocalTime { .. }, Source::Environment { .. }) => true, - // stay as file, but mtime has changed - (Source::LocalTime { mtime: old_mtime }, Source::LocalTime { mtime }) - if old_mtime != mtime => - { - true - } - // stay as env, but hash of variable has changed - (Source::Environment { hash: old_hash }, Source::Environment { hash }) - if old_hash != hash => - { - true - } - // cache can be reused - _ => false, - }; - - if out_of_date { - self.zone = current_zone(env_ref); - } + fn offset( + &mut self, + d: NaiveDateTime, + local: bool, + ) -> Result>, Error> { - self.last_checked = now; - self.source = new_source; - } - } + // TODO Check why this was added + // if self.source.out_of_date() { + // *self = Cache::default(); + // } if !local { - let offset = self - .zone - .find_local_time_type(d.timestamp()) - .expect("unable to select local time type") - .offset(); - - return match FixedOffset::east_opt(offset) { - Some(offset) => LocalResult::Single(DateTime::from_utc(d, offset)), - None => LocalResult::None, - }; + let offset = FixedOffset::east( + self.zone + .find_local_time_type(d.timestamp()) + .expect("unable to select local time type") + .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 @@ -166,19 +140,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_opt(early.offset()).unwrap(); - let late_offset = FixedOffset::east_opt(late.offset()).unwrap(); + None => Err(Error::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_opt(tt.offset()).unwrap(); - 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 60ac56e32a..d238144f18 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -11,6 +11,7 @@ use std::io; use std::mem; use std::ptr; +use std::ptr; use std::time::{SystemTime, UNIX_EPOCH}; use windows_sys::Win32::Foundation::FILETIME; @@ -22,15 +23,19 @@ use windows_sys::Win32::System::Time::SystemTimeToTzSpecificLocalTime; use windows_sys::Win32::System::Time::TzSpecificLocalTimeToSystemTime; use super::{FixedOffset, Local}; -use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; +use crate::error::{Error, ErrorKind}; +use crate::offset::LocalResult; +use crate::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; -pub(super) fn now() -> DateTime { - let datetime = tm_to_datetime(Timespec::now().local()); - datetime.single().expect("invalid time") +pub(super) fn now() -> Result, Error> { + 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>, Error> { let tm = Tm { tm_sec: d.second() as i32, tm_min: d.minute() as i32, @@ -49,46 +54,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; - tm_to_datetime(tm) + // #TODO - there should be ambiguous cases, investigate? + Ok(LocalResult::Single(tm_to_datetime(tm)?)) } /// Converts a `time::Tm` struct into the timezone-aware `DateTime`. -fn tm_to_datetime(mut tm: Tm) -> LocalResult> { +fn tm_to_datetime(mut tm: Tm) -> Result, Error> { 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_opt(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32) - .unwrap(); - - let time = NaiveTime::from_hms_nano_opt( + 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, - ); - - match time { - Some(time) => { - let offset = FixedOffset::east_opt(tm.tm_utcoff).unwrap(); - let datetime = DateTime::from_utc(date.and_time(time) - offset, offset); - // #TODO - there should be ambiguous cases, investigate? - LocalResult::Single(datetime) - } - None => LocalResult::None, - } + )?; + + 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 @@ -103,14 +100,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(|_| ErrorKind::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, @@ -124,9 +122,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) } } @@ -242,13 +240,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(Error::new(ErrorKind::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<(), Error> { let ft = time_to_file_time(sec); unsafe { let mut utc = mem::zeroed(); @@ -267,25 +264,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 sys_time = tm_to_system_time(tm); - call!(TzSpecificLocalTimeToSystemTime(ptr::null(), &sys_time, &mut utc)); + call!(TzSpecificLocalTimeToSystemTime(ptr::null_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 09d0714e98..f6cdbace79 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -20,11 +20,9 @@ use core::fmt; -use crate::format::{parse, ParseResult, Parsed, StrftimeItems}; +use crate::format::{parse, Parsed, StrftimeItems}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; -use crate::Weekday; -#[allow(deprecated)] -use crate::{Date, DateTime}; +use crate::{Date, DateTime, Error, Weekday}; mod fixed; pub use self::fixed::FixedOffset; @@ -40,9 +38,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. @@ -51,38 +46,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(Error)` if the result is ambiguous. + /// + /// # Errors + /// + /// Returns `Err(Error)` 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(Error::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)?)), + } + } } #[allow(deprecated)] @@ -92,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, Error> { + self.single()?.and_time(time) } /// Makes a new `DateTime` from the current date, hour, minute and second. @@ -106,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, Error> { + 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, Error> { + 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, Error> { + 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, Error> { + 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() } } @@ -208,54 +185,29 @@ pub trait TimeZone: Sized + Clone { /// The original `TimeZone` value can be recovered via `TimeZone::from_offset`. type Offset: Offset; - /// Make a new `DateTime` from year, month, day, time components and current time zone. + /// 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. /// - /// 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 `LocalResult::None` on invalid input data. - fn with_ymd_and_hms( - &self, - year: i32, - month: u32, - day: u32, - hour: u32, - min: u32, - sec: u32, - ) -> LocalResult> { - match NaiveDate::from_ymd_opt(year, month, day).and_then(|d| d.and_hms_opt(hour, min, sec)) - { - Some(dt) => self.from_local_datetime(&dt), - None => LocalResult::None, - } - } - - /// 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 `Err(Error)` on the out-of-range date, invalid month + /// and/or day. /// - /// Panics on the out-of-range date, invalid month and/or day. - #[deprecated(since = "0.4.23", note = "use `with_ymd_and_hms()` instead")] - #[allow(deprecated)] - 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. + /// # Example /// - /// 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. + /// ``` + /// use chrono::{Utc, TimeZone}; /// - /// Returns `None` on the out-of-range date, invalid month and/or day. - #[deprecated(since = "0.4.23", note = "use `with_ymd_and_hms()` instead")] - #[allow(deprecated)] - 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, - } + /// 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::Error>(()) + /// ``` + fn ymd(&self, year: i32, month: u32, day: u32) -> Result>, Error> { + 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. @@ -264,140 +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. - #[deprecated( - since = "0.4.23", - note = "use `from_local_datetime()` with a `NaiveDateTime` instead" - )] - #[allow(deprecated)] - 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. + /// Returns `Err(Error)` on the out-of-range date and/or invalid DOY. /// - /// 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. + /// # Example /// - /// Returns `None` on the out-of-range date and/or invalid DOY. - #[deprecated( - since = "0.4.23", - note = "use `from_local_datetime()` with a `NaiveDateTime` instead" - )] - #[allow(deprecated)] - 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, - } + /// ``` + /// use chrono::{Error, Utc, TimeZone}; + /// + /// assert_eq!(Utc.yo(2015, 135)?.single()?.to_string(), "2015-05-15UTC"); + /// # Ok::<_, chrono::Error>(()) + /// ``` + fn yo(&self, year: i32, ordinal: u32) -> Result>, Error> { + 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. - #[deprecated( - since = "0.4.23", - note = "use `from_local_datetime()` with a `NaiveDateTime` instead" - )] - #[allow(deprecated)] - 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. + /// Returns `Err(Error)` on the out-of-range date and/or invalid week + /// number. /// - /// 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. + /// # Example /// - /// Returns `None` on the out-of-range date and/or invalid week number. - #[deprecated( - since = "0.4.23", - note = "use `from_local_datetime()` with a `NaiveDateTime` instead" - )] - #[allow(deprecated)] - 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, - } - } - - /// 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. - /// - /// Panics on the out-of-range number of seconds and/or invalid nanosecond, - /// for a non-panicking version see [`timestamp_opt`](#method.timestamp_opt). - #[deprecated(since = "0.4.23", note = "use `timestamp_opt()` instead")] - fn timestamp(&self, secs: i64, nsecs: u32) -> DateTime { - self.timestamp_opt(secs, nsecs).unwrap() + /// ``` + /// use chrono::{Utc, Weekday, TimeZone}; + /// + /// assert_eq!(Utc.isoywd(2015, 20, Weekday::Fri)?.single()?.to_string(), "2015-05-15UTC"); + /// # Ok::<_, chrono::Error>(()) + /// ``` + fn isoywd( + &self, + year: i32, + week: u32, + weekday: Weekday, + ) -> Result>, Error> { + 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. /// - /// Returns `LocalResult::None` on out-of-range number of seconds and/or - /// invalid nanosecond, otherwise always returns `LocalResult::Single`. + /// Returns `Err(Error)` 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_opt(1431648000, 0).unwrap().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::Error>(()) /// ``` - 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, - } + fn timestamp(&self, secs: i64, nsecs: u32) -> Result, Error> { + let dt = NaiveDateTime::from_timestamp(secs, nsecs)?; + self.from_utc_datetime(&dt) } - /// 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). - #[deprecated(since = "0.4.23", note = "use `timestamp_millis_opt()` instead")] - 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"). - /// + /// 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`. + /// Returns `Err(Error)` on out-of-range number of milliseconds and/or + /// invalid nanosecond. /// /// # Example /// /// ``` - /// use chrono::{Utc, TimeZone, LocalResult}; - /// match Utc.timestamp_millis_opt(1431648000) { - /// LocalResult::Single(dt) => assert_eq!(dt.timestamp(), 1431648), - /// _ => panic!("Incorrect timestamp_millis"), - /// }; + /// use chrono::{Utc, TimeZone}; + /// assert_eq!(Utc.timestamp_millis(1431648000)?.timestamp(), 1431648); + /// # Ok::<_, chrono::Error>(()) /// ``` - fn timestamp_millis_opt(&self, millis: i64) -> LocalResult> { + fn timestamp_millis(&self, millis: i64) -> Result, Error> { 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 @@ -411,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::Error>(()) /// ``` - fn timestamp_nanos(&self, nanos: i64) -> DateTime { + fn timestamp_nanos(&self, nanos: i64) -> Result, Error> { 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 @@ -433,7 +337,7 @@ pub trait TimeZone: Sized + Clone { /// /// See also [`DateTime::parse_from_str`] which gives a [`DateTime`] with /// parsed [`FixedOffset`]. - fn datetime_from_str(&self, s: &str, fmt: &str) -> ParseResult> { + fn datetime_from_str(&self, s: &str, fmt: &str) -> Result, Error> { let mut parsed = Parsed::new(); parse(&mut parsed, s, StrftimeItems::new(fmt))?; parsed.to_datetime_with_timezone(self) @@ -443,49 +347,77 @@ 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, Error>; /// 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, Error>; /// Converts the local `NaiveDate` to the timezone-aware `Date` if possible. #[allow(clippy::wrong_self_convention)] - #[deprecated(since = "0.4.23", note = "use `from_local_datetime()` instead")] - #[allow(deprecated)] - 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>, Error> { + 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>, Error> { + 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, Error> { + 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, Error> { + 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(crate) 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)] - #[deprecated(since = "0.4.23", note = "use `from_utc_datetime()` instead")] - #[allow(deprecated)] - 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)) } } @@ -495,21 +427,21 @@ mod tests { #[test] fn test_negative_millis() { - let dt = Utc.timestamp_millis_opt(-1000).unwrap(); + let dt = Utc.timestamp_millis(-1000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:59 UTC"); - let dt = Utc.timestamp_millis_opt(-7000).unwrap(); + let dt = Utc.timestamp_millis(-7000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:53 UTC"); - let dt = Utc.timestamp_millis_opt(-7001).unwrap(); + 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_opt(-7003).unwrap(); + 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_opt(-999).unwrap(); + 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_opt(-1).unwrap(); + 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_opt(-60000).unwrap(); + let dt = Utc.timestamp_millis(-60000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:59:00 UTC"); - let dt = Utc.timestamp_millis_opt(-3600000).unwrap(); + let dt = Utc.timestamp_millis(-3600000).unwrap(); assert_eq!(dt.to_string(), "1969-12-31 23:00:00 UTC"); for (millis, expected) in &[ @@ -517,33 +449,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 cfed754b2f..effcef6df7 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -17,11 +17,12 @@ 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")] #[allow(deprecated)] use crate::{Date, DateTime}; +use crate::{Error, 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). @@ -35,10 +36,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.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap(), dt); +/// assert_eq!(Utc.timestamp(61, 0)?, dt); +/// assert_eq!(Utc.ymd(1970, 1, 1)?.and_hms(0, 1, 1)?, dt); +/// # Ok::<_, chrono::Error>(()) /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -49,13 +51,8 @@ pub struct Utc; #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] impl Utc { /// Returns a `Date` which corresponds to the current date. - #[deprecated( - since = "0.4.23", - note = "use `Utc::now()` instead, potentially with `.date_naive()`" - )] - #[allow(deprecated)] - pub fn today() -> Date { - Utc::now().date() + pub fn today() -> Result, Error> { + Ok(Utc::now()?.date()) } /// Returns a `DateTime` which corresponds to the current date and time. @@ -64,12 +61,11 @@ impl Utc { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - pub fn now() -> DateTime { + pub fn now() -> Result, Error> { let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); - let naive = - NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos()).unwrap(); - 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. @@ -78,37 +74,51 @@ impl Utc { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] - pub fn now() -> DateTime { + pub fn now() -> Result, Error> { + use std::convert::TryFrom; + let now = js_sys::Date::new_0(); - DateTime::::from(now) + DateTime::::try_from(now) } } impl TimeZone for Utc { - type Offset = Utc; + type Offset = Self; + + fn from_offset(_: &Self) -> Self { + Self + } + + fn offset_from_local_date(&self, _: &NaiveDate) -> Result, Error> { + Ok(LocalResult::Single(Self)) + } - fn from_offset(_state: &Utc) -> Utc { - Utc + fn offset_from_local_datetime(&self, _: &NaiveDateTime) -> Result, Error> { + Ok(LocalResult::Single(Self)) } - fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult { - LocalResult::Single(Utc) + fn offset_from_utc_date(&self, _: &NaiveDate) -> Result { + Ok(Self) } - fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult { - LocalResult::Single(Utc) + + fn offset_from_utc_datetime(&self, _: &NaiveDateTime) -> Result { + Ok(Self) } +} - fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Utc { - Utc +impl FixedTimeZone for Utc { + fn offset_from_utc_date_fixed(&self, _: &NaiveDate) -> Self::Offset { + Self } - fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Utc { - Utc + + fn offset_from_utc_datetime_fixed(&self, _: &NaiveDateTime) -> Self::Offset { + Self } } impl Offset for Utc { fn fix(&self) -> FixedOffset { - FixedOffset::east_opt(0).unwrap() + FixedOffset::UTC } } diff --git a/src/round.rs b/src/round.rs index 0143fa186b..a45f474881 100644 --- a/src/round.rs +++ b/src/round.rs @@ -24,10 +24,11 @@ pub trait SubsecRound { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); + /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; + /// 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::Error>(()) /// ``` fn round_subsecs(self, digits: u16) -> Self; @@ -36,10 +37,11 @@ pub trait SubsecRound { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); + /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; + /// 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::Error>(()) /// ``` fn trunc_subsecs(self, digits: u16) -> Self; } @@ -111,16 +113,17 @@ pub trait DurationRound: Sized { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); + /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc}; + /// 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(), + /// dt.duration_round(TimeDelta::milliseconds(10))?.to_string(), /// "2018-01-11 12:00:00.150 UTC" /// ); /// assert_eq!( - /// dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), + /// dt.duration_round(TimeDelta::days(1))?.to_string(), /// "2018-01-12 00:00:00 UTC" /// ); + /// # Ok::<_, Box>(()) /// ``` fn duration_round(self, duration: TimeDelta) -> Result; @@ -128,16 +131,17 @@ pub trait DurationRound: Sized { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); + /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc}; + /// 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(), + /// dt.duration_trunc(TimeDelta::milliseconds(10))?.to_string(), /// "2018-01-11 12:00:00.150 UTC" /// ); /// assert_eq!( - /// dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), + /// dt.duration_trunc(TimeDelta::days(1))?.to_string(), /// "2018-01-11 00:00:00 UTC" /// ); + /// # Ok::<_, Box>(()) /// ``` fn duration_trunc(self, duration: TimeDelta) -> Result; } @@ -244,25 +248,27 @@ pub enum RoundingError { /// /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0).unwrap(); + /// 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::Error>(()) /// ``` DurationExceedsTimestamp, /// Error when `TimeDelta.num_nanoseconds` exceeds the limit. /// /// ``` rust - /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd_opt(2260, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 1_75_500_000).unwrap().and_local_timezone(Utc).unwrap(); + /// # 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)?; /// /// assert_eq!( /// dt.duration_round(TimeDelta::days(300 * 365)), /// Err(RoundingError::DurationExceedsLimit) /// ); + /// # Ok::<_, chrono::Error>(()) /// ``` DurationExceedsLimit, @@ -270,9 +276,10 @@ pub enum RoundingError { /// /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0).unwrap(); + /// 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::Error>(()) /// ``` TimestampExceedsLimit, } @@ -311,15 +318,8 @@ mod tests { #[test] fn test_round_subsecs() { - let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap(); - let dt = pst - .from_local_datetime( - &NaiveDate::from_ymd_opt(2018, 1, 11) - .unwrap() - .and_hms_nano_opt(10, 5, 13, 84_660_684) - .unwrap(), - ) - .unwrap(); + 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); @@ -335,14 +335,7 @@ mod tests { assert_eq!(dt.round_subsecs(0).nanosecond(), 0); assert_eq!(dt.round_subsecs(0).second(), 13); - let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2018, 1, 11) - .unwrap() - .and_hms_nano_opt(10, 5, 27, 750_500_000) - .unwrap(), - ) - .unwrap(); + 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); @@ -355,14 +348,7 @@ mod tests { #[test] fn test_round_leap_nanos() { - let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2016, 12, 31) - .unwrap() - .and_hms_nano_opt(23, 59, 59, 1_750_500_000) - .unwrap(), - ) - .unwrap(); + 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); @@ -375,15 +361,8 @@ mod tests { #[test] fn test_trunc_subsecs() { - let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap(); - let dt = pst - .from_local_datetime( - &NaiveDate::from_ymd_opt(2018, 1, 11) - .unwrap() - .and_hms_nano_opt(10, 5, 13, 84_660_684) - .unwrap(), - ) - .unwrap(); + 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); @@ -399,14 +378,7 @@ mod tests { assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0); assert_eq!(dt.trunc_subsecs(0).second(), 13); - let dt = pst - .from_local_datetime( - &NaiveDate::from_ymd_opt(2018, 1, 11) - .unwrap() - .and_hms_nano_opt(10, 5, 27, 750_500_000) - .unwrap(), - ) - .unwrap(); + 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); @@ -419,14 +391,7 @@ mod tests { #[test] fn test_trunc_leap_nanos() { - let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2016, 12, 31) - .unwrap() - .and_hms_nano_opt(23, 59, 59, 1_750_500_000) - .unwrap(), - ) - .unwrap(); + 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); @@ -439,14 +404,7 @@ mod tests { #[test] fn test_duration_round() { - let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2016, 12, 31) - .unwrap() - .and_hms_nano_opt(23, 59, 59, 175_500_000) - .unwrap(), - ) - .unwrap(); + 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(), @@ -459,27 +417,13 @@ mod tests { ); // round up - let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2012, 12, 12) - .unwrap() - .and_hms_milli_opt(18, 22, 30, 0) - .unwrap(), - ) - .unwrap(); + 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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2012, 12, 12) - .unwrap() - .and_hms_milli_opt(18, 22, 29, 999) - .unwrap(), - ) - .unwrap(); + 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" @@ -504,7 +448,7 @@ mod tests { // timezone east let dt = - FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap(); + 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" @@ -516,7 +460,7 @@ mod tests { // timezone west let dt = - FixedOffset::west_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap(); + 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" @@ -530,12 +474,9 @@ mod tests { #[test] fn test_duration_round_naive() { let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2016, 12, 31) - .unwrap() - .and_hms_nano_opt(23, 59, 59, 175_500_000) - .unwrap(), - ) + .ymd(2016, 12, 31) + .unwrap() + .and_hms_nano(23, 59, 59, 175_500_000) .unwrap() .naive_utc(); @@ -550,29 +491,13 @@ mod tests { ); // round up - let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2012, 12, 12) - .unwrap() - .and_hms_milli_opt(18, 22, 30, 0) - .unwrap(), - ) - .unwrap() - .naive_utc(); + 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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2012, 12, 12) - .unwrap() - .and_hms_milli_opt(18, 22, 29, 999) - .unwrap(), - ) - .unwrap() - .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" @@ -598,7 +523,7 @@ mod tests { #[test] fn test_duration_round_pre_epoch() { - let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap(); + 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" @@ -607,14 +532,7 @@ mod tests { #[test] fn test_duration_trunc() { - let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2016, 12, 31) - .unwrap() - .and_hms_nano_opt(23, 59, 59, 175_500_000) - .unwrap(), - ) - .unwrap(); + 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(), @@ -622,27 +540,13 @@ mod tests { ); // would round up - let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2012, 12, 12) - .unwrap() - .and_hms_milli_opt(18, 22, 30, 0) - .unwrap(), - ) - .unwrap(); + 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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2012, 12, 12) - .unwrap() - .and_hms_milli_opt(18, 22, 29, 999) - .unwrap(), - ) - .unwrap(); + 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" @@ -666,7 +570,7 @@ mod tests { // timezone east let dt = - FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap(); + 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" @@ -678,7 +582,7 @@ mod tests { // timezone west let dt = - FixedOffset::west_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap(); + 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" @@ -692,12 +596,9 @@ mod tests { #[test] fn test_duration_trunc_naive() { let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2016, 12, 31) - .unwrap() - .and_hms_nano_opt(23, 59, 59, 175_500_000) - .unwrap(), - ) + .ymd(2016, 12, 31) + .unwrap() + .and_hms_nano(23, 59, 59, 175_500_000) .unwrap() .naive_utc(); @@ -707,29 +608,13 @@ mod tests { ); // would round up - let dt = Utc - .from_local_datetime( - &NaiveDate::from_ymd_opt(2012, 12, 12) - .unwrap() - .and_hms_milli_opt(18, 22, 30, 0) - .unwrap(), - ) - .unwrap() - .naive_utc(); + 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 - .from_local_datetime( - &NaiveDate::from_ymd_opt(2012, 12, 12) - .unwrap() - .and_hms_milli_opt(18, 22, 29, 999) - .unwrap(), - ) - .unwrap() - .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" diff --git a/src/time_delta.rs b/src/time_delta.rs index 538b123fa4..e6fbb09773 100644 --- a/src/time_delta.rs +++ b/src/time_delta.rs @@ -211,14 +211,14 @@ impl TimeDelta { } /// Add two durations, returning `None` if overflow occurred. - pub fn checked_add(&self, rhs: &TimeDelta) -> Option { + pub fn checked_add(&self, rhs: &TimeDelta) -> Option { let mut secs = try_opt!(self.secs.checked_add(rhs.secs)); let mut nanos = self.nanos + rhs.nanos; if nanos >= NANOS_PER_SEC { nanos -= NANOS_PER_SEC; secs = try_opt!(secs.checked_add(1)); } - let d = TimeDelta { secs, nanos }; + let d = Self { secs, nanos }; // Even if d is within the bounds of i64 seconds, // it might still overflow i64 milliseconds. if d < MIN || d > MAX { @@ -229,14 +229,14 @@ impl TimeDelta { } /// Subtract two durations, returning `None` if overflow occurred. - pub fn checked_sub(&self, rhs: &TimeDelta) -> Option { + pub fn checked_sub(&self, rhs: &TimeDelta) -> Option { let mut secs = try_opt!(self.secs.checked_sub(rhs.secs)); let mut nanos = self.nanos - rhs.nanos; if nanos < 0 { nanos += NANOS_PER_SEC; secs = try_opt!(secs.checked_sub(1)); } - let d = TimeDelta { secs, nanos }; + let d = Self { secs, nanos }; // Even if d is within the bounds of i64 seconds, // it might still overflow i64 milliseconds. if d < MIN || d > MAX { diff --git a/src/traits.rs b/src/traits.rs index bfc792936b..f52e686d6c 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,4 +1,4 @@ -use crate::{IsoWeek, Weekday}; +use crate::{Error, IsoWeek, Weekday}; /// The common set of methods for date component. pub trait Datelike: Sized { @@ -55,38 +55,38 @@ 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; + /// Returns `Err(Error)` when the resulting value would be invalid. + 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; + /// Returns `Err(Error)` when the resulting value would be invalid. + 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; + /// Returns `Err(Error)` when the resulting value would be invalid. + 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; + /// Returns `Err(Error)` when the resulting value would be invalid. + 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; + /// Returns `Err(Error)` when the resulting value would be invalid. + 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; + /// Returns `Err(Error)` when the resulting value would be invalid. + 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; + /// Returns `Err(Error)` when the resulting value would be invalid. + 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_opt(1970, 1, 1).unwrap().num_days_from_ce(), 719_163); - /// assert_eq!(NaiveDate::from_ymd_opt(2, 1, 1).unwrap().num_days_from_ce(), 366); - /// assert_eq!(NaiveDate::from_ymd_opt(1, 1, 1).unwrap().num_days_from_ce(), 1); - /// assert_eq!(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().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::Error>(()) /// ``` fn num_days_from_ce(&self) -> i32 { // See test_num_days_from_ce_against_alternative_impl below for a more straightforward @@ -148,27 +149,28 @@ 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; + /// Returns `Err(Error)` when the resulting value would be invalid. + 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; + /// Returns `Err(Error)` when the resulting value would be invalid. + 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; + /// Returns `Err(Error)` 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) -> Result; - /// Makes a new value with nanoseconds since the whole non-leap second changed. + /// 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; + /// Returns `Err(Error)` 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) -> Result; /// Returns the number of non-leap seconds past the last midnight. #[inline] @@ -222,7 +224,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_opt(year, 1, 1).unwrap(); + 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/dateutils.rs b/tests/dateutils.rs index aabab29a78..8d7fa6587f 100644 --- a/tests/dateutils.rs +++ b/tests/dateutils.rs @@ -1,11 +1,11 @@ use chrono::offset::TimeZone; use chrono::Local; -use chrono::{Datelike, NaiveDate, NaiveDateTime, Timelike}; +use chrono::{Datelike, Error, NaiveDate, NaiveDateTime, Timelike}; use std::{path, process}; #[cfg(unix)] -fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) { +fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) -> Result<(), Error> { let output = process::Command::new(path) .arg("-d") .arg(format!("{}-{:02}-{:02} {:02}:05:01", dt.year(), dt.month(), dt.day(), dt.hour())) @@ -34,18 +34,16 @@ fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) { // be exactly matched, or whether LocalResult::Ambigious should be handled // differently - let date = NaiveDate::from_ymd_opt(dt.year(), dt.month(), dt.day()).unwrap(); - match Local.from_local_datetime(&date.and_hms_opt(dt.hour(), 5, 1).unwrap()) { - chrono::LocalResult::Ambiguous(a, b) => assert!( - format!("{}\n", a) == date_command_str || format!("{}\n", b) == date_command_str - ), + let date = NaiveDate::from_ymd(dt.year(), dt.month(), dt.day())?.and_hms(dt.hour(), 5, 1)?; + match Local.from_local_datetime(&date).unwrap() { + chrono::LocalResult::Ambiguous(a, b) => { + assert!(format!("{}\n", a) == date_command_str || format!("{}\n", b) == date_command_str); + }, chrono::LocalResult::Single(a) => { assert_eq!(format!("{}\n", a), date_command_str); - } - chrono::LocalResult::None => { - assert_eq!("", date_command_str); - } + }, } + Ok(()) } #[test] @@ -61,7 +59,7 @@ fn try_verify_against_date_command() { return; } - let mut date = NaiveDate::from_ymd_opt(1975, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); + 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()) @@ -106,9 +104,11 @@ fn verify_against_date_command_format_local(path: &'static str, dt: NaiveDateTim .unwrap(); let date_command_str = String::from_utf8(output.stdout).unwrap(); - let date = NaiveDate::from_ymd_opt(dt.year(), dt.month(), dt.day()).unwrap(); + let date = NaiveDate::from_ymd(dt.year(), dt.month(), dt.day()).unwrap(); let ldt = Local - .from_local_datetime(&date.and_hms_opt(dt.hour(), dt.minute(), dt.second()).unwrap()) + .from_local_datetime(&date.and_hms(dt.hour(), dt.minute(), dt.second()).unwrap()) + .unwrap() + .single() .unwrap(); let formated_date = format!("{}\n", ldt.format(required_format)); assert_eq!(date_command_str, formated_date); @@ -123,7 +123,7 @@ fn try_verify_against_date_command_format() { // date command not found, skipping return; } - let mut date = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_opt(12, 11, 13).unwrap(); + let mut date = NaiveDate::from_ymd(1970, 1, 1).unwrap().and_hms(12, 11, 13).unwrap(); while date.year() < 2008 { verify_against_date_command_format_local(date_path, date); date += chrono::TimeDelta::days(55); diff --git a/tests/wasm.rs b/tests/wasm.rs index f003d4db9d..2322435db2 100644 --- a/tests/wasm.rs +++ b/tests/wasm.rs @@ -9,15 +9,15 @@ use self::wasm_bindgen_test::*; #[wasm_bindgen_test] fn now() { - let utc: DateTime = Utc::now(); - let local: DateTime = Local::now(); + let utc: DateTime = Utc::now()?; + let local: DateTime = Local::now()?; // Ensure time set by the test script is correct let now = env!("NOW"); - let actual = Utc.datetime_from_str(&now, "%s").unwrap(); + let actual = Utc.datetime_from_str(&now, "%s")?; let diff = utc - actual; assert!( - diff < chrono::Duration::minutes(5), + diff < chrono::TimeDelta::minutes(5), "expected {} - {} == {} < 5m (env var: {})", utc, actual, @@ -30,11 +30,11 @@ fn now() { // Ensure offset retrieved when getting local time is correct let expected_offset = match tz { - "ACST-9:30" => FixedOffset::east_opt(19 * 30 * 60).unwrap(), - "Asia/Katmandu" => FixedOffset::east_opt(23 * 15 * 60).unwrap(), // No DST thankfully - "EDT" | "EST4" | "-0400" => FixedOffset::east_opt(-4 * 60 * 60).unwrap(), - "EST" | "-0500" => FixedOffset::east_opt(-5 * 60 * 60).unwrap(), - "UTC0" | "+0000" => FixedOffset::east_opt(0).unwrap(), + "ACST-9:30" => FixedOffset::east(19 * 30 * 60).unwrap(), + "Asia/Katmandu" => FixedOffset::east(23 * 15 * 60).unwrap(), // No DST thankfully + "EDT" | "EST4" | "-0400" => FixedOffset::east(-4 * 60 * 60).unwrap(), + "EST" | "-0500" => FixedOffset::east(-5 * 60 * 60).unwrap(), + "UTC0" | "+0000" => FixedOffset::east(0).unwrap(), tz => panic!("unexpected TZ {}", tz), }; assert_eq!( @@ -50,19 +50,16 @@ fn now() { fn from_is_exact() { let now = js_sys::Date::new_0(); - let dt = DateTime::::from(now.clone()); + let dt = DateTime::::try_from(now.clone()).unwrap(); assert_eq!(now.get_time() as i64, dt.timestamp_millis_opt().unwrap()); } #[wasm_bindgen_test] fn local_from_local_datetime() { - let now = Local::now(); + let now = Local::now()?; let ndt = now.naive_local(); - let res = match Local.from_local_datetime(&ndt).single() { - Some(v) => v, - None => panic! {"Required for test!"}, - }; + let res = Local.from_local_datetime(&ndt)?.single()?; assert_eq!(now, res); }