From 8b3732f9c7d2867d4e65f285e78ed0f426e2b111 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Wed, 22 Mar 2023 13:24:22 +0100 Subject: [PATCH 01/54] Fallable constructors for less panics (#815) - Creates a global Error enum - Breaks backwards compatiblility mainly because of promoting fallable functions (#263) - Some tests still fall - Not all doctests are fixed - to_naive_datetime_with_offset function is broken and needs fixing - serde related stuff is not checked properly This is a rebase of #817 onto the 0.5 main branch. Main differences: - Unify three different error structs - Removed ErrorKind - Adapted a lot of unit tests - Removed some commits from presumably unrelated branches (#829) or mainlined commits (#271) Co-authored-by: John-John Tedro --- README.md | 4 +- benches/chrono.rs | 28 +- ci/core-test/src/lib.rs | 2 +- src/date.rs | 237 ++-- src/datetime/mod.rs | 336 ++--- src/datetime/serde.rs | 139 +- src/datetime/tests.rs | 1601 +++-------------------- src/error.rs | 186 +++ src/format/mod.rs | 85 +- src/format/parse.rs | 1048 ++++++++------- src/format/parsed.rs | 794 ++++++------ src/format/scan.rs | 117 +- src/format/strftime.rs | 28 +- src/lib.rs | 122 +- src/month.rs | 22 +- src/naive/date.rs | 1782 +++++++++++++------------- src/naive/datetime/mod.rs | 904 ++++++------- src/naive/datetime/serde.rs | 170 +-- src/naive/datetime/tests.rs | 185 +-- src/naive/internals.rs | 66 +- src/naive/isoweek.rs | 42 +- src/naive/time/mod.rs | 671 +++++----- src/naive/time/serde.rs | 2 +- src/naive/time/tests.rs | 216 ++-- src/offset/fixed.rs | 121 +- src/offset/local/mod.rs | 199 ++- src/offset/local/stub.rs | 23 +- src/offset/local/tz_info/mod.rs | 92 -- src/offset/local/tz_info/parser.rs | 17 +- src/offset/local/tz_info/rule.rs | 56 +- src/offset/local/tz_info/timezone.rs | 30 +- src/offset/local/unix.rs | 106 +- src/offset/local/windows.rs | 78 +- src/offset/mod.rs | 448 +++---- src/offset/utc.rs | 68 +- src/round.rs | 219 +--- src/time_delta.rs | 8 +- src/traits.rs | 68 +- tests/dateutils.rs | 30 +- tests/wasm.rs | 27 +- 40 files changed, 4478 insertions(+), 5899 deletions(-) create mode 100644 src/error.rs 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); } From ee9871dd135a7cad59d4180ddab954559e58aa9b Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Wed, 22 Mar 2023 21:43:18 +0100 Subject: [PATCH 02/54] reconstruct_from_timestamp --- src/datetime/mod.rs | 14 ---- src/format/parsed.rs | 168 ++++++++++++++++++++---------------------- src/naive/time/mod.rs | 8 +- src/round.rs | 7 +- 4 files changed, 87 insertions(+), 110 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 94a5ba58d1..28f80da624 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -588,20 +588,6 @@ 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 diff --git a/src/format/parsed.rs b/src/format/parsed.rs index eecbf8693d..aaaa173fdb 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -129,7 +129,7 @@ impl Parsed { /// Tries to set the [`year`](#structfield.year) field from given value. #[inline] pub fn set_year(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.year, i32::try_from(value)?) } /// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value. @@ -138,7 +138,7 @@ impl Parsed { if value < 0 { return Err(Error::ParsingOutOfRange); } - set_if_consistent(&mut self.year_div_100, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.year_div_100, i32::try_from(value)?) } /// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value. @@ -147,13 +147,13 @@ impl Parsed { if value < 0 { return Err(Error::ParsingOutOfRange); } - set_if_consistent(&mut self.year_mod_100, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.year_mod_100, i32::try_from(value)?) } /// Tries to set the [`isoyear`](#structfield.isoyear) field from given value. #[inline] pub fn set_isoyear(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.isoyear, i32::try_from(value)?) } /// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value. @@ -164,7 +164,7 @@ impl Parsed { } set_if_consistent( &mut self.isoyear_div_100, - i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?, + i32::try_from(value)?, ) } @@ -176,32 +176,32 @@ impl Parsed { } set_if_consistent( &mut self.isoyear_mod_100, - i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?, + i32::try_from(value)?, ) } /// Tries to set the [`month`](#structfield.month) field from given value. #[inline] pub fn set_month(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.month, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.month, u32::try_from(value)?) } /// 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) -> Result<(), Error> { - set_if_consistent(&mut self.week_from_sun, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.week_from_sun, u32::try_from(value)?) } /// 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) -> Result<(), Error> { - set_if_consistent(&mut self.week_from_mon, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.week_from_mon, u32::try_from(value)?) } /// Tries to set the [`isoweek`](#structfield.isoweek) field from given value. #[inline] pub fn set_isoweek(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.isoweek, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.isoweek, u32::try_from(value)?) } /// Tries to set the [`weekday`](#structfield.weekday) field from given value. @@ -213,13 +213,13 @@ impl Parsed { /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value. #[inline] pub fn set_ordinal(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.ordinal, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.ordinal, u32::try_from(value)?) } /// Tries to set the [`day`](#structfield.day) field from given value. #[inline] pub fn set_day(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.day, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.day, u32::try_from(value)?) } /// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value. @@ -243,7 +243,7 @@ impl Parsed { /// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value. #[inline] pub fn set_hour(&mut self, value: i64) -> Result<(), Error> { - let v = u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?; + let v = u32::try_from(value)?; set_if_consistent(&mut self.hour_div_12, v / 12)?; set_if_consistent(&mut self.hour_mod_12, v % 12)?; Ok(()) @@ -252,19 +252,19 @@ impl Parsed { /// Tries to set the [`minute`](#structfield.minute) field from given value. #[inline] pub fn set_minute(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.minute, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.minute, u32::try_from(value)?) } /// Tries to set the [`second`](#structfield.second) field from given value. #[inline] pub fn set_second(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.second, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.second, u32::try_from(value)?) } /// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value. #[inline] pub fn set_nanosecond(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.nanosecond, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.nanosecond, u32::try_from(value)?) } /// Tries to set the [`timestamp`](#structfield.timestamp) field from given value. @@ -276,7 +276,7 @@ impl Parsed { /// Tries to set the [`offset`](#structfield.offset) field from given value. #[inline] pub fn set_offset(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent(&mut self.offset, i32::try_from(value)?) } /// Returns a parsed naive date out of given fields. @@ -393,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(year, month, day).map_err(|_| Error::ParsingOutOfRange)?; + let date = NaiveDate::from_ymd(year, month, day)?; (verify_isoweekdate(date) && verify_ordinal(date), date) } (Some(year), _, &Parsed { ordinal: Some(ordinal), .. }) => { // year, day of the year - let date = NaiveDate::from_yo(year, ordinal).map_err(|_| Error::ParsingOutOfRange)?; + let date = NaiveDate::from_yo(year, ordinal)?; (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date) } @@ -409,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(year, 1).map_err(|_| Error::ParsingOutOfRange)?; + let newyear = NaiveDate::from_yo(year, 1)?; let firstweek = match newyear.weekday() { Weekday::Sun => 0, Weekday::Mon => 6, @@ -442,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(year, 1).map_err(|_| Error::ParsingOutOfRange)?; + let newyear = NaiveDate::from_yo(year, 1)?; let firstweek = match newyear.weekday() { Weekday::Sun => 1, Weekday::Mon => 0, @@ -471,7 +471,7 @@ impl Parsed { (_, Some(isoyear), &Parsed { isoweek: Some(isoweek), weekday: Some(weekday), .. }) => { // ISO year, week, day of the week let date = - NaiveDate::from_isoywd(isoyear, isoweek, weekday).map_err(|_| Error::ParsingOutOfRange)?; + NaiveDate::from_isoywd(isoyear, isoweek, weekday)?; (verify_ymd(date) && verify_ordinal(date), date) } @@ -526,7 +526,7 @@ impl Parsed { None => 0, }; - NaiveTime::from_hms_nano(hour, minute, second, nano).map_err(|_| Error::ParsingOutOfRange) + NaiveTime::from_hms_nano(hour, minute, second, nano) } /// Returns a parsed naive date and time out of given fields, @@ -537,9 +537,9 @@ impl Parsed { /// 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) -> Result { - match (self.to_naive_date(), self.to_naive_time()) { + match (self.to_naive_date(), self.to_naive_time(), self.timestamp) { // Both are unproblematic - (Ok(date), Ok(time)) => { + (Ok(date), Ok(time), _) => { let datetime = date.and_time(time); // verify the timestamp field if any @@ -556,53 +556,54 @@ impl Parsed { 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)) - // } + + // If either is problematic, fallback on the timestamp + // TODO, the condition for reconstruction of date and time fields from timestamp is unclear + (Err(e1), _, Some(ts)) => self.reconstruct_from_timestamp(ts, offset).ok().ok_or(e1), + (_, Err(e2), Some(ts)) => self.reconstruct_from_timestamp(ts, offset).ok().ok_or(e2), + + // If both are problematic or timestamp is not available, return the first error + (Err(e1), _, None) => Err(e1), + (_, Err(e2), None) => Err(e2), + } + } + + fn reconstruct_from_timestamp(&self, mut timestamp: i64, offset: i32) -> Result { + timestamp = timestamp.checked_add(i64::from(offset)).ok_or(Error::ParsingOutOfRange)?; + let mut datetime = NaiveDateTime::from_timestamp(timestamp, 0)?; + + // 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) -> Result { let offset = self.offset.ok_or(Error::ParsingOutOfRange)?; - FixedOffset::east(offset).map_err(|_| Error::ParsingOutOfRange) + FixedOffset::east(offset) } /// Returns a parsed timezone-aware date and time out of given fields. @@ -614,13 +615,13 @@ impl Parsed { 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(offset).map_err(|_| Error::ParsingOutOfRange)?; + let offset = FixedOffset::east(offset)?; // this is used to prevent an overflow when calling FixedOffset::from_local_datetime // TODO: is this still needed? datetime.checked_sub_signed(TimeDelta::seconds(i64::from(offset.local_minus_utc())))?; - offset.from_local_datetime(&datetime).and_then(|dt| dt.single()).map_err(|_| Error::ParsingOutOfRange) + offset.from_local_datetime(&datetime)?.single() } /// Returns a parsed timezone-aware date and time out of given fields, @@ -639,34 +640,23 @@ impl Parsed { // make a naive `DateTime` from given timestamp and (if any) nanosecond. // an empty `nanosecond` is always equal to zero, so missing nanosecond is fine. let nanosecond = self.nanosecond.unwrap_or(0); - let dt = - NaiveDateTime::from_timestamp(timestamp, nanosecond).map_err(|_| Error::ParsingOutOfRange)?; - guessed_offset = - tz.offset_from_utc_datetime(&dt).map_err(|_| Error::ParsingOutOfRange)?.fix().local_minus_utc(); + let dt = NaiveDateTime::from_timestamp(timestamp, nanosecond)?; + guessed_offset = tz.offset_from_utc_datetime(&dt)?.fix().local_minus_utc(); } - // checks if the given `DateTime` has a consistent `Offset` with given `self.offset`. - let check_offset = |dt: &DateTime| { - if let Some(offset) = self.offset { - dt.offset().fix().local_minus_utc() == offset - } else { - true - } - }; - // `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)?; - let dt = tz - .from_local_datetime(&datetime) - .and_then(|dt| dt.single()) - .map_err(|_| Error::ParsingOutOfRange)?; + let dt = tz.from_local_datetime(&datetime)?.single()?; - if check_offset(&dt) { - Ok(dt) - } else { - Err(Error::ParsingImpossible) + // checks if the given `DateTime` has a consistent `Offset` with given `self.offset`. + match self.offset { + Some(so) => match dt.offset().fix().local_minus_utc() == so { + true => Ok(dt), + false => Err(Error::ParsingImpossible) + } + None => Ok(dt), } } } diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index b65637a475..cb96e5a3aa 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -893,8 +893,8 @@ impl Timelike for NaiveTime { /// Makes a new `NaiveTime` with the second number changed. /// - /// Returns `Err(Error)` when the resulting `NaiveTime` would be - /// invalid. As with the [`second`](#method.second) method, the input range + /// 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 @@ -919,8 +919,8 @@ impl Timelike for NaiveTime { /// Makes a new `NaiveTime` with nanoseconds since the whole non-leap second /// changed. /// - /// Returns `Err(Error)` when the resulting `NaiveTime` would be - /// invalid. As with the [`nanosecond`](#method.nanosecond) method, the + /// 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 diff --git a/src/round.rs b/src/round.rs index a45f474881..62a7a43224 100644 --- a/src/round.rs +++ b/src/round.rs @@ -313,7 +313,7 @@ impl std::error::Error for RoundingError { mod tests { use super::{DurationRound, SubsecRound, TimeDelta}; use crate::offset::{FixedOffset, TimeZone, Utc}; - use crate::NaiveDate; + use crate::{NaiveDate, Error}; use crate::Timelike; #[test] @@ -638,11 +638,12 @@ mod tests { } #[test] - fn test_duration_trunc_pre_epoch() { - let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap(); + fn test_duration_trunc_pre_epoch() -> Result<(), Error> { + let dt = Utc.ymd(1969, 12, 12)?.and_hms(12, 12, 12)?; assert_eq!( dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(), "1969-12-12 12:10:00 UTC" ); + Ok(()) } } From e29524fdf1d76b352ad0f78ea5a43344ef953404 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 23 Mar 2023 09:37:40 +0100 Subject: [PATCH 03/54] ParsingNotEnough seems better for partial fields --- src/format/parsed.rs | 66 +++++++++++++++++------------------------- src/naive/date.rs | 16 ++++------ src/naive/internals.rs | 8 ++--- 3 files changed, 37 insertions(+), 53 deletions(-) diff --git a/src/format/parsed.rs b/src/format/parsed.rs index aaaa173fdb..79b6f90823 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -129,7 +129,7 @@ impl Parsed { /// Tries to set the [`year`](#structfield.year) field from given value. #[inline] pub fn set_year(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.year, i32::try_from(value)?) + 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. @@ -138,7 +138,7 @@ impl Parsed { if value < 0 { return Err(Error::ParsingOutOfRange); } - set_if_consistent(&mut self.year_div_100, i32::try_from(value)?) + 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. @@ -147,13 +147,13 @@ impl Parsed { if value < 0 { return Err(Error::ParsingOutOfRange); } - set_if_consistent(&mut self.year_mod_100, i32::try_from(value)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.isoyear, i32::try_from(value)?) + 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. @@ -164,7 +164,7 @@ impl Parsed { } set_if_consistent( &mut self.isoyear_div_100, - i32::try_from(value)?, + i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?, ) } @@ -176,32 +176,32 @@ impl Parsed { } set_if_consistent( &mut self.isoyear_mod_100, - i32::try_from(value)?, + 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) -> Result<(), Error> { - set_if_consistent(&mut self.month, u32::try_from(value)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.week_from_sun, u32::try_from(value)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.week_from_mon, u32::try_from(value)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.isoweek, u32::try_from(value)?) + 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. @@ -213,13 +213,13 @@ impl Parsed { /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value. #[inline] pub fn set_ordinal(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.ordinal, u32::try_from(value)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.day, u32::try_from(value)?) + 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. @@ -252,19 +252,19 @@ impl Parsed { /// Tries to set the [`minute`](#structfield.minute) field from given value. #[inline] pub fn set_minute(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.minute, u32::try_from(value)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.second, u32::try_from(value)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.nanosecond, u32::try_from(value)?) + 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. @@ -276,7 +276,7 @@ impl Parsed { /// Tries to set the [`offset`](#structfield.offset) field from given value. #[inline] pub fn set_offset(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.offset, i32::try_from(value)?) + set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) } /// Returns a parsed naive date out of given fields. @@ -559,8 +559,8 @@ impl Parsed { // If either is problematic, fallback on the timestamp // TODO, the condition for reconstruction of date and time fields from timestamp is unclear - (Err(e1), _, Some(ts)) => self.reconstruct_from_timestamp(ts, offset).ok().ok_or(e1), - (_, Err(e2), Some(ts)) => self.reconstruct_from_timestamp(ts, offset).ok().ok_or(e2), + (Err(e1), _, Some(ts)) => self.reconstruct_from_timestamp(ts, offset).map_err(|_| e1), + (_, Err(e2), Some(ts)) => self.reconstruct_from_timestamp(ts, offset).map_err(|_| e2), // If both are problematic or timestamp is not available, return the first error (Err(e1), _, None) => Err(e1), @@ -763,10 +763,7 @@ mod tests { 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, 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))); @@ -1081,23 +1078,14 @@ mod tests { ); // leap seconds #1: partial fields - 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), - Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)) - ); - assert_eq!( - parse!(second: 60, timestamp: 1_341_100_800), - Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)) - ); + assert_eq!(parse!(second: 59, timestamp: 1_341_100_798), Err(Error::ParsingNotEnough)); + 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::ParsingNotEnough)); + assert_eq!(parse!(second: 60, timestamp: 1_341_100_799), Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000))); + assert_eq!(parse!(second: 60, timestamp: 1_341_100_800), Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000))); 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)); + assert_eq!(parse!(second: 1, timestamp: 1_341_100_800), Err(Error::ParsingNotEnough)); + assert_eq!(parse!(second: 60, timestamp: 1_341_100_801), Err(Error::ParsingNotEnough)); // leap seconds #2: full fields // we need to have separate tests for them since it uses another control flow. @@ -1191,7 +1179,7 @@ mod tests { 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(Error::ParsingOutOfRange) + Err(Error::InvalidTimeZone) ); // `FixedOffset` does not support such huge offset } diff --git a/src/naive/date.rs b/src/naive/date.rs index 2b3a31d2d3..ea6ee89487 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -608,13 +608,13 @@ impl NaiveDate { /// /// assert_eq!( /// NaiveDate::from_ymd(2022, 2, 20)?.checked_sub_months(Months::new(6)), - /// Some(NaiveDate::from_ymd(2021, 8, 20)?) + /// NaiveDate::from_ymd(2021, 8, 20) /// ); /// /// assert!( /// NaiveDate::from_ymd(2014, 1, 1)? /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)) - /// .is_none() + /// .is_err() /// ); /// # Ok::<_, chrono::Error>(()) /// ``` @@ -623,11 +623,7 @@ impl NaiveDate { return Ok(self); } - let d = match i32::try_from(months.0)?.checked_neg() { - None => return Err(Error::InvalidDate), - Some(d) => d, - }; - + let d = i32::try_from(months.0)?.checked_neg().ok_or(Error::ParsingOutOfRange)?; self.diff_months(d) } @@ -639,7 +635,7 @@ impl NaiveDate { let year = if (years > 0 && years > (MAX_YEAR - self.year())) || (years < 0 && years < (MIN_YEAR - self.year())) { - return Err(Error::InvalidDate); + return Err(Error::ParsingOutOfRange); } else { self.year() + years }; @@ -649,13 +645,13 @@ impl NaiveDate { let month = self.month() as i32 + left; let (year, month) = if month <= 0 { if year == MIN_YEAR { - return Err(Error::InvalidDate); + return Err(Error::ParsingOutOfRange); } (year - 1, month + 12) } else if month > 12 { if year == MAX_YEAR { - return Err(Error::InvalidDate); + return Err(Error::ParsingOutOfRange); } (year + 1, month - 12) diff --git a/src/naive/internals.rs b/src/naive/internals.rs index 541c30ef92..87546cb7d5 100644 --- a/src/naive/internals.rs +++ b/src/naive/internals.rs @@ -275,7 +275,7 @@ impl Of { pub(super) fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Result { match ordinal <= 366 { true => Ok(Of((ordinal << 4) | u32::from(flags))), - false => Err(Error::InvalidDate), + false => Err(Error::ParsingOutOfRange), } } @@ -376,7 +376,7 @@ impl Mdf { pub(super) fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Result { match month <= 12 && day <= 31 { true => Ok(Mdf((month << 9) | (day << 4) | u32::from(flags))), - false => Err(Error::InvalidDate), + false => Err(Error::ParsingOutOfRange), } } @@ -408,7 +408,7 @@ impl Mdf { #[inline] pub(super) fn with_month(&self, month: u32) -> Result { if month > 12 { - return Err(Error::InvalidDate); + return Err(Error::ParsingOutOfRange); } let Mdf(mdf) = *self; @@ -424,7 +424,7 @@ impl Mdf { #[inline] pub(super) fn with_day(&self, day: u32) -> Result { if day > 31 { - return Err(Error::InvalidDate); + return Err(Error::ParsingOutOfRange); } let Mdf(mdf) = *self; From d1bd74e77a623b5cf66a01b7a69470a3dd0c25c2 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 23 Mar 2023 15:59:22 +0100 Subject: [PATCH 04/54] Finished regular tests, doctests missing --- src/error.rs | 34 ++++++++++++++-------- src/naive/date.rs | 6 ++-- src/naive/datetime/tests.rs | 12 ++++---- src/offset/local/mod.rs | 56 +++++++++++++------------------------ tests/dateutils.rs | 47 ++++++++++--------------------- 5 files changed, 65 insertions(+), 90 deletions(-) diff --git a/src/error.rs b/src/error.rs index ebda37e6d6..c5e89fb5af 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,7 @@ // This is a part of Chrono. // See README.md and LICENSE.txt for details. -use core::{fmt, num::{TryFromIntError, ParseIntError}, str::Utf8Error}; +use core::fmt; use std::time::SystemTimeError; /// Chrono error @@ -70,7 +70,7 @@ pub enum Error { /// Out of range error OutOfRange(&'static str), /// Integer parsing error - ParseInt(ParseIntError), + ParseInt(core::num::ParseIntError), /// Date time projection error ProjectDateTime(&'static str), /// System time error @@ -84,10 +84,13 @@ pub enum Error { /// Unsupported TZ string UnsupportedTzString(&'static str), /// UTF-8 error - Utf8(Utf8Error), + Utf8(core::str::Utf8Error), /// Error when tryint to convert from int - TryFromIntError(TryFromIntError), + TryFromIntError, + + /// Error when tryint to convert a string to utf8 + FromUtf8Error, /// Unexpected end of file UnexpectedEOF, @@ -136,7 +139,8 @@ impl fmt::Display for Error { Error::UnsupportedTzString(error) => write!(f, "unsupported TZ string: {}", error), Error::Utf8(error) => error.fmt(f), - Error::TryFromIntError(error) => error.fmt(f), + Error::TryFromIntError => write!(f, "failed to convert int"), + Error::FromUtf8Error => write!(f, "failed to convert utf8"), Error::UnexpectedEOF => write!(f, "unexpected end of file"), Error::InvalidData => write!(f, "invalid data"), @@ -155,9 +159,15 @@ impl std::error::Error for Error { } } -impl From for Error { - fn from(error: TryFromIntError) -> Self { - Error::TryFromIntError(error) +impl From for Error { + fn from(_: std::string::FromUtf8Error) -> Self { + Error::FromUtf8Error + } +} + +impl From for Error { + fn from(_: core::num::TryFromIntError) -> Self { + Error::TryFromIntError } } @@ -167,8 +177,8 @@ impl From for Error { } } -impl From for Error { - fn from(error: ParseIntError) -> Self { +impl From for Error { + fn from(error: core::num::ParseIntError) -> Self { Error::ParseInt(error) } } @@ -179,8 +189,8 @@ impl From for Error { } } -impl From for Error { - fn from(error: Utf8Error) -> Self { +impl From for Error { + fn from(error: core::str::Utf8Error) -> Self { Error::Utf8(error) } } \ No newline at end of file diff --git a/src/naive/date.rs b/src/naive/date.rs index ea6ee89487..025dbb1c9d 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -415,7 +415,7 @@ impl NaiveDate { } } } else { - Err(Error::InvalidDate) + Err(Error::ParsingOutOfRange) } } @@ -2803,7 +2803,7 @@ mod tests { 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"), + NaiveDate::parse_from_str("2015-W06-1=2015-033", "%G-W%V-%u=%Y-%j"), Ok(ymd!(2015, 2, 2)) ); assert_eq!( @@ -2853,7 +2853,7 @@ mod tests { assert_eq!(ymd!(-12345, 1, 1).format("%Y").to_string(), "-12345"); // corner cases - assert_eq!(ymd!(2007, 12, 31).format("%G,%g,%U,%W,%V").to_string(), "2008,08,53,53,01"); + assert_eq!(ymd!(2007, 12, 31).format("%G,%g,%U,%W,%V").to_string(), "2008,08,52,53,01"); assert_eq!(ymd!(2010, 1, 3).format("%G,%g,%U,%W,%V").to_string(), "2009,09,01,00,53"); } diff --git a/src/naive/datetime/tests.rs b/src/naive/datetime/tests.rs index fb7c36d752..85b606d650 100644 --- a/src/naive/datetime/tests.rs +++ b/src/naive/datetime/tests.rs @@ -294,7 +294,7 @@ fn test_datetime_parse_from_str() { 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"), + 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!( @@ -310,23 +310,23 @@ 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).unwrap()) + ymdhms(2015, 9, 5, 23, 56, 4) ); assert_eq!( NaiveDateTime::parse_from_str("1283929614.1234", "%s.%f"), - Ok(ymdhmsn(2010, 9, 8, 7, 6, 54, 1234).unwrap()) + ymdhmsn(2010, 9, 8, 7, 6, 54, 1234) ); assert_eq!( NaiveDateTime::parse_from_str("1441497364.649", "%s%.3f"), - Ok(ymdhmsn(2015, 9, 5, 23, 56, 4, 649000000).unwrap()) + ymdhmsn(2015, 9, 5, 23, 56, 4, 649000000) ); assert_eq!( NaiveDateTime::parse_from_str("1497854303.087654", "%s%.6f"), - Ok(ymdhmsn(2017, 6, 19, 6, 38, 23, 87654000).unwrap()) + ymdhmsn(2017, 6, 19, 6, 38, 23, 87654000) ); assert_eq!( NaiveDateTime::parse_from_str("1437742189.918273645", "%s%.9f"), - Ok(ymdhmsn(2015, 7, 24, 12, 49, 49, 918273645).unwrap()) + ymdhmsn(2015, 7, 24, 12, 49, 49, 918273645) ); } diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 0807a05173..d63e49172d 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -185,7 +185,7 @@ impl TimeZone for Local { mod tests { use super::Local; use crate::offset::TimeZone; - use crate::{Datelike, TimeDelta}; + use crate::{Datelike, Error, TimeDelta}; #[cfg(unix)] use crate::{NaiveDate, NaiveDateTime, Timelike}; @@ -193,7 +193,7 @@ mod tests { 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())) @@ -201,43 +201,24 @@ mod tests { .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); + let date_command_str = String::from_utf8(output.stdout)?; + + match Local.from_local_datetime( + &NaiveDate::from_ymd(dt.year(), dt.month(), dt.day())?.and_hms(dt.hour(), 5, 1)? + ) { + // compare a legit date to the "date" output + Ok(crate::LocalResult::Single(dt)) => assert_eq!(format!("{}\n", dt), date_command_str), + // "date" command always returns a given time when it is ambiguous (dt.earliest()) + Ok(crate::LocalResult::Ambiguous(dt1, _dt2)) => assert_eq!(format!("{}\n", dt1), date_command_str), + // "date" command returns an empty string for an invalid time (e.g. spring forward gap due to DST) + Err(_) => assert_eq!(date_command_str, ""), + } + Ok(()) } #[test] #[cfg(unix)] - fn try_verify_against_date_command() { + fn try_verify_against_date_command() -> Result<(), Error> { let date_path = "/usr/bin/date"; if !path::Path::new(date_path).exists() { @@ -245,7 +226,7 @@ mod tests { // avoid running this on macOS, which has path /bin/date // as the required CLI arguments are not present in the // macOS build. - return; + return Ok(()); } let mut date = NaiveDate::from_ymd(1975, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); @@ -255,11 +236,12 @@ mod tests { || (2020..=2022).contains(&date.year()) || (2073..=2077).contains(&date.year()) { - verify_against_date_command_local(date_path, date); + verify_against_date_command_local(date_path, date)?; } date += crate::TimeDelta::hours(1); } + Ok(()) } #[test] diff --git a/tests/dateutils.rs b/tests/dateutils.rs index 8d7fa6587f..19ab2744db 100644 --- a/tests/dateutils.rs +++ b/tests/dateutils.rs @@ -13,42 +13,24 @@ fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) -> R .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 - // .with_ymd_and_hms(year, month, day, 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 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); - }, + let date_command_str = String::from_utf8(output.stdout)?; + + match Local.from_local_datetime( + &NaiveDate::from_ymd(dt.year(), dt.month(), dt.day())?.and_hms(dt.hour(), 5, 1)? + ) { + // compare a legit date to the "date" output + Ok(chrono::LocalResult::Single(dt)) => assert_eq!(format!("{}\n", dt), date_command_str), + // "date" command always returns a given time when it is ambiguous (dt.earliest()) + Ok(chrono::LocalResult::Ambiguous(dt1, _dt2)) => assert_eq!(format!("{}\n", dt1), date_command_str), + // "date" command returns an empty string for an invalid time (e.g. spring forward gap due to DST) + Err(_) => assert_eq!(date_command_str, ""), } Ok(()) } #[test] #[cfg(unix)] -fn try_verify_against_date_command() { +fn try_verify_against_date_command() -> Result<(), Error> { let date_path = "/usr/bin/date"; if !path::Path::new(date_path).exists() { @@ -56,7 +38,7 @@ fn try_verify_against_date_command() { // avoid running this on macOS, which has path /bin/date // as the required CLI arguments are not present in the // macOS build. - return; + return Ok(()); } let mut date = NaiveDate::from_ymd(1975, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); @@ -66,11 +48,12 @@ fn try_verify_against_date_command() { || (2020..=2022).contains(&date.year()) || (2073..=2077).contains(&date.year()) { - verify_against_date_command_local(date_path, date); + verify_against_date_command_local(date_path, date)?; } date += chrono::TimeDelta::hours(1); } + Ok(()) } #[cfg(target_os = "linux")] From 63c3494a448079acd60fa21bcf1acfda227ad094 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 23 Mar 2023 19:32:54 +0100 Subject: [PATCH 05/54] Fixed all tests --- src/datetime/mod.rs | 10 ++--- src/lib.rs | 2 +- src/month.rs | 1 - src/naive/date.rs | 24 +++++----- src/naive/datetime/mod.rs | 95 ++++++++++++++++++--------------------- src/naive/time/mod.rs | 12 +++-- 6 files changed, 66 insertions(+), 78 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 28f80da624..4e08d9cb76 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -125,8 +125,8 @@ impl DateTime { /// 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(2000, 1, 12)?.unwrap().and_hms(10, 0, 0).unwrap()?; + /// let timezone_east = FixedOffset::east(8 * 60 * 60)?; + /// let naivedatetime_east = NaiveDate::from_ymd(2000, 1, 12)?.and_hms(10, 0, 0)?; /// let datetime_east = DateTime::::from_local(naivedatetime_east, timezone_east); /// /// let timezone_west = FixedOffset::west(7 * 60 * 60)?; @@ -651,9 +651,9 @@ impl DateTime { /// ```rust /// use chrono::{DateTime, TimeZone, Utc}; /// - /// let dt = DateTime::::parse_from_str( - /// "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))); + /// let dt = DateTime::::parse_from_str("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)?)); + /// # Ok::<_, chrono::Error>(()) /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> Result, Error> { DateTime::::parse_from_str(s, fmt).map(|result| result.into()) diff --git a/src/lib.rs b/src/lib.rs index 3dd2afe634..0147eba650 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -301,7 +301,7 @@ //! //! ```rust //! // We need the trait in scope to use Utc::timestamp(). -//! use chrono::{DateTime, FixedOffset, FixedOffset, TimeZone, Utc}; +//! use chrono::{DateTime, FixedOffset, TimeZone, Utc}; //! //! // Construct a datetime from epoch: //! let dt = Utc.timestamp(1_500_000_000, 0)?; diff --git a/src/month.rs b/src/month.rs index b6d2d1428e..f3234f6947 100644 --- a/src/month.rs +++ b/src/month.rs @@ -13,7 +13,6 @@ use crate::OutOfRange; /// It is possible to convert from a date to a month independently. /// /// ``` -/// # use std::convert::TryFrom; /// use chrono::prelude::*; /// use std::convert::TryFrom; /// let date = Utc.ymd(2019, 10, 28)?.and_hms(9, 10, 11)?; diff --git a/src/naive/date.rs b/src/naive/date.rs index 025dbb1c9d..ee654806cc 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -580,11 +580,11 @@ impl NaiveDate { /// # use chrono::{NaiveDate, Months}; /// assert_eq!( /// NaiveDate::from_ymd(2022, 2, 20)?.checked_add_months(Months::new(6)), - /// Some(NaiveDate::from_ymd(2022, 8, 20)?) + /// Ok(NaiveDate::from_ymd(2022, 8, 20)?) /// ); /// assert_eq!( /// NaiveDate::from_ymd(2022, 7, 31)?.checked_add_months(Months::new(2)), - /// Some(NaiveDate::from_ymd(2022, 9, 30)?) + /// Ok(NaiveDate::from_ymd(2022, 9, 30)?) /// ); /// # Ok::<_, chrono::Error>(()) /// ``` @@ -1008,7 +1008,7 @@ impl NaiveDate { /// /// let d = NaiveDate::from_ymd(2015, 9, 5)?; /// assert_eq!(d.checked_add_signed(TimeDelta::days(40)), - /// Ok(NaiveDate::from_ymd(2015, 10, 15).unwrap()?)); + /// Ok(NaiveDate::from_ymd(2015, 10, 15)?)); /// assert_eq!(d.checked_add_signed(TimeDelta::days(-40)), /// Ok(NaiveDate::from_ymd(2015, 7, 27)?)); /// assert!(d.checked_add_signed(TimeDelta::days(1_000_000_000)).is_err()); @@ -1616,10 +1616,10 @@ impl Datelike for NaiveDate { /// NaiveDate::from_ymd(2015, 3, 1)?); /// assert!(NaiveDate::from_ymd(2015, 1, 1)?.with_ordinal(366).is_err()); // 2015 had only 365 days /// - /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.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()?); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal(60)?, + /// NaiveDate::from_ymd(2016, 2, 29)?); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal(366)?, + /// NaiveDate::from_ymd(2016, 12, 31)?); /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] @@ -1640,10 +1640,10 @@ impl Datelike for NaiveDate { /// NaiveDate::from_ymd(2015, 3, 1)?); /// assert!(NaiveDate::from_ymd(2015, 1, 1)?.with_ordinal0(365).is_err()); // 2015 had only 365 days /// - /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.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()?); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal0(59)?, + /// NaiveDate::from_ymd(2016, 2, 29)?); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal0(365)?, + /// NaiveDate::from_ymd(2016, 12, 31)?); /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] @@ -2039,7 +2039,7 @@ impl str::FromStr for NaiveDate { /// ``` impl Default for NaiveDate { fn default() -> Self { - NaiveDate::MIN + NaiveDate::from_ymd(1970, 1, 1).unwrap() } } diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index a006b38d61..d25f9b79c2 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -149,14 +149,13 @@ impl NaiveDateTime { /// use chrono::NaiveDateTime; /// let timestamp_millis: i64 = 1662921288000; //Sunday, September 11, 2022 6:34:48 PM /// let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis); - /// assert!(naive_datetime.is_some()); - /// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis()); + /// assert_eq!(timestamp_millis, naive_datetime?.timestamp_millis()); /// /// // Negative timestamps (before the UNIX epoch) are supported as well. /// let timestamp_millis: i64 = -2208936075000; //Mon Jan 01 1900 14:38:45 GMT+0000 /// let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis); - /// assert!(naive_datetime.is_some()); - /// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis()); + /// assert_eq!(timestamp_millis, naive_datetime?.timestamp_millis()); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] pub fn from_timestamp_millis(millis: i64) -> Result { @@ -175,14 +174,13 @@ impl NaiveDateTime { /// use chrono::NaiveDateTime; /// let timestamp_micros: i64 = 1662921288000000; //Sunday, September 11, 2022 6:34:48 PM /// let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros); - /// assert!(naive_datetime.is_some()); - /// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros()); + /// assert_eq!(timestamp_micros, naive_datetime?.timestamp_micros()); /// /// // Negative timestamps (before the UNIX epoch) are supported as well. /// let timestamp_micros: i64 = -2208936075000000; //Mon Jan 01 1900 14:38:45 GMT+0000 /// let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros); - /// assert!(naive_datetime.is_some()); - /// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros()); + /// assert_eq!(timestamp_micros, naive_datetime?.timestamp_micros()); + /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] pub fn from_timestamp_micros(micros: i64) -> Result { @@ -364,10 +362,10 @@ impl NaiveDateTime { /// let dt = NaiveDate::from_ymd(1970, 1, 1)?.and_hms_milli(0, 0, 1, 980)?; /// assert_eq!(dt.timestamp(), 1); /// - /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.unwrap().and_hms(1, 46, 40).unwrap()?; + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms(1, 46, 40)?; /// assert_eq!(dt.timestamp(), 1_000_000_000); /// - /// let dt = NaiveDate::from_ymd(1969, 12, 31)?.unwrap().and_hms(23, 59, 59).unwrap()?; + /// let dt = NaiveDate::from_ymd(1969, 12, 31)?.and_hms(23, 59, 59)?; /// assert_eq!(dt.timestamp(), -1); /// /// let dt = NaiveDate::from_ymd(-1, 1, 1)?.and_hms(0, 0, 0)?; @@ -400,7 +398,7 @@ impl NaiveDateTime { /// let dt = NaiveDate::from_ymd(1970, 1, 1)?.and_hms_milli(0, 0, 1, 444)?; /// assert_eq!(dt.timestamp_millis(), 1_444); /// - /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.unwrap().and_hms_milli_opt(1, 46, 40, 555).unwrap()?; + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_milli(1, 46, 40, 555)?; /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); /// /// let dt = NaiveDate::from_ymd(1969, 12, 31)?.and_hms_milli(23, 59, 59, 100)?; @@ -565,27 +563,21 @@ impl NaiveDateTime { /// /// 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)?)); + /// Ok(hms(3, 5, 7)?)); /// assert_eq!(hms(3, 5, 7)?.checked_add_signed(TimeDelta::seconds(1)), - /// Some(hms(3, 5, 8)?)); + /// Ok(hms(3, 5, 8)?)); /// assert_eq!(hms(3, 5, 7)?.checked_add_signed(TimeDelta::seconds(-1)), - /// Some(hms(3, 5, 6)?)); + /// Ok(hms(3, 5, 6)?)); /// assert_eq!(hms(3, 5, 7)?.checked_add_signed(TimeDelta::seconds(3600 + 60)), - /// Some(hms(4, 6, 7)?)); + /// Ok(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)?)); + /// Ok(NaiveDate::from_ymd(2016, 7, 9)?.and_hms(3, 5, 7)?)); /// /// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli); /// assert_eq!(hmsm(3, 5, 7, 980)?.checked_add_signed(TimeDelta::milliseconds(450)), - /// Some(hmsm(3, 5, 8, 430)?)); - /// # Ok::<_, chrono::Error>(()) - /// ``` - /// - /// Overflow returns `Err(Error)`. - /// - /// ``` - /// 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(hmsm(3, 5, 8, 430)?)); + /// + /// assert!(NaiveDate::from_ymd(2016, 7, 8)?.and_hms(3, 5, 7)?.checked_add_signed(TimeDelta::days(1_000_000_000)).is_err()); /// # Ok::<_, chrono::Error>(()) /// ``` /// @@ -598,19 +590,19 @@ impl NaiveDateTime { /// # 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)?)); + /// Ok(hmsm(3, 5, 59, 1_300)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(-500)), - /// Some(hmsm(3, 5, 59, 800)?)); + /// Ok(hmsm(3, 5, 59, 800)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(500)), - /// Some(hmsm(3, 5, 59, 1_800)?)); + /// Ok(hmsm(3, 5, 59, 1_800)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(800)), - /// Some(hmsm(3, 6, 0, 100)?)); + /// Ok(hmsm(3, 6, 0, 100)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(10)), - /// Some(hmsm(3, 6, 9, 300)?)); + /// Ok(hmsm(3, 6, 9, 300)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(-10)), - /// Some(hmsm(3, 5, 50, 300)?)); + /// Ok(hmsm(3, 5, 50, 300)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::days(1)), - /// Some(from_ymd(2016, 7, 9)?.and_hms_milli(3, 5, 59, 300)?)); + /// Ok(from_ymd(2016, 7, 9)?.and_hms_milli(3, 5, 59, 300)?)); /// # Ok::<_, chrono::Error>(()) /// ``` pub fn checked_add_signed(self, rhs: TimeDelta) -> Result { @@ -638,7 +630,7 @@ impl NaiveDateTime { /// assert_eq!( /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)? /// .checked_add_months(Months::new(1)), - /// Ok(NaiveDate::from_ymd(2014, 2, 1)?.unwrap().and_hms(1, 0, 0).unwrap()?) + /// Ok(NaiveDate::from_ymd(2014, 2, 1)?.and_hms(1, 0, 0)?) /// ); /// /// assert!( @@ -669,21 +661,21 @@ impl NaiveDateTime { /// let d = NaiveDate::from_ymd(2016, 7, 8)?; /// /// assert_eq!(d.and_hms(3, 5, 7)?.checked_sub_signed(TimeDelta::zero()), - /// Some(d.and_hms(3, 5, 7)?)); + /// Ok(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)?)); + /// Ok(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)?)); + /// Ok(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)?)); + /// Ok(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)?)); + /// Ok(NaiveDate::from_ymd(2016, 7, 7)?.and_hms(3, 5, 7)?)); /// /// 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)?)); + /// Ok(d.and_hms_milli(3, 5, 6, 780)?)); /// /// 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()); + /// assert!(dt.checked_sub_signed(TimeDelta::days(1_000_000_000)).is_err()); /// # Ok::<_, chrono::Error>(()) /// ``` /// @@ -696,15 +688,15 @@ impl NaiveDateTime { /// # 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)?)); + /// Ok(hmsm(3, 5, 59, 1_300)?)); /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(200)), - /// Some(hmsm(3, 5, 59, 1_100)?)); + /// Ok(hmsm(3, 5, 59, 1_100)?)); /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(500)), - /// Some(hmsm(3, 5, 59, 800)?)); + /// Ok(hmsm(3, 5, 59, 800)?)); /// assert_eq!(leap.checked_sub_signed(TimeDelta::seconds(60)), - /// Some(hmsm(3, 5, 0, 300)?)); + /// Ok(hmsm(3, 5, 0, 300)?)); /// assert_eq!(leap.checked_sub_signed(TimeDelta::days(1)), - /// Some(from_ymd(2016, 7, 7)?.and_hms_milli(3, 6, 0, 300)?)); + /// Ok(from_ymd(2016, 7, 7)?.and_hms_milli(3, 6, 0, 300)?)); /// # Ok::<_, chrono::Error>(()) /// ``` pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result { @@ -730,15 +722,14 @@ impl NaiveDateTime { /// use chrono::{Months, NaiveDate, NaiveDateTime}; /// /// assert_eq!( - /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)? - /// .checked_sub_months(Months::new(1)), - /// Some(NaiveDate::from_ymd(2013, 12, 1)?.unwrap().and_hms(1, 0, 0).unwrap()?) + /// NaiveDate::from_ymd(2014, 1, 1)?.and_hms(1, 0, 0)?.checked_sub_months(Months::new(1)), + /// Ok(NaiveDate::from_ymd(2013, 12, 1)?.and_hms(1, 0, 0)?) /// ); /// /// 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() + /// .is_err() /// ); /// # Ok::<_, chrono::Error>(()) /// ``` @@ -1634,8 +1625,8 @@ impl SubAssign for NaiveDateTime { /// NaiveDate::from_ymd(2013, 02, 01)?.and_hms(01, 00, 00)? /// ); /// assert_eq!( -/// 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()? +/// NaiveDate::from_ymd(2014, 01, 01)?.and_hms(00, 02, 00)? - Months::new(12), +/// NaiveDate::from_ymd(2013, 01, 01)?.and_hms(00, 02, 00)? /// ); /// assert_eq!( /// NaiveDate::from_ymd(2014, 01, 01)?.and_hms(00, 00, 03)? - Months::new(13), @@ -1850,7 +1841,7 @@ impl str::FromStr for NaiveDateTime { /// ``` impl Default for NaiveDateTime { fn default() -> Self { - NaiveDateTime::UNIX_EPOCH + NaiveDateTime::from_timestamp(0, 0).unwrap() } } diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index cb96e5a3aa..a65f8cc719 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -181,6 +181,7 @@ mod tests; /// 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")?, dt); +/// # Ok::<_, chrono::Error>(()) /// ``` /// /// Since Chrono alone cannot determine any existence of leap seconds, @@ -960,12 +961,9 @@ impl Timelike for NaiveTime { /// ``` /// use chrono::{NaiveTime, Timelike}; /// - /// assert_eq!(NaiveTime::from_hms(1, 2, 3)?.num_seconds_from_midnight(), - /// 3723); - /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?.unwrap().num_seconds_from_midnight(), - /// 86164); - /// assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000)?.num_seconds_from_midnight(), - /// 86399); + /// assert_eq!(NaiveTime::from_hms(1, 2, 3)?.num_seconds_from_midnight(), 3723); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?.num_seconds_from_midnight(), 86164); + /// assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000)?.num_seconds_from_midnight(), 86399); /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] @@ -1268,7 +1266,7 @@ impl fmt::Display for NaiveTime { /// let t = NaiveTime::from_hms(23, 56, 4)?; /// assert_eq!("23:56:04".parse::(), Ok(t)); /// -/// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).unwrap()?; +/// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; /// assert_eq!("23:56:4.012345678".parse::(), Ok(t)); /// /// let t = NaiveTime::from_hms_nano(23, 59, 59, 1_234_567_890)?; // leap second From d27efa6531e7ad4cf2604b3b75f67b4bcaebf736 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 23 Mar 2023 20:56:46 +0100 Subject: [PATCH 06/54] Readded lost locales --- src/naive/date.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/naive/date.rs b/src/naive/date.rs index ee654806cc..9bcf2efdae 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -13,6 +13,10 @@ 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, Parsed, StrftimeItems}; From 5b1b7113dd6489b165c9fac95a78aea8795d5d5f Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 23 Mar 2023 21:32:45 +0100 Subject: [PATCH 07/54] arbitiary --- src/format/strftime.rs | 1 + src/naive/date.rs | 2 +- src/naive/datetime/mod.rs | 12 +++++------- src/naive/time/mod.rs | 6 +++--- src/offset/fixed.rs | 2 +- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/format/strftime.rs b/src/format/strftime.rs index 893010a426..829c035dd5 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -743,6 +743,7 @@ fn test_strftime_docs() { #[test] fn test_strftime_docs_localized() { use crate::{FixedOffset, NaiveDate}; + use crate::offset::TimeZone; let dt = FixedOffset::east(34200) .unwrap() diff --git a/src/naive/date.rs b/src/naive/date.rs index 9bcf2efdae..1402541d34 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -204,7 +204,7 @@ impl arbitrary::Arbitrary<'_> for NaiveDate { let year = u.int_in_range(MIN_YEAR..=MAX_YEAR)?; let max_days = YearFlags::from_year(year).ndays(); let ord = u.int_in_range(1..=max_days)?; - NaiveDate::from_yo_opt(year, ord).ok_or(arbitrary::Error::IncorrectFormat) + NaiveDate::from_yo(year, ord).map_err(|_| arbitrary::Error::IncorrectFormat) } } diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index d25f9b79c2..5e4192bb82 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -1892,25 +1892,23 @@ where ); assert_eq!( 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() + NaiveDate::from_ymd(2016, 7, 8).unwrap().and_hms_milli(9, 10, 48, 90).unwrap() ); assert_eq!( from_str(r#""2014-07-24T12:34:06""#).unwrap(), - NaiveDate::from_ymd(2014, 7, 24).unwrap().unwrap().and_hms(12, 34, 6).unwrap().unwrap() + NaiveDate::from_ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() ); assert_eq!( 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() + NaiveDate::from_ymd(0, 1, 1).unwrap().and_hms_milli(0, 0, 59, 1_000).unwrap() ); assert_eq!( from_str(r#""0-1-1T0:0:60""#).unwrap(), - NaiveDate::from_ymd(0, 1, 1).unwrap().unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap().unwrap() + NaiveDate::from_ymd(0, 1, 1).unwrap().and_hms_milli(0, 0, 59, 1_000).unwrap() ); assert_eq!( 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() + NaiveDate::from_ymd(-1, 12, 31).unwrap().and_hms_nano(23, 59, 59, 7).unwrap() ); assert_eq!( from_str(r#""-262144-01-01T00:00:00""#).unwrap(), diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index a65f8cc719..c52b92e32c 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -198,7 +198,7 @@ impl arbitrary::Arbitrary<'_> for NaiveTime { fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result { let secs = u.int_in_range(0..=86_399)?; let nano = u.int_in_range(0..=1_999_999_999)?; - let time = NaiveTime::from_num_seconds_from_midnight_opt(secs, nano) + let time = NaiveTime::from_num_seconds_from_midnight(secs, nano) .expect("Could not generate a valid chrono::NaiveTime. It looks like implementation of Arbitrary for NaiveTime is erroneous."); Ok(time) } @@ -1379,11 +1379,11 @@ where 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""#).unwrap(), - NaiveTime::from_hms_micro_opt(12, 34, 56, 789).unwrap().unwrap() + NaiveTime::from_hms_micro(12, 34, 56, 789).unwrap() ); assert_eq!( from_str(r#""23:59:60.999999999""#).unwrap(), - NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999).unwrap().unwrap() + NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999).unwrap() ); assert_eq!( from_str(r#""23:59:60.9999999999997""#).unwrap(), // excess digits are ignored diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index e9792f77b8..e7231e444d 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -153,7 +153,7 @@ impl fmt::Display for FixedOffset { impl arbitrary::Arbitrary<'_> for FixedOffset { fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result { let secs = u.int_in_range(-86_399..=86_399)?; - let fixed_offset = FixedOffset::east_opt(secs) + let fixed_offset = FixedOffset::east(secs) .expect("Could not generate a valid chrono::FixedOffset. It looks like implementation of Arbitrary for FixedOffset is erroneous."); Ok(fixed_offset) } From 6eb7743be556cd78544ec4395b07dbb491dd716a Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 23 Mar 2023 21:40:28 +0100 Subject: [PATCH 08/54] cargo fmt --- benches/chrono.rs | 4 +- src/datetime/mod.rs | 12 +- src/datetime/tests.rs | 4 +- src/error.rs | 3 +- src/format/parse.rs | 70 +++++++---- src/format/parsed.rs | 210 ++++++++++++++++++++++++------- src/format/strftime.rs | 2 +- src/naive/date.rs | 24 ++-- src/naive/datetime/mod.rs | 2 +- src/naive/datetime/tests.rs | 29 ++--- src/naive/internals.rs | 4 +- src/naive/time/tests.rs | 76 ++--------- src/offset/local/mod.rs | 13 +- src/offset/local/tz_info/mod.rs | 1 - src/offset/local/tz_info/rule.rs | 2 +- src/offset/local/unix.rs | 1 - src/round.rs | 2 +- tests/dateutils.rs | 8 +- 18 files changed, 286 insertions(+), 181 deletions(-) diff --git a/benches/chrono.rs b/benches/chrono.rs index dcacb796c2..e9a7cc3875 100644 --- a/benches/chrono.rs +++ b/benches/chrono.rs @@ -37,7 +37,7 @@ fn bench_datetime_from_str(c: &mut Criterion) { fn bench_datetime_to_rfc2822(c: &mut Criterion) { 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)? + &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())); } @@ -45,7 +45,7 @@ fn bench_datetime_to_rfc2822(c: &mut Criterion) { fn bench_datetime_to_rfc3339(c: &mut Criterion) { 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)? + &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())); } diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 4e08d9cb76..b1eff54f7c 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -366,21 +366,27 @@ impl DateTime { /// /// See [`NaiveDate::checked_sub_months`] for more details on behavior pub fn checked_sub_months(self, rhs: Months) -> Result { - self.naive_local().checked_sub_months(rhs)?.and_local_timezone(Tz::from_offset(&self.offset)) + 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 `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)) + 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 `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)) + self.datetime + .checked_sub_days(days)? + .and_local_timezone(TimeZone::from_offset(&self.offset)) } /// Subtracts another `DateTime` from the current date and time. diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index d0b80774a5..69bd3e794c 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1,14 +1,14 @@ 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::TimeDelta; use crate::NaiveDate; +use crate::NaiveTime; +use crate::TimeDelta; macro_rules! ymd { ($year:expr, $month:expr, $day:expr) => { diff --git a/src/error.rs b/src/error.rs index c5e89fb5af..757792b939 100644 --- a/src/error.rs +++ b/src/error.rs @@ -112,7 +112,6 @@ impl fmt::Display for Error { #[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"), @@ -193,4 +192,4 @@ impl From for Error { fn from(error: core::str::Utf8Error) -> Self { Error::Utf8(error) } -} \ No newline at end of file +} diff --git a/src/format/parse.rs b/src/format/parse.rs index 541bc1b165..9380b0de29 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -12,7 +12,7 @@ use core::usize; use super::scan; use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric, Pad, Parsed}; -use crate::{Error, DateTime, FixedOffset, Weekday}; +use crate::{DateTime, Error, FixedOffset, Weekday}; fn set_weekday_with_num_days_from_sunday(p: &mut Parsed, v: i64) -> Result<(), Error> { p.set_weekday(match v { @@ -1360,12 +1360,27 @@ fn test_rfc2822() { 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("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)\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 @@ -1375,13 +1390,14 @@ fn test_rfc2822() { 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 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! + 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)] @@ -1457,31 +1473,37 @@ fn test_rfc3339() { // 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("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.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("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("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 - + 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 79b6f90823..90ce342c55 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -10,7 +10,7 @@ use num_integer::div_rem; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; use crate::offset::{FixedOffset, Offset, TimeZone}; -use crate::{Error, DateTime, Datelike, TimeDelta, Timelike, Weekday}; +use crate::{DateTime, Datelike, Error, TimeDelta, Timelike, Weekday}; /// Parsed parts of date and time. There are two classes of methods: /// @@ -129,7 +129,10 @@ impl Parsed { /// Tries to set the [`year`](#structfield.year) field from given value. #[inline] pub fn set_year(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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. @@ -138,7 +141,10 @@ impl Parsed { if value < 0 { return Err(Error::ParsingOutOfRange); } - set_if_consistent(&mut self.year_div_100, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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. @@ -147,13 +153,19 @@ impl Parsed { if value < 0 { return Err(Error::ParsingOutOfRange); } - set_if_consistent(&mut self.year_mod_100, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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. @@ -183,25 +195,37 @@ impl Parsed { /// Tries to set the [`month`](#structfield.month) field from given value. #[inline] pub fn set_month(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.month, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.week_from_sun, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.week_from_mon, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.isoweek, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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. @@ -213,13 +237,19 @@ impl Parsed { /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value. #[inline] pub fn set_ordinal(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.ordinal, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.day, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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. @@ -252,19 +282,28 @@ impl Parsed { /// Tries to set the [`minute`](#structfield.minute) field from given value. #[inline] pub fn set_minute(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.minute, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.second, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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) -> Result<(), Error> { - set_if_consistent(&mut self.nanosecond, u32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + 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. @@ -276,7 +315,10 @@ impl Parsed { /// Tries to set the [`offset`](#structfield.offset) field from given value. #[inline] pub fn set_offset(&mut self, value: i64) -> Result<(), Error> { - set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?) + set_if_consistent( + &mut self.offset, + i32::try_from(value).map_err(|_| Error::ParsingOutOfRange)?, + ) } /// Returns a parsed naive date out of given fields. @@ -427,8 +469,7 @@ impl Parsed { 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)))?; + let date = newyear.checked_add_signed(TimeDelta::days(i64::from(ndays)))?; if date.year() != year { return Err(Error::ParsingOutOfRange); } // early exit for correct error @@ -470,8 +511,7 @@ impl Parsed { (_, Some(isoyear), &Parsed { isoweek: Some(isoweek), weekday: Some(weekday), .. }) => { // ISO year, week, day of the week - let date = - NaiveDate::from_isoywd(isoyear, isoweek, weekday)?; + let date = NaiveDate::from_isoywd(isoyear, isoweek, weekday)?; (verify_ymd(date) && verify_ordinal(date), date) } @@ -548,14 +588,15 @@ impl Parsed { 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) + && !(datetime.nanosecond() >= 1_000_000_000 + && given_timestamp == timestamp + 1) { return Err(Error::ParsingImpossible); } } Ok(datetime) - }, + } // If either is problematic, fallback on the timestamp // TODO, the condition for reconstruction of date and time fields from timestamp is unclear @@ -568,7 +609,11 @@ impl Parsed { } } - fn reconstruct_from_timestamp(&self, mut timestamp: i64, offset: i32) -> Result { + fn reconstruct_from_timestamp( + &self, + mut timestamp: i64, + offset: i32, + ) -> Result { timestamp = timestamp.checked_add(i64::from(offset)).ok_or(Error::ParsingOutOfRange)?; let mut datetime = NaiveDateTime::from_timestamp(timestamp, 0)?; @@ -654,8 +699,8 @@ impl Parsed { match self.offset { Some(so) => match dt.offset().fix().local_minus_utc() == so { true => Ok(dt), - false => Err(Error::ParsingImpossible) - } + false => Err(Error::ParsingImpossible), + }, None => Ok(dt), } } @@ -666,8 +711,8 @@ mod tests { use super::Parsed; use crate::naive::{NaiveDate, NaiveTime}; use crate::offset::{FixedOffset, TimeZone, Utc}; - use crate::{Datelike, Error}; use crate::Weekday::*; + use crate::{Datelike, Error}; macro_rules! ymd { ($year:expr, $month:expr, $day:expr) => { @@ -762,9 +807,18 @@ mod tests { 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, 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))); @@ -798,9 +852,15 @@ mod tests { parse!(year_div_100: 19, year_mod_100: 100, month: 1, day: 1), Err(Error::ParsingOutOfRange) ); - assert_eq!(parse!(year_div_100: 19, year_mod_100: -1, month: 1, day: 1), Err(Error::ParsingOutOfRange)); + 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)); + 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, @@ -815,9 +875,15 @@ mod tests { // ymd: conflicting inputs 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_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_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), Ok(ymd!(1984, 1, 1)) @@ -838,15 +904,27 @@ mod tests { parse!(year: -1, year_div_100: -1, year_mod_100: 99, month: 1, day: 1), Err(Error::ParsingOutOfRange) ); - 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)); + 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(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: 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))); @@ -860,9 +938,18 @@ mod tests { 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: 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 @@ -887,7 +974,10 @@ mod tests { 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: 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)); @@ -930,7 +1020,10 @@ mod tests { week_from_sun: 52, week_from_mon: 52), 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(Error::ParsingNotEnough)); + 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,9 +1063,18 @@ mod tests { ); // out-of-range conditions - 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: 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(Error::ParsingOutOfRange) @@ -1079,10 +1181,19 @@ mod tests { // leap seconds #1: partial fields assert_eq!(parse!(second: 59, timestamp: 1_341_100_798), Err(Error::ParsingNotEnough)); - 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_799), + Ok(ymdhms(2012, 6, 30, 23, 59, 59)) + ); assert_eq!(parse!(second: 59, timestamp: 1_341_100_800), Err(Error::ParsingNotEnough)); - assert_eq!(parse!(second: 60, timestamp: 1_341_100_799), Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000))); - assert_eq!(parse!(second: 60, timestamp: 1_341_100_800), Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000))); + assert_eq!( + parse!(second: 60, timestamp: 1_341_100_799), + Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)) + ); + assert_eq!( + parse!(second: 60, timestamp: 1_341_100_800), + Ok(ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)) + ); 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::ParsingNotEnough)); assert_eq!(parse!(second: 60, timestamp: 1_341_100_801), Err(Error::ParsingNotEnough)); @@ -1227,7 +1338,10 @@ mod tests { parse!(Utc; timestamp: 1_420_000_000, offset: 0), 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(Error::ParsingImpossible)); + assert_eq!( + parse!(Utc; timestamp: 1_420_000_000, offset: 32400), + Err(Error::ParsingImpossible) + ); assert_eq!( parse!(FixedOffset::east(32400).unwrap(); timestamp: 1_420_000_000, offset: 0), Err(Error::ParsingImpossible) diff --git a/src/format/strftime.rs b/src/format/strftime.rs index 829c035dd5..c0870a0d12 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -742,8 +742,8 @@ fn test_strftime_docs() { #[cfg(feature = "unstable-locales")] #[test] fn test_strftime_docs_localized() { - use crate::{FixedOffset, NaiveDate}; use crate::offset::TimeZone; + use crate::{FixedOffset, NaiveDate}; let dt = FixedOffset::east(34200) .unwrap() diff --git a/src/naive/date.rs b/src/naive/date.rs index 1402541d34..1daab326c5 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -1024,7 +1024,9 @@ impl NaiveDate { 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 = i32::try_from((cycle as i64).checked_add(rhs.num_days()).ok_or(Error::ParsingOutOfRange)?)?; + 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; @@ -1056,7 +1058,9 @@ impl NaiveDate { 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 = i32::try_from((cycle as i64).checked_sub(rhs.num_days()).ok_or(Error::ParsingOutOfRange)?)?; + 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; @@ -2198,7 +2202,7 @@ mod tests { MIN_YEAR, }; use crate::time_delta::TimeDelta; - use crate::{Datelike, Weekday, Error}; + use crate::{Datelike, Error, Weekday}; use std::{ convert::{TryFrom, TryInto}, i32, u32, @@ -2247,7 +2251,9 @@ mod tests { assert!(ymd!(2022, 8, 3).checked_add_months(Months::new(i32::MAX as u32 + 1)).is_err()); // 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()); + assert!(ymd!(2022, 8, 3) + .checked_sub_months(Months::new((i32::MIN as i64).abs() as u32 + 1)) + .is_err()); // add overflowing year assert!(NaiveDate::MAX.checked_add_months(Months::new(1)).is_err()); @@ -2256,7 +2262,10 @@ mod tests { assert!(NaiveDate::MIN.checked_sub_months(Months::new(1)).is_err()); // sub crossing year 0 boundary - assert_eq!(ymd!(2022, 8, 3).checked_sub_months(Months::new(2050 * 12)),Ok(ymd!(-28, 8, 3))); + assert_eq!( + ymd!(2022, 8, 3).checked_sub_months(Months::new(2050 * 12)), + Ok(ymd!(-28, 8, 3)) + ); // add crossing year boundary assert_eq!(ymd!(2022, 8, 3).checked_add_months(Months::new(6)), Ok(ymd!(2023, 2, 3))); @@ -2933,8 +2942,9 @@ mod tests { ); // last day must always be in week 52 or 53 - assert!([52, 53] - .contains(&NaiveDate::from_ymd(*y, 12, 31).unwrap().weeks_from(*day)),); + assert!( + [52, 53].contains(&NaiveDate::from_ymd(*y, 12, 31).unwrap().weeks_from(*day)), + ); } } diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 5e4192bb82..14a957800b 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -576,7 +576,7 @@ impl NaiveDateTime { /// 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)), /// Ok(hmsm(3, 5, 8, 430)?)); - /// + /// /// assert!(NaiveDate::from_ymd(2016, 7, 8)?.and_hms(3, 5, 7)?.checked_add_signed(TimeDelta::days(1_000_000_000)).is_err()); /// # Ok::<_, chrono::Error>(()) /// ``` diff --git a/src/naive/datetime/tests.rs b/src/naive/datetime/tests.rs index 85b606d650..e30c426da1 100644 --- a/src/naive/datetime/tests.rs +++ b/src/naive/datetime/tests.rs @@ -1,6 +1,6 @@ use super::NaiveDateTime; use crate::time_delta::TimeDelta; -use crate::{Datelike, Error, FixedOffset, Utc, NaiveDate}; +use crate::{Datelike, Error, FixedOffset, NaiveDate, Utc}; use std::i64; #[test] @@ -105,11 +105,7 @@ fn test_datetime_add() { } 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(-(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))); @@ -120,23 +116,27 @@ fn test_datetime_add() { // (they are private constants, but the equivalence is tested in that module.) let max_days_from_year_0 = NaiveDate::MAX.signed_duration_since(NaiveDate::from_ymd(0, 1, 1).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, - Ok((NaiveDate::MAX.year(), 12, 31, 0, 0, 0)) + max_days_from_year_0 + TimeDelta::seconds(86399), + Ok((NaiveDate::MAX.year(), 12, 31, 23, 59, 59)), ); check!( (0, 1, 1, 0, 0, 0), - max_days_from_year_0 + TimeDelta::seconds(86399), - Ok((NaiveDate::MAX.year(), 12, 31, 23, 59, 59)), + max_days_from_year_0 + TimeDelta::seconds(86_400), + Err(Error::ParsingOutOfRange), ); - 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(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), + min_days_from_year_0 - TimeDelta::seconds(1), + Err(Error::ParsingOutOfRange), + ); check!((0, 1, 1, 0, 0, 0), TimeDelta::min_value(), Err(Error::ParsingOutOfRange),); } @@ -308,10 +308,7 @@ fn test_datetime_parse_from_str() { .is_err()); assert!(NaiveDateTime::parse_from_str("2014-5-7 12:3456", "%Y-%m-%d %H:%M:%S").is_err()); assert!(NaiveDateTime::parse_from_str("12:34:56", "%H:%M:%S").is_err()); // insufficient - assert_eq!( - NaiveDateTime::parse_from_str("1441497364", "%s"), - ymdhms(2015, 9, 5, 23, 56, 4) - ); + assert_eq!(NaiveDateTime::parse_from_str("1441497364", "%s"), ymdhms(2015, 9, 5, 23, 56, 4)); assert_eq!( NaiveDateTime::parse_from_str("1283929614.1234", "%s.%f"), ymdhmsn(2010, 9, 8, 7, 6, 54, 1234) diff --git a/src/naive/internals.rs b/src/naive/internals.rs index 87546cb7d5..62c244ea39 100644 --- a/src/naive/internals.rs +++ b/src/naive/internals.rs @@ -550,7 +550,9 @@ mod tests { let mdf = match Mdf::new(month, day, flags) { Ok(mdf) => mdf, Err(..) if !expected => continue, - Err(..) => panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags), + Err(..) => { + panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags) + } }; assert!( diff --git a/src/naive/time/tests.rs b/src/naive/time/tests.rs index 55bebb4eb9..8d13ae23ec 100644 --- a/src/naive/time/tests.rs +++ b/src/naive/time/tests.rs @@ -97,36 +97,12 @@ fn test_time_add() { 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)); @@ -135,11 +111,7 @@ 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] @@ -204,11 +176,7 @@ fn test_time_sub() { 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), @@ -217,32 +185,14 @@ 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) - ); + assert_eq!(hmsm(3, 5, 6, 800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200)); + assert_eq!(hmsm(3, 5, 6, 1_800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200)); } #[test] diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index d63e49172d..35212e9484 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -193,7 +193,10 @@ mod tests { use std::{path, process}; #[cfg(unix)] - fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) -> Result<(), Error> { + 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())) @@ -202,14 +205,16 @@ mod tests { .unwrap(); let date_command_str = String::from_utf8(output.stdout)?; - + match Local.from_local_datetime( - &NaiveDate::from_ymd(dt.year(), dt.month(), dt.day())?.and_hms(dt.hour(), 5, 1)? + &NaiveDate::from_ymd(dt.year(), dt.month(), dt.day())?.and_hms(dt.hour(), 5, 1)?, ) { // compare a legit date to the "date" output Ok(crate::LocalResult::Single(dt)) => assert_eq!(format!("{}\n", dt), date_command_str), // "date" command always returns a given time when it is ambiguous (dt.earliest()) - Ok(crate::LocalResult::Ambiguous(dt1, _dt2)) => assert_eq!(format!("{}\n", dt1), date_command_str), + Ok(crate::LocalResult::Ambiguous(dt1, _dt2)) => { + assert_eq!(format!("{}\n", dt1), date_command_str) + } // "date" command returns an empty string for an invalid time (e.g. spring forward gap due to DST) Err(_) => assert_eq!(date_command_str, ""), } diff --git a/src/offset/local/tz_info/mod.rs b/src/offset/local/tz_info/mod.rs index 96e098e6a9..a7201384be 100644 --- a/src/offset/local/tz_info/mod.rs +++ b/src/offset/local/tz_info/mod.rs @@ -7,7 +7,6 @@ pub(crate) use timezone::TimeZone; mod parser; mod rule; - // MSRV: 1.38 #[inline] fn rem_euclid(v: i64, rhs: i64) -> i64 { diff --git a/src/offset/local/tz_info/rule.rs b/src/offset/local/tz_info/rule.rs index 7635eb732f..beed6d1301 100644 --- a/src/offset/local/tz_info/rule.rs +++ b/src/offset/local/tz_info/rule.rs @@ -779,7 +779,7 @@ mod tests { use super::super::timezone::Transition; use super::super::TimeZone; use super::{AlternateTime, LocalTimeType, RuleDay, TransitionRule}; - use crate::{Error, matches}; + use crate::{matches, Error}; #[test] fn test_quoted() -> Result<(), Error> { diff --git a/src/offset/local/unix.rs b/src/offset/local/unix.rs index c1fcc6c866..5729fe2f78 100644 --- a/src/offset/local/unix.rs +++ b/src/offset/local/unix.rs @@ -116,7 +116,6 @@ impl Cache { d: NaiveDateTime, local: bool, ) -> Result>, Error> { - // TODO Check why this was added // if self.source.out_of_date() { // *self = Cache::default(); diff --git a/src/round.rs b/src/round.rs index 62a7a43224..dd3ed41edc 100644 --- a/src/round.rs +++ b/src/round.rs @@ -313,8 +313,8 @@ impl std::error::Error for RoundingError { mod tests { use super::{DurationRound, SubsecRound, TimeDelta}; use crate::offset::{FixedOffset, TimeZone, Utc}; - use crate::{NaiveDate, Error}; use crate::Timelike; + use crate::{Error, NaiveDate}; #[test] fn test_round_subsecs() { diff --git a/tests/dateutils.rs b/tests/dateutils.rs index 19ab2744db..b6a3d3fef5 100644 --- a/tests/dateutils.rs +++ b/tests/dateutils.rs @@ -14,14 +14,16 @@ fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) -> R .unwrap(); let date_command_str = String::from_utf8(output.stdout)?; - + match Local.from_local_datetime( - &NaiveDate::from_ymd(dt.year(), dt.month(), dt.day())?.and_hms(dt.hour(), 5, 1)? + &NaiveDate::from_ymd(dt.year(), dt.month(), dt.day())?.and_hms(dt.hour(), 5, 1)?, ) { // compare a legit date to the "date" output Ok(chrono::LocalResult::Single(dt)) => assert_eq!(format!("{}\n", dt), date_command_str), // "date" command always returns a given time when it is ambiguous (dt.earliest()) - Ok(chrono::LocalResult::Ambiguous(dt1, _dt2)) => assert_eq!(format!("{}\n", dt1), date_command_str), + Ok(chrono::LocalResult::Ambiguous(dt1, _dt2)) => { + assert_eq!(format!("{}\n", dt1), date_command_str) + } // "date" command returns an empty string for an invalid time (e.g. spring forward gap due to DST) Err(_) => assert_eq!(date_command_str, ""), } From 5a8eff8472edf9a3fe8785961efdc62863617c93 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Mon, 27 Mar 2023 17:14:38 +0200 Subject: [PATCH 09/54] Fixed some warnings --- src/datetime/mod.rs | 4 +++- src/naive/date.rs | 2 +- src/naive/datetime/mod.rs | 2 +- src/offset/local/mod.rs | 7 ++++++- src/offset/local/tz_info/rule.rs | 2 +- src/offset/local/tz_info/timezone.rs | 2 +- src/offset/mod.rs | 10 +++++++++- src/offset/utc.rs | 3 ++- src/round.rs | 2 +- 9 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index b1eff54f7c..b5dc855ef7 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -33,7 +33,9 @@ use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime}; #[cfg(feature = "clock")] use crate::offset::Local; use crate::offset::{FixedOffset, FixedTimeZone, Offset, TimeZone, Utc}; -use crate::{Date, Datelike, Error, Months, TimeDelta, Timelike, Weekday}; +#[allow(deprecated)] +use crate::Date; +use crate::{Datelike, Error, Months, TimeDelta, Timelike, Weekday}; /// documented at re-export site #[cfg(feature = "serde")] diff --git a/src/naive/date.rs b/src/naive/date.rs index 1daab326c5..d9b9ee8717 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -2202,7 +2202,7 @@ mod tests { MIN_YEAR, }; use crate::time_delta::TimeDelta; - use crate::{Datelike, Error, Weekday}; + use crate::{Datelike, Weekday}; use std::{ convert::{TryFrom, TryInto}, i32, u32, diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 14a957800b..99320dfbc8 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -229,7 +229,7 @@ impl NaiveDateTime { let date = i32::try_from(days) .ok() .and_then(|days| days.checked_add(719_163)) - .ok_or_else(|| Error::InvalidDateTime) + .ok_or(Error::InvalidDateTime) .and_then(NaiveDate::from_num_days_from_ce)?; let time = NaiveTime::from_num_seconds_from_midnight(secs as u32, nsecs)?; diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 35212e9484..091bb34fc0 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -9,7 +9,9 @@ use rkyv::{Archive, Deserialize, Serialize}; use super::fixed::FixedOffset; use crate::naive::{NaiveDate, NaiveDateTime}; use crate::offset::LocalResult; -use crate::{Date, DateTime, Error, TimeZone}; +#[allow(deprecated)] +use crate::Date; +use crate::{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 @@ -58,6 +60,7 @@ pub struct Local; impl Local { /// Returns a `Date` which corresponds to the current date. + #[allow(deprecated)] pub fn today() -> Result, Error> { Ok(Local::now()?.date()) } @@ -119,6 +122,7 @@ impl TimeZone for Local { } // override them for avoiding redundant works + #[allow(deprecated)] 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 @@ -155,6 +159,7 @@ impl TimeZone for Local { inner::naive_to_local(local, true) } + #[allow(deprecated)] 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())) diff --git a/src/offset/local/tz_info/rule.rs b/src/offset/local/tz_info/rule.rs index beed6d1301..5c5c04d6d2 100644 --- a/src/offset/local/tz_info/rule.rs +++ b/src/offset/local/tz_info/rule.rs @@ -354,7 +354,7 @@ impl AlternateTime { fn parse_name<'a>(cursor: &mut Cursor<'a>) -> Result<&'a [u8], Error> { match cursor.peek() { Some(b'<') => {} - _ => return Ok(cursor.read_while(u8::is_ascii_alphabetic)?), + _ => return cursor.read_while(u8::is_ascii_alphabetic), } cursor.read_exact(1)?; diff --git a/src/offset/local/tz_info/timezone.rs b/src/offset/local/tz_info/timezone.rs index 55710ecc6a..70f4ead919 100644 --- a/src/offset/local/tz_info/timezone.rs +++ b/src/offset/local/tz_info/timezone.rs @@ -604,7 +604,7 @@ fn find_tz_file(path: impl AsRef) -> Result { } } - Err(Error::Io(io::ErrorKind::NotFound.into())) + Err(Error::Io(io::ErrorKind::NotFound)) } } diff --git a/src/offset/mod.rs b/src/offset/mod.rs index f6cdbace79..fbfbc78d90 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -22,7 +22,9 @@ use core::fmt; use crate::format::{parse, Parsed, StrftimeItems}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; -use crate::{Date, DateTime, Error, Weekday}; +#[allow(deprecated)] +use crate::Date; +use crate::{DateTime, Error, Weekday}; mod fixed; pub use self::fixed::FixedOffset; @@ -205,6 +207,7 @@ pub trait TimeZone: Sized + Clone { /// assert!(Utc.ymd(2000, 0, 0).is_err()); /// # Ok::<_, chrono::Error>(()) /// ``` + #[allow(deprecated)] fn ymd(&self, year: i32, month: u32, day: u32) -> Result>, Error> { let d = NaiveDate::from_ymd(year, month, day)?; self.from_local_date(&d) @@ -226,6 +229,7 @@ pub trait TimeZone: Sized + Clone { /// assert_eq!(Utc.yo(2015, 135)?.single()?.to_string(), "2015-05-15UTC"); /// # Ok::<_, chrono::Error>(()) /// ``` + #[allow(deprecated)] fn yo(&self, year: i32, ordinal: u32) -> Result>, Error> { let d = NaiveDate::from_yo(year, ordinal)?; self.from_local_date(&d) @@ -251,6 +255,7 @@ pub trait TimeZone: Sized + Clone { /// assert_eq!(Utc.isoywd(2015, 20, Weekday::Fri)?.single()?.to_string(), "2015-05-15UTC"); /// # Ok::<_, chrono::Error>(()) /// ``` + #[allow(deprecated)] fn isoywd( &self, year: i32, @@ -358,6 +363,7 @@ pub trait TimeZone: Sized + Clone { /// Converts the local `NaiveDate` to the timezone-aware `Date` if possible. #[allow(clippy::wrong_self_convention)] + #[allow(deprecated)] 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)); @@ -384,6 +390,7 @@ pub trait TimeZone: Sized + Clone { /// 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)] + #[allow(deprecated)] fn from_utc_date(&self, utc: &NaiveDate) -> Result, Error> { Ok(Date::from_utc(*utc, self.offset_from_utc_date(utc)?)) } @@ -409,6 +416,7 @@ pub(crate) trait FixedTimeZone: TimeZone { /// 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)] + #[allow(deprecated)] fn from_utc_date_fixed(&self, utc: &NaiveDate) -> Date { Date::from_utc(*utc, self.offset_from_utc_date_fixed(utc)) } diff --git a/src/offset/utc.rs b/src/offset/utc.rs index effcef6df7..ee14b3ccb2 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -51,6 +51,7 @@ pub struct Utc; #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] impl Utc { /// Returns a `Date` which corresponds to the current date. + #[allow(deprecated)] pub fn today() -> Result, Error> { Ok(Utc::now()?.date()) } @@ -64,7 +65,7 @@ impl Utc { pub fn now() -> Result, Error> { let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); - let naive = NaiveDateTime::from_timestamp(now.as_secs() as i64, now.subsec_nanos() as u32)?; + let naive = NaiveDateTime::from_timestamp(now.as_secs() as i64, now.subsec_nanos())?; Ok(DateTime::from_utc(naive, Utc)) } diff --git a/src/round.rs b/src/round.rs index dd3ed41edc..f863c803ff 100644 --- a/src/round.rs +++ b/src/round.rs @@ -313,8 +313,8 @@ impl std::error::Error for RoundingError { mod tests { use super::{DurationRound, SubsecRound, TimeDelta}; use crate::offset::{FixedOffset, TimeZone, Utc}; + use crate::Error; use crate::Timelike; - use crate::{Error, NaiveDate}; #[test] fn test_round_subsecs() { From 619115688d861c0f1f8a9a93967dbdc792f30518 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sat, 1 Apr 2023 18:09:13 +0200 Subject: [PATCH 10/54] restore some tests --- src/datetime/tests.rs | 380 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 345 insertions(+), 35 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 69bd3e794c..e1467d4371 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -6,78 +6,386 @@ use crate::offset::Local; use crate::offset::{FixedOffset, TimeZone, Utc}; #[cfg(feature = "clock")] use crate::Datelike; -use crate::NaiveDate; -use crate::NaiveTime; -use crate::TimeDelta; +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() + } -macro_rules! ymd { - ($year:expr, $month:expr, $day:expr) => { - NaiveDate::from_ymd($year, $month, $day).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, + ) -> Result, Error> { + let local_to_winter_transition_start = NaiveDate::from_ymd( + local.year(), + DstTester::TO_WINTER_MONTH_DAY.0, + DstTester::TO_WINTER_MONTH_DAY.1, + )? + .and_time(DstTester::transition_start_local()); + + let local_to_winter_transition_end = NaiveDate::from_ymd( + local.year(), + DstTester::TO_WINTER_MONTH_DAY.0, + DstTester::TO_WINTER_MONTH_DAY.1, + )? + .and_time(DstTester::transition_start_local() - TimeDelta::hours(1)); + + let local_to_summer_transition_start = NaiveDate::from_ymd( + local.year(), + DstTester::TO_SUMMER_MONTH_DAY.0, + DstTester::TO_SUMMER_MONTH_DAY.1, + )? + .and_time(DstTester::transition_start_local()); + + let local_to_summer_transition_end = NaiveDate::from_ymd( + local.year(), + DstTester::TO_SUMMER_MONTH_DAY.0, + DstTester::TO_SUMMER_MONTH_DAY.1, + )? + .and_time(DstTester::transition_start_local() + TimeDelta::hours(1)); + + if *local < local_to_winter_transition_end || *local >= local_to_summer_transition_end { + LocalResult::Single(DstTester::summer_offset()) + } 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_offset() { +fn test_datetime_add_days() -> Result<(), Error> { + let est = FixedOffset::west(5 * 60 * 60)?; + let kst = FixedOffset::east(9 * 60 * 60)?; + + 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" + ); + Ok(()) +} + +#[test] +fn test_datetime_sub_days() -> Result<(), Error> { let est = FixedOffset::west(5 * 60 * 60).unwrap(); - let edt = FixedOffset::west(4 * 60 * 60).unwrap(); let kst = FixedOffset::east(9 * 60 * 60).unwrap(); assert_eq!( - format!("{}", Utc.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + 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" + ); + + 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" + ); + Ok(()) +} + +#[test] +fn test_datetime_add_months() -> Result<(), Error> { + 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" + ); + Ok(()) +} + +#[test] +fn test_datetime_sub_months() -> Result<(), Error> { + let est = FixedOffset::west(5 * 60 * 60)?; + let kst = FixedOffset::east(9 * 60 * 60)?; + + 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" + ); + Ok(()) +} + +// local helper function to easily create a DateTime +fn ymdhms( + fixedoffset: &FixedOffset, + year: i32, + month: u32, + day: u32, + hour: u32, + min: u32, + sec: u32, +) -> Result, Error> { + fixedoffset.with_ymd_and_hms(year, month, day, hour, min, sec) +} + +// 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, +) -> Result, Error> { + fixedoffset + .with_ymd_and_hms(year, month, day, hour, min, sec)? + .checked_add_signed(TimeDelta::milliseconds(milli))? +} + +// 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, +) -> Result, Error> { + fixedoffset + .with_ymd_and_hms(year, month, day, hour, min, sec)? + .checked_add_signed(TimeDelta::microseconds(micro))? +} + +// 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, +) -> Result, Error> { + fixedoffset + .with_ymd_and_hms(year, month, day, hour, min, sec)? + .checked_add_signed(TimeDelta::nanoseconds(nano))? +} + +// local helper function to easily create a DateTime +fn ymdhms_utc(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> Result, Error> { + Utc.with_ymd_and_hms(year, month, day, hour, min, sec)? +} + +// 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, +) -> Result, Error> { + Utc.with_ymd_and_hms(year, month, day, hour, min, sec)? + .checked_add_signed(TimeDelta::milliseconds(milli))? +} + +#[test] +fn test_datetime_offset() -> Result<(), Error> { + let est = FixedOffset::west(5 * 60 * 60)?; + let edt = FixedOffset::west(4 * 60 * 60)?; + let kst = FixedOffset::east(9 * 60 * 60)?; + + assert_eq!( + format!("{}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), "2014-05-06 07:08:09 UTC" ); assert_eq!( - format!("{}", edt.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + format!("{}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), "2014-05-06 07:08:09 -04:00" ); assert_eq!( - format!("{}", kst.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), "2014-05-06 07:08:09 +09:00" ); assert_eq!( - format!("{:?}", Utc.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), "2014-05-06T07:08:09Z" ); assert_eq!( - format!("{:?}", edt.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), "2014-05-06T07:08:09-04:00" ); assert_eq!( - format!("{:?}", kst.ymd(2014, 5, 6).unwrap().and_hms(7, 8, 9).unwrap()), + format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), "2014-05-06T07:08:09+09:00" ); // edge cases assert_eq!( - format!("{:?}", Utc.ymd(2014, 5, 6).unwrap().and_hms(0, 0, 0).unwrap()), + format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 0, 0, 0)?), "2014-05-06T00:00:00Z" ); assert_eq!( - format!("{:?}", edt.ymd(2014, 5, 6).unwrap().and_hms(0, 0, 0).unwrap()), + format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 0, 0, 0)?), "2014-05-06T00:00:00-04:00" ); assert_eq!( - format!("{:?}", kst.ymd(2014, 5, 6).unwrap().and_hms(0, 0, 0).unwrap()), + format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 0, 0, 0)?), "2014-05-06T00:00:00+09:00" ); assert_eq!( - format!("{:?}", Utc.ymd(2014, 5, 6).unwrap().and_hms(23, 59, 59).unwrap()), + format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 23, 59, 59)?), "2014-05-06T23:59:59Z" ); assert_eq!( - format!("{:?}", edt.ymd(2014, 5, 6).unwrap().and_hms(23, 59, 59).unwrap()), + format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 23, 59, 59)?), "2014-05-06T23:59:59-04:00" ); assert_eq!( - format!("{:?}", kst.ymd(2014, 5, 6).unwrap().and_hms(23, 59, 59).unwrap()), + format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 23, 59, 59)?), "2014-05-06T23:59:59+09:00" ); - 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()); + let dt = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?; + assert_eq!(dt, edt.with_ymd_and_hms(2014, 5, 6, 3, 8, 9)?); assert_eq!( dt + TimeDelta::seconds(3600 + 60 + 1), - Utc.ymd(2014, 5, 6).unwrap().and_hms(8, 9, 10).unwrap() + Utc.with_ymd_and_hms(2014, 5, 6, 8, 9, 10)? ); assert_eq!( dt.signed_duration_since(edt.ymd(2014, 5, 6).unwrap().and_hms(10, 11, 12).unwrap()), @@ -118,22 +426,23 @@ fn test_datetime_date_and_time() { #[test] #[cfg(feature = "clock")] -fn test_datetime_with_timezone() { - let local_now = Local::now().unwrap(); - let utc_now = local_now.with_timezone(&Utc).unwrap(); - let local_now2 = utc_now.with_timezone(&Local).unwrap(); +fn test_datetime_with_timezone() -> Result<(), Error> { + let local_now = Local::now()?; + let utc_now = local_now.with_timezone(&Utc)?; + let local_now2 = utc_now.with_timezone(&Local)?; assert_eq!(local_now, local_now2); + Ok(()) } #[test] -fn test_datetime_rfc2822_and_rfc3339() { - let edt = FixedOffset::east(5 * 60 * 60).unwrap(); +fn test_datetime_rfc2822_and_rfc3339() -> Result<(), Error> { + let edt = FixedOffset::east(5 * 60 * 60)?; assert_eq!( - Utc.ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap().to_rfc2822(), + Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.to_rfc2822(), "Wed, 18 Feb 2015 23:16:09 +0000" ); assert_eq!( - Utc.ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap().to_rfc3339(), + Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.to_rfc3339(), "2015-02-18T23:16:09+00:00" ); assert_eq!( @@ -163,17 +472,18 @@ fn test_datetime_rfc2822_and_rfc3339() { ); assert_eq!( DateTime::::parse_from_rfc3339("2015-02-18T23:16:09Z"), - Ok(FixedOffset::east(0).unwrap().ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).unwrap()) + Ok(FixedOffset::east(0).unwrap().ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).?) ); assert_eq!( DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"), - Ok(edt.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 59, 59, 1_000).unwrap()) + Ok(edt.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 59, 59, 1_000)?) ); assert!(DateTime::::parse_from_rfc2822("31 DEC 262143 23:59 -2359").is_err()); assert_eq!( DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"), - Ok(edt.ymd(2015, 2, 18).unwrap().and_hms_micro(23, 59, 59, 1_234_567).unwrap()) + Ok(edt.ymd(2015, 2, 18).unwrap().and_hms_micro(23, 59, 59, 1_234_567)?) ); + Ok(()) } #[test] From 225b3e4073c990911664faad410a31fafa78195a Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sat, 1 Apr 2023 18:20:36 +0200 Subject: [PATCH 11/54] cosmetic fix --- src/format/scan.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/format/scan.rs b/src/format/scan.rs index 73f9e7f643..87ecc47e51 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -363,8 +363,8 @@ 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`). +/// Same as `timezone_offset` but also allows for RFC 2822 legacy timezones. +/// May return `Err(Error)` 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()); From 228a689883be7eed04b3c25b32db05f805092a4d Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sun, 2 Apr 2023 17:15:35 +0200 Subject: [PATCH 12/54] moving forward --- src/offset/fixed.rs | 8 +- src/offset/local/mod.rs | 66 ++++----------- src/offset/mod.rs | 174 +++++++++++----------------------------- 3 files changed, 67 insertions(+), 181 deletions(-) diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index e7231e444d..1219ece0a6 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -105,11 +105,11 @@ impl TimeZone for FixedOffset { Ok(LocalResult::Single(*self)) } - fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Result { - Ok(*self) + fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Self { + *self } - fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Result { - Ok(*self) + fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Self { + *self } } diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 091bb34fc0..b21febea84 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -98,37 +98,12 @@ impl TimeZone for Local { Local } - // they are easier to define in terms of the finished date and time unlike other offsets - fn offset_from_local_date( - &self, - local: &NaiveDate, - ) -> Result, Error> { - Ok(self.from_local_date(local)?.map(|o| *o.offset())) + fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> Result, Error> { + self.from_local_datetime(local)?.single()?.offset() } - fn offset_from_local_datetime( - &self, - local: &NaiveDateTime, - ) -> Result, Error> { - Ok(self.from_local_datetime(local)?.map(|o| *o.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) -> Result { - Ok(*self.from_utc_datetime(utc)?.offset()) - } - - // override them for avoiding redundant works - #[allow(deprecated)] - 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_midnight())?; - Ok(midnight.map(|midnight| Date::from_utc(*local, *midnight.offset()))) + fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset { + *self.from_utc_datetime(utc).offset() } #[cfg(all( @@ -136,13 +111,11 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] - fn from_local_datetime( - &self, - local: &NaiveDateTime, - ) -> Result>, Error> { + 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((js_sys::Date::new_0().get_timezone_offset() as i32) * 60)?; + 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); Ok(LocalResult::Single(DateTime::from_utc(local, offset))) } @@ -152,28 +125,21 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - fn from_local_datetime( - &self, - local: &NaiveDateTime, - ) -> Result>, Error> { + fn from_local_datetime(&self, local: &NaiveDateTime) -> Result>, Error> { inner::naive_to_local(local, true) } - #[allow(deprecated)] - 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( target_arch = "wasm32", feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] - fn from_utc_datetime(&self, utc: &NaiveDateTime) -> Result, Error> { + fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime { // Get the offset from the js runtime - let offset = FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60)?; - Ok(DateTime::from_utc(*utc, offset)) + let offset = + FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) + .unwrap(); + DateTime::from_utc(*utc, offset) } #[cfg(not(all( @@ -181,8 +147,10 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - fn from_utc_datetime(&self, utc: &NaiveDateTime) -> Result, Error> { - inner::naive_to_local(utc, false)?.single() + 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() } } diff --git a/src/offset/mod.rs b/src/offset/mod.rs index fbfbc78d90..26590e797d 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -177,6 +177,7 @@ pub trait Offset: Sized + Clone + fmt::Debug { fn fix(&self) -> FixedOffset; } + /// The time zone. /// /// The methods here are the primarily constructors for [`Date`](../struct.Date.html) and @@ -187,119 +188,62 @@ pub trait TimeZone: Sized + Clone { /// The original `TimeZone` value can be recovered via `TimeZone::from_offset`. type Offset: Offset; - /// Makes a new `Date` from year, month, day and the current time zone. This - /// assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. - /// - /// 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. + /// Make a new `DateTime` from year, month, day, time components and current time zone. /// - /// Returns `Err(Error)` on the out-of-range date, invalid month - /// and/or day. - /// - /// # Example - /// - /// ``` - /// use chrono::{Utc, TimeZone}; - /// - /// 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>(()) - /// ``` - #[allow(deprecated)] - 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. /// 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 and/or invalid DOY. - /// - /// # Example - /// - /// ``` - /// use chrono::{Error, Utc, TimeZone}; - /// - /// assert_eq!(Utc.yo(2015, 135)?.single()?.to_string(), "2015-05-15UTC"); - /// # Ok::<_, chrono::Error>(()) - /// ``` - #[allow(deprecated)] - 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. - /// - /// 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 and/or invalid week - /// number. - /// - /// # Example - /// - /// ``` - /// use chrono::{Utc, Weekday, TimeZone}; - /// - /// assert_eq!(Utc.isoywd(2015, 20, Weekday::Fri)?.single()?.to_string(), "2015-05-15UTC"); - /// # Ok::<_, chrono::Error>(()) - /// ``` - #[allow(deprecated)] - fn isoywd( + /// Returns `Err(chrono::Error)` on invalid input data. + fn with_ymd_and_hms( &self, year: i32, - week: u32, - weekday: Weekday, - ) -> Result>, Error> { - let d = NaiveDate::from_isoywd(year, week, weekday)?; - self.from_local_date(&d) + month: u32, + day: u32, + hour: u32, + min: u32, + sec: u32, + ) -> Result>, Error> { + Ok(self.from_local_datetime( + NaiveDate::from_ymd(year, month, day).and_then(|d| d.and_hms(hour, min, sec))? + )) } /// 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 `Err(Error)` on out-of-range number of seconds and/or - /// invalid nanosecond, otherwise always returns [`LocalResult::Single`]. + /// Returns `Err(chrono::Error)` on out-of-range number of seconds and/or + /// invalid nanosecond, otherwise always returns `Ok(LocalResult::Single)`. /// /// # Example /// /// ``` /// use chrono::{Utc, TimeZone}; /// - /// assert_eq!(Utc.timestamp(1431648000, 0)?.to_string(), "2015-05-15 00:00:00 UTC"); - /// # Ok::<_, chrono::Error>(()) + /// assert_eq!(Utc.timestamp(1431648000, 0).unwrap().to_string(), "2015-05-15 00:00:00 UTC"); /// ``` - fn timestamp(&self, secs: i64, nsecs: u32) -> Result, Error> { - let dt = NaiveDateTime::from_timestamp(secs, nsecs)?; - self.from_utc_datetime(&dt) + fn timestamp(&self, secs: i64, nsecs: u32) -> Result>, Error> { + Ok(LocalResult::Single(self.from_utc_datetime(NaiveDateTime::from_timestamp(secs, nsecs)?))) } - /// 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 `Err(Error)` on out-of-range number of milliseconds and/or - /// invalid nanosecond. + /// + /// Returns `Err(chrono::Error)` on out-of-range number of milliseconds + /// and/or invalid nanosecond, otherwise always returns + /// `LocalResult::Single`. /// /// # Example /// /// ``` - /// use chrono::{Utc, TimeZone}; - /// assert_eq!(Utc.timestamp_millis(1431648000)?.timestamp(), 1431648); - /// # Ok::<_, chrono::Error>(()) + /// use chrono::{Utc, TimeZone, LocalResult}; + /// match Utc.timestamp_millis_opt(1431648000) { + /// Ok(LocalResult::Single(dt)) => assert_eq!(dt.timestamp(), 1431648), + /// Ok(LocalResult::Ambiguous(dt1, dt2)) => panic!("Ambiguous timestamp should not be possible"), + /// Err(_) => panic!("Incorrect timestamp_millis"), + /// }; /// ``` - fn timestamp_millis(&self, millis: i64) -> Result, Error> { + fn timestamp_millis(&self, millis: i64) -> Result>, Error> { let (mut secs, mut millis) = (millis / 1000, millis % 1000); if millis < 0 { secs -= 1; @@ -311,16 +255,15 @@ pub trait TimeZone: Sized + Clone { /// Makes a new `DateTime` from the number of non-leap nanoseconds /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). /// - /// Unlike [`timestamp_millis`](#method.timestamp_millis), this never - /// panics. + /// Just like [`timestamp_millis`](#method.timestamp_millis), this + /// returns `Err(chrono::Error)` in case of failure. /// /// # Example /// /// ``` /// use chrono::{Utc, TimeZone}; /// - /// assert_eq!(Utc.timestamp_nanos(1431648000000000)?.timestamp(), 1431648); - /// # Ok::<_, chrono::Error>(()) + /// assert_eq!(Utc.timestamp_nanos(1431648000000000).timestamp(), 1431648); /// ``` fn timestamp_nanos(&self, nanos: i64) -> Result, Error> { let (mut secs, mut nanos) = (nanos / 1_000_000_000, nanos % 1_000_000_000); @@ -328,7 +271,7 @@ pub trait TimeZone: Sized + Clone { secs -= 1; nanos += 1_000_000_000; } - self.timestamp(secs, nanos as u32) + self.timestamp(secs, nanos as u32)? } /// Parses a string with the specified format string and returns a @@ -352,54 +295,29 @@ 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) - -> Result, Error>; + 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, - ) -> Result, Error>; - - /// Converts the local `NaiveDate` to the timezone-aware `Date` if possible. - #[allow(clippy::wrong_self_convention)] - #[allow(deprecated)] - 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) - } + fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> Result, Error>; /// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible. #[allow(clippy::wrong_self_convention)] - 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) + fn from_local_datetime(&self, local: &NaiveDateTime) -> Result>, Error> { + self.offset_from_local_datetime(local) + .map(|offset| DateTime::from_utc(*local - offset.fix(), offset)) } /// Creates the offset for given UTC `NaiveDate`. This cannot fail. - fn offset_from_utc_date(&self, utc: &NaiveDate) -> Result; + fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset; /// 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)] - #[allow(deprecated)] - fn from_utc_date(&self, utc: &NaiveDate) -> Result, Error> { - Ok(Date::from_utc(*utc, self.offset_from_utc_date(utc)?)) - } + fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset; /// 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)?)) + fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime { + DateTime::from_utc(*utc, self.offset_from_utc_datetime(utc)) } } From db74841bb1e6562829482e916324592a6f30580e Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Mon, 3 Apr 2023 13:30:57 +0200 Subject: [PATCH 13/54] time to be or not to be --- src/offset/local/mod.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index b21febea84..1c04f6593c 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -98,8 +98,17 @@ impl TimeZone for Local { Local } + // they are easier to define in terms of the finished date and time unlike other offsets + fn offset_from_local_date(&self, local: &NaiveDate) -> Result, Error> { + self.from_local_datetime(local).map(|date| *date.offset()) + } + fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> Result, Error> { - self.from_local_datetime(local)?.single()?.offset() + self.from_local_datetime(local).map(|datetime| *datetime.offset()) + } + + fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset { + *self.from_utc_datedate(utc).offset() } fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset { @@ -111,13 +120,14 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] - fn from_local_datetime(&self, local: &NaiveDateTime) -> Result>, Error> { + fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult> { let mut local = local.clone(); // Get the offset from the js runtime let offset = - FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60)?; + FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) + .unwrap(); local -= crate::TimeDelta::seconds(offset.local_minus_utc() as i64); - Ok(LocalResult::Single(DateTime::from_utc(local, offset))) + LocalResult::Single(DateTime::from_utc(local, offset)) } #[cfg(not(all( @@ -125,10 +135,10 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - fn from_local_datetime(&self, local: &NaiveDateTime) -> Result>, Error> { + fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult> { inner::naive_to_local(local, true) } - + #[cfg(all( target_arch = "wasm32", feature = "wasmbind", From 6655ba33620090b97afd8cf2966cd74b3228a780 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 15:58:08 +0200 Subject: [PATCH 14/54] UTC/Local date stuff --- src/date.rs | 14 +---------- src/datetime/mod.rs | 3 ++- src/offset/fixed.rs | 8 +++--- src/offset/local/mod.rs | 28 ++++++++++----------- src/offset/mod.rs | 55 ++++++++++++++++++++++++++--------------- 5 files changed, 56 insertions(+), 52 deletions(-) diff --git a/src/date.rs b/src/date.rs index a874b54ee0..82678c3fa1 100644 --- a/src/date.rs +++ b/src/date.rs @@ -566,18 +566,6 @@ mod tests { date_add += TimeDelta::days(5); assert_eq!(date_add, date + TimeDelta::days(5)); - - 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(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)); } #[test] @@ -585,7 +573,7 @@ mod tests { fn test_date_add_assign_local() { let naivedate = NaiveDate::from_ymd(2000, 1, 1).unwrap(); - let date = Local.from_utc_date(&naivedate).unwrap(); + let date = Local.from_utc(&naivedate).unwrap(); let mut date_add = date; date_add += TimeDelta::days(5); diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index b5dc855ef7..bf8af46c26 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1150,7 +1150,8 @@ impl From for DateTime { } }; - // TODO: remove this conversion since it can panic or can we make it not panic? + // TODO: This may panic + // Either return Result instead or ensure that timestamp() cannot fail. Utc.timestamp(sec, nsec).unwrap() } } diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index 1219ece0a6..e7231e444d 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -105,11 +105,11 @@ impl TimeZone for FixedOffset { Ok(LocalResult::Single(*self)) } - fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Self { - *self + fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Result { + Ok(*self) } - fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Self { - *self + fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Result { + Ok(*self) } } diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 1c04f6593c..5253679a1b 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -99,20 +99,20 @@ impl TimeZone for Local { } // they are easier to define in terms of the finished date and time unlike other offsets - fn offset_from_local_date(&self, local: &NaiveDate) -> Result, Error> { - self.from_local_datetime(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) -> Result, Error> { - 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())) } - fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset { - *self.from_utc_datedate(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()) } #[cfg(all( @@ -135,7 +135,7 @@ 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) } @@ -151,16 +151,16 @@ impl TimeZone for Local { .unwrap(); DateTime::from_utc(*utc, offset) } - + // TODO: A local time from a UTC timestamp is never ambiguous, + // but this still returns `Result`. If it reall is not ambiguous, + // make sure that `inner::naive_to_local` returns `T` first. #[cfg(not(all( target_arch = "wasm32", 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() } } diff --git a/src/offset/mod.rs b/src/offset/mod.rs index 26590e797d..68429a7445 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -24,7 +24,7 @@ use crate::format::{parse, Parsed, StrftimeItems}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; #[allow(deprecated)] use crate::Date; -use crate::{DateTime, Error, Weekday}; +use crate::{DateTime, Error}; mod fixed; pub use self::fixed::FixedOffset; @@ -202,9 +202,9 @@ pub trait TimeZone: Sized + Clone { min: u32, sec: u32, ) -> Result>, Error> { - Ok(self.from_local_datetime( - NaiveDate::from_ymd(year, month, day).and_then(|d| d.and_hms(hour, min, sec))? - )) + self.from_local_datetime( + &NaiveDate::from_ymd(year, month, day)?.and_hms(hour, min, sec)? + ) } /// Makes a new `DateTime` from the number of non-leap seconds @@ -221,8 +221,8 @@ pub trait TimeZone: Sized + Clone { /// /// assert_eq!(Utc.timestamp(1431648000, 0).unwrap().to_string(), "2015-05-15 00:00:00 UTC"); /// ``` - fn timestamp(&self, secs: i64, nsecs: u32) -> Result>, Error> { - Ok(LocalResult::Single(self.from_utc_datetime(NaiveDateTime::from_timestamp(secs, nsecs)?))) + fn timestamp(&self, secs: i64, nsecs: u32) -> Result, Error> { + self.from_utc_datetime(&NaiveDateTime::from_timestamp(secs, nsecs)?) } /// Makes a new `DateTime` from the number of non-leap milliseconds @@ -230,20 +230,18 @@ pub trait TimeZone: Sized + Clone { /// /// /// Returns `Err(chrono::Error)` on out-of-range number of milliseconds - /// and/or invalid nanosecond, otherwise always returns - /// `LocalResult::Single`. + /// and/or invalid nanosecond /// /// # Example /// /// ``` /// use chrono::{Utc, TimeZone, LocalResult}; /// match Utc.timestamp_millis_opt(1431648000) { - /// Ok(LocalResult::Single(dt)) => assert_eq!(dt.timestamp(), 1431648), - /// Ok(LocalResult::Ambiguous(dt1, dt2)) => panic!("Ambiguous timestamp should not be possible"), + /// Ok(dt) => assert_eq!(dt.timestamp(), 1431648), /// Err(_) => panic!("Incorrect timestamp_millis"), /// }; /// ``` - fn timestamp_millis(&self, millis: i64) -> Result>, Error> { + fn timestamp_millis(&self, millis: i64) -> Result, Error> { let (mut secs, mut millis) = (millis / 1000, millis % 1000); if millis < 0 { secs -= 1; @@ -271,7 +269,7 @@ pub trait TimeZone: Sized + Clone { secs -= 1; nanos += 1_000_000_000; } - self.timestamp(secs, nanos as u32)? + self.timestamp(secs, nanos as u32) } /// Parses a string with the specified format string and returns a @@ -300,24 +298,41 @@ pub trait TimeZone: Sized + Clone { /// Creates the offset(s) for given local `NaiveDateTime` if possible. 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)] + #[allow(deprecated)] + fn from_local_date(&self, local: &NaiveDate) -> Result>, Error> { + // TODO: This might be total nonsense, but the functionality is required at quite a few places + // Is the default time of a day midnight or noon? + Ok(self.offset_from_local_date(local)? + .map(|offset| Date::from_utc((local.and_midnight() - offset.fix()).date(), offset))) + } + /// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible. #[allow(clippy::wrong_self_convention)] fn from_local_datetime(&self, local: &NaiveDateTime) -> Result>, Error> { - self.offset_from_local_datetime(local) - .map(|offset| DateTime::from_utc(*local - offset.fix(), offset)) + Ok(self.offset_from_local_datetime(local)? + .map(|offset| DateTime::from_utc(*local - offset.fix(), offset))) } - /// Creates the offset for given UTC `NaiveDate`. This cannot fail. - fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset; + /// Creates the offset for given UTC `NaiveDate`. + 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) -> Self::Offset; + /// Creates the offset for given UTC `NaiveDateTime`. + fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Result; + + /// Converts the UTC `NaiveDate` to the local date. + #[allow(deprecated)] + 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). + // TODO: At least one implementation of this function can fail. #[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(&self, utc: &NaiveDateTime) -> Result, Error> { + Ok(DateTime::from_utc(*utc, self.offset_from_utc_datetime(utc)?)) } } From 890e4c9b22c42dbbbfb27219aebde8af73a96dee Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 16:33:32 +0200 Subject: [PATCH 15/54] Test fixes --- src/datetime/tests.rs | 1362 ++++++++++++++++++++++++++++++++------- src/offset/local/mod.rs | 14 +- src/offset/mod.rs | 24 +- 3 files changed, 1145 insertions(+), 255 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index e1467d4371..2562e8e270 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -17,17 +17,17 @@ struct DstTester; impl DstTester { fn winter_offset() -> FixedOffset { - FixedOffset::east_opt(8 * 60 * 60).unwrap() + FixedOffset::east(8 * 60 * 60).unwrap() } fn summer_offset() -> FixedOffset { - FixedOffset::east_opt(9 * 60 * 60).unwrap() + FixedOffset::east(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() + NaiveTime::from_hms(2, 0, 0).unwrap() } } @@ -38,14 +38,17 @@ impl TimeZone for DstTester { DstTester } - fn offset_from_local_date(&self, _: &NaiveDate) -> crate::LocalResult { + fn offset_from_local_date( + &self, + _: &NaiveDate, + ) -> Result, crate::Error> { unimplemented!() } fn offset_from_local_datetime( &self, local: &NaiveDateTime, - ) -> Result, Error> { + ) -> Result, crate::Error> { let local_to_winter_transition_start = NaiveDate::from_ymd( local.year(), DstTester::TO_WINTER_MONTH_DAY.0, @@ -75,170 +78,168 @@ impl TimeZone for DstTester { .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()) + Ok(LocalResult::Single(DstTester::summer_offset())) } else if *local >= local_to_winter_transition_start && *local < local_to_summer_transition_start { - LocalResult::Single(DstTester::winter_offset()) + Ok(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()) + Ok(LocalResult::Ambiguous(DstTester::winter_offset(), DstTester::summer_offset())) } else if *local >= local_to_summer_transition_start && *local < local_to_summer_transition_end { - LocalResult::None + Err(crate::Error::InvalidDateTime) } else { - panic!("Unexpected local time {}", local) + Err(crate::Error::InvalidDateTime) } } - fn offset_from_utc_date(&self, _: &NaiveDate) -> Self::Offset { + fn offset_from_utc_date(&self, _: &NaiveDate) -> Result { unimplemented!() } - fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset { - let utc_to_winter_transition = NaiveDate::from_ymd_opt( + fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Result { + let utc_to_winter_transition = NaiveDate::from_ymd( 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( + let utc_to_summer_transition = NaiveDate::from_ymd( 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() + Ok(DstTester::summer_offset()) } else if *utc >= utc_to_winter_transition && *utc < utc_to_summer_transition { - DstTester::winter_offset() + Ok(DstTester::winter_offset()) } else { - panic!("Unexpected utc time {}", utc) + Err(crate::Error::InvalidDateTime) } } } #[test] -fn test_datetime_add_days() -> Result<(), Error> { +fn test_datetime_add_days() -> Result<(), crate::Error> { let est = FixedOffset::west(5 * 60 * 60)?; let kst = FixedOffset::east(9 * 60 * 60)?; assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Days::new(5)), + format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", DstTester.with_ymd_and_hms(2014, 4, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", DstTester.with_ymd_and_hms(2014, 4, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", DstTester.with_ymd_and_hms(2014, 9, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", DstTester.with_ymd_and_hms(2014, 9, 6, 7, 8, 9)?.single()? + Days::new(10)), "2014-09-16 07:08:09 +09:00" ); Ok(()) } #[test] -fn test_datetime_sub_days() -> Result<(), Error> { - let est = FixedOffset::west(5 * 60 * 60).unwrap(); - let kst = FixedOffset::east(9 * 60 * 60).unwrap(); +fn test_datetime_sub_days() -> Result<(), crate::Error> { + let est = FixedOffset::west(5 * 60 * 60)?; + let kst = FixedOffset::east(9 * 60 * 60)?; assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(5)), + format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? - 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)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? - Days::new(5)), "2014-05-01 07:08:09 +09:00" ); assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(35)), + format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? - 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)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? - Days::new(35)), "2014-04-01 07:08:09 +09:00" ); Ok(()) } #[test] -fn test_datetime_add_months() -> Result<(), Error> { - let est = FixedOffset::west_opt(5 * 60 * 60).unwrap(); - let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap(); +fn test_datetime_add_months() -> Result<(), crate::Error> { + let est = FixedOffset::west(5 * 60 * 60)?; + let kst = FixedOffset::east(9 * 60 * 60)?; assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Months::new(1)), + format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? + 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)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? + Months::new(5)), "2014-10-06 07:08:09 +09:00" ); Ok(()) } #[test] -fn test_datetime_sub_months() -> Result<(), Error> { +fn test_datetime_sub_months() -> Result<(), crate::Error> { let est = FixedOffset::west(5 * 60 * 60)?; let kst = FixedOffset::east(9 * 60 * 60)?; assert_eq!( - format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Months::new(1)), + format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? - 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)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).?.single()? - 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)), + format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).?.single()? - 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)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).?.single()? - Months::new(5)), "2013-12-06 07:08:09 +09:00" ); Ok(()) @@ -253,8 +254,8 @@ fn ymdhms( hour: u32, min: u32, sec: u32, -) -> Result, Error> { - fixedoffset.with_ymd_and_hms(year, month, day, hour, min, sec) +) -> DateTime { + fixedoffset.with_ymd_and_hms(year, month, day, hour, min, sec).unwrap().single().unwrap() } // local helper function to easily create a DateTime @@ -267,10 +268,12 @@ fn ymdhms_milli( min: u32, sec: u32, milli: i64, -) -> Result, Error> { +) -> DateTime { fixedoffset - .with_ymd_and_hms(year, month, day, hour, min, sec)? - .checked_add_signed(TimeDelta::milliseconds(milli))? + .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 @@ -283,10 +286,12 @@ fn ymdhms_micro( min: u32, sec: u32, micro: i64, -) -> Result, Error> { +) -> DateTime { fixedoffset - .with_ymd_and_hms(year, month, day, hour, min, sec)? - .checked_add_signed(TimeDelta::microseconds(micro))? + .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 @@ -299,15 +304,17 @@ fn ymdhms_nano( min: u32, sec: u32, nano: i64, -) -> Result, Error> { +) -> DateTime { fixedoffset - .with_ymd_and_hms(year, month, day, hour, min, sec)? - .checked_add_signed(TimeDelta::nanoseconds(nano))? + .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) -> Result, Error> { - Utc.with_ymd_and_hms(year, month, day, hour, min, sec)? +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 @@ -319,114 +326,112 @@ fn ymdhms_milli_utc( min: u32, sec: u32, milli: i64, -) -> Result, Error> { - Utc.with_ymd_and_hms(year, month, day, hour, min, sec)? - .checked_add_signed(TimeDelta::milliseconds(milli))? +) -> DateTime { + Utc.with_ymd_and_hms(year, month, day, hour, min, sec) + .unwrap() + .checked_add_signed(TimeDelta::milliseconds(milli)) + .unwrap() } #[test] -fn test_datetime_offset() -> Result<(), Error> { +fn test_datetime_offset() -> Result<(), crate::Error> { let est = FixedOffset::west(5 * 60 * 60)?; let edt = FixedOffset::west(4 * 60 * 60)?; let kst = FixedOffset::east(9 * 60 * 60)?; assert_eq!( - format!("{}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), + format!("{}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?), "2014-05-06 07:08:09 UTC" ); assert_eq!( - format!("{}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), + format!("{}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?), "2014-05-06 07:08:09 -04:00" ); assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?), "2014-05-06 07:08:09 +09:00" ); assert_eq!( - format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), + format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?), "2014-05-06T07:08:09Z" ); assert_eq!( - format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), + format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?), "2014-05-06T07:08:09-04:00" ); assert_eq!( - format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?), + format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 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)?), + format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()), "2014-05-06T00:00:00Z" ); assert_eq!( - format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 0, 0, 0)?), + format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 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)?), + format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 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)?), + format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()), "2014-05-06T23:59:59Z" ); assert_eq!( - format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 23, 59, 59)?), + format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 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)?), + format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()), "2014-05-06T23:59:59+09:00" ); - let dt = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?; - assert_eq!(dt, edt.with_ymd_and_hms(2014, 5, 6, 3, 8, 9)?); + let dt = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?; + assert_eq!(dt, edt.with_ymd_and_hms(2014, 5, 6, 3, 8, 9)?.single()?); assert_eq!( dt + TimeDelta::seconds(3600 + 60 + 1), - Utc.with_ymd_and_hms(2014, 5, 6, 8, 9, 10)? + Utc.with_ymd_and_hms(2014, 5, 6, 8, 9, 10)?.single()? ); assert_eq!( - dt.signed_duration_since(edt.ymd(2014, 5, 6).unwrap().and_hms(10, 11, 12).unwrap()), + dt.signed_duration_since(edt.with_ymd_and_hms(2014, 5, 6, 10, 11, 12)?.single()?), TimeDelta::seconds(-7 * 3600 - 3 * 60 - 3) ); - 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); + assert_eq!(*Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?.offset(), Utc); + assert_eq!(*edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?.offset(), edt); + assert!(*edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?.offset() != est); + Ok(()) } #[test] -fn test_datetime_date_and_time() { - 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(); +fn test_datetime_date_and_time() -> Result<(), crate::Error> { + let tz = FixedOffset::east(5 * 60 * 60)?; + let d = tz.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?; + assert_eq!(d.time(), NaiveTime::from_hms(7, 8, 9)?); + assert_eq!(d.date_naive(), NaiveDate::from_ymd(2014, 5, 6)?); + + let tz = FixedOffset::east(4 * 60 * 60)?; + let d = tz.with_ymd_and_hms(2016, 5, 4, 3, 2, 1)?.single()?; + assert_eq!(d.time(), NaiveTime::from_hms(3, 2, 1)?); + assert_eq!(d.date_naive(), NaiveDate::from_ymd(2016, 5, 4)?); + + let tz = FixedOffset::west(13 * 60 * 60)?; + let d = tz.with_ymd_and_hms(2017, 8, 9, 12, 34, 56)?.single()?; + assert_eq!(d.time(), NaiveTime::from_hms(12, 34, 56)?); + assert_eq!(d.date_naive(), NaiveDate::from_ymd(2017, 8, 9)?); + + let utc_d = Utc.with_ymd_and_hms(2017, 8, 9, 12, 34, 56)?.single()?; assert!(utc_d < d); + Ok(()) } #[test] #[cfg(feature = "clock")] -fn test_datetime_with_timezone() -> Result<(), Error> { +fn test_datetime_with_timezone() -> Result<(), crate::Error> { let local_now = Local::now()?; let utc_now = local_now.with_timezone(&Utc)?; let local_now2 = utc_now.with_timezone(&Local)?; @@ -435,162 +440,1006 @@ fn test_datetime_with_timezone() -> Result<(), Error> { } #[test] -fn test_datetime_rfc2822_and_rfc3339() -> Result<(), Error> { - let edt = FixedOffset::east(5 * 60 * 60)?; +fn test_datetime_rfc2822() -> Result<(), crate::Error> { + let edt = FixedOffset::east(5 * 60 * 60).unwrap(); + + // timezone 0 assert_eq!( - Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.to_rfc2822(), + Utc.with_ymd_and_hms(2015, 2, 18, 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(2015, 2, 18).unwrap().and_hms_milli(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(2015, 2, 18) + .unwrap() + .and_hms_micro(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(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(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(-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(-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() -> Result<(), crate::Error> { + let edt5 = FixedOffset::east(5 * 60 * 60)?; + let edt0 = FixedOffset::east(0)?; + + // timezone 0 assert_eq!( Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.to_rfc3339(), "2015-02-18T23:16:09+00:00" ); + // timezone +05 assert_eq!( - edt.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap().to_rfc2822(), - "Wed, 18 Feb 2015 23:16:09 +0500" + edt5.from_local_datetime( + &NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 16, 9, 150)? + )? + .single()? + .to_rfc3339(), + "2015-02-18T23:16:09.150+05:00" ); + + assert_eq!(ymdhms_utc(2015, 2, 18, 23, 16, 9).to_rfc3339(), "2015-02-18T23:16:09+00:00"); assert_eq!( - edt.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap().to_rfc3339(), + ymdhms_milli(&edt5, 2015, 2, 18, 23, 16, 9, 150).to_rfc3339(), "2015-02-18T23:16:09.150+05:00" ); assert_eq!( - 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" + 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)) ); assert_eq!( - 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" + DateTime::::parse_from_rfc3339("2015-02-18T23:16:09Z"), + Ok(ymdhms(&edt0, 2015, 2, 18, 23, 16, 9)) ); assert_eq!( - 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()) + 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_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()) + ymdhms_milli(&edt5, 2015, 2, 18, 23, 16, 9, 150).to_rfc3339(), + "2015-02-18T23:16:09.150+05:00" + ); + 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)) ); assert_eq!( DateTime::::parse_from_rfc3339("2015-02-18T23:16:09Z"), - Ok(FixedOffset::east(0).unwrap().ymd(2015, 2, 18).unwrap().and_hms(23, 16, 9).?) + Ok(ymdhms(&edt0, 2015, 2, 18, 23, 16, 9)) ); assert_eq!( - DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"), - Ok(edt.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 59, 59, 1_000)?) + DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500")?, + edt5.from_local_datetime( + &NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 59, 59, 1_000)? + )? ); assert!(DateTime::::parse_from_rfc2822("31 DEC 262143 23:59 -2359").is_err()); assert_eq!( DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"), - Ok(edt.ymd(2015, 2, 18).unwrap().and_hms_micro(23, 59, 59, 1_234_567)?) + Ok(edt5 + .from_local_datetime( + &NaiveDate::from_ymd(2015, 2, 18) + .unwrap() + .and_hms_micro(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(()) } #[test] -fn test_rfc3339_opts() { +fn test_rfc3339s() -> Result<(), crate::Error> { use crate::SecondsFormat::*; - 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"); - assert_eq!(dt.to_rfc3339_opts(Micros, false), "2018-01-11T10:05:13.084660+08:00"); - assert_eq!(dt.to_rfc3339_opts(Nanos, false), "2018-01-11T10:05:13.084660000+08:00"); - assert_eq!(dt.to_rfc3339_opts(AutoSi, false), "2018-01-11T10:05:13.084660+08:00"); + let pst = FixedOffset::east(8 * 60 * 60)?; + let dt = pst + .from_local_datetime( + &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_000)?, + )?.single()?; + assert_eq!(dt.to_rfc3339s(Secs, false), "2018-01-11T10:05:13+08:00"); + assert_eq!(dt.to_rfc3339s(Secs, true), "2018-01-11T10:05:13+08:00"); + assert_eq!(dt.to_rfc3339s(Millis, false), "2018-01-11T10:05:13.084+08:00"); + assert_eq!(dt.to_rfc3339s(Micros, false), "2018-01-11T10:05:13.084660+08:00"); + assert_eq!(dt.to_rfc3339s(Nanos, false), "2018-01-11T10:05:13.084660000+08:00"); + assert_eq!(dt.to_rfc3339s(AutoSi, false), "2018-01-11T10:05:13.084660+08:00"); let ut = DateTime::::from_utc(dt.naive_utc(), Utc); - assert_eq!(ut.to_rfc3339_opts(Secs, false), "2018-01-11T02:05:13+00:00"); - assert_eq!(ut.to_rfc3339_opts(Secs, true), "2018-01-11T02:05:13Z"); - assert_eq!(ut.to_rfc3339_opts(Millis, false), "2018-01-11T02:05:13.084+00:00"); - assert_eq!(ut.to_rfc3339_opts(Millis, true), "2018-01-11T02:05:13.084Z"); - assert_eq!(ut.to_rfc3339_opts(Micros, true), "2018-01-11T02:05:13.084660Z"); - assert_eq!(ut.to_rfc3339_opts(Nanos, true), "2018-01-11T02:05:13.084660000Z"); - assert_eq!(ut.to_rfc3339_opts(AutoSi, true), "2018-01-11T02:05:13.084660Z"); + assert_eq!(ut.to_rfc3339s(Secs, false), "2018-01-11T02:05:13+00:00"); + assert_eq!(ut.to_rfc3339s(Secs, true), "2018-01-11T02:05:13Z"); + assert_eq!(ut.to_rfc3339s(Millis, false), "2018-01-11T02:05:13.084+00:00"); + assert_eq!(ut.to_rfc3339s(Millis, true), "2018-01-11T02:05:13.084Z"); + assert_eq!(ut.to_rfc3339s(Micros, true), "2018-01-11T02:05:13.084660Z"); + assert_eq!(ut.to_rfc3339s(Nanos, true), "2018-01-11T02:05:13.084660000Z"); + assert_eq!(ut.to_rfc3339s(AutoSi, true), "2018-01-11T02:05:13.084660Z"); + Ok(()) } #[test] #[should_panic] -fn test_rfc3339_opts_nonexhaustive() { +fn test_rfc3339s_nonexhaustive() -> Result<(), crate::Error> { use crate::SecondsFormat; - let dt = Utc.ymd(1999, 10, 9).unwrap().and_hms(1, 2, 3).unwrap(); - dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true); + let dt = Utc.with_ymd_and_hms(1999, 10, 9, 1, 2, 3)?; + dt.to_rfc3339s(SecondsFormat::__NonExhaustive, true); } #[test] -fn test_datetime_from_str() { +fn test_datetime_from_str() -> Result<(), crate::Error> { assert_eq!( - "2015-02-18T23:16:9.15Z".parse::>(), - Ok(FixedOffset::east(0) - .unwrap() - .ymd(2015, 2, 18) + "2015-02-18T23:16:9.15Z".parse::>()?, + FixedOffset::east(0)? + .from_local_datetime(&NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 16, 9, 150)?)? + .single()? + ); + assert_eq!( + "2015-02-18T23:16:9.15Z".parse::>()?, + Utc.from_local_datetime(&NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 16, 9, 150)?)? + .single()? + ); + assert_eq!( + "2015-02-18T23:16:9.15 UTC".parse::>()?, + Utc.from_local_datetime(&NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 16, 9, 150)?)? + .single()? + ); + assert_eq!( + "2015-02-18T23:16:9.15UTC".parse::>()?, + Utc.from_local_datetime(&NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 16, 9, 150)?)? + .single()? + ); + + assert_eq!( + "2015-2-18T23:16:9.15Z".parse::>()?, + FixedOffset::east(0)? + .from_local_datetime(&NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 16, 9, 150)?)? + .single()? + ); + assert_eq!( + "2015-2-18T13:16:9.15-10:00".parse::>()?, + FixedOffset::west(10 * 3600) .unwrap() - .and_hms_milli(23, 16, 9, 150) - .unwrap()) + .from_local_datetime(&NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(13, 16, 9, 150)?)? + .single()? + ); + assert!("2015-2-18T23:16:9.15".parse::>().is_err()); + + assert_eq!( + "2015-2-18T23:16:9.15Z".parse::>()?, + Utc.from_local_datetime(&NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 16, 9, 150)?)? + .single()? + ); + assert_eq!( + "2015-2-18T13:16:9.15-10:00".parse::>()?, + Utc.from_local_datetime(&NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 16, 9, 150)?)? + .single()? + ); + assert!("2015-2-18T23:16:9.15".parse::>().is_err()); + + // no test for `DateTime`, we cannot verify that much. + Ok(()) +} + +#[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(570 * 60).unwrap(); + let edt0 = FixedOffset::east(0).unwrap(); + let wdt = FixedOffset::west(10 * 3600).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)) + ); // ignore offset + assert!(DateTime::::parse_from_str("20140507000000", "%Y%m%d%H%M%S").is_err()); // no offset + assert!(DateTime::::parse_from_str( + "Fri, 09 Aug 2013 23:54:35 GMT", + "%a, %d %b %Y %H:%M:%S GMT" + ) + .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(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) + Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)), ); assert_eq!( "2015-02-18T23:16:9.15 UTC".parse::>(), - Ok(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) + Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)) ); assert_eq!( "2015-02-18T23:16:9.15UTC".parse::>(), - Ok(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) + Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)) ); assert_eq!( "2015-2-18T23:16:9.15Z".parse::>(), - Ok(FixedOffset::east(0) - .unwrap() - .ymd(2015, 2, 18) - .unwrap() - .and_hms_milli(23, 16, 9, 150) - .unwrap()) + Ok(ymdhms_milli(&edt0, 2015, 2, 18, 23, 16, 9, 150)) ); assert_eq!( "2015-2-18T13:16:9.15-10:00".parse::>(), - Ok(FixedOffset::west(10 * 3600) - .unwrap() - .ymd(2015, 2, 18) - .unwrap() - .and_hms_milli(13, 16, 9, 150) - .unwrap()) + 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(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) + Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)) ); assert_eq!( "2015-2-18T13:16:9.15-10:00".parse::>(), - Ok(Utc.ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap()) + 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 ymdhms = |y, m, d, h, n, s, off| { - FixedOffset::east(off).unwrap().ymd(y, m, d).unwrap().and_hms(h, n, s).unwrap() - }; + let dt = ymdhms(&FixedOffset::east(-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("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), - 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 + 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( - "Fri, 09 Aug 2013 23:54:35 GMT", - "%a, %d %b %Y %H:%M:%S GMT" + "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!( - Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT"), - Ok(Utc.ymd(2013, 8, 9).unwrap().and_hms(23, 54, 35).unwrap()) + 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), ); // bad timezone data assert!(DateTime::::parse_from_str( @@ -632,20 +1481,20 @@ fn test_datetime_parse_from_str() { #[test] fn test_to_string_round_trip() { - let dt = Utc.ymd(2000, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); + let dt = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap(); let _dt: DateTime = dt.to_string().parse().unwrap(); - let ndt_fixed = dt.with_fixed_timezone(&FixedOffset::east(3600).unwrap()); + let ndt_fixed = dt.with_timezone(&FixedOffset::east(3600).unwrap()); let _dt: DateTime = ndt_fixed.to_string().parse().unwrap(); - let ndt_fixed = dt.with_fixed_timezone(&FixedOffset::east(0).unwrap()); + let ndt_fixed = dt.with_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().unwrap(); + let ndt = Local::now(); let _dt: DateTime = ndt.to_string().parse().unwrap(); } @@ -653,15 +1502,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().unwrap().with_month(5).unwrap(); - assert_eq!(dt.format("%Y").to_string(), dt.with_fixed_timezone(&Utc).format("%Y").to_string()); + let dt = Local::now().with_month(5).unwrap(); + assert_eq!(dt.format("%Y").to_string(), dt.with_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().unwrap(); + let a = Utc::now(); let b = a; assert_eq!(a, b); } @@ -682,7 +1531,11 @@ fn test_datetime_is_send() { #[test] fn test_subsecond_part() { - let datetime = Utc.ymd(2014, 7, 8).unwrap().and_hms_nano(9, 10, 11, 1234567).unwrap(); + let datetime = Utc + .from_local_datetime( + &NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms_nano(9, 10, 11, 1234567).unwrap(), + ) + .unwrap(); assert_eq!(1, datetime.timestamp_subsec_millis()); assert_eq!(1234, datetime.timestamp_subsec_micros()); @@ -694,42 +1547,58 @@ fn test_subsecond_part() { fn test_from_system_time() { use std::time::Duration; - let epoch = Utc.ymd(1970, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); + let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap(); let nanos = 999_999_999; // SystemTime -> DateTime assert_eq!(DateTime::::from(UNIX_EPOCH), epoch); assert_eq!( DateTime::::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)), - Utc.ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() + Utc.from_local_datetime( + &NaiveDate::from_ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() + ) + .unwrap() ); assert_eq!( DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), - Utc.ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1).unwrap() + Utc.from_local_datetime( + &NaiveDate::from_ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1).unwrap() + ) + .unwrap() ); // DateTime -> SystemTime assert_eq!(SystemTime::from(epoch), UNIX_EPOCH); assert_eq!( - SystemTime::from(Utc.ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap()), + SystemTime::from( + Utc.from_local_datetime( + &NaiveDate::from_ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() + ) + .unwrap() + ), UNIX_EPOCH + Duration::new(999_999_999, nanos) ); assert_eq!( - SystemTime::from(Utc.ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1).unwrap()), + SystemTime::from( + Utc.from_local_datetime( + &NaiveDate::from_ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1).unwrap() + ) + .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).unwrap()), UNIX_EPOCH); + assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH); } assert_eq!( - SystemTime::from(epoch.with_fixed_timezone(&FixedOffset::east(32400).unwrap())), + SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400).unwrap())), UNIX_EPOCH ); assert_eq!( - SystemTime::from(epoch.with_fixed_timezone(&FixedOffset::west(28800).unwrap())), + SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800).unwrap())), UNIX_EPOCH ); } @@ -737,59 +1606,68 @@ 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.ymd(1970, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); + let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap(); // SystemTime -> DateTime assert_eq!(DateTime::::from(UNIX_EPOCH), epoch); assert_eq!( DateTime::::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)), - Utc.ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() + Utc.from_local_datetime( + &NaiveDate::from_ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() + ) + .unwrap() ); assert_eq!( DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), - Utc.ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1_000).unwrap() + Utc.from_local_datetime( + &NaiveDate::from_ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1_000).unwrap() + ) + .unwrap() ); // DateTime -> SystemTime - assert_eq!(SystemTime::try_from(epoch).unwrap(), UNIX_EPOCH); + assert_eq!(SystemTime::from(epoch), UNIX_EPOCH); assert_eq!( - SystemTime::try_from(Utc.ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap()) - .unwrap(), + SystemTime::from( + Utc.from_local_datetime( + &NaiveDate::from_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::try_from( - Utc.ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1_000).unwrap() - ) - .unwrap(), + SystemTime::from( + Utc.from_local_datetime( + &NaiveDate::from_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::try_from(epoch.with_timezone(&Local).unwrap()).unwrap(), UNIX_EPOCH); + assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH); } assert_eq!( - SystemTime::try_from(epoch.with_fixed_timezone(&FixedOffset::east(32400).unwrap())) - .unwrap(), + SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400).unwrap())), UNIX_EPOCH ); assert_eq!( - SystemTime::try_from(epoch.with_fixed_timezone(&FixedOffset::west(28800).unwrap())) - .unwrap(), + SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800).unwrap())), UNIX_EPOCH ); } #[test] fn test_datetime_format_alignment() { - let datetime = Utc.ymd(2007, 1, 2).unwrap().unwrap(); + let datetime = Utc.with_ymd_and_hms(2007, 1, 2, 0, 0, 0).unwrap(); // Item::Literal let percent = datetime.format("%%"); @@ -820,21 +1698,21 @@ fn test_datetime_format_alignment() { #[test] fn test_datetime_from_local() { // 2000-01-12T02:00:00Z - let naivedatetime_utc = ymd!(2000, 1, 12).and_hms(2, 0, 0).unwrap(); + let naivedatetime_utc = NaiveDate::from_ymd(2000, 1, 12).unwrap().and_hms(2, 0, 0).unwrap(); let datetime_utc = DateTime::::from_utc(naivedatetime_utc, Utc); // 2000-01-12T10:00:00+8:00:00 let timezone_east = FixedOffset::east(8 * 60 * 60).unwrap(); - let naivedatetime_east = ymd!(2000, 1, 12).and_hms(10, 0, 0).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); // 2000-01-11T19:00:00-7:00:00 let timezone_west = FixedOffset::west(7 * 60 * 60).unwrap(); - let naivedatetime_west = ymd!(2000, 1, 11).and_hms(19, 0, 0).unwrap(); + let naivedatetime_west = NaiveDate::from_ymd(2000, 1, 11).unwrap().and_hms(19, 0, 0).unwrap(); let datetime_west = DateTime::::from_local(naivedatetime_west, timezone_west); - assert_eq!(datetime_east, datetime_utc.with_fixed_timezone(&timezone_east)); - assert_eq!(datetime_west, datetime_utc.with_fixed_timezone(&timezone_west)); + assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east)); + assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)); } #[test] @@ -844,22 +1722,22 @@ fn test_years_elapsed() { // This is always at least one year because 1 year = 52.1775 weeks. let one_year_ago = - Utc::today().unwrap() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); + Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); // A bit more than 2 years. let two_year_ago = - Utc::today().unwrap() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); + Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); - assert_eq!(Utc::today().unwrap().years_since(one_year_ago), Some(1)); - assert_eq!(Utc::today().unwrap().years_since(two_year_ago), Some(2)); + assert_eq!(Utc::now().date_naive().years_since(one_year_ago), Some(1)); + assert_eq!(Utc::now().date_naive().years_since(two_year_ago), Some(2)); // If the given DateTime is later than now, the function will always return 0. - let future = Utc::today().unwrap() + TimeDelta::weeks(12); - assert_eq!(Utc::today().unwrap().years_since(future), None); + let future = Utc::now().date_naive() + TimeDelta::weeks(12); + assert_eq!(Utc::now().date_naive().years_since(future), None); } #[test] fn test_datetime_add_assign() { - let naivedatetime = ymd!(2000, 1, 1).and_hms(0, 0, 0).unwrap(); + let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); let datetime = DateTime::::from_utc(naivedatetime, Utc); let mut datetime_add = datetime; @@ -867,14 +1745,14 @@ fn test_datetime_add_assign() { assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); let timezone = FixedOffset::east(60 * 60).unwrap(); - let datetime = datetime.with_timezone(&timezone).unwrap(); - let datetime_add = datetime_add.with_timezone(&timezone).unwrap(); + let datetime = datetime.with_timezone(&timezone); + let datetime_add = datetime_add.with_timezone(&timezone); assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); let timezone = FixedOffset::west(2 * 60 * 60).unwrap(); - let datetime = datetime.with_timezone(&timezone).unwrap(); - let datetime_add = datetime_add.with_timezone(&timezone).unwrap(); + let datetime = datetime.with_timezone(&timezone); + let datetime_add = datetime_add.with_timezone(&timezone); assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); } @@ -882,10 +1760,10 @@ fn test_datetime_add_assign() { #[test] #[cfg(feature = "clock")] fn test_datetime_add_assign_local() { - let naivedatetime = ymd!(2022, 1, 1).and_hms(0, 0, 0).unwrap(); + let naivedatetime = NaiveDate::from_ymd(2022, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); - let datetime = Local.from_utc_datetime(&naivedatetime).unwrap(); - let mut datetime_add = Local.from_utc_datetime(&naivedatetime).unwrap(); + let datetime = Local.from_utc_datetime(&naivedatetime); + let mut datetime_add = Local.from_utc_datetime(&naivedatetime); // ensure we cross a DST transition for i in 1..=365 { @@ -896,7 +1774,7 @@ fn test_datetime_add_assign_local() { #[test] fn test_datetime_sub_assign() { - let naivedatetime = ymd!(2000, 1, 1).and_hms(12, 0, 0).unwrap(); + let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).unwrap().and_hms(12, 0, 0).unwrap(); let datetime = DateTime::::from_utc(naivedatetime, Utc); let mut datetime_sub = datetime; @@ -904,14 +1782,14 @@ fn test_datetime_sub_assign() { assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); let timezone = FixedOffset::east(60 * 60).unwrap(); - let datetime = datetime.with_timezone(&timezone).unwrap(); - let datetime_sub = datetime_sub.with_timezone(&timezone).unwrap(); + let datetime = datetime.with_timezone(&timezone); + let datetime_sub = datetime_sub.with_timezone(&timezone); assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); let timezone = FixedOffset::west(2 * 60 * 60).unwrap(); - let datetime = datetime.with_timezone(&timezone).unwrap(); - let datetime_sub = datetime_sub.with_timezone(&timezone).unwrap(); + let datetime = datetime.with_timezone(&timezone); + let datetime_sub = datetime_sub.with_timezone(&timezone); assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); } @@ -919,10 +1797,10 @@ fn test_datetime_sub_assign() { #[test] #[cfg(feature = "clock")] fn test_datetime_sub_assign_local() { - let naivedatetime = ymd!(2022, 1, 1).and_hms(0, 0, 0).unwrap(); + let naivedatetime = NaiveDate::from_ymd(2022, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); - let datetime = Local.from_utc_datetime(&naivedatetime).unwrap(); - let mut datetime_sub = Local.from_utc_datetime(&naivedatetime).unwrap(); + let datetime = Local.from_utc_datetime(&naivedatetime); + let mut datetime_sub = Local.from_utc_datetime(&naivedatetime); // ensure we cross a DST transition for i in 1..=365 { diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 5253679a1b..af421f1dfb 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -99,11 +99,14 @@ impl TimeZone for Local { } // they are easier to define in terms of the finished date and time unlike other offsets - fn offset_from_local_date(&self, local: &NaiveDate,) -> Result, Error> { + 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,) -> Result, Error> { + fn offset_from_local_datetime( + &self, + local: &NaiveDateTime, + ) -> Result, Error> { Ok(self.from_local_datetime(local)?.map(|o| *o.offset())) } @@ -135,10 +138,13 @@ impl TimeZone for Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] - fn from_local_datetime(&self, local: &NaiveDateTime) -> Result>, Error> { + fn from_local_datetime( + &self, + local: &NaiveDateTime, + ) -> Result>, Error> { inner::naive_to_local(local, true) } - + #[cfg(all( target_arch = "wasm32", feature = "wasmbind", diff --git a/src/offset/mod.rs b/src/offset/mod.rs index 68429a7445..f0d0065ddc 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -177,7 +177,6 @@ pub trait Offset: Sized + Clone + fmt::Debug { fn fix(&self) -> FixedOffset; } - /// The time zone. /// /// The methods here are the primarily constructors for [`Date`](../struct.Date.html) and @@ -202,9 +201,7 @@ pub trait TimeZone: Sized + Clone { min: u32, sec: u32, ) -> Result>, Error> { - self.from_local_datetime( - &NaiveDate::from_ymd(year, month, day)?.and_hms(hour, min, sec)? - ) + self.from_local_datetime(&NaiveDate::from_ymd(year, month, day)?.and_hms(hour, min, sec)?) } /// Makes a new `DateTime` from the number of non-leap seconds @@ -293,10 +290,14 @@ 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) -> Result, Error>; + 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) -> Result, Error>; + 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)] @@ -304,14 +305,19 @@ pub trait TimeZone: Sized + Clone { fn from_local_date(&self, local: &NaiveDate) -> Result>, Error> { // TODO: This might be total nonsense, but the functionality is required at quite a few places // Is the default time of a day midnight or noon? - Ok(self.offset_from_local_date(local)? + Ok(self + .offset_from_local_date(local)? .map(|offset| Date::from_utc((local.and_midnight() - offset.fix()).date(), offset))) } /// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible. #[allow(clippy::wrong_self_convention)] - fn from_local_datetime(&self, local: &NaiveDateTime) -> Result>, Error> { - Ok(self.offset_from_local_datetime(local)? + fn from_local_datetime( + &self, + local: &NaiveDateTime, + ) -> Result>, Error> { + Ok(self + .offset_from_local_datetime(local)? .map(|offset| DateTime::from_utc(*local - offset.fix(), offset))) } From 34f05c16e635884d562d789da56ab820d2d01d75 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 16:57:57 +0200 Subject: [PATCH 16/54] Missed some utc/local date offset --- src/offset/local/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index af421f1dfb..8e73819a1b 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -118,6 +118,16 @@ impl TimeZone for Local { Ok(*self.from_utc_datetime(utc)?.offset()) } + // override them for avoiding redundant works + #[allow(deprecated)] + 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_midnight())?; + Ok(midnight.map(|datetime| Date::from_utc(*local, *datetime.offset()))) + } + #[cfg(all( target_arch = "wasm32", feature = "wasmbind", @@ -145,6 +155,12 @@ impl TimeZone for Local { inner::naive_to_local(local, true) } + #[allow(deprecated)] + 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( target_arch = "wasm32", feature = "wasmbind", From 92a43080f3caa5be8c7534f7f4d560d19bf5059f Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 17:47:01 +0200 Subject: [PATCH 17/54] Fix more tests --- src/datetime/tests.rs | 188 ++++++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 88 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 2562e8e270..48848e0152 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -230,16 +230,16 @@ fn test_datetime_sub_months() -> Result<(), crate::Error> { "2014-04-06 07:08:09 -05:00" ); assert_eq!( - format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).?.single()? - Months::new(1)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? - 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).?.single()? - Months::new(5)), + format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? - 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).?.single()? - Months::new(5)), + format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()? - Months::new(5)), "2013-12-06 07:08:09 +09:00" ); Ok(()) @@ -272,6 +272,8 @@ fn ymdhms_milli( fixedoffset .with_ymd_and_hms(year, month, day, hour, min, sec) .unwrap() + .single() + .unwrap() .checked_add_signed(TimeDelta::milliseconds(milli)) .unwrap() } @@ -290,6 +292,8 @@ fn ymdhms_micro( fixedoffset .with_ymd_and_hms(year, month, day, hour, min, sec) .unwrap() + .single() + .unwrap() .checked_add_signed(TimeDelta::microseconds(micro)) .unwrap() } @@ -308,13 +312,15 @@ fn ymdhms_nano( fixedoffset .with_ymd_and_hms(year, month, day, hour, min, sec) .unwrap() + .single() + .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() + Utc.with_ymd_and_hms(year, month, day, hour, min, sec).unwrap().single().unwrap() } // local helper function to easily create a DateTime @@ -328,6 +334,8 @@ fn ymdhms_milli_utc( milli: i64, ) -> DateTime { Utc.with_ymd_and_hms(year, month, day, hour, min, sec) + .unwrap() + .single() .unwrap() .checked_add_signed(TimeDelta::milliseconds(milli)) .unwrap() @@ -441,54 +449,49 @@ fn test_datetime_with_timezone() -> Result<(), crate::Error> { #[test] fn test_datetime_rfc2822() -> Result<(), crate::Error> { - let edt = FixedOffset::east(5 * 60 * 60).unwrap(); + let edt = FixedOffset::east(5 * 60 * 60)?; // timezone 0 assert_eq!( - Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc2822(), + Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.single()?.to_rfc2822(), "Wed, 18 Feb 2015 23:16:09 +0000" ); // timezone +05 assert_eq!( - edt.from_local_datetime( - &NaiveDate::from_ymd(2015, 2, 18).unwrap().and_hms_milli(23, 16, 9, 150).unwrap() - ) - .unwrap() - .to_rfc2822(), + edt.from_local_datetime(&NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 16, 9, 150)?)? + .single()? + .to_rfc2822(), "Wed, 18 Feb 2015 23:16:09 +0500" ); // seconds 60 assert_eq!( edt.from_local_datetime( - &NaiveDate::from_ymd(2015, 2, 18) - .unwrap() - .and_hms_micro(23, 59, 59, 1_234_567) - .unwrap() - ) - .unwrap() + &NaiveDate::from_ymd(2015, 2, 18)?.and_hms_micro(23, 59, 59, 1_234_567)? + )? + .single()? .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(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()) + DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000")?, + FixedOffset::east(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.single()? ); assert_eq!( - DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000"), - Ok(FixedOffset::east(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()) + DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000")?, + FixedOffset::east(0)?.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.single()? ); 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)) + DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:58 +0500")?, + 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)) + DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:58 +0500")?, + ymdhms_milli(&edt, 2015, 2, 18, 23, 59, 58, 500) ); // many varying whitespace intermixed @@ -536,6 +539,7 @@ fn test_datetime_rfc2822() -> Result<(), crate::Error> { assert!( DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000 ").is_err() ); + Ok(()) } #[test] @@ -545,7 +549,7 @@ fn test_datetime_rfc3339() -> Result<(), crate::Error> { // timezone 0 assert_eq!( - Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.to_rfc3339(), + Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.single()?.to_rfc3339(), "2015-02-18T23:16:09+00:00" ); // timezone +05 @@ -605,18 +609,18 @@ fn test_datetime_rfc3339() -> Result<(), crate::Error> { edt5.from_local_datetime( &NaiveDate::from_ymd(2015, 2, 18)?.and_hms_milli(23, 59, 59, 1_000)? )? + .single()? ); 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(2015, 2, 18) - .unwrap() - .and_hms_micro(23, 59, 59, 1_234_567) - .unwrap() - ) - .unwrap()) + DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00")?, + edt5.from_local_datetime( + &NaiveDate::from_ymd(2015, 2, 18) + .unwrap() + .and_hms_micro(23, 59, 59, 1_234_567) + .unwrap() + )? + .single()? ); assert_eq!(ymdhms_utc(2015, 2, 18, 23, 16, 9).to_rfc3339(), "2015-02-18T23:16:09+00:00"); @@ -653,40 +657,42 @@ fn test_datetime_rfc3339() -> Result<(), crate::Error> { assert!( DateTime::::parse_from_rfc3339("2015-02-18T23:59:60.234567A+05:00").is_err() ); + Ok(()) } #[test] -fn test_rfc3339s() -> Result<(), crate::Error> { +fn test_rfc3339_opts() -> Result<(), crate::Error> { use crate::SecondsFormat::*; let pst = FixedOffset::east(8 * 60 * 60)?; let dt = pst .from_local_datetime( - &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_000)?, - )?.single()?; - assert_eq!(dt.to_rfc3339s(Secs, false), "2018-01-11T10:05:13+08:00"); - assert_eq!(dt.to_rfc3339s(Secs, true), "2018-01-11T10:05:13+08:00"); - assert_eq!(dt.to_rfc3339s(Millis, false), "2018-01-11T10:05:13.084+08:00"); - assert_eq!(dt.to_rfc3339s(Micros, false), "2018-01-11T10:05:13.084660+08:00"); - assert_eq!(dt.to_rfc3339s(Nanos, false), "2018-01-11T10:05:13.084660000+08:00"); - assert_eq!(dt.to_rfc3339s(AutoSi, false), "2018-01-11T10:05:13.084660+08:00"); + &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_000)? + )? + .single()?; + 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"); + assert_eq!(dt.to_rfc3339_opts(Micros, false), "2018-01-11T10:05:13.084660+08:00"); + assert_eq!(dt.to_rfc3339_opts(Nanos, false), "2018-01-11T10:05:13.084660000+08:00"); + assert_eq!(dt.to_rfc3339_opts(AutoSi, false), "2018-01-11T10:05:13.084660+08:00"); let ut = DateTime::::from_utc(dt.naive_utc(), Utc); - assert_eq!(ut.to_rfc3339s(Secs, false), "2018-01-11T02:05:13+00:00"); - assert_eq!(ut.to_rfc3339s(Secs, true), "2018-01-11T02:05:13Z"); - assert_eq!(ut.to_rfc3339s(Millis, false), "2018-01-11T02:05:13.084+00:00"); - assert_eq!(ut.to_rfc3339s(Millis, true), "2018-01-11T02:05:13.084Z"); - assert_eq!(ut.to_rfc3339s(Micros, true), "2018-01-11T02:05:13.084660Z"); - assert_eq!(ut.to_rfc3339s(Nanos, true), "2018-01-11T02:05:13.084660000Z"); - assert_eq!(ut.to_rfc3339s(AutoSi, true), "2018-01-11T02:05:13.084660Z"); + assert_eq!(ut.to_rfc3339_opts(Secs, false), "2018-01-11T02:05:13+00:00"); + assert_eq!(ut.to_rfc3339_opts(Secs, true), "2018-01-11T02:05:13Z"); + assert_eq!(ut.to_rfc3339_opts(Millis, false), "2018-01-11T02:05:13.084+00:00"); + assert_eq!(ut.to_rfc3339_opts(Millis, true), "2018-01-11T02:05:13.084Z"); + assert_eq!(ut.to_rfc3339_opts(Micros, true), "2018-01-11T02:05:13.084660Z"); + assert_eq!(ut.to_rfc3339_opts(Nanos, true), "2018-01-11T02:05:13.084660000Z"); + assert_eq!(ut.to_rfc3339_opts(AutoSi, true), "2018-01-11T02:05:13.084660Z"); Ok(()) } #[test] #[should_panic] -fn test_rfc3339s_nonexhaustive() -> Result<(), crate::Error> { +fn test_rfc3339_nonexhaustive() { use crate::SecondsFormat; - let dt = Utc.with_ymd_and_hms(1999, 10, 9, 1, 2, 3)?; - dt.to_rfc3339s(SecondsFormat::__NonExhaustive, true); + let dt = Utc.with_ymd_and_hms(1999, 10, 9, 1, 2, 3).unwrap().single().unwrap(); + dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true); } #[test] @@ -838,10 +844,10 @@ fn test_parse_datetime_utc() { } #[test] -fn test_utc_datetime_from_str() { - let edt = FixedOffset::east(570 * 60).unwrap(); - let edt0 = FixedOffset::east(0).unwrap(); - let wdt = FixedOffset::west(10 * 3600).unwrap(); +fn test_utc_datetime_from_str() -> Result<(), crate::Error> { + let edt = FixedOffset::east(570 * 60)?; + let edt0 = FixedOffset::east(0)?; + let wdt = FixedOffset::west(10 * 3600)?; 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)) @@ -853,8 +859,8 @@ 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()) + Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT")?, + Utc.with_ymd_and_hms(2013, 8, 9, 23, 54, 35)?.single()? ); assert_eq!( @@ -895,6 +901,7 @@ fn test_utc_datetime_from_str() { assert!("2015-2-18T23:16:9.15".parse::>().is_err()); // no test for `DateTime`, we cannot verify that much. + Ok(()) } #[test] @@ -1480,22 +1487,24 @@ 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: DateTime = dt.to_string().parse().unwrap(); +fn test_to_string_round_trip() -> Result<(), crate::Error> { + let dt = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0)?.single()?; + let _dt: DateTime = dt.to_string().parse()?; - let ndt_fixed = dt.with_timezone(&FixedOffset::east(3600).unwrap()); - let _dt: DateTime = ndt_fixed.to_string().parse().unwrap(); + let ndt_fixed = dt.with_timezone(&FixedOffset::east(3600)?)?; + let _dt: DateTime = ndt_fixed.to_string().parse()?; - let ndt_fixed = dt.with_timezone(&FixedOffset::east(0).unwrap()); - let _dt: DateTime = ndt_fixed.to_string().parse().unwrap(); + let ndt_fixed = dt.with_timezone(&FixedOffset::east(0)?)?; + let _dt: DateTime = ndt_fixed.to_string().parse()?; + Ok(()) } #[test] #[cfg(feature = "clock")] -fn test_to_string_round_trip_with_local() { - let ndt = Local::now(); - let _dt: DateTime = ndt.to_string().parse().unwrap(); +fn test_to_string_round_trip_with_local() -> Result<(), crate::Error> { + let ndt = Local::now()?; + let _dt: DateTime = ndt.to_string().parse()?; + Ok(()) } #[test] @@ -1717,59 +1726,62 @@ fn test_datetime_from_local() { #[test] #[cfg(feature = "clock")] -fn test_years_elapsed() { +fn test_years_elapsed() -> Result<(), crate::Error> { 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::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); + Utc::now()?.date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64); // A bit more than 2 years. let two_year_ago = - Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); + Utc::now()?.date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64); - assert_eq!(Utc::now().date_naive().years_since(one_year_ago), Some(1)); - assert_eq!(Utc::now().date_naive().years_since(two_year_ago), Some(2)); + assert_eq!(Utc::now()?.date_naive().years_since(one_year_ago), Some(1)); + assert_eq!(Utc::now()?.date_naive().years_since(two_year_ago), Some(2)); // If the given DateTime is later than now, the function will always return 0. - let future = Utc::now().date_naive() + TimeDelta::weeks(12); - assert_eq!(Utc::now().date_naive().years_since(future), None); + let future = Utc::now()?.date_naive() + TimeDelta::weeks(12); + assert_eq!(Utc::now()?.date_naive().years_since(future), None); + Ok(()) } #[test] -fn test_datetime_add_assign() { - let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); +fn test_datetime_add_assign() -> Result<(), crate::Error> { + let naivedatetime = NaiveDate::from_ymd(2000, 1, 1)?.and_hms(0, 0, 0)?; let datetime = DateTime::::from_utc(naivedatetime, Utc); let mut datetime_add = datetime; datetime_add += TimeDelta::seconds(60); assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); - let timezone = FixedOffset::east(60 * 60).unwrap(); - let datetime = datetime.with_timezone(&timezone); - let datetime_add = datetime_add.with_timezone(&timezone); + let timezone = FixedOffset::east(60 * 60)?; + let datetime = datetime.with_timezone(&timezone)?; + let datetime_add = datetime_add.with_timezone(&timezone)?; assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); - let timezone = FixedOffset::west(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)?; + let datetime = datetime.with_timezone(&timezone)?; + let datetime_add = datetime_add.with_timezone(&timezone)?; assert_eq!(datetime_add, datetime + TimeDelta::seconds(60)); + Ok(()) } #[test] #[cfg(feature = "clock")] -fn test_datetime_add_assign_local() { - let naivedatetime = NaiveDate::from_ymd(2022, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); +fn test_datetime_add_assign_local() -> Result<(), crate::Error> { + let naivedatetime = NaiveDate::from_ymd(2022, 1, 1)?.and_hms(0, 0, 0)?; let datetime = Local.from_utc_datetime(&naivedatetime); - let mut datetime_add = Local.from_utc_datetime(&naivedatetime); + let mut datetime_add = Local.from_utc_datetime(&naivedatetime)?; // ensure we cross a DST transition for i in 1..=365 { datetime_add += TimeDelta::days(1); assert_eq!(datetime_add, datetime + TimeDelta::days(i)) } + Ok(()) } #[test] From 0d0d5ba5aaa7691e8b49d2665cbee6be6e8aa469 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 18:08:22 +0200 Subject: [PATCH 18/54] Test fixing --- src/date.rs | 2 +- src/datetime/tests.rs | 8 +- src/month.rs | 4 +- src/round.rs | 334 ++++++++++++++++++++++-------------------- 4 files changed, 180 insertions(+), 168 deletions(-) diff --git a/src/date.rs b/src/date.rs index 82678c3fa1..3b411a73d7 100644 --- a/src/date.rs +++ b/src/date.rs @@ -573,7 +573,7 @@ mod tests { fn test_date_add_assign_local() { let naivedate = NaiveDate::from_ymd(2000, 1, 1).unwrap(); - let date = Local.from_utc(&naivedate).unwrap(); + let date = Local.from_utc_date(&naivedate).unwrap(); let mut date_add = date; date_add += TimeDelta::days(5); diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 48848e0152..d08b2af5e6 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -666,7 +666,7 @@ fn test_rfc3339_opts() -> Result<(), crate::Error> { let pst = FixedOffset::east(8 * 60 * 60)?; let dt = pst .from_local_datetime( - &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_000)? + &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_000)?, )? .single()?; assert_eq!(dt.to_rfc3339_opts(Secs, false), "2018-01-11T10:05:13+08:00"); @@ -1511,7 +1511,7 @@ fn test_to_string_round_trip_with_local() -> Result<(), crate::Error> { #[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(); + let dt = Local::now()?.with_month(5).unwrap(); assert_eq!(dt.format("%Y").to_string(), dt.with_timezone(&Utc).format("%Y").to_string()); } @@ -1544,7 +1544,7 @@ fn test_subsecond_part() { .from_local_datetime( &NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms_nano(9, 10, 11, 1234567).unwrap(), ) - .unwrap(); + .unwrap().single().unwrap(); assert_eq!(1, datetime.timestamp_subsec_millis()); assert_eq!(1234, datetime.timestamp_subsec_micros()); @@ -1773,7 +1773,7 @@ fn test_datetime_add_assign() -> Result<(), crate::Error> { fn test_datetime_add_assign_local() -> Result<(), crate::Error> { let naivedatetime = NaiveDate::from_ymd(2022, 1, 1)?.and_hms(0, 0, 0)?; - let datetime = Local.from_utc_datetime(&naivedatetime); + let datetime = Local.from_utc_datetime(&naivedatetime)?; let mut datetime_add = Local.from_utc_datetime(&naivedatetime)?; // ensure we cross a DST transition diff --git a/src/month.rs b/src/month.rs index f3234f6947..54a1f66ae0 100644 --- a/src/month.rs +++ b/src/month.rs @@ -324,11 +324,11 @@ mod tests { assert_eq!(Month::try_from(12), Ok(Month::December)); assert_eq!(Month::try_from(13), Err(OutOfRange::new())); - let date = Utc.ymd(2019, 10, 28).unwrap().and_hms(9, 10, 11).unwrap(); + let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap().single().unwrap(); assert_eq!(Month::try_from(date.month() as u8), Ok(Month::October)); let month = Month::January; - let dt = Utc.ymd(2019, month.number_from_month(), 28).unwrap().and_hms(9, 10, 11).unwrap(); + let dt = Utc.with_ymd_and_hms(2019, month.number_from_month(), 28, 9, 10, 11).unwrap().single().unwrap(); assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28)); } diff --git a/src/round.rs b/src/round.rs index f863c803ff..b681580e85 100644 --- a/src/round.rs +++ b/src/round.rs @@ -24,11 +24,11 @@ pub trait SubsecRound { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?; + /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd(2018, 1, 11).?.and_hms_milli(12, 0, 0, 154).?.and_local_timezone(Utc).?; /// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` fn round_subsecs(self, digits: u16) -> Self; @@ -37,11 +37,11 @@ pub trait SubsecRound { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?; + /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd(2018, 1, 11).?.and_hms_milli(12, 0, 0, 154).?.and_local_timezone(Utc).?; /// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` fn trunc_subsecs(self, digits: u16) -> Self; } @@ -113,17 +113,17 @@ pub trait DurationRound: Sized { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?; + /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd(2018, 1, 11).?.and_hms_milli(12, 0, 0, 154).?.and_local_timezone(Utc).?; /// assert_eq!( - /// dt.duration_round(TimeDelta::milliseconds(10))?.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))?.to_string(), + /// dt.duration_round(TimeDelta::days(1)).?.to_string(), /// "2018-01-12 00:00:00 UTC" /// ); - /// # Ok::<_, Box>(()) + /// Ok(()) /// ``` fn duration_round(self, duration: TimeDelta) -> Result; @@ -131,17 +131,17 @@ pub trait DurationRound: Sized { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?; + /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd(2018, 1, 11).?.and_hms_milli(12, 0, 0, 154).?.and_local_timezone(Utc).?; /// assert_eq!( - /// dt.duration_trunc(TimeDelta::milliseconds(10))?.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))?.to_string(), + /// dt.duration_trunc(TimeDelta::days(1)).?.to_string(), /// "2018-01-11 00:00:00 UTC" /// ); - /// # Ok::<_, Box>(()) + /// Ok(()) /// ``` fn duration_trunc(self, duration: TimeDelta) -> Result; } @@ -248,27 +248,27 @@ pub enum RoundingError { /// /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.ymd(1970, 12, 12)?.and_hms(0, 0, 0)?; + /// let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0)?.single()?; /// /// assert_eq!( /// dt.duration_round(TimeDelta::days(365)), /// Err(RoundingError::DurationExceedsTimestamp), /// ); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` DurationExceedsTimestamp, /// Error when `TimeDelta.num_nanoseconds` exceeds the limit. /// /// ``` rust - /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.ymd(2260, 12, 31)?.and_hms_nano(23, 59, 59, 1_75_500_000)?; + /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd(2260, 12, 31).?.and_hms_nano(23, 59, 59, 1_75_500_000).?.and_local_timezone(Utc).?; /// /// assert_eq!( /// dt.duration_round(TimeDelta::days(300 * 365)), /// Err(RoundingError::DurationExceedsLimit) /// ); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` DurationExceedsLimit, @@ -276,10 +276,10 @@ pub enum RoundingError { /// /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.ymd(2300, 12, 12)?.and_hms(0, 0, 0)?; + /// let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0)?.single()?; /// /// assert_eq!(dt.duration_round(TimeDelta::days(1)), Err(RoundingError::TimestampExceedsLimit),); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` TimestampExceedsLimit, } @@ -313,13 +313,15 @@ impl std::error::Error for RoundingError { mod tests { use super::{DurationRound, SubsecRound, TimeDelta}; use crate::offset::{FixedOffset, TimeZone, Utc}; - use crate::Error; + use crate::NaiveDate; use crate::Timelike; #[test] - fn test_round_subsecs() { - 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(); + fn test_round_subsecs() -> Result<(), crate::Error> { + let pst = FixedOffset::east(8 * 60 * 60)?; + let dt = pst.from_local_datetime( + &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_684)?, + )?.single()?; assert_eq!(dt.round_subsecs(10), dt); assert_eq!(dt.round_subsecs(9), dt); @@ -335,7 +337,12 @@ mod tests { assert_eq!(dt.round_subsecs(0).nanosecond(), 0); assert_eq!(dt.round_subsecs(0).second(), 13); - let dt = Utc.ymd(2018, 1, 11).unwrap().and_hms_nano(10, 5, 27, 750_500_000).unwrap(); + let dt = Utc.from_local_datetime(&NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano( + 10, + 5, + 27, + 750_500_000, + )?)?; assert_eq!(dt.round_subsecs(9), dt); assert_eq!(dt.round_subsecs(4), dt); assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000); @@ -344,11 +351,17 @@ mod tests { assert_eq!(dt.round_subsecs(0).nanosecond(), 0); assert_eq!(dt.round_subsecs(0).second(), 28); + Ok(()) } #[test] - fn test_round_leap_nanos() { - let dt = Utc.ymd(2016, 12, 31).unwrap().and_hms_nano(23, 59, 59, 1_750_500_000).unwrap(); + fn test_round_leap_nanos() -> Result<(), crate::Error> { + let dt = Utc.from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 1_750_500_000, + )?)?; 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); @@ -357,12 +370,15 @@ mod tests { assert_eq!(dt.round_subsecs(0).nanosecond(), 0); assert_eq!(dt.round_subsecs(0).second(), 0); + Ok(()) } #[test] - fn test_trunc_subsecs() { - 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(); + fn test_trunc_subsecs() -> Result<(), crate::Error> { + let pst = FixedOffset::east(8 * 60 * 60)?; + let dt = pst.from_local_datetime( + &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_684)?, + )?; assert_eq!(dt.trunc_subsecs(10), dt); assert_eq!(dt.trunc_subsecs(9), dt); @@ -378,7 +394,12 @@ mod tests { assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0); assert_eq!(dt.trunc_subsecs(0).second(), 13); - let dt = pst.ymd(2018, 1, 11).unwrap().and_hms_nano(10, 5, 27, 750_500_000).unwrap(); + let dt = pst.from_local_datetime(&NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano( + 10, + 5, + 27, + 750_500_000, + )?)?; assert_eq!(dt.trunc_subsecs(9), dt); assert_eq!(dt.trunc_subsecs(4), dt); assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000); @@ -387,11 +408,17 @@ mod tests { assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0); assert_eq!(dt.trunc_subsecs(0).second(), 27); + Ok(()) } #[test] - fn test_trunc_leap_nanos() { - let dt = Utc.ymd(2016, 12, 31).unwrap().and_hms_nano(23, 59, 59, 1_750_500_000).unwrap(); + fn test_trunc_leap_nanos() -> Result<(), crate::Error> { + let dt = Utc.from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 1_750_500_000, + )?)?; 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); @@ -400,248 +427,233 @@ mod tests { assert_eq!(dt.trunc_subsecs(0).nanosecond(), 1_000_000_000); assert_eq!(dt.trunc_subsecs(0).second(), 59); + Ok(()) } #[test] - fn test_duration_round() { - let dt = Utc.ymd(2016, 12, 31).unwrap().and_hms_nano(23, 59, 59, 175_500_000).unwrap(); + fn test_duration_round() -> Result<(), crate::Error> { + let dt = Utc.from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 175_500_000, + )?)?; assert_eq!( - dt.duration_round(TimeDelta::zero()).unwrap().to_string(), + dt.duration_round(TimeDelta::zero())?.to_string(), "2016-12-31 23:59:59.175500 UTC" ); assert_eq!( - dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(), + dt.duration_round(TimeDelta::milliseconds(10))?.to_string(), "2016-12-31 23:59:59.180 UTC" ); // round up - let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 30, 0).unwrap(); + let dt = Utc.from_local_datetime( + &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?, + )?; assert_eq!( - dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:25:00 UTC" ); // round down - let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 29, 999).unwrap(); + let dt = Utc.from_local_datetime( + &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, + )?; assert_eq!( - dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00 UTC" ); assert_eq!( - dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(10))?.to_string(), "2012-12-12 18:20:00 UTC" ); assert_eq!( - dt.duration_round(TimeDelta::minutes(30)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(30))?.to_string(), "2012-12-12 18:30:00 UTC" ); - assert_eq!( - dt.duration_round(TimeDelta::hours(1)).unwrap().to_string(), - "2012-12-12 18:00:00 UTC" - ); - assert_eq!( - dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), - "2012-12-13 00:00:00 UTC" - ); + assert_eq!(dt.duration_round(TimeDelta::hours(1))?.to_string(), "2012-12-12 18:00:00 UTC"); + assert_eq!(dt.duration_round(TimeDelta::days(1))?.to_string(), "2012-12-13 00:00:00 UTC"); // timezone east - let dt = - FixedOffset::east(3600).unwrap().ymd(2020, 10, 27).unwrap().and_hms(15, 0, 0).unwrap(); + let dt = FixedOffset::east(3600)?.with_ymd_and_hms(2020, 10, 27, 15, 0, 0)?.single()?; assert_eq!( - dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::days(1))?.to_string(), "2020-10-28 00:00:00 +01:00" ); assert_eq!( - dt.duration_round(TimeDelta::weeks(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::weeks(1))?.to_string(), "2020-10-29 00:00:00 +01:00" ); // timezone west - let dt = - FixedOffset::west(3600).unwrap().ymd(2020, 10, 27).unwrap().and_hms(15, 0, 0).unwrap(); + let dt = FixedOffset::west(3600)?.with_ymd_and_hms(2020, 10, 27, 15, 0, 0)?.single()?; assert_eq!( - dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::days(1))?.to_string(), "2020-10-28 00:00:00 -01:00" ); assert_eq!( - dt.duration_round(TimeDelta::weeks(1)).unwrap().to_string(), + dt.duration_round(TimeDelta::weeks(1))?.to_string(), "2020-10-29 00:00:00 -01:00" ); + Ok(()) } #[test] - fn test_duration_round_naive() { + fn test_duration_round_naive() -> Result<(), crate::Error> { let dt = Utc - .ymd(2016, 12, 31) - .unwrap() - .and_hms_nano(23, 59, 59, 175_500_000) - .unwrap() + .from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 175_500_000, + )?)? .naive_utc(); - assert_eq!( - dt.duration_round(TimeDelta::zero()).unwrap().to_string(), - "2016-12-31 23:59:59.175500" - ); + assert_eq!(dt.duration_round(TimeDelta::zero())?.to_string(), "2016-12-31 23:59:59.175500"); assert_eq!( - dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(), + dt.duration_round(TimeDelta::milliseconds(10))?.to_string(), "2016-12-31 23:59:59.180" ); // round up - 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" - ); + let dt = Utc + .from_local_datetime(&NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?)? + .naive_utc(); + assert_eq!(dt.duration_round(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:25:00"); // round down - 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" - ); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, + )? + .naive_utc(); + assert_eq!(dt.duration_round(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00"); - assert_eq!( - dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(), - "2012-12-12 18:20:00" - ); - assert_eq!( - dt.duration_round(TimeDelta::minutes(30)).unwrap().to_string(), - "2012-12-12 18:30:00" - ); - assert_eq!( - dt.duration_round(TimeDelta::hours(1)).unwrap().to_string(), - "2012-12-12 18:00:00" - ); - assert_eq!( - dt.duration_round(TimeDelta::days(1)).unwrap().to_string(), - "2012-12-13 00:00:00" - ); + assert_eq!(dt.duration_round(TimeDelta::minutes(10))?.to_string(), "2012-12-12 18:20:00"); + assert_eq!(dt.duration_round(TimeDelta::minutes(30))?.to_string(), "2012-12-12 18:30:00"); + assert_eq!(dt.duration_round(TimeDelta::hours(1))?.to_string(), "2012-12-12 18:00:00"); + assert_eq!(dt.duration_round(TimeDelta::days(1))?.to_string(), "2012-12-13 00:00:00"); + Ok(()) } #[test] - fn test_duration_round_pre_epoch() { - let dt = Utc.ymd(1969, 12, 12).unwrap().and_hms(12, 12, 12).unwrap(); + fn test_duration_round_pre_epoch() -> Result<(), crate::Error> { + let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12)?; assert_eq!( - dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(), + dt.duration_round(TimeDelta::minutes(10))?.to_string(), "1969-12-12 12:10:00 UTC" ); + Ok(()) } #[test] - fn test_duration_trunc() { - let dt = Utc.ymd(2016, 12, 31).unwrap().and_hms_nano(23, 59, 59, 175_500_000).unwrap(); + fn test_duration_trunc() -> Result<(), crate::Error> { + let dt = Utc.from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 175_500_000, + )?)?; assert_eq!( - dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::milliseconds(10))?.to_string(), "2016-12-31 23:59:59.170 UTC" ); // would round up - let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 30, 0).unwrap(); + let dt = Utc.from_local_datetime( + &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?, + )?; assert_eq!( - dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00 UTC" ); // would round down - let dt = Utc.ymd(2012, 12, 12).unwrap().and_hms_milli(18, 22, 29, 999).unwrap(); + let dt = Utc.from_local_datetime( + &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, + )?; assert_eq!( - dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00 UTC" ); assert_eq!( - dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(10))?.to_string(), "2012-12-12 18:20:00 UTC" ); assert_eq!( - dt.duration_trunc(TimeDelta::minutes(30)).unwrap().to_string(), - "2012-12-12 18:00:00 UTC" - ); - assert_eq!( - dt.duration_trunc(TimeDelta::hours(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(30))?.to_string(), "2012-12-12 18:00:00 UTC" ); - assert_eq!( - dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), - "2012-12-12 00:00:00 UTC" - ); + assert_eq!(dt.duration_trunc(TimeDelta::hours(1))?.to_string(), "2012-12-12 18:00:00 UTC"); + assert_eq!(dt.duration_trunc(TimeDelta::days(1))?.to_string(), "2012-12-12 00:00:00 UTC"); // timezone east - let dt = - FixedOffset::east(3600).and_then(|o| o.ymd(2020, 10, 27)?.and_hms(15, 0, 0)).unwrap(); + let dt = FixedOffset::east(3600)?.with_ymd_and_hms(2020, 10, 27, 15, 0, 0)?; assert_eq!( - dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::days(1))?.to_string(), "2020-10-27 00:00:00 +01:00" ); assert_eq!( - dt.duration_trunc(TimeDelta::weeks(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::weeks(1))?.to_string(), "2020-10-22 00:00:00 +01:00" ); // timezone west - let dt = - FixedOffset::west(3600).and_then(|o| o.ymd(2020, 10, 27)?.and_hms(15, 0, 0)).unwrap(); + let dt = FixedOffset::west(3600)?.with_ymd_and_hms(2020, 10, 27, 15, 0, 0)?; assert_eq!( - dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::days(1))?.to_string(), "2020-10-27 00:00:00 -01:00" ); assert_eq!( - dt.duration_trunc(TimeDelta::weeks(1)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::weeks(1))?.to_string(), "2020-10-22 00:00:00 -01:00" ); + Ok(()) } #[test] - fn test_duration_trunc_naive() { + fn test_duration_trunc_naive() -> Result<(), crate::Error> { let dt = Utc - .ymd(2016, 12, 31) - .unwrap() - .and_hms_nano(23, 59, 59, 175_500_000) - .unwrap() + .from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 175_500_000, + )?)? .naive_utc(); assert_eq!( - dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::milliseconds(10))?.to_string(), "2016-12-31 23:59:59.170" ); // would round up - 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" - ); + let dt = Utc + .from_local_datetime(&NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?)? + .naive_utc(); + assert_eq!(dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00"); // would round down - 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" - ); - assert_eq!( - dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(), - "2012-12-12 18:20:00" - ); - assert_eq!( - dt.duration_trunc(TimeDelta::minutes(30)).unwrap().to_string(), - "2012-12-12 18:00:00" - ); - assert_eq!( - dt.duration_trunc(TimeDelta::hours(1)).unwrap().to_string(), - "2012-12-12 18:00:00" - ); - assert_eq!( - dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(), - "2012-12-12 00:00:00" - ); + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, + )? + .naive_utc(); + assert_eq!(dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00"); + assert_eq!(dt.duration_trunc(TimeDelta::minutes(10))?.to_string(), "2012-12-12 18:20:00"); + assert_eq!(dt.duration_trunc(TimeDelta::minutes(30))?.to_string(), "2012-12-12 18:00:00"); + assert_eq!(dt.duration_trunc(TimeDelta::hours(1))?.to_string(), "2012-12-12 18:00:00"); + assert_eq!(dt.duration_trunc(TimeDelta::days(1))?.to_string(), "2012-12-12 00:00:00"); + Ok(()) } #[test] - fn test_duration_trunc_pre_epoch() -> Result<(), Error> { - let dt = Utc.ymd(1969, 12, 12)?.and_hms(12, 12, 12)?; + fn test_duration_trunc_pre_epoch() -> Result<(), crate::Error> { + let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12)?.single()?; assert_eq!( - dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(), + dt.duration_trunc(TimeDelta::minutes(10))?.to_string(), "1969-12-12 12:10:00 UTC" ); Ok(()) From ec9637805b2b19af3aab222dd30c547dceade35e Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 18:52:07 +0200 Subject: [PATCH 19/54] More test fixes --- src/datetime/mod.rs | 219 ++++++++++++++++++------------------------ src/datetime/tests.rs | 4 +- src/month.rs | 6 +- src/round.rs | 22 +++-- 4 files changed, 114 insertions(+), 137 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index bf8af46c26..2be0468157 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -11,8 +11,7 @@ use alloc::string::{String, ToString}; #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::cmp::Ordering; -#[cfg(feature = "clock")] -use core::convert::TryFrom; +use core::fmt::Write; use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::{fmt, hash, str}; #[cfg(feature = "std")] @@ -32,7 +31,7 @@ use crate::format::{Fixed, Item}; use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime}; #[cfg(feature = "clock")] use crate::offset::Local; -use crate::offset::{FixedOffset, FixedTimeZone, Offset, TimeZone, Utc}; +use crate::offset::{FixedOffset, Offset, TimeZone, Utc, FixedTimeZone}; #[allow(deprecated)] use crate::Date; use crate::{Datelike, Error, Months, TimeDelta, Timelike, Weekday}; @@ -104,8 +103,8 @@ impl DateTime { /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc}; /// /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0)?, Utc); - /// assert_eq!(Utc.timestamp(61, 0)?, dt); - /// # Ok::<_, chrono::Error>(()) + /// assert_eq!(Utc.timestamp(61, 0).unwrap(), dt); + /// Ok(()) /// ``` // // note: this constructor is purposely not named to `new` to discourage the direct usage. @@ -134,10 +133,10 @@ impl DateTime { /// 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)?); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` #[inline] pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { @@ -151,18 +150,6 @@ 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)] @@ -178,14 +165,15 @@ impl DateTime { /// ``` /// use chrono::prelude::*; /// - /// let date: DateTime = Utc.ymd(2020, 1, 1)?.and_hms(0, 0, 0)?; - /// let other: DateTime = FixedOffset::east(23)?.ymd(2020, 1, 1)?.and_hms(0, 0, 0)?; + /// let date: DateTime = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0)?.single()?; + /// let other: DateTime = FixedOffset::east(23)?.with_ymd_and_hms(2020, 1, 1, 0, 0, 0)?.single()?; /// assert_eq!(date.date_naive(), other.date_naive()); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` #[inline] pub fn date_naive(&self) -> NaiveDate { - self.naive_local().date() + let local = self.naive_local(); + NaiveDate::from_ymd(local.year(), local.month(), local.day()).unwrap() } /// Retrieves a time component. @@ -214,12 +202,12 @@ impl DateTime { /// ``` /// use chrono::{Utc, TimeZone, NaiveDate}; /// - /// let dt = Utc.ymd(1970, 1, 1)?.and_hms_milli(0, 0, 1, 444)?; + /// let dt = NaiveDate::from_ymd(1970, 1, 1)?.and_hms_milli(0, 0, 1, 444)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_millis(), 1_444); /// - /// let dt = Utc.ymd(2001, 9, 9)?.and_hms_milli(1, 46, 40, 555)?; + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_milli(1, 46, 40, 555)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` #[inline] pub fn timestamp_millis(&self) -> i64 { @@ -238,12 +226,11 @@ impl DateTime { /// ``` /// use chrono::{Utc, TimeZone, NaiveDate}; /// - /// let dt = Utc.ymd(1970, 1, 1)?.and_hms_micro(0, 0, 1, 444)?; + /// let dt = NaiveDate::from_ymd(1970, 1, 1)?.and_hms_micro(0, 0, 1, 444)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_micros(), 1_000_444); /// - /// let dt = Utc.ymd(2001, 9, 9)?.and_hms_micro(1, 46, 40, 555)?; + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_micro(1, 46, 40, 555)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); - /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] pub fn timestamp_micros(&self) -> i64 { @@ -262,12 +249,12 @@ impl DateTime { /// ``` /// use chrono::{Utc, TimeZone, NaiveDate}; /// - /// let dt = Utc.ymd(1970, 1, 1)?.and_hms_nano(0, 0, 1, 444)?; + /// let dt = NaiveDate::from_ymd(1970, 1, 1)?.and_hms_nano(0, 0, 1, 444)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444); /// - /// let dt = Utc.ymd(2001, 9, 9)?.and_hms_nano(1, 46, 40, 555)?; + /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_nano(1, 46, 40, 555)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` #[inline] pub fn timestamp_nanos(&self) -> i64 { @@ -334,7 +321,7 @@ impl DateTime { /// /// Returns `Err(Error)` when it will result in overflow. #[inline] - pub fn checked_add_signed(self, rhs: TimeDelta) -> Result { + pub fn checked_add_signed(self, rhs: TimeDelta) -> Result, Error> { let datetime = self.datetime.checked_add_signed(rhs)?; let tz = self.timezone(); tz.from_utc_datetime(&datetime) @@ -346,16 +333,17 @@ impl DateTime { /// local time is not valid on the newly calculated date. /// /// See [`NaiveDate::checked_add_months`] for more details on behavior - pub fn checked_add_months(self, rhs: Months) -> Result { - let datetime = self.naive_local().checked_add_months(rhs)?; - datetime.and_local_timezone(Tz::from_offset(&self.offset)) + pub fn checked_add_months(self, rhs: Months) -> Result, Error> { + self.naive_local() + .checked_add_months(rhs)? + .and_local_timezone(Tz::from_offset(&self.offset)) } /// Subtracts given `Duration` from the current date and time. /// /// Returns `Err(Error)` when it will result in overflow. #[inline] - pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result { + pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result, Error> { let datetime = self.datetime.checked_sub_signed(rhs)?; let tz = self.timezone(); tz.from_utc_datetime(&datetime) @@ -367,7 +355,7 @@ impl DateTime { /// local time is not valid on the newly calculated date. /// /// See [`NaiveDate::checked_sub_months`] for more details on behavior - pub fn checked_sub_months(self, rhs: Months) -> Result { + pub fn checked_sub_months(self, rhs: Months) -> Result, Error> { self.naive_local() .checked_sub_months(rhs)? .and_local_timezone(Tz::from_offset(&self.offset)) @@ -377,7 +365,7 @@ impl DateTime { /// /// Returns `Err(Error)` if the resulting date would be out of range. pub fn checked_add_days(self, days: Days) -> Result { - self.datetime + self.naive_local() .checked_add_days(days)? .and_local_timezone(TimeZone::from_offset(&self.offset)) } @@ -386,7 +374,7 @@ impl DateTime { /// /// Returns `Err(Error)` if the resulting date would be out of range. pub fn checked_sub_days(self, days: Days) -> Result { - self.datetime + self.naive_local() .checked_sub_days(days)? .and_local_timezone(TimeZone::from_offset(&self.offset)) } @@ -435,7 +423,8 @@ impl DateTime { impl Default for DateTime { fn default() -> Self { - Utc.from_utc_datetime_fixed(&NaiveDateTime::default()) + // TODO: Cannot avoid fallible operation, so this probably has to be removed + Utc.from_utc_datetime(&NaiveDateTime::default()).unwrap() } } @@ -443,7 +432,6 @@ impl Default for DateTime { #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] impl Default for DateTime { fn default() -> Self { - // TODO: Cannot avoid fallible operation, so this probably has to be removed. Local.from_utc_datetime(&NaiveDateTime::default()).unwrap() } } @@ -461,21 +449,19 @@ 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_fixed_timezone(&FixedOffset::UTC) + src.with_timezone(&FixedOffset::east(0).unwrap()) } } /// Convert a `DateTime` instance into a `DateTime` instance. #[cfg(feature = "clock")] #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] -impl TryFrom> for DateTime { - type Error = Error; - +impl From> for DateTime { /// Convert this `DateTime` instance into a `DateTime` instance. /// /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in timezones. - fn try_from(value: DateTime) -> Result { - value.with_timezone(&Local) + fn from(src: DateTime) -> Self { + src.with_timezone(&Local) } } @@ -486,22 +472,20 @@ impl From> for DateTime { /// Conversion is performed via [`DateTime::with_timezone`], accounting for the timezone /// difference. fn from(src: DateTime) -> Self { - src.with_fixed_timezone(&Utc) + src.with_timezone(&Utc) } } /// Convert a `DateTime` instance into a `DateTime` instance. #[cfg(feature = "clock")] #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] -impl TryFrom> for DateTime { - type Error = Error; - +impl From> for DateTime { /// Convert this `DateTime` instance into a `DateTime` instance. /// /// Conversion is performed via [`DateTime::with_timezone`]. Returns the equivalent value in local /// time. - fn try_from(value: DateTime) -> Result { - value.with_timezone(&Local) + fn from(src: DateTime) -> Self { + src.with_timezone(&Local) } } @@ -514,7 +498,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_fixed_timezone(&Utc) + src.with_timezone(&Utc) } } @@ -527,7 +511,7 @@ 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_fixed_timezone(&FixedOffset::UTC) + src.with_timezone(&FixedOffset::east(0).unwrap()) } } @@ -536,8 +520,7 @@ fn map_local(dt: &DateTime, mut f: F) -> Result Result, { - let datetime = f(dt.naive_local())?; - dt.timezone().from_local_datetime(&datetime)?.single() + f(dt.naive_local()).and_then(|datetime| dt.timezone().from_local_datetime(&datetime)?.single()) } impl DateTime { @@ -549,13 +532,16 @@ 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")?, - /// FixedOffset::east(0)?.ymd(2015, 2, 18)?.and_hms(23, 16, 9)? + /// DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(), + /// FixedOffset::east(0)?.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.single()? /// ); - /// # Ok::<_, Box>(()) + /// Ok(()) /// ``` /// /// [RFC 2822 Appendix A.5]: https://www.rfc-editor.org/rfc/rfc2822#appendix-A.5 @@ -601,9 +587,10 @@ impl DateTime { /// ```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, FixedOffset::east(0)?.ymd(1983, 4, 13)?.and_hms_milli(12, 9, 14, 274)?); - /// # Ok::<_, Box>(()) + /// 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)?.from_local_datetime(&NaiveDate::from_ymd(1983, 4, 13)?.and_hms_milli(12, 9, 14, 274)?)?); + /// Ok(()) /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> Result, Error> { let mut parsed = Parsed::new(); @@ -659,9 +646,9 @@ impl DateTime { /// ```rust /// use chrono::{DateTime, TimeZone, Utc}; /// - /// let dt = DateTime::::parse_from_str("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)?)); - /// # Ok::<_, chrono::Error>(()) + /// let dt = DateTime::::parse_from_str( + /// "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) -> Result, Error> { DateTime::::parse_from_str(s, fmt).map(|result| result.into()) @@ -702,8 +689,8 @@ where /// # Examples /// /// ```rust - /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc}; - /// let dt = Utc.ymd(2018, 1, 26)?.and_hms_micro(18, 30, 9, 453_829)?; + /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc, NaiveDate}; + /// let dt = NaiveDate::from_ymd(2018, 1, 26)?.and_hms_micro(18, 30, 9, 453_829)?.and_local_timezone(Utc)?; /// 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), @@ -712,10 +699,9 @@ where /// "2018-01-26T18:30:09Z"); /// /// let pst = FixedOffset::east(8 * 60 * 60)?; - /// let dt = pst.ymd(2018, 1, 26)?.and_hms_micro(10, 30, 9, 453_829)?; + /// let dt = pst.from_local_datetime(&NaiveDate::from_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"))))] @@ -782,10 +768,9 @@ where /// ```rust /// use chrono::prelude::*; /// - /// let date_time: DateTime = Utc.ymd(2017, 04, 02)?.and_hms(12, 50, 32)?; + /// let date_time: DateTime = Utc.with_ymd_and_hms(2017, 04, 02, 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"))))] @@ -967,14 +952,14 @@ impl PartialOrd> for DateTime { /// ``` /// use chrono::prelude::*; /// - /// let earlier = Utc.ymd(2015, 5, 15)?.and_hms(2, 0, 0)?.with_timezone(&FixedOffset::west(1 * 3600)?)?; - /// let later = Utc.ymd(2015, 5, 15)?.and_hms(3, 0, 0)?.with_timezone(&FixedOffset::west(5 * 3600)?)?; + /// let earlier = Utc.with_ymd_and_hms(2015, 5, 15, 2, 0, 0)?.single().with_timezone(&FixedOffset::west(1 * 3600)?); + /// let later = Utc.with_ymd_and_hms(2015, 5, 15, 3, 0, 0)?.single().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>(()) + /// Ok(()) /// ``` fn partial_cmp(&self, other: &DateTime) -> Option { self.datetime.partial_cmp(&other.datetime) @@ -1035,7 +1020,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).unwrap(); + *self = tz.from_utc_datetime(&datetime).unwrap() } } @@ -1085,7 +1070,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.naive_local().fmt(f)?; - f.write_str(" ")?; + f.write_char(' ')?; self.offset.fmt(f) } } @@ -1105,8 +1090,7 @@ impl str::FromStr for DateTime { type Err = Error; fn from_str(s: &str) -> Result, Error> { - let dt = s.parse::>()?; - dt.with_timezone(&Utc).map_err(|_| Error::ParsingOutOfRange) + s.parse::>().map(|dt| dt.with_timezone(&Utc)) } } @@ -1127,8 +1111,7 @@ impl str::FromStr for DateTime { type Err = Error; fn from_str(s: &str) -> Result, Error> { - let dt = s.parse::>()?; - dt.with_timezone(&Local).map_err(|_| Error::ParsingOutOfRange) + s.parse::>().map(|dt| dt.with_timezone(&Local)) } } @@ -1149,9 +1132,6 @@ impl From for DateTime { } } }; - - // TODO: This may panic - // Either return Result instead or ensure that timestamp() cannot fail. Utc.timestamp(sec, nsec).unwrap() } } @@ -1160,8 +1140,7 @@ impl From for DateTime { #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] impl From for DateTime { fn from(t: SystemTime) -> DateTime { - // TODO: can we get rid of this panic? - DateTime::::from(t).with_timezone(&Local).unwrap() + DateTime::::from(t).with_timezone(&Local) } } @@ -1195,11 +1174,9 @@ impl From> for SystemTime { not(any(target_os = "emscripten", target_os = "wasi")) ))) )] -impl std::convert::TryFrom for DateTime { - type Error = Error; - - fn try_from(date: js_sys::Date) -> Result { - DateTime::::try_from(&date) +impl From for DateTime { + fn from(date: js_sys::Date) -> DateTime { + DateTime::::from(&date) } } @@ -1216,11 +1193,9 @@ impl std::convert::TryFrom for DateTime { not(any(target_os = "emscripten", target_os = "wasi")) ))) )] -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) +impl From<&js_sys::Date> for DateTime { + fn from(date: &js_sys::Date) -> DateTime { + Utc.timestamp_millis(date.get_time() as i64).unwrap() } } @@ -1264,30 +1239,26 @@ where #[test] fn test_add_sub_months() { - 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(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(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(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(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(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(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()); + 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()); } #[test] fn test_auto_conversion() { - let utc_dt = Utc.ymd(2018, 9, 5).unwrap().and_hms(23, 58, 0).unwrap(); - let cdt_dt = FixedOffset::west(5 * 60 * 60) - .unwrap() - .ymd(2018, 9, 5) - .unwrap() - .and_hms(18, 58, 0) - .unwrap(); + let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); + let cdt_dt = + FixedOffset::west(5 * 60 * 60).unwrap().with_ymd_and_hms(2018, 9, 5, 18, 58, 0).unwrap(); let utc_dt2: DateTime = cdt_dt.into(); assert_eq!(utc_dt, utc_dt2); } @@ -1300,20 +1271,20 @@ where E: ::core::fmt::Debug, { assert_eq!( - to_string_utc(&Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap()).ok(), + to_string_utc(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(), Some(r#""2014-07-24T12:34:06Z""#.into()) ); assert_eq!( to_string_fixed( - &FixedOffset::east(3660).unwrap().ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() + &FixedOffset::east(3660).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() ) .ok(), Some(r#""2014-07-24T12:34:06+01:01""#.into()) ); assert_eq!( to_string_fixed( - &FixedOffset::east(3650).unwrap().ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() + &FixedOffset::east(3650).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() ) .ok(), Some(r#""2014-07-24T12:34:06+01:00:50""#.into()) @@ -1338,17 +1309,17 @@ fn test_decodable_json( assert_eq!( norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()), - norm(&Some(Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap())) + norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap())) ); assert_eq!( norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()), - norm(&Some(Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap())) + norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap())) ); assert_eq!( norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()), norm(&Some( - FixedOffset::east(0).unwrap().ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() + FixedOffset::east(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() )) ); assert_eq!( @@ -1356,9 +1327,7 @@ fn test_decodable_json( norm(&Some( FixedOffset::east(60 * 60 + 23 * 60) .unwrap() - .ymd(2014, 7, 24) - .unwrap() - .and_hms(13, 57, 6) + .with_ymd_and_hms(2014, 7, 24, 13, 57, 6) .unwrap() )) ); @@ -1367,11 +1336,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.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() + Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() ); assert_eq!( local_from_str(r#""2014-07-24T13:57:06+01:23""#).expect("local should parse with offset"), - Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap() + Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() ); assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index d08b2af5e6..869c7030f2 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1544,7 +1544,9 @@ fn test_subsecond_part() { .from_local_datetime( &NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms_nano(9, 10, 11, 1234567).unwrap(), ) - .unwrap().single().unwrap(); + .unwrap() + .single() + .unwrap(); assert_eq!(1, datetime.timestamp_subsec_millis()); assert_eq!(1234, datetime.timestamp_subsec_micros()); diff --git a/src/month.rs b/src/month.rs index 54a1f66ae0..80f268cae6 100644 --- a/src/month.rs +++ b/src/month.rs @@ -328,7 +328,11 @@ mod tests { 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().single().unwrap(); + let dt = Utc + .with_ymd_and_hms(2019, month.number_from_month(), 28, 9, 10, 11) + .unwrap() + .single() + .unwrap(); assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28)); } diff --git a/src/round.rs b/src/round.rs index b681580e85..88a9b34161 100644 --- a/src/round.rs +++ b/src/round.rs @@ -319,9 +319,11 @@ mod tests { #[test] fn test_round_subsecs() -> Result<(), crate::Error> { let pst = FixedOffset::east(8 * 60 * 60)?; - let dt = pst.from_local_datetime( - &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_684)?, - )?.single()?; + let dt = pst + .from_local_datetime( + &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_684)?, + )? + .single()?; assert_eq!(dt.round_subsecs(10), dt); assert_eq!(dt.round_subsecs(9), dt); @@ -556,7 +558,7 @@ mod tests { 59, 59, 175_500_000, - )?)?; + )?)?.single()?; assert_eq!( dt.duration_trunc(TimeDelta::milliseconds(10))?.to_string(), @@ -566,7 +568,7 @@ mod tests { // would round up let dt = Utc.from_local_datetime( &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?, - )?; + )?.single()?; assert_eq!( dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00 UTC" @@ -574,7 +576,7 @@ mod tests { // would round down let dt = Utc.from_local_datetime( &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, - )?; + )?.single()?; assert_eq!( dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00 UTC" @@ -591,7 +593,7 @@ mod tests { assert_eq!(dt.duration_trunc(TimeDelta::days(1))?.to_string(), "2012-12-12 00:00:00 UTC"); // timezone east - let dt = FixedOffset::east(3600)?.with_ymd_and_hms(2020, 10, 27, 15, 0, 0)?; + let dt = FixedOffset::east(3600)?.with_ymd_and_hms(2020, 10, 27, 15, 0, 0)?.single()?; assert_eq!( dt.duration_trunc(TimeDelta::days(1))?.to_string(), "2020-10-27 00:00:00 +01:00" @@ -602,7 +604,7 @@ mod tests { ); // timezone west - let dt = FixedOffset::west(3600)?.with_ymd_and_hms(2020, 10, 27, 15, 0, 0)?; + let dt = FixedOffset::west(3600)?.with_ymd_and_hms(2020, 10, 27, 15, 0, 0)?.single()?; assert_eq!( dt.duration_trunc(TimeDelta::days(1))?.to_string(), "2020-10-27 00:00:00 -01:00" @@ -632,14 +634,14 @@ mod tests { // would round up let dt = Utc - .from_local_datetime(&NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?)? + .from_local_datetime(&NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?)?.single()? .naive_utc(); assert_eq!(dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00"); // would round down let dt = Utc .from_local_datetime( &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, - )? + )?.single()? .naive_utc(); assert_eq!(dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00"); assert_eq!(dt.duration_trunc(TimeDelta::minutes(10))?.to_string(), "2012-12-12 18:20:00"); From 7a39b6eb65f09d806e9aa0ee21ab0a24a7ba754a Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 19:26:04 +0200 Subject: [PATCH 20/54] Rounding Error --- src/datetime/mod.rs | 20 +++--- src/error.rs | 16 +++++ src/lib.rs | 2 +- src/round.rs | 171 +++++++++++++++----------------------------- 4 files changed, 83 insertions(+), 126 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 2be0468157..08bf9e6ba7 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -31,7 +31,7 @@ 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, FixedTimeZone}; +use crate::offset::{FixedOffset, FixedTimeZone, Offset, TimeZone, Utc}; #[allow(deprecated)] use crate::Date; use crate::{Datelike, Error, Months, TimeDelta, Timelike, Weekday}; @@ -449,7 +449,7 @@ impl From> for DateTime { /// Conversion is done via [`DateTime::with_timezone`]. Note that the converted value returned by /// this will be created with a fixed timezone offset of 0. fn from(src: DateTime) -> Self { - src.with_timezone(&FixedOffset::east(0).unwrap()) + src.with_fixed_timezone(&FixedOffset::UTC) } } @@ -461,7 +461,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(&Local) + src.with_timezone(&Local).unwrap() } } @@ -472,7 +472,7 @@ 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) } } @@ -485,7 +485,7 @@ impl From> for DateTime { /// Conversion is performed via [`DateTime::with_timezone`]. Returns the equivalent value in local /// time. fn from(src: DateTime) -> Self { - src.with_timezone(&Local) + src.with_timezone(&Local).unwrap() } } @@ -498,7 +498,7 @@ impl From> for DateTime { /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in /// timezones. fn from(src: DateTime) -> Self { - src.with_timezone(&Utc) + src.with_fixed_timezone(&Utc) } } @@ -511,7 +511,7 @@ impl From> for DateTime { /// Conversion is performed via [`DateTime::with_timezone`]. Note that the converted value returned /// by this will be created with a fixed timezone offset of 0. fn from(src: DateTime) -> Self { - src.with_timezone(&FixedOffset::east(0).unwrap()) + src.with_fixed_timezone(&FixedOffset::UTC) } } @@ -1090,7 +1090,7 @@ impl str::FromStr for DateTime { type Err = Error; fn from_str(s: &str) -> Result, Error> { - s.parse::>().map(|dt| dt.with_timezone(&Utc)) + s.parse::>()?.with_timezone(&Utc) } } @@ -1111,7 +1111,7 @@ impl str::FromStr for DateTime { type Err = Error; fn from_str(s: &str) -> Result, Error> { - s.parse::>().map(|dt| dt.with_timezone(&Local)) + s.parse::>()?.with_timezone(&Local) } } @@ -1140,7 +1140,7 @@ 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) + DateTime::::from(t).with_timezone(&Local).unwrap() } } diff --git a/src/error.rs b/src/error.rs index 757792b939..2bdae06589 100644 --- a/src/error.rs +++ b/src/error.rs @@ -97,6 +97,16 @@ pub enum Error { /// Invalid data InvalidData, + + /* Rounding errors */ + /// Error when the TimeDelta exceeds the TimeDelta from or until the Unix epoch. + DurationExceedsTimestamp, + + /// Error when `TimeDelta.num_nanoseconds` exceeds the limit. + DurationExceedsLimit, + + /// Error when `DateTime.timestamp_nanos` exceeds the limit. + TimestampExceedsLimit, } impl fmt::Display for Error { @@ -143,6 +153,12 @@ impl fmt::Display for Error { Error::UnexpectedEOF => write!(f, "unexpected end of file"), Error::InvalidData => write!(f, "invalid data"), + + Error::DurationExceedsTimestamp => { + write!(f, "duration in nanoseconds exceeds timestamp") + } + Error::DurationExceedsLimit => write!(f, "duration exceeds num_nanoseconds limit"), + Error::TimestampExceedsLimit => write!(f, "timestamp exceeds num_nanoseconds limit"), } } } diff --git a/src/lib.rs b/src/lib.rs index 0147eba650..f83125d604 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -465,7 +465,7 @@ pub use offset::Local; pub use offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc}; mod round; -pub use round::{DurationRound, RoundingError, SubsecRound}; +pub use round::{DurationRound, SubsecRound}; mod weekday; pub use weekday::{ParseWeekdayError, Weekday}; diff --git a/src/round.rs b/src/round.rs index 88a9b34161..bcba6af1e7 100644 --- a/src/round.rs +++ b/src/round.rs @@ -4,10 +4,10 @@ use crate::datetime::DateTime; use crate::naive::NaiveDateTime; use crate::time_delta::TimeDelta; +use crate::Error; use crate::TimeZone; use crate::Timelike; use core::cmp::Ordering; -use core::fmt; use core::marker::Sized; use core::ops::{Add, Sub}; @@ -101,10 +101,6 @@ fn span_for_digits(digits: u16) -> u32 { /// `TimeDelta` or the `DateTime` are too big to represented as nanoseconds. They /// will also fail if the `TimeDelta` is bigger than the timestamp. pub trait DurationRound: Sized { - /// Error that can occur in rounding or truncating - #[cfg(any(feature = "std", test))] - type Err: std::error::Error; - /// Error that can occur in rounding or truncating #[cfg(not(any(feature = "std", test)))] type Err: fmt::Debug + fmt::Display; @@ -125,7 +121,7 @@ pub trait DurationRound: Sized { /// ); /// Ok(()) /// ``` - fn duration_round(self, duration: TimeDelta) -> Result; + fn duration_round(self, duration: TimeDelta) -> Result; /// Return a copy truncated by TimeDelta. /// @@ -143,51 +139,43 @@ pub trait DurationRound: Sized { /// ); /// Ok(()) /// ``` - fn duration_trunc(self, duration: TimeDelta) -> Result; + fn duration_trunc(self, duration: TimeDelta) -> Result; } /// The maximum number of seconds a DateTime can be to be represented as nanoseconds const MAX_SECONDS_TIMESTAMP_FOR_NANOS: i64 = 9_223_372_036; impl DurationRound for DateTime { - type Err = RoundingError; - - fn duration_round(self, duration: TimeDelta) -> Result { + fn duration_round(self, duration: TimeDelta) -> Result { duration_round(self.naive_local(), self, duration) } - fn duration_trunc(self, duration: TimeDelta) -> Result { + fn duration_trunc(self, duration: TimeDelta) -> Result { duration_trunc(self.naive_local(), self, duration) } } impl DurationRound for NaiveDateTime { - type Err = RoundingError; - - fn duration_round(self, duration: TimeDelta) -> Result { + fn duration_round(self, duration: TimeDelta) -> Result { duration_round(self, self, duration) } - fn duration_trunc(self, duration: TimeDelta) -> Result { + fn duration_trunc(self, duration: TimeDelta) -> Result { duration_trunc(self, self, duration) } } -fn duration_round( - naive: NaiveDateTime, - original: T, - duration: TimeDelta, -) -> Result +fn duration_round(naive: NaiveDateTime, original: T, duration: TimeDelta) -> Result where T: Timelike + Add + Sub, { if let Some(span) = duration.num_nanoseconds() { if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { - return Err(RoundingError::TimestampExceedsLimit); + return Err(Error::TimestampExceedsLimit); } let stamp = naive.timestamp_nanos(); if span > stamp.abs() { - return Err(RoundingError::DurationExceedsTimestamp); + return Err(Error::DurationExceedsTimestamp); } if span == 0 { return Ok(original); @@ -208,25 +196,21 @@ where } } } else { - Err(RoundingError::DurationExceedsLimit) + Err(Error::DurationExceedsLimit) } } -fn duration_trunc( - naive: NaiveDateTime, - original: T, - duration: TimeDelta, -) -> Result +fn duration_trunc(naive: NaiveDateTime, original: T, duration: TimeDelta) -> Result where T: Timelike + Add + Sub, { if let Some(span) = duration.num_nanoseconds() { if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { - return Err(RoundingError::TimestampExceedsLimit); + return Err(Error::TimestampExceedsLimit); } let stamp = naive.timestamp_nanos(); if span > stamp.abs() { - return Err(RoundingError::DurationExceedsTimestamp); + return Err(Error::DurationExceedsTimestamp); } let delta_down = stamp % span; match delta_down.cmp(&0) { @@ -235,77 +219,7 @@ where Ordering::Less => Ok(original - TimeDelta::nanoseconds(span - delta_down.abs())), } } else { - Err(RoundingError::DurationExceedsLimit) - } -} - -/// An error from rounding by `TimeDelta` -/// -/// See: [`DurationRound`] -#[derive(Debug, Clone, PartialEq, Eq, Copy)] -pub enum RoundingError { - /// Error when the TimeDelta exceeds the TimeDelta from or until the Unix epoch. - /// - /// ``` rust - /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0)?.single()?; - /// - /// assert_eq!( - /// dt.duration_round(TimeDelta::days(365)), - /// Err(RoundingError::DurationExceedsTimestamp), - /// ); - /// Ok(()) - /// ``` - DurationExceedsTimestamp, - - /// Error when `TimeDelta.num_nanoseconds` exceeds the limit. - /// - /// ``` rust - /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd(2260, 12, 31).?.and_hms_nano(23, 59, 59, 1_75_500_000).?.and_local_timezone(Utc).?; - /// - /// assert_eq!( - /// dt.duration_round(TimeDelta::days(300 * 365)), - /// Err(RoundingError::DurationExceedsLimit) - /// ); - /// Ok(()) - /// ``` - DurationExceedsLimit, - - /// Error when `DateTime.timestamp_nanos` exceeds the limit. - /// - /// ``` rust - /// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc}; - /// let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0)?.single()?; - /// - /// assert_eq!(dt.duration_round(TimeDelta::days(1)), Err(RoundingError::TimestampExceedsLimit),); - /// Ok(()) - /// ``` - TimestampExceedsLimit, -} - -impl fmt::Display for RoundingError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - RoundingError::DurationExceedsTimestamp => { - write!(f, "duration in nanoseconds exceeds timestamp") - } - RoundingError::DurationExceedsLimit => { - write!(f, "duration exceeds num_nanoseconds limit") - } - RoundingError::TimestampExceedsLimit => { - write!(f, "timestamp exceeds num_nanoseconds limit") - } - } - } -} - -#[cfg(any(feature = "std", test))] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::error::Error for RoundingError { - #[allow(deprecated)] - fn description(&self) -> &str { - "error from rounding or truncating with DurationRound" + Err(Error::DurationExceedsLimit) } } @@ -553,12 +467,14 @@ mod tests { #[test] fn test_duration_trunc() -> Result<(), crate::Error> { - let dt = Utc.from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( - 23, - 59, - 59, - 175_500_000, - )?)?.single()?; + let dt = Utc + .from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 175_500_000, + )?)? + .single()?; assert_eq!( dt.duration_trunc(TimeDelta::milliseconds(10))?.to_string(), @@ -566,17 +482,19 @@ mod tests { ); // would round up - let dt = Utc.from_local_datetime( - &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?, - )?.single()?; + let dt = Utc + .from_local_datetime(&NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?)? + .single()?; assert_eq!( dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00 UTC" ); // would round down - let dt = Utc.from_local_datetime( - &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, - )?.single()?; + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, + )? + .single()?; assert_eq!( dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00 UTC" @@ -634,14 +552,16 @@ mod tests { // would round up let dt = Utc - .from_local_datetime(&NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?)?.single()? + .from_local_datetime(&NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?)? + .single()? .naive_utc(); assert_eq!(dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00"); // would round down let dt = Utc .from_local_datetime( &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, - )?.single()? + )? + .single()? .naive_utc(); assert_eq!(dt.duration_trunc(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00"); assert_eq!(dt.duration_trunc(TimeDelta::minutes(10))?.to_string(), "2012-12-12 18:20:00"); @@ -660,4 +580,25 @@ mod tests { ); Ok(()) } + + #[test] + fn test_duration_round_error() -> Result<(), crate::Error> { + use crate::{DateTime, DurationRound, Error, NaiveDate, TimeDelta, TimeZone, Utc}; + let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0)?.single()?; + assert_eq!(dt.duration_round(TimeDelta::days(365)), Err(Error::DurationExceedsTimestamp),); + + let dt = NaiveDate::from_ymd(2260, 12, 31)? + .and_hms_nano(23, 59, 59, 1_75_500_000)? + .and_local_timezone(Utc)?; + + assert_eq!(dt.duration_round(TimeDelta::days(300 * 365)), Err(Error::DurationExceedsLimit)); + + let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0)?.single()?; + + assert_eq!( + dt.duration_round(TimeDelta::days(1)), + Err(RoundingError::TimestampExceedsLimit), + ); + Ok(()) + } } From 7f8f39b83a834528ae8d8246dc695dc4b49c1bad Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 19:28:37 +0200 Subject: [PATCH 21/54] Move test_duration_round_error --- src/round.rs | 67 ++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/src/round.rs b/src/round.rs index bcba6af1e7..5a39dbb416 100644 --- a/src/round.rs +++ b/src/round.rs @@ -329,12 +329,14 @@ mod tests { #[test] fn test_trunc_leap_nanos() -> Result<(), crate::Error> { - let dt = Utc.from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( - 23, - 59, - 59, - 1_750_500_000, - )?)?; + let dt = Utc + .from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 1_750_500_000, + )?)? + .single()?; 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); @@ -348,12 +350,14 @@ mod tests { #[test] fn test_duration_round() -> Result<(), crate::Error> { - let dt = Utc.from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( - 23, - 59, - 59, - 175_500_000, - )?)?; + let dt = Utc + .from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 175_500_000, + )?)? + .single()?; assert_eq!( dt.duration_round(TimeDelta::zero())?.to_string(), @@ -534,6 +538,24 @@ mod tests { Ok(()) } + #[test] + fn test_duration_round_error() -> Result<(), crate::Error> { + use crate::{DurationRound, Error, NaiveDate, TimeDelta, TimeZone, Utc}; + + let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0)?.single()?; + assert_eq!(dt.duration_round(TimeDelta::days(365)), Err(Error::DurationExceedsTimestamp),); + + let dt = NaiveDate::from_ymd(2260, 12, 31)? + .and_hms_nano(23, 59, 59, 1_75_500_000)? + .and_local_timezone(Utc)?; + assert_eq!(dt.duration_round(TimeDelta::days(300 * 365)), Err(Error::DurationExceedsLimit)); + + let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0)?.single()?; + assert_eq!(dt.duration_round(TimeDelta::days(1)), Err(Error::TimestampExceedsLimit),); + + Ok(()) + } + #[test] fn test_duration_trunc_naive() -> Result<(), crate::Error> { let dt = Utc @@ -580,25 +602,4 @@ mod tests { ); Ok(()) } - - #[test] - fn test_duration_round_error() -> Result<(), crate::Error> { - use crate::{DateTime, DurationRound, Error, NaiveDate, TimeDelta, TimeZone, Utc}; - let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0)?.single()?; - assert_eq!(dt.duration_round(TimeDelta::days(365)), Err(Error::DurationExceedsTimestamp),); - - let dt = NaiveDate::from_ymd(2260, 12, 31)? - .and_hms_nano(23, 59, 59, 1_75_500_000)? - .and_local_timezone(Utc)?; - - assert_eq!(dt.duration_round(TimeDelta::days(300 * 365)), Err(Error::DurationExceedsLimit)); - - let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0)?.single()?; - - assert_eq!( - dt.duration_round(TimeDelta::days(1)), - Err(RoundingError::TimestampExceedsLimit), - ); - Ok(()) - } } From af680917043b0ac138a8fac144b0b0089d05b7bc Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 19:47:55 +0200 Subject: [PATCH 22/54] Test fixing... --- src/datetime/mod.rs | 30 +++++++++++++------------ src/datetime/tests.rs | 51 +++++++++++++++++++++--------------------- src/format/strftime.rs | 15 +++++-------- src/round.rs | 30 ++++++++++++++++--------- 4 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 08bf9e6ba7..c8bba9e2c7 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1238,29 +1238,31 @@ 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()); +fn test_add_sub_months() -> Result<(), crate::Error> { + let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0)?.single()?; + assert_eq!(utc_dt + Months::new(15), Utc.with_ymd_and_hms(2019, 12, 5, 23, 58, 0)?.single()?); - 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.with_ymd_and_hms(2020, 1, 31, 23, 58, 0)?.single()?; + assert_eq!(utc_dt + Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0)?.single()?); + assert_eq!(utc_dt + Months::new(2), Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0)?.single()?); - 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.with_ymd_and_hms(2018, 9, 5, 23, 58, 0)?.single()?; + assert_eq!(utc_dt - Months::new(15), Utc.with_ymd_and_hms(2017, 6, 5, 23, 58, 0)?.single()?); - 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.with_ymd_and_hms(2020, 3, 31, 23, 58, 0)?.single()?; + assert_eq!(utc_dt - Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0)?.single()?); + assert_eq!(utc_dt - Months::new(2), Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0)?.single()?); + Ok(()) } #[test] -fn test_auto_conversion() { - let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); +fn test_auto_conversion() -> Result<(), crate::Error> { + let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0)?.single()?; let cdt_dt = - FixedOffset::west(5 * 60 * 60).unwrap().with_ymd_and_hms(2018, 9, 5, 18, 58, 0).unwrap(); + FixedOffset::west(5 * 60 * 60)?.with_ymd_and_hms(2018, 9, 5, 18, 58, 0)?.single()?; let utc_dt2: DateTime = cdt_dt.into(); assert_eq!(utc_dt, utc_dt2); + Ok(()) } #[cfg(all(test, feature = "serde"))] diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 869c7030f2..363ae4ed87 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1509,10 +1509,11 @@ fn test_to_string_round_trip_with_local() -> Result<(), crate::Error> { #[test] #[cfg(feature = "clock")] -fn test_datetime_format_with_local() { +fn test_datetime_format_with_local() -> Result<(), crate::Error> { // 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()); + assert_eq!(dt.format("%Y").to_string(), dt.with_timezone(&Utc)?.format("%Y").to_string()); + Ok(()) } #[test] @@ -1555,10 +1556,10 @@ fn test_subsecond_part() { #[test] #[cfg(not(target_os = "windows"))] -fn test_from_system_time() { +fn test_from_system_time() -> Result<(), crate::Error> { use std::time::Duration; - let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap(); + let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0)?.single()?; let nanos = 999_999_999; // SystemTime -> DateTime @@ -1567,15 +1568,15 @@ fn test_from_system_time() { DateTime::::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)), Utc.from_local_datetime( &NaiveDate::from_ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() - ) - .unwrap() + )? + .single()? ); assert_eq!( DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), Utc.from_local_datetime( &NaiveDate::from_ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1).unwrap() - ) - .unwrap() + )? + .single()? ); // DateTime -> SystemTime @@ -1584,8 +1585,8 @@ fn test_from_system_time() { SystemTime::from( Utc.from_local_datetime( &NaiveDate::from_ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() - ) - .unwrap() + )? + .single()? ), UNIX_EPOCH + Duration::new(999_999_999, nanos) ); @@ -1593,8 +1594,8 @@ fn test_from_system_time() { SystemTime::from( Utc.from_local_datetime( &NaiveDate::from_ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1).unwrap() - ) - .unwrap() + )? + .single()? ), UNIX_EPOCH - Duration::new(999_999_999, 999_999_999) ); @@ -1602,16 +1603,17 @@ fn test_from_system_time() { // 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)?), UNIX_EPOCH); } assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400).unwrap())), + SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400)?)?), UNIX_EPOCH ); assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800).unwrap())), + SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800)?)?), UNIX_EPOCH ); + Ok(()) } #[test] @@ -1621,23 +1623,21 @@ fn test_from_system_time() { let nanos = 999_999_000; - let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap(); + let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0)?.single()?; // 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(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() - ) - .unwrap() + &NaiveDate::from_ymd(2001, 9, 9)?.and_hms_nano(1, 46, 39, nanos)? + )? ); assert_eq!( DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), Utc.from_local_datetime( - &NaiveDate::from_ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1_000).unwrap() - ) - .unwrap() + &NaiveDate::from_ymd(1938, 4, 24)?.and_hms_nano(22, 13, 20, 1_000)? + )? ); // DateTime -> SystemTime @@ -1674,6 +1674,7 @@ fn test_from_system_time() { SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800).unwrap())), UNIX_EPOCH ); + Ok(()) } #[test] @@ -1810,11 +1811,11 @@ fn test_datetime_sub_assign() { #[test] #[cfg(feature = "clock")] -fn test_datetime_sub_assign_local() { - let naivedatetime = NaiveDate::from_ymd(2022, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); +fn test_datetime_sub_assign_local() -> Result<(), crate::Error> { + let naivedatetime = NaiveDate::from_ymd(2022, 1, 1)?.and_hms(0, 0, 0)?; let datetime = Local.from_utc_datetime(&naivedatetime); - let mut datetime_sub = Local.from_utc_datetime(&naivedatetime); + let mut datetime_sub = Local.from_utc_datetime(&naivedatetime)?; // ensure we cross a DST transition for i in 1..=365 { diff --git a/src/format/strftime.rs b/src/format/strftime.rs index c0870a0d12..e335de3f7c 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -628,18 +628,13 @@ fn test_strftime_items() { assert_eq!(parse_and_collect("%#m"), [Item::Error]); } -#[cfg(test)] +#[cfg(feature = "unstable-locales")] #[test] -fn test_strftime_docs() { - use crate::NaiveDate; - use crate::{DateTime, FixedOffset, TimeZone, Timelike, Utc}; +fn test_strftime_docs_localized() -> Result<(), Error> { + use crate::offset::TimeZone; + use crate::{FixedOffset, NaiveDate}; - let dt = FixedOffset::east(34200) - .unwrap() - .ymd(2001, 7, 8) - .unwrap() - .and_hms_nano(0, 34, 59, 1_026_490_708) - .unwrap(); + let dt = FixedOffset::east(34200)?.ymd(2001, 7, 8)?.and_hms_nano(0, 34, 59, 1_026_490_708)?; // date specifiers assert_eq!(dt.format("%Y").to_string(), "2001"); diff --git a/src/round.rs b/src/round.rs index 5a39dbb416..7dd9b48861 100644 --- a/src/round.rs +++ b/src/round.rs @@ -292,9 +292,11 @@ mod tests { #[test] fn test_trunc_subsecs() -> Result<(), crate::Error> { let pst = FixedOffset::east(8 * 60 * 60)?; - let dt = pst.from_local_datetime( - &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_684)?, - )?; + let dt = pst + .from_local_datetime( + &NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano(10, 5, 13, 84_660_684)?, + )? + .single()?; assert_eq!(dt.trunc_subsecs(10), dt); assert_eq!(dt.trunc_subsecs(9), dt); @@ -315,7 +317,7 @@ mod tests { 5, 27, 750_500_000, - )?)?; + )?)?.single()?; assert_eq!(dt.trunc_subsecs(9), dt); assert_eq!(dt.trunc_subsecs(4), dt); assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000); @@ -370,17 +372,19 @@ mod tests { ); // round up - let dt = Utc.from_local_datetime( - &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?, - )?; + let dt = Utc + .from_local_datetime(&NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?)? + .single()?; assert_eq!( dt.duration_round(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:25:00 UTC" ); // round down - let dt = Utc.from_local_datetime( - &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, - )?; + let dt = Utc + .from_local_datetime( + &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, + )? + .single()?; assert_eq!( dt.duration_round(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00 UTC" @@ -430,6 +434,7 @@ mod tests { 59, 175_500_000, )?)? + .single()? .naive_utc(); assert_eq!(dt.duration_round(TimeDelta::zero())?.to_string(), "2016-12-31 23:59:59.175500"); @@ -442,6 +447,7 @@ mod tests { // round up let dt = Utc .from_local_datetime(&NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 30, 0)?)? + .single()? .naive_utc(); assert_eq!(dt.duration_round(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:25:00"); // round down @@ -449,6 +455,7 @@ mod tests { .from_local_datetime( &NaiveDate::from_ymd(2012, 12, 12)?.and_hms_milli(18, 22, 29, 999)?, )? + .single()? .naive_utc(); assert_eq!(dt.duration_round(TimeDelta::minutes(5))?.to_string(), "2012-12-12 18:20:00"); @@ -461,7 +468,7 @@ mod tests { #[test] fn test_duration_round_pre_epoch() -> Result<(), crate::Error> { - let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12)?; + let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12)?.single()?; assert_eq!( dt.duration_round(TimeDelta::minutes(10))?.to_string(), "1969-12-12 12:10:00 UTC" @@ -565,6 +572,7 @@ mod tests { 59, 175_500_000, )?)? + .single()? .naive_utc(); assert_eq!( From a3a8e450cae5a7de2752946d3a33c24fe459247b Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 19:48:24 +0200 Subject: [PATCH 23/54] Test fixing...2 --- src/round.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/round.rs b/src/round.rs index 7dd9b48861..ef2a14a67b 100644 --- a/src/round.rs +++ b/src/round.rs @@ -277,7 +277,7 @@ mod tests { 59, 59, 1_750_500_000, - )?)?; + )?)?.single()?; 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); From 251f7b996b1e0076613289809c999f3bca341c93 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 20:00:28 +0200 Subject: [PATCH 24/54] some ymd --- src/datetime/tests.rs | 21 +++++++-------------- src/offset/fixed.rs | 33 ++++++++------------------------ src/offset/local/mod.rs | 5 ++++- src/offset/utc.rs | 6 +++--- src/round.rs | 42 +++++++++++++++++++++++------------------ 5 files changed, 46 insertions(+), 61 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 363ae4ed87..222bb7c4f0 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1605,14 +1605,8 @@ fn test_from_system_time() -> Result<(), crate::Error> { { assert_eq!(SystemTime::from(epoch.with_timezone(&Local)?), UNIX_EPOCH); } - assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400)?)?), - UNIX_EPOCH - ); - assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800)?)?), - UNIX_EPOCH - ); + assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400)?)?), UNIX_EPOCH); + assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800)?)?), UNIX_EPOCH); Ok(()) } @@ -1629,9 +1623,7 @@ fn test_from_system_time() { 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(2001, 9, 9)?.and_hms_nano(1, 46, 39, nanos)? - )? + Utc.from_local_datetime(&NaiveDate::from_ymd(2001, 9, 9)?.and_hms_nano(1, 46, 39, nanos)?)? ); assert_eq!( DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), @@ -1708,7 +1700,7 @@ fn test_datetime_format_alignment() { } #[test] -fn test_datetime_from_local() { +fn test_datetime_from_local() -> Result<(), crate::Error> { // 2000-01-12T02:00:00Z let naivedatetime_utc = NaiveDate::from_ymd(2000, 1, 12).unwrap().and_hms(2, 0, 0).unwrap(); let datetime_utc = DateTime::::from_utc(naivedatetime_utc, Utc); @@ -1723,8 +1715,9 @@ fn test_datetime_from_local() { let naivedatetime_west = NaiveDate::from_ymd(2000, 1, 11).unwrap().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_timezone(&timezone_east)?); + assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)?); + Ok(()) } #[test] diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index e7231e444d..68ed9bb0b1 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -43,7 +43,7 @@ impl FixedOffset { /// let hour = 3600; /// let datetime = FixedOffset::east(5 * hour)?.ymd(2016, 11, 08)?.and_hms(0, 0, 0)?; /// assert_eq!(datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00"); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` pub fn east(secs: i32) -> Result { if -86_400 < secs && secs < 86_400 { @@ -64,7 +64,7 @@ impl FixedOffset { /// let hour = 3600; /// let datetime = FixedOffset::west(5 * hour)?.ymd(2016, 11, 08)?.and_hms(0, 0, 0)?; /// assert_eq!(datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00"); - /// # Ok::<_, chrono::Error>(()) + /// Ok(()) /// ``` pub fn west(secs: i32) -> Result { if -86_400 < secs && secs < 86_400 { @@ -234,40 +234,23 @@ mod tests { use crate::offset::TimeZone; #[test] - fn test_date_extreme_offset() { + fn test_date_extreme_offset() -> Result<(), crate::Error> { // starting from 0.3 we don't have an offset exceeding one day. // this makes everything easier! - assert_eq!( - format!("{:?}", FixedOffset::east(86399).unwrap().ymd(2012, 2, 29).unwrap().unwrap()), - "2012-02-29+23:59:59" - ); assert_eq!( format!( "{:?}", - FixedOffset::east(86399) - .unwrap() - .ymd(2012, 2, 29) - .unwrap() - .and_hms(5, 6, 7) - .unwrap() + FixedOffset::east(86399)?.with_ymd_and_hms(2012, 2, 29, 5, 6, 7)?.single()? ), - "2012-02-29T05:06:07+23:59:59" - ); - assert_eq!( - format!("{:?}", FixedOffset::west(86399).unwrap().ymd(2012, 3, 4).unwrap().unwrap()), - "2012-03-04-23:59:59" + "2012-02-29T05:06:07+23:59:59".to_string() ); assert_eq!( format!( "{:?}", - FixedOffset::west(86399) - .unwrap() - .ymd(2012, 3, 4) - .unwrap() - .and_hms(5, 6, 7) - .unwrap() + FixedOffset::west(86399)?.with_ymd_and_hms(2012, 3, 4, 5, 6, 7)?.single()? ), - "2012-03-04T05:06:07-23:59:59" + "2012-03-04T05:06:07-23:59:59".to_string() ); + Ok(()) } } diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 8e73819a1b..628caa532f 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -300,7 +300,10 @@ mod tests { #[test] fn test_local_date_sanity_check() { // issue #27 - assert_eq!(Local.ymd(2999, 12, 28).unwrap().unwrap().day(), 28); + assert_eq!( + Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0).unwrap().single().unwrap().day(), + 28 + ); } #[test] diff --git a/src/offset/utc.rs b/src/offset/utc.rs index ee14b3ccb2..b27cbbade4 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -38,9 +38,9 @@ use crate::{Error, LocalResult}; /// /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0)?, Utc); /// -/// assert_eq!(Utc.timestamp(61, 0)?, dt); -/// assert_eq!(Utc.ymd(1970, 1, 1)?.and_hms(0, 1, 1)?, dt); -/// # Ok::<_, chrono::Error>(()) +/// assert_eq!(Utc.timestamp(61, 0), dt); +/// assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1)?.single()?, dt); +/// Ok(()) /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] diff --git a/src/round.rs b/src/round.rs index ef2a14a67b..d25516bedb 100644 --- a/src/round.rs +++ b/src/round.rs @@ -253,12 +253,14 @@ 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(2018, 1, 11)?.and_hms_nano( - 10, - 5, - 27, - 750_500_000, - )?)?; + let dt = Utc + .from_local_datetime(&NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano( + 10, + 5, + 27, + 750_500_000, + )?)? + .single()?; assert_eq!(dt.round_subsecs(9), dt); assert_eq!(dt.round_subsecs(4), dt); assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000); @@ -272,12 +274,14 @@ mod tests { #[test] fn test_round_leap_nanos() -> Result<(), crate::Error> { - let dt = Utc.from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( - 23, - 59, - 59, - 1_750_500_000, - )?)?.single()?; + let dt = Utc + .from_local_datetime(&NaiveDate::from_ymd(2016, 12, 31)?.and_hms_nano( + 23, + 59, + 59, + 1_750_500_000, + )?)? + .single()?; 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); @@ -312,12 +316,14 @@ 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(2018, 1, 11)?.and_hms_nano( - 10, - 5, - 27, - 750_500_000, - )?)?.single()?; + let dt = pst + .from_local_datetime(&NaiveDate::from_ymd(2018, 1, 11)?.and_hms_nano( + 10, + 5, + 27, + 750_500_000, + )?)? + .single()?; assert_eq!(dt.trunc_subsecs(9), dt); assert_eq!(dt.trunc_subsecs(4), dt); assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000); From 7652f24d33b138f68b94ba74e63b396be702fa50 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 20:33:48 +0200 Subject: [PATCH 25/54] final ymd --- src/datetime/tests.rs | 18 ++++++++-------- src/format/parse.rs | 20 ++++++++---------- src/format/parsed.rs | 48 +++++++++++++++++++++---------------------- 3 files changed, 42 insertions(+), 44 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 222bb7c4f0..323623cbd9 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1781,7 +1781,7 @@ fn test_datetime_add_assign_local() -> Result<(), crate::Error> { } #[test] -fn test_datetime_sub_assign() { +fn test_datetime_sub_assign() -> Result<(), crate::Error> { let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).unwrap().and_hms(12, 0, 0).unwrap(); let datetime = DateTime::::from_utc(naivedatetime, Utc); let mut datetime_sub = datetime; @@ -1789,17 +1789,18 @@ fn test_datetime_sub_assign() { datetime_sub -= TimeDelta::minutes(90); assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); - let timezone = FixedOffset::east(60 * 60).unwrap(); - let datetime = datetime.with_timezone(&timezone); - let datetime_sub = datetime_sub.with_timezone(&timezone); + let timezone = FixedOffset::east(60 * 60)?; + let datetime = datetime.with_timezone(&timezone)?; + let datetime_sub = datetime_sub.with_timezone(&timezone)?; assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); - let timezone = FixedOffset::west(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)?; + let datetime = datetime.with_timezone(&timezone)?; + let datetime_sub = datetime_sub.with_timezone(&timezone)?; assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90)); + Ok(()) } #[test] @@ -1807,7 +1808,7 @@ fn test_datetime_sub_assign() { fn test_datetime_sub_assign_local() -> Result<(), crate::Error> { let naivedatetime = NaiveDate::from_ymd(2022, 1, 1)?.and_hms(0, 0, 0)?; - let datetime = Local.from_utc_datetime(&naivedatetime); + let datetime = Local.from_utc_datetime(&naivedatetime)?; let mut datetime_sub = Local.from_utc_datetime(&naivedatetime)?; // ensure we cross a DST transition @@ -1815,4 +1816,5 @@ fn test_datetime_sub_assign_local() -> Result<(), crate::Error> { datetime_sub -= TimeDelta::days(1); assert_eq!(datetime_sub, datetime - TimeDelta::days(i)) } + Ok(()) } diff --git a/src/format/parse.rs b/src/format/parse.rs index 9380b0de29..0414c9d980 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -1402,13 +1402,13 @@ fn test_rfc2822() { #[cfg(test)] #[test] -fn parse_rfc850() { +fn parse_rfc850() -> Result<(), crate::Error> { use crate::{TimeZone, Utc}; static RFC850_FMT: &str = "%A, %d-%b-%y %T GMT"; let dt_str = "Sunday, 06-Nov-94 08:49:37 GMT"; - let dt = Utc.ymd(1994, 11, 6).unwrap().and_hms(8, 49, 37).unwrap(); + let dt = Utc.with_ymd_and_hms(1994, 11, 6, 8, 49, 37)?.single()?; // Check that the format is what we expect assert_eq!(dt.format(RFC850_FMT).to_string(), dt_str); @@ -1419,28 +1419,25 @@ 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)?.single()?, "Monday, 07-Nov-94 08:49:37 GMT"), ( - Utc.ymd(1994, 11, 7).unwrap().and_hms(8, 49, 37).unwrap(), - "Monday, 07-Nov-94 08:49:37 GMT", - ), - ( - Utc.ymd(1994, 11, 8).unwrap().and_hms(8, 49, 37).unwrap(), + Utc.with_ymd_and_hms(1994, 11, 8, 8, 49, 37)?.single()?, "Tuesday, 08-Nov-94 08:49:37 GMT", ), ( - Utc.ymd(1994, 11, 9).unwrap().and_hms(8, 49, 37).unwrap(), + Utc.with_ymd_and_hms(1994, 11, 9, 8, 49, 37)?.single()?, "Wednesday, 09-Nov-94 08:49:37 GMT", ), ( - Utc.ymd(1994, 11, 10).unwrap().and_hms(8, 49, 37).unwrap(), + Utc.with_ymd_and_hms(1994, 11, 10, 8, 49, 37)?.single()?, "Thursday, 10-Nov-94 08:49:37 GMT", ), ( - Utc.ymd(1994, 11, 11).unwrap().and_hms(8, 49, 37).unwrap(), + Utc.with_ymd_and_hms(1994, 11, 11, 8, 49, 37)?.single()?, "Friday, 11-Nov-94 08:49:37 GMT", ), ( - Utc.ymd(1994, 11, 12).unwrap().and_hms(8, 49, 37).unwrap(), + Utc.with_ymd_and_hms(1994, 11, 12, 8, 49, 37)?.single()?, "Saturday, 12-Nov-94 08:49:37 GMT", ), ]; @@ -1448,6 +1445,7 @@ fn parse_rfc850() { for val in &testdates { assert_eq!(Ok(val.0), Utc.datetime_from_str(val.1, RFC850_FMT)); } + Ok(()) } #[cfg(test)] diff --git a/src/format/parsed.rs b/src/format/parsed.rs index 90ce342c55..38c4ec95ff 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -1250,7 +1250,7 @@ mod tests { } #[test] - fn test_parsed_to_datetime() { + fn test_parsed_to_datetime() -> Result<(), crate::Error> { macro_rules! parse { ($($k:ident: $v:expr),*) => ( Parsed { $($k: Some($v),)* ..Parsed::new() }.to_datetime() @@ -1258,12 +1258,11 @@ mod tests { } let ymdhmsn = |y, m, d, h, n, s, nano, off| { - FixedOffset::east(off) - .unwrap() - .ymd(y, m, d) - .unwrap() - .and_hms_nano(h, n, s, nano) - .unwrap() + FixedOffset::east(off)? + .from_local_datetime( + &NaiveDate::from_ymd(y, m, d)?.and_hms_nano(h, n, s, nano)?, + )? + .single() }; assert_eq!(parse!(offset: 0), Err(Error::ParsingNotEnough)); @@ -1275,27 +1274,28 @@ mod tests { assert_eq!( parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, nanosecond: 12_345_678, offset: 0), - Ok(ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678, 0)) + 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), - Ok(ymdhmsn(2014, 12, 31, 13, 26, 40, 12_345_678, 32400)) + 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), - Ok(ymdhmsn(2014, 12, 31, 1, 42, 4, 12_345_678, -9876)) + 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(Error::InvalidTimeZone) ); // `FixedOffset` does not support such huge offset + Ok(()) } #[test] - fn test_parsed_to_datetime_with_timezone() { + fn test_parsed_to_datetime_with_timezone() -> Result<(), crate::Error> { macro_rules! parse { ($tz:expr; $($k:ident: $v:expr),*) => ( Parsed { $($k: Some($v),)* ..Parsed::new() }.to_datetime_with_timezone(&$tz) @@ -1307,7 +1307,10 @@ mod tests { parse!(Utc; year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, nanosecond: 12_345_678, offset: 0), - Ok(Utc.ymd(2014, 12, 31).unwrap().and_hms_nano(4, 26, 40, 12_345_678).unwrap()) + Utc.from_local_datetime( + &NaiveDate::from_ymd(2014, 12, 31)?.and_hms_nano(4, 26, 40, 12_345_678)? + )? + .single() ); assert_eq!( parse!(Utc; @@ -1325,18 +1328,17 @@ mod tests { parse!(FixedOffset::east(32400).unwrap(); year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1, minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400), - Ok(FixedOffset::east(32400) - .unwrap() - .ymd(2014, 12, 31) - .unwrap() - .and_hms_nano(13, 26, 40, 12_345_678) - .unwrap()) + FixedOffset::east(32400)? + .from_local_datetime( + &NaiveDate::from_ymd(2014, 12, 31)?.and_hms_nano(13, 26, 40, 12_345_678)? + )? + .single() ); // single result from timestamp assert_eq!( parse!(Utc; timestamp: 1_420_000_000, offset: 0), - Ok(Utc.ymd(2014, 12, 31).unwrap().and_hms(4, 26, 40).unwrap()) + Utc.with_ymd_and_hms(2014, 12, 31, 4, 26, 40)?.single() ); assert_eq!( parse!(Utc; timestamp: 1_420_000_000, offset: 32400), @@ -1348,14 +1350,10 @@ mod tests { ); assert_eq!( parse!(FixedOffset::east(32400).unwrap(); timestamp: 1_420_000_000, offset: 32400), - Ok(FixedOffset::east(32400) - .unwrap() - .ymd(2014, 12, 31) - .unwrap() - .and_hms(13, 26, 40) - .unwrap()) + FixedOffset::east(32400)?.with_ymd_and_hms(2014, 12, 31, 13, 26, 40)?.single() ); // TODO test with a variable time zone (for None and Ambiguous cases) + Ok(()) } } From de821dca7b7d220f14896865f4ee6372d61570f5 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 21:34:36 +0200 Subject: [PATCH 26/54] doctest --- src/date.rs | 4 ++-- src/datetime/mod.rs | 18 ++++++++++-------- src/datetime/tests.rs | 37 ++++++++++++++++++------------------- src/format/parsed.rs | 4 +--- src/month.rs | 6 +++--- src/naive/time/mod.rs | 14 +++++++------- src/offset/fixed.rs | 8 ++++---- src/offset/mod.rs | 11 ++++------- src/offset/utc.rs | 6 +++--- src/round.rs | 24 ++++++++++++------------ tests/wasm.rs | 2 +- 11 files changed, 65 insertions(+), 69 deletions(-) diff --git a/src/date.rs b/src/date.rs index 3b411a73d7..bee4b1df83 100644 --- a/src/date.rs +++ b/src/date.rs @@ -158,7 +158,7 @@ impl Date { /// ``` /// use chrono::prelude::*; /// - /// assert_eq!(Utc.ymd(2022, 09, 12)?.single()?.succ()?, Utc.ymd(2022, 09, 13)?.single()?); + /// assert_eq!(NaiveDate::from_ymd(2022, 09, 12)?.succ()?, NaiveDate::from_ymd(2022, 09, 13)?); /// /// assert!(Date::::MAX_UTC.succ().is_err()); /// Ok::<_, Error>(()) @@ -302,7 +302,7 @@ where /// ```rust /// use chrono::prelude::*; /// - /// let date_time: Date = Utc.ymd(2017, 04, 02)?.single()?; + /// let date_time = NaiveDate::from_ymd(2017, 04, 02)?.and_hms(0, 0, 0)?.and_local_timezone(Utc)?; /// let formatted = format!("{}", date_time.format("%d/%m/%Y")); /// assert_eq!(formatted, "02/04/2017"); /// Ok::<_, chrono::Error>(()) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index c8bba9e2c7..277832ee2e 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -104,7 +104,7 @@ impl DateTime { /// /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0)?, Utc); /// assert_eq!(Utc.timestamp(61, 0).unwrap(), dt); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` // // note: this constructor is purposely not named to `new` to discourage the direct usage. @@ -136,7 +136,7 @@ impl DateTime { /// assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east)?); /// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)?); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { @@ -168,7 +168,7 @@ impl DateTime { /// let date: DateTime = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0)?.single()?; /// let other: DateTime = FixedOffset::east(23)?.with_ymd_and_hms(2020, 1, 1, 0, 0, 0)?.single()?; /// assert_eq!(date.date_naive(), other.date_naive()); - /// Ok(()) + /// Ok::<(), Error>(()) /// ``` #[inline] pub fn date_naive(&self) -> NaiveDate { @@ -207,7 +207,7 @@ impl DateTime { /// /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_milli(1, 46, 40, 555)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_millis(&self) -> i64 { @@ -231,6 +231,7 @@ impl DateTime { /// /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_micro(1, 46, 40, 555)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); + /// Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_micros(&self) -> i64 { @@ -254,7 +255,7 @@ impl DateTime { /// /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_nano(1, 46, 40, 555)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_nanos(&self) -> i64 { @@ -541,7 +542,7 @@ impl DateTime { /// DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(), /// FixedOffset::east(0)?.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.single()? /// ); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` /// /// [RFC 2822 Appendix A.5]: https://www.rfc-editor.org/rfc/rfc2822#appendix-A.5 @@ -590,7 +591,7 @@ impl DateTime { /// 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)?.from_local_datetime(&NaiveDate::from_ymd(1983, 4, 13)?.and_hms_milli(12, 9, 14, 274)?)?); - /// Ok(()) + /// Ok::<(), Error>(()) /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> Result, Error> { let mut parsed = Parsed::new(); @@ -771,6 +772,7 @@ where /// let date_time: DateTime = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32)?; /// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M")); /// assert_eq!(formatted, "02/04/2017 12:50"); + /// Ok::<(), Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -959,7 +961,7 @@ impl PartialOrd> for DateTime { /// assert_eq!(later.to_string(), "2015-05-14 22:00:00 -05:00"); /// /// assert!(later > earlier); - /// Ok(()) + /// Ok::<(), Error>(()) /// ``` fn partial_cmp(&self, other: &DateTime) -> Option { self.datetime.partial_cmp(&other.datetime) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 323623cbd9..b0d62bb2b5 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -368,33 +368,33 @@ fn test_datetime_offset() -> Result<(), crate::Error> { "2014-05-06T07:08:09-04:00" ); assert_eq!( - format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()), + format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9)?.single()?), "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.with_ymd_and_hms(2014, 5, 6, 0, 0, 0)?.single()?), "2014-05-06T00:00:00Z" ); assert_eq!( - format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()), + format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 0, 0, 0)?.single()?), "2014-05-06T00:00:00-04:00" ); assert_eq!( - format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()), + format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 0, 0, 0)?.single()?), "2014-05-06T00:00:00+09:00" ); assert_eq!( - format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()), + format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 23, 59, 59)?.single()?), "2014-05-06T23:59:59Z" ); assert_eq!( - format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()), + format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 23, 59, 59)?.single()?), "2014-05-06T23:59:59-04:00" ); assert_eq!( - format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()), + format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 23, 59, 59)?.single()?), "2014-05-06T23:59:59+09:00" ); @@ -1518,11 +1518,12 @@ fn test_datetime_format_with_local() -> Result<(), crate::Error> { #[test] #[cfg(feature = "clock")] -fn test_datetime_is_copy() { +fn test_datetime_is_copy() -> Result<(), crate::Error> { // UTC is known to be `Copy`. - let a = Utc::now(); + let a = Utc::now()?; let b = a; assert_eq!(a, b); + Ok(()) } #[test] @@ -1531,7 +1532,7 @@ fn test_datetime_is_send() { use std::thread; // UTC is known to be `Send`. - let a = Utc::now(); + let a = Utc::now().unwrap(); thread::spawn(move || { let _ = a; }) @@ -1540,18 +1541,15 @@ fn test_datetime_is_send() { } #[test] -fn test_subsecond_part() { +fn test_subsecond_part() -> Result<(), crate::Error> { let datetime = Utc - .from_local_datetime( - &NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms_nano(9, 10, 11, 1234567).unwrap(), - ) - .unwrap() - .single() - .unwrap(); + .from_local_datetime(&NaiveDate::from_ymd(2014, 7, 8)?.and_hms_nano(9, 10, 11, 1234567)?)? + .single()?; assert_eq!(1, datetime.timestamp_subsec_millis()); assert_eq!(1234, datetime.timestamp_subsec_micros()); assert_eq!(1234567, datetime.timestamp_subsec_nanos()); + Ok(()) } #[test] @@ -1670,8 +1668,8 @@ fn test_from_system_time() { } #[test] -fn test_datetime_format_alignment() { - let datetime = Utc.with_ymd_and_hms(2007, 1, 2, 0, 0, 0).unwrap(); +fn test_datetime_format_alignment() -> Result<(), crate::Error> { + let datetime = Utc.with_ymd_and_hms(2007, 1, 2, 0, 0, 0)?.single()?; // Item::Literal let percent = datetime.format("%%"); @@ -1697,6 +1695,7 @@ fn test_datetime_format_alignment() { assert_eq!(format!(" {}", ymd_formatted), format!("{:>17}", ymd)); assert_eq!(format!("{} ", ymd_formatted), format!("{:<17}", ymd)); assert_eq!(format!(" {} ", ymd_formatted), format!("{:^17}", ymd)); + Ok(()) } #[test] diff --git a/src/format/parsed.rs b/src/format/parsed.rs index 38c4ec95ff..213f1e853e 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -1259,9 +1259,7 @@ mod tests { let ymdhmsn = |y, m, d, h, n, s, nano, off| { FixedOffset::east(off)? - .from_local_datetime( - &NaiveDate::from_ymd(y, m, d)?.and_hms_nano(h, n, s, nano)?, - )? + .from_local_datetime(&NaiveDate::from_ymd(y, m, d)?.and_hms_nano(h, n, s, nano)?)? .single() }; diff --git a/src/month.rs b/src/month.rs index 80f268cae6..7c8e800f6e 100644 --- a/src/month.rs +++ b/src/month.rs @@ -15,11 +15,11 @@ use crate::OutOfRange; /// ``` /// use chrono::prelude::*; /// use std::convert::TryFrom; -/// let date = Utc.ymd(2019, 10, 28)?.and_hms(9, 10, 11)?; +/// let date = NaiveDate::from_ymd(2019, 10, 28)?.and_hms(9, 10, 11)?; /// // `2019-10-28T09:10:11Z` /// let month = Month::try_from(u8::try_from(date.month())?).ok(); /// assert_eq!(month, Some(Month::October)); -/// # Ok::<_, Box>(()) +/// Ok::<(), chrono::Error>(()) /// ``` /// /// Or from a Month to an integer usable by dates @@ -27,7 +27,7 @@ use crate::OutOfRange; /// ``` /// # use chrono::prelude::*; /// let month = Month::January; -/// let dt = Utc.ymd(2019, month.number_from_month(), 28)?.and_hms(9, 10, 11)?; +/// let dt = NaiveDate::from_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>(()) /// ``` diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index c52b92e32c..023f4afc1c 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -76,9 +76,9 @@ mod tests; /// /// let dt1 = NaiveDate::from_ymd(2015, 7, 1)?.and_hms_micro(8, 59, 59, 1_000_000)?; /// -/// let dt2 = Utc.ymd(2015, 6, 30)?.and_hms_nano(23, 59, 59, 1_000_000_000)?; -/// # let _ = (t, dt1, dt2); -/// # Ok::<_, chrono::Error>(()) +/// let dt2 = NaiveDate::from_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; @@ -160,9 +160,9 @@ mod tests; /// ``` /// use chrono::{Utc, TimeZone, NaiveDate}; /// -/// let dt = Utc.ymd(2015, 6, 30)?.and_hms_milli(23, 59, 59, 1_000)?; +/// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms_milli(23, 59, 59, 1_000)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60Z"); -/// # Ok::<_, chrono::Error>(()) +/// Ok::<(), chrono::Error>(()) /// ``` /// /// There are hypothetical leap seconds not on the minute boundary @@ -175,10 +175,10 @@ mod tests; /// ``` /// use chrono::{DateTime, Utc, TimeZone, NaiveDate}; /// -/// let dt = Utc.ymd(2015, 6, 30)?.and_hms_milli(23, 56, 4, 1_000)?; +/// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms_milli(23, 56, 4, 1_000)?.and_local_timezone(Utc)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z"); /// -/// let dt = Utc.ymd(2015, 6, 30)?.and_hms(23, 56, 5)?; +/// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms(23, 56, 5)?.and_local_timezone(Utc)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z"); /// assert_eq!(DateTime::::parse_from_rfc3339("2015-06-30T23:56:05Z")?, dt); /// # Ok::<_, chrono::Error>(()) diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index 68ed9bb0b1..a12bfc6e11 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -41,9 +41,9 @@ impl FixedOffset { /// ``` /// use chrono::{FixedOffset, TimeZone}; /// let hour = 3600; - /// let datetime = FixedOffset::east(5 * hour)?.ymd(2016, 11, 08)?.and_hms(0, 0, 0)?; + /// let datetime = FixedOffset::east(5 * hour)?.with_ymd(2016, 11, 08)?.and_hms(0, 0, 0)?; /// assert_eq!(datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00"); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` pub fn east(secs: i32) -> Result { if -86_400 < secs && secs < 86_400 { @@ -62,9 +62,9 @@ impl FixedOffset { /// ``` /// use chrono::{FixedOffset, TimeZone}; /// let hour = 3600; - /// let datetime = FixedOffset::west(5 * hour)?.ymd(2016, 11, 08)?.and_hms(0, 0, 0)?; + /// let datetime = FixedOffset::west(5 * hour)?.with_ymd_and_hms(2016, 11, 08, 0, 0, 0)?.single()?; /// assert_eq!(datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00"); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` pub fn west(secs: i32) -> Result { if -86_400 < secs && secs < 86_400 { diff --git a/src/offset/mod.rs b/src/offset/mod.rs index f0d0065ddc..a77a2f1d13 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -49,11 +49,7 @@ pub enum LocalResult { impl LocalResult { /// 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 + /// `Err(chrono::Error)` if the result is ambiguous. /// [LocalResult::Single]. pub fn single(self) -> Result { match self { @@ -233,7 +229,7 @@ pub trait TimeZone: Sized + Clone { /// /// ``` /// use chrono::{Utc, TimeZone, LocalResult}; - /// match Utc.timestamp_millis_opt(1431648000) { + /// match Utc.timestamp_millis(1431648000) { /// Ok(dt) => assert_eq!(dt.timestamp(), 1431648), /// Err(_) => panic!("Incorrect timestamp_millis"), /// }; @@ -258,7 +254,8 @@ 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) -> Result, Error> { let (mut secs, mut nanos) = (nanos / 1_000_000_000, nanos % 1_000_000_000); diff --git a/src/offset/utc.rs b/src/offset/utc.rs index b27cbbade4..6a26713cdc 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -38,9 +38,9 @@ use crate::{Error, LocalResult}; /// /// 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)?.single()?, dt); -/// Ok(()) +/// assert_eq!(dt, Utc.timestamp(61, 0)?); +/// assert_eq!(dt, Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1)?.single()?); +/// Ok::<(), chrono::Error>(()) /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] diff --git a/src/round.rs b/src/round.rs index d25516bedb..d48e4139e5 100644 --- a/src/round.rs +++ b/src/round.rs @@ -25,10 +25,10 @@ pub trait SubsecRound { /// # Example /// ``` rust /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd(2018, 1, 11).?.and_hms_milli(12, 0, 0, 154).?.and_local_timezone(Utc).?; + /// let dt = NaiveDate::from_ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?.and_local_timezone(Utc)?; /// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` fn round_subsecs(self, digits: u16) -> Self; @@ -38,10 +38,10 @@ pub trait SubsecRound { /// # Example /// ``` rust /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd(2018, 1, 11).?.and_hms_milli(12, 0, 0, 154).?.and_local_timezone(Utc).?; + /// let dt = NaiveDate::from_ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?.and_local_timezone(Utc)?; /// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` fn trunc_subsecs(self, digits: u16) -> Self; } @@ -110,16 +110,16 @@ pub trait DurationRound: Sized { /// # Example /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd(2018, 1, 11).?.and_hms_milli(12, 0, 0, 154).?.and_local_timezone(Utc).?; + /// let dt = NaiveDate::from_ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?.and_local_timezone(Utc)?; /// assert_eq!( - /// dt.duration_round(TimeDelta::milliseconds(10)).?.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)).?.to_string(), + /// dt.duration_round(TimeDelta::days(1))?.to_string(), /// "2018-01-12 00:00:00 UTC" /// ); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` fn duration_round(self, duration: TimeDelta) -> Result; @@ -128,16 +128,16 @@ pub trait DurationRound: Sized { /// # Example /// ``` rust /// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc, NaiveDate}; - /// let dt = NaiveDate::from_ymd(2018, 1, 11).?.and_hms_milli(12, 0, 0, 154).?.and_local_timezone(Utc).?; + /// let dt = NaiveDate::from_ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?.and_local_timezone(Utc)?; /// assert_eq!( - /// dt.duration_trunc(TimeDelta::milliseconds(10)).?.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)).?.to_string(), + /// dt.duration_trunc(TimeDelta::days(1))?.to_string(), /// "2018-01-11 00:00:00 UTC" /// ); - /// Ok(()) + /// Ok::<(), chrono::Error>(()) /// ``` fn duration_trunc(self, duration: TimeDelta) -> Result; } diff --git a/tests/wasm.rs b/tests/wasm.rs index 2322435db2..d80f6f75cd 100644 --- a/tests/wasm.rs +++ b/tests/wasm.rs @@ -52,7 +52,7 @@ fn from_is_exact() { let dt = DateTime::::try_from(now.clone()).unwrap(); - assert_eq!(now.get_time() as i64, dt.timestamp_millis_opt().unwrap()); + assert_eq!(now.get_time() as i64, dt.timestamp_millis().unwrap()); } #[wasm_bindgen_test] From a817932fffa5c502c13eb6e27b5a1437324ab10f Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 23:29:38 +0200 Subject: [PATCH 27/54] doctests --- ci/core-test/src/lib.rs | 2 +- src/date.rs | 18 ------------- src/datetime/mod.rs | 18 ++++++++----- src/lib.rs | 59 +++++++++++++++++++++++------------------ src/naive/time/mod.rs | 6 ++--- src/offset/fixed.rs | 2 +- 6 files changed, 49 insertions(+), 56 deletions(-) diff --git a/ci/core-test/src/lib.rs b/ci/core-test/src/lib.rs index e311edb5bc..fc0405843e 100644 --- a/ci/core-test/src/lib.rs +++ b/ci/core-test/src/lib.rs @@ -3,5 +3,5 @@ use chrono::{TimeZone, Utc}; pub fn create_time() { - let _ = Utc.ymd(2019, 1, 1).and_hms(0, 0, 0); + let _ = Utc.with_ymd_and_hms(2019, 1, 1, 0, 0, 0)?.single()?; } diff --git a/src/date.rs b/src/date.rs index bee4b1df83..d164e128f5 100644 --- a/src/date.rs +++ b/src/date.rs @@ -154,15 +154,6 @@ impl Date { /// Makes a new `Date` for the next date. /// /// Returns `Err(Error)` when `self` is the last representable date. - /// - /// ``` - /// use chrono::prelude::*; - /// - /// assert_eq!(NaiveDate::from_ymd(2022, 09, 12)?.succ()?, NaiveDate::from_ymd(2022, 09, 13)?); - /// - /// assert!(Date::::MAX_UTC.succ().is_err()); - /// Ok::<_, Error>(()) - /// ``` #[inline] pub fn succ(&self) -> Result, Error> { let date = self.date.succ()?; @@ -172,15 +163,6 @@ impl Date { /// Makes a new `Date` for the prior 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(&self) -> Result, Error> { let date = self.date.pred()?; diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 277832ee2e..a2b1fd22af 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -590,8 +590,10 @@ impl DateTime { /// /// 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)?.from_local_datetime(&NaiveDate::from_ymd(1983, 4, 13)?.and_hms_milli(12, 9, 14, 274)?)?); - /// Ok::<(), Error>(()) + /// assert_eq!(dt, FixedOffset::east(0)?.from_local_datetime( + /// &NaiveDate::from_ymd(1983, 4, 13)?.and_hms_milli(12, 9, 14, 274)? + /// )?.single()?); + /// Ok::<(), chrono::Error>(()) /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> Result, Error> { let mut parsed = Parsed::new(); @@ -645,11 +647,12 @@ impl DateTime { /// # Example /// /// ```rust - /// use chrono::{DateTime, TimeZone, Utc}; + /// use chrono::{DateTime, NaiveDate, TimeZone, Utc}; /// /// let dt = DateTime::::parse_from_str( - /// "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))); + /// "1983 Apr 13 12:09:14.274 +0100", "%Y %b %d %H:%M:%S%.3f %z")?; + /// assert_eq!(dt, NaiveDate::from_ymd(1983, 4, 13)?.and_hms_milli(11, 9, 14, 274)?.and_local_timezone(Utc)?); + /// Ok::<(), chrono::Error>(()) /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> Result, Error> { DateTime::::parse_from_str(s, fmt).map(|result| result.into()) @@ -700,9 +703,10 @@ where /// "2018-01-26T18:30:09Z"); /// /// let pst = FixedOffset::east(8 * 60 * 60)?; - /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd(2018, 1, 26)?.and_hms_micro(10, 30, 9, 453_829)?)?; + /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd(2018, 1, 26)?.single()?.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"))))] @@ -769,7 +773,7 @@ where /// ```rust /// use chrono::prelude::*; /// - /// let date_time: DateTime = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32)?; + /// let date_time: DateTime = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32)?.single()?; /// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M")); /// assert_eq!(formatted, "02/04/2017 12:50"); /// Ok::<(), Error>(()) diff --git a/src/lib.rs b/src/lib.rs index f83125d604..6ed95831ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,26 +111,31 @@ //! //! ```rust //! use chrono::prelude::*; +//! use chrono::offset::LocalResult; //! -//! let dt = Utc.ymd(2014, 7, 8)?.and_hms(9, 10, 11)?; // `2014-07-08T09:10:11Z` +//! let dt = Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)?.single()?; // `2014-07-08T09:10:11Z` //! // July 8 is 188th day of the year 2014 (`o` for "ordinal") -//! assert_eq!(dt, Utc.yo(2014, 189)?.and_hms(9, 10, 11)?); +//! assert_eq!(dt, Utc.yo(2014, 189).and_hms(9, 10, 11)?); //! // July 8 is Tuesday in ISO week 28 of the year 2014. -//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue)?.and_hms(9, 10, 11)?); +//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11)?); //! -//! let dt = Utc.ymd(2014, 7, 8)?.and_hms_milli(9, 10, 11, 12)?; // `2014-07-08T09:10:11.012Z` -//! assert_eq!(dt, Utc.ymd(2014, 7, 8)?.and_hms_micro(9, 10, 11, 12_000)?); -//! assert_eq!(dt, Utc.ymd(2014, 7, 8)?.and_hms_nano(9, 10, 11, 12_000_000)?); +//! let dt = NaiveDate::from_ymd(2014, 7, 8)?.and_hms_milli(9, 10, 11, 12).unwrap().and_local_timezone(Utc).unwrap(); // `2014-07-08T09:10:11.012Z` +//! assert_eq!(dt, NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms_micro(9, 10, 11, 12_000).unwrap().and_local_timezone(Utc).unwrap()); +//! assert_eq!(dt, NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms_nano(9, 10, 11, 12_000_000).unwrap().and_local_timezone(Utc).unwrap()); //! //! // dynamic verification -//! 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()); +//! assert!(Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33)?.single().is_ok()); +//! assert!(Utc.with_ymd_and_hms(2014, 7, 8, 80, 15, 33).is_err()); +//! assert!(Utc.with_ymd_and_hms(2014, 7, 38, 21, 15, 33).is_err()); //! //! // other time zone objects can be used to construct a local datetime. //! // obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical. -//! let local_dt = Local.ymd(2014, 7, 8)?.and_hms_milli(9, 10, 11, 12)?; -//! let fixed_dt = FixedOffset::east(9 * 3600)?.ymd(2014, 7, 8)?.and_hms_milli(18, 10, 11, 12)?; +//! let local_dt = Local.from_local_datetime( +//! &NaiveDate::from_ymd(2014, 7, 8)?.and_hms_milli(9, 10, 11, 12)? +//! )?.single()?; +//! let fixed_dt = FixedOffset::east(9 * 3600)?.from_local_datetime( +//! &NaiveDate::from_ymd(2014, 7, 8)?.and_hms_milli(18, 10, 11, 12)? +//! )?.single()?; //! assert_eq!(dt, fixed_dt); //! # let _ = local_dt; //! # Ok::<_, chrono::Error>(()) @@ -147,7 +152,9 @@ //! use chrono::TimeDelta; //! //! // assume this returned `2014-11-28T21:45:59.324310806+09:00`: -//! let dt = FixedOffset::east(9*3600)?.ymd(2014, 11, 28)?.and_hms_nano(21, 45, 59, 324310806)?; +//! let dt = FixedOffset::east(9*3600)?.from_local_datetime( +//! &NaiveDate::from_ymd(2014, 11, 28)?.and_hms_nano(21, 45, 59, 324310806)? +//! )?.single()?; //! //! // property accessors //! assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28)); @@ -161,7 +168,7 @@ //! // time zone accessor and manipulation //! assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600); //! assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600)?); -//! assert_eq!(dt.with_timezone(&Utc)?, Utc.ymd(2014, 11, 28)?.and_hms_nano(12, 45, 59, 324310806)?); +//! assert_eq!(dt.with_timezone(&Utc)?, Utc.with_ymd_and_hms(2014, 11, 28, 12, 45, 59)?.single().and_nano(324310806)?); //! //! // a sample of property manipulations (validates dynamically) //! assert_eq!(dt.with_day(29)?.weekday(), Weekday::Sat); // 2014-11-29 is Saturday @@ -169,14 +176,14 @@ //! assert_eq!(dt.with_year(-300)?.num_days_from_ce(), -109606); // November 29, 301 BCE //! //! // arithmetic operations -//! let dt1 = Utc.ymd(2014, 11, 14)?.and_hms(8, 9, 10)?; -//! let dt2 = Utc.ymd(2014, 11, 14)?.and_hms(10, 9, 8)?; +//! let dt1 = Utc.with_ymd_and_hms(2014, 11, 14, 8, 9, 10)?.single()?; +//! let dt2 = Utc.with_ymd_and_hms(2014, 11, 14, 10, 9, 8)?.single()?; //! assert_eq!(dt1.signed_duration_since(dt2), TimeDelta::seconds(-2 * 3600 + 2)); //! assert_eq!(dt2.signed_duration_since(dt1), TimeDelta::seconds(2 * 3600 - 2)); -//! assert_eq!(Utc.ymd(1970, 1, 1)?.and_hms(0, 0, 0)? + TimeDelta::seconds(1_000_000_000), -//! Utc.ymd(2001, 9, 9)?.and_hms(1, 46, 40)?); -//! assert_eq!(Utc.ymd(1970, 1, 1)?.and_hms(0, 0, 0)? - TimeDelta::seconds(1_000_000_000), -//! Utc.ymd(1938, 4, 24)?.and_hms(22, 13, 20)?); +//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0)?.single()? + TimeDelta::seconds(1_000_000_000), +//! Utc.with_ymd_and_hms(2001, 9, 9, 1, 46, 40)?.single()?); +//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0)?.single()? - TimeDelta::seconds(1_000_000_000), +//! Utc.with_ymd_and_hms(1938, 4, 24, 22, 13, 20)?.single()?); //! # Ok::<_, chrono::Error>(()) //! ``` //! @@ -257,7 +264,7 @@ //! ```rust //! use chrono::prelude::*; //! -//! let dt = Utc.ymd(2014, 11, 28)?.and_hms(12, 0, 9)?; +//! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9)?.single()?; //! let fixed_dt = dt.with_timezone(&FixedOffset::east(9*3600)?)?; //! //! // method 1 @@ -323,14 +330,14 @@ //! use chrono::prelude::*; //! //! # // 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()?.naive_utc(), Utc::now()?.date_naive()); +//! assert_eq!(Local::today()?.naive_local(), Local::now()?.date_naive()); //! -//! 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(), +//! assert_eq!(Utc.with_ymd_and_hms(2014, 11, 28, 0, 0, 0)?.single()?.weekday(), Weekday::Fri); +//! assert!(Utc.with_ymd_and_hms(2014, 11, 31, 0, 0, 0)?.single().is_err()); +//! assert_eq!(Utc.with_ymd_and_hms(2014, 11, 28, 7, 8, 9)?.single()?.format("%H%M%S").to_string(), //! "070809"); -//! # Ok::<_, chrono::Error>(()) +//! Ok::<(), chrono::Error>(()) //! ``` //! //! There is no timezone-aware `Time` due to the lack of usefulness and also the complexity. diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 023f4afc1c..a7a702a621 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -160,7 +160,7 @@ mod tests; /// ``` /// use chrono::{Utc, TimeZone, NaiveDate}; /// -/// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms_milli(23, 59, 59, 1_000)?; +/// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms_milli(23, 59, 59, 1_000)?.and_local_timezone(Utc)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60Z"); /// Ok::<(), chrono::Error>(()) /// ``` @@ -178,10 +178,10 @@ mod tests; /// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms_milli(23, 56, 4, 1_000)?.and_local_timezone(Utc)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z"); /// -/// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms(23, 56, 5)?.and_local_timezone(Utc)?; +/// let dt = Utc.with_ymd_and_hms(2015, 6, 30, 23, 56, 5)?.single()?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z"); /// assert_eq!(DateTime::::parse_from_rfc3339("2015-06-30T23:56:05Z")?, dt); -/// # Ok::<_, chrono::Error>(()) +/// Ok::<(), chrono::Error>(()) /// ``` /// /// Since Chrono alone cannot determine any existence of leap seconds, diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index a12bfc6e11..43e1c7bff9 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -41,7 +41,7 @@ impl FixedOffset { /// ``` /// use chrono::{FixedOffset, TimeZone}; /// let hour = 3600; - /// let datetime = FixedOffset::east(5 * hour)?.with_ymd(2016, 11, 08)?.and_hms(0, 0, 0)?; + /// let datetime = FixedOffset::east(5 * hour)?.with_ymd_and_hms(2016, 11, 08, 0, 0, 0)?.single()?; /// assert_eq!(datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00"); /// Ok::<(), chrono::Error>(()) /// ``` From 0432bd1b3416707189db27d3d0b30fa313e5b1f7 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2023 23:51:00 +0200 Subject: [PATCH 28/54] Doctests pass again --- src/datetime/mod.rs | 8 ++++---- src/format/mod.rs | 2 +- src/lib.rs | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index a2b1fd22af..f88a348005 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -589,7 +589,7 @@ impl DateTime { /// 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"); + /// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z")?; /// assert_eq!(dt, FixedOffset::east(0)?.from_local_datetime( /// &NaiveDate::from_ymd(1983, 4, 13)?.and_hms_milli(12, 9, 14, 274)? /// )?.single()?); @@ -703,7 +703,7 @@ where /// "2018-01-26T18:30:09Z"); /// /// let pst = FixedOffset::east(8 * 60 * 60)?; - /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd(2018, 1, 26)?.single()?.and_hms_micro(10, 30, 9, 453_829)?)?; + /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd(2018, 1, 26)?.and_hms_micro(10, 30, 9, 453_829)?)?.single()?; /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), /// "2018-01-26T10:30:09+08:00"); /// Ok::<(), chrono::Error>(()) @@ -958,8 +958,8 @@ impl PartialOrd> for DateTime { /// ``` /// use chrono::prelude::*; /// - /// let earlier = Utc.with_ymd_and_hms(2015, 5, 15, 2, 0, 0)?.single().with_timezone(&FixedOffset::west(1 * 3600)?); - /// let later = Utc.with_ymd_and_hms(2015, 5, 15, 3, 0, 0)?.single().with_timezone(&FixedOffset::west(5 * 3600)?); + /// let earlier = Utc.with_ymd_and_hms(2015, 5, 15, 2, 0, 0)?.single()?.with_timezone(&FixedOffset::west(1 * 3600)?)?; + /// let later = Utc.with_ymd_and_hms(2015, 5, 15, 3, 0, 0)?.single()?.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"); diff --git a/src/format/mod.rs b/src/format/mod.rs index 0bc145cf43..36355106b9 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -20,7 +20,7 @@ //! # use std::error::Error; //! use chrono::prelude::*; //! -//! let date_time = Utc.ymd(2020, 11, 10)?.and_hms(0, 1, 32)?; +//! let date_time = Utc.with_ymd_and_hms(2020, 11, 10, 0, 1, 32)?.single()?; //! //! let formatted = format!("{}", date_time.format("%Y-%m-%d %H:%M:%S")); //! assert_eq!(formatted, "2020-11-10 00:01:32"); diff --git a/src/lib.rs b/src/lib.rs index 6ed95831ec..a6f86b199a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,13 +115,13 @@ //! //! let dt = Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)?.single()?; // `2014-07-08T09:10:11Z` //! // July 8 is 188th day of the year 2014 (`o` for "ordinal") -//! assert_eq!(dt, Utc.yo(2014, 189).and_hms(9, 10, 11)?); +//! assert_eq!(dt, NaiveDate::from_yo(2014, 189)?.and_hms(9, 10, 11)?.and_local_timezone(Utc)?); //! // July 8 is Tuesday in ISO week 28 of the year 2014. -//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11)?); +//! assert_eq!(dt, NaiveDate::from_isoywd(2014, 28, Weekday::Tue)?.and_hms(9, 10, 11)?.and_local_timezone(Utc)?); //! -//! let dt = NaiveDate::from_ymd(2014, 7, 8)?.and_hms_milli(9, 10, 11, 12).unwrap().and_local_timezone(Utc).unwrap(); // `2014-07-08T09:10:11.012Z` -//! assert_eq!(dt, NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms_micro(9, 10, 11, 12_000).unwrap().and_local_timezone(Utc).unwrap()); -//! assert_eq!(dt, NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms_nano(9, 10, 11, 12_000_000).unwrap().and_local_timezone(Utc).unwrap()); +//! let dt = NaiveDate::from_ymd(2014, 7, 8)?.and_hms_milli(9, 10, 11, 12)?.and_local_timezone(Utc)?; // `2014-07-08T09:10:11.012Z` +//! assert_eq!(dt, NaiveDate::from_ymd(2014, 7, 8)?.and_hms_micro(9, 10, 11, 12_000)?.and_local_timezone(Utc)?); +//! assert_eq!(dt, NaiveDate::from_ymd(2014, 7, 8)?.and_hms_nano(9, 10, 11, 12_000_000)?.and_local_timezone(Utc)?); //! //! // dynamic verification //! assert!(Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33)?.single().is_ok()); @@ -168,7 +168,7 @@ //! // time zone accessor and manipulation //! assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600); //! assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600)?); -//! assert_eq!(dt.with_timezone(&Utc)?, Utc.with_ymd_and_hms(2014, 11, 28, 12, 45, 59)?.single().and_nano(324310806)?); +//! assert_eq!(dt.with_timezone(&Utc)?, NaiveDate::from_ymd(2014, 11, 28)?.and_hms_nano(12, 45, 59, 324310806)?.and_local_timezone(Utc)?); //! //! // a sample of property manipulations (validates dynamically) //! assert_eq!(dt.with_day(29)?.weekday(), Weekday::Sat); // 2014-11-29 is Saturday @@ -334,7 +334,7 @@ //! assert_eq!(Local::today()?.naive_local(), Local::now()?.date_naive()); //! //! assert_eq!(Utc.with_ymd_and_hms(2014, 11, 28, 0, 0, 0)?.single()?.weekday(), Weekday::Fri); -//! assert!(Utc.with_ymd_and_hms(2014, 11, 31, 0, 0, 0)?.single().is_err()); +//! assert!(Utc.with_ymd_and_hms(2014, 11, 31, 0, 0, 0).is_err()); //! assert_eq!(Utc.with_ymd_and_hms(2014, 11, 28, 7, 8, 9)?.single()?.format("%H%M%S").to_string(), //! "070809"); //! Ok::<(), chrono::Error>(()) From 5e512954bbcddcdf3892979955fb11ad910e3c57 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 00:02:35 +0200 Subject: [PATCH 29/54] and_hms_opt for backwards compablity --- src/date.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/date.rs b/src/date.rs index d164e128f5..95f45001fb 100644 --- a/src/date.rs +++ b/src/date.rs @@ -100,6 +100,12 @@ impl Date { self.and_time(time) } + /// Wraps `and_hms` for backwards compability. + #[deprecated(since = "0.5.0", note = "Use and_hms instead")] + pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Result, Error> { + self.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. From 07df76ec2614b1310429032ed9950888d331eb2c Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 01:06:45 +0200 Subject: [PATCH 30/54] cosmetic changes --- src/date.rs | 25 ++++++------------------- src/datetime/serde.rs | 8 ++++---- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/date.rs b/src/date.rs index 95f45001fb..b11c7be573 100644 --- a/src/date.rs +++ b/src/date.rs @@ -153,8 +153,7 @@ impl Date { sec: u32, nano: u32, ) -> Result, Error> { - let time = NaiveTime::from_hms_nano(hour, min, sec, nano)?; - self.and_time(time) + self.and_time(NaiveTime::from_hms_nano(hour, min, sec, nano)?) } /// Makes a new `Date` for the next date. @@ -162,8 +161,7 @@ impl Date { /// Returns `Err(Error)` when `self` is the last representable date. #[inline] pub fn succ(&self) -> Result, Error> { - let date = self.date.succ()?; - Ok(Date::from_utc(date, self.offset.clone())) + Ok(Date::from_utc(self.date.succ()?, self.offset.clone())) } /// Makes a new `Date` for the prior date. @@ -171,8 +169,7 @@ impl Date { /// Returns `Err(Error)` when `self` is the first representable date. #[inline] pub fn pred(&self) -> Result, Error> { - let date = self.date.pred()?; - Ok(Date::from_utc(date, self.offset.clone())) + Ok(Date::from_utc(self.date.pred()?, self.offset.clone())) } /// Retrieves an associated offset from UTC. @@ -199,8 +196,7 @@ impl Date { /// Returns `Err(Error)` when it will result in overflow. #[inline] pub fn checked_add_signed(self, rhs: TimeDelta) -> Result { - let date = self.date.checked_add_signed(rhs)?; - Ok(Self { date, offset: self.offset }) + Ok(Self { date: self.date.checked_add_signed(rhs)?, offset: self.offset }) } /// Subtracts given `Duration` from the current date. @@ -208,8 +204,7 @@ impl Date { /// Returns `Err(Error)` when it will result in overflow. #[inline] pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result { - let date = self.date.checked_sub_signed(rhs)?; - Ok(Self { date, offset: self.offset }) + Ok(Self { date: self.date.checked_sub_signed(rhs)?, offset: self.offset }) } /// Subtracts another `Date` from the current date. @@ -240,15 +235,7 @@ impl Date { /// Returns the number of whole years from the given `base` until `self`. pub fn years_since(&self, base: Self) -> Option { - 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, - } + self.date.years_since(base.date) } /// The minimum possible `Date`. diff --git a/src/datetime/serde.rs b/src/datetime/serde.rs index 9f5167fe53..5152962682 100644 --- a/src/datetime/serde.rs +++ b/src/datetime/serde.rs @@ -118,7 +118,7 @@ impl<'de> de::Deserialize<'de> for DateTime { /// time: DateTime /// } /// -/// let time = Utc.ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?; +/// let time = NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?.and_local_timezone(Utc).ok(); /// let my_s = S { /// time: time.clone(), /// }; @@ -153,7 +153,7 @@ pub mod ts_nanoseconds { /// } /// /// let my_s = S { - /// time: Utc.ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?, + /// time: NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?.and_local_timezone(Utc).ok(), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); @@ -236,7 +236,7 @@ pub mod ts_nanoseconds { /// time: Option> /// } /// -/// let time = Some(Utc.ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?); +/// let time = NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?.and_local_timezone(Utc).ok(); /// let my_s = S { /// time: time.clone(), /// }; @@ -272,7 +272,7 @@ pub mod ts_nanoseconds_option { /// } /// /// let my_s = S { - /// time: Some(Utc.ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?), + /// time: NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?.and_local_timezone(Utc).ok(), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); From 33c06475d4b6a06ccf146b2f6ae3078320cb0066 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 07:49:15 +0200 Subject: [PATCH 31/54] Turn result to option --- src/date.rs | 4 ++-- src/naive/time/mod.rs | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/date.rs b/src/date.rs index b11c7be573..8949298b6f 100644 --- a/src/date.rs +++ b/src/date.rs @@ -102,8 +102,8 @@ impl Date { /// Wraps `and_hms` for backwards compability. #[deprecated(since = "0.5.0", note = "Use and_hms instead")] - pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Result, Error> { - self.and_hms(hour, min, sec) + pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option> { + self.and_hms(hour, min, sec).ok() } /// Makes a new `DateTime` from the current date, hour, minute, second and millisecond. diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 3b8b011a16..08afd0a10e 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -342,7 +342,12 @@ impl NaiveTime { /// # Ok::<_, chrono::Error>(()) /// ``` #[inline] - pub const fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> Result { + pub const 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 Err(Error::InvalidTime); } From 3c319cab12a5ed2c5837c9f47413f9421c5f8bb9 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 07:54:49 +0200 Subject: [PATCH 32/54] Fix clippy --- src/offset/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/offset/mod.rs b/src/offset/mod.rs index a77a2f1d13..0eb274cee2 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -326,6 +326,7 @@ pub trait TimeZone: Sized + Clone { /// Converts the UTC `NaiveDate` to the local date. #[allow(deprecated)] + #[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)?)) } From a52b57d88d2eca6c3589cb0171aa165e97e73eb4 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 09:03:04 +0200 Subject: [PATCH 33/54] all features --- .vscode/settings.json | 5 +++++ src/datetime/mod.rs | 41 +++++++++++++++++++++---------------- src/datetime/serde.rs | 13 ++++++------ src/error.rs | 13 +++++++++++- src/format/strftime.rs | 37 +++++++++++++++++++++------------ src/naive/datetime/serde.rs | 5 +++-- 6 files changed, 74 insertions(+), 40 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..e32e912475 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.linkedProjects": [ + "/Cargo.toml" + ] +} \ No newline at end of file diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index f88a348005..6beed9a000 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1272,31 +1272,36 @@ fn test_auto_conversion() -> Result<(), crate::Error> { } #[cfg(all(test, feature = "serde"))] -fn test_encodable_json(to_string_utc: FUtc, to_string_fixed: FFixed) +fn test_encodable_json( + to_string_utc: FUtc, + to_string_fixed: FFixed, +) -> Result<(), crate::Error> where FUtc: Fn(&DateTime) -> Result, FFixed: Fn(&DateTime) -> Result, E: ::core::fmt::Debug, + crate::Error: From, { assert_eq!( - to_string_utc(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(), + to_string_utc(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single()?).ok(), Some(r#""2014-07-24T12:34:06Z""#.into()) ); assert_eq!( to_string_fixed( - &FixedOffset::east(3660).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() + &FixedOffset::east(3660)?.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single()? ) .ok(), Some(r#""2014-07-24T12:34:06+01:01""#.into()) ); assert_eq!( to_string_fixed( - &FixedOffset::east(3650).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() + &FixedOffset::east(3650)?.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single()? ) .ok(), Some(r#""2014-07-24T12:34:06+01:00:50""#.into()) ); + Ok(()) } #[cfg(all(test, feature = "clock", feature = "serde"))] @@ -1304,7 +1309,8 @@ fn test_decodable_json( utc_from_str: FUtc, fixed_from_str: FFixed, local_from_str: FLocal, -) where +) -> Result<(), crate::Error> +where FUtc: Fn(&str) -> Result, E>, FFixed: Fn(&str) -> Result, E>, FLocal: Fn(&str) -> Result, E>, @@ -1317,40 +1323,39 @@ 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(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single().ok()) ); 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(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single().ok()) ); assert_eq!( norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()), - norm(&Some( - FixedOffset::east(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() - )) + norm(&FixedOffset::east(0)?.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single().ok()) ); assert_eq!( norm(&fixed_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()), - norm(&Some( - FixedOffset::east(60 * 60 + 23 * 60) - .unwrap() - .with_ymd_and_hms(2014, 7, 24, 13, 57, 6) - .unwrap() - )) + norm( + &FixedOffset::east(60 * 60 + 23 * 60)? + .with_ymd_and_hms(2014, 7, 24, 13, 57, 6)? + .single() + .ok() + ) ); // we don't know the exact local offset but we can check that // the conversion didn't change the instant itself assert_eq!( local_from_str(r#""2014-07-24T12:34:06Z""#).expect("local shouuld parse"), - Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() + Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single()? ); 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.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single()? ); assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); assert!(fixed_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); + Ok(()) } diff --git a/src/datetime/serde.rs b/src/datetime/serde.rs index 5152962682..867b36689f 100644 --- a/src/datetime/serde.rs +++ b/src/datetime/serde.rs @@ -1101,29 +1101,30 @@ pub mod ts_seconds_option { } #[test] -fn test_serde_serialize() { - super::test_encodable_json(serde_json::to_string, serde_json::to_string); +fn test_serde_serialize() -> Result<(), crate::Error> { + super::test_encodable_json(serde_json::to_string, serde_json::to_string) } #[cfg(feature = "clock")] #[test] -fn test_serde_deserialize() { +fn test_serde_deserialize() -> Result<(), crate::Error> { super::test_decodable_json( |input| serde_json::from_str(input), |input| serde_json::from_str(input), |input| serde_json::from_str(input), - ); + ) } #[test] -fn test_serde_bincode() { +fn test_serde_bincode() -> Result<(), crate::Error> { // Bincode is relevant to test separately from JSON because // it is not self-describing. use bincode::{deserialize, serialize}; - let dt = Utc.ymd(2014, 7, 24).unwrap().and_hms(12, 34, 6).unwrap(); + let dt = Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single()?; let encoded = serialize(&dt).unwrap(); let decoded: DateTime = deserialize(&encoded).unwrap(); assert_eq!(dt, decoded); assert_eq!(dt.offset(), decoded.offset()); + Ok(()) } diff --git a/src/error.rs b/src/error.rs index 2bdae06589..4b2da3420b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -98,7 +98,6 @@ pub enum Error { /// Invalid data InvalidData, - /* Rounding errors */ /// Error when the TimeDelta exceeds the TimeDelta from or until the Unix epoch. DurationExceedsTimestamp, @@ -107,6 +106,9 @@ pub enum Error { /// Error when `DateTime.timestamp_nanos` exceeds the limit. TimestampExceedsLimit, + + /// Error when serialization fails. + SerializationError, } impl fmt::Display for Error { @@ -159,6 +161,8 @@ impl fmt::Display for Error { } Error::DurationExceedsLimit => write!(f, "duration exceeds num_nanoseconds limit"), Error::TimestampExceedsLimit => write!(f, "timestamp exceeds num_nanoseconds limit"), + + Error::SerializationError => write!(f, "date could not be serialized"), } } } @@ -209,3 +213,10 @@ impl From for Error { Error::Utf8(error) } } + +#[cfg(feature = "serde")] +impl From for Error { + fn from(_: serde_json::Error) -> Self { + Error::SerializationError + } +} diff --git a/src/format/strftime.rs b/src/format/strftime.rs index e335de3f7c..fa634e3dd4 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -628,13 +628,20 @@ fn test_strftime_items() { assert_eq!(parse_and_collect("%#m"), [Item::Error]); } -#[cfg(feature = "unstable-locales")] +#[cfg(test)] #[test] -fn test_strftime_docs_localized() -> Result<(), Error> { - use crate::offset::TimeZone; - use crate::{FixedOffset, NaiveDate}; - - let dt = FixedOffset::east(34200)?.ymd(2001, 7, 8)?.and_hms_nano(0, 34, 59, 1_026_490_708)?; +fn test_strftime_docs() -> Result<(), crate::Error> { + use crate::NaiveDate; + use crate::{DateTime, FixedOffset, TimeZone, Timelike, Utc}; + + let dt = FixedOffset::east(34200)? + .from_local_datetime(&NaiveDate::from_ymd(2001, 7, 8)?.and_hms_nano( + 0, + 34, + 59, + 1_026_490_708, + )?)? + .single()?; // date specifiers assert_eq!(dt.format("%Y").to_string(), "2001"); @@ -732,20 +739,23 @@ fn test_strftime_docs_localized() -> Result<(), Error> { dt.format(" %Y%d%m%%%%%t%H:%P:%M%S%:::z\t").to_string(), " 20010807%%\t00:am:3460+09\t" ); + Ok(()) } #[cfg(feature = "unstable-locales")] #[test] -fn test_strftime_docs_localized() { +fn test_strftime_docs_localized() -> Result<(), crate::Error> { use crate::offset::TimeZone; use crate::{FixedOffset, NaiveDate}; - let dt = FixedOffset::east(34200) - .unwrap() - .ymd(2001, 7, 8) - .unwrap() - .and_hms_nano(0, 34, 59, 1_026_490_708) - .unwrap(); + let dt = FixedOffset::east(34200)? + .from_local_datetime(&NaiveDate::from_ymd(2001, 7, 8)?.and_hms_nano( + 0, + 34, + 59, + 1_026_490_708, + )?)? + .single()?; // date specifiers assert_eq!(dt.format_localized("%b", Locale::fr_BE).to_string(), "jui"); @@ -784,4 +794,5 @@ fn test_strftime_docs_localized() { assert_eq!(nd.format_localized("%x", Locale::de_DE).to_string(), "08.07.2001"); assert_eq!(nd.format_localized("%F", Locale::de_DE).to_string(), "2001-07-08"); assert_eq!(nd.format_localized("%v", Locale::de_DE).to_string(), " 8-Jul-2001"); + Ok(()) } diff --git a/src/naive/datetime/serde.rs b/src/naive/datetime/serde.rs index 5124ff8bd3..a841f76c51 100644 --- a/src/naive/datetime/serde.rs +++ b/src/naive/datetime/serde.rs @@ -1053,7 +1053,7 @@ fn test_serde_bincode() { } #[test] -fn test_serde_bincode_optional() { +fn test_serde_bincode_optional() -> Result<(), crate::Error> { use crate::prelude::*; use crate::serde::ts_nanoseconds_option; use bincode::{deserialize, serialize}; @@ -1067,9 +1067,10 @@ fn test_serde_bincode_optional() { } let expected = - Test { one: Some(1), two: Some(Utc.ymd(1970, 1, 1).unwrap().and_hms(0, 1, 1).unwrap()) }; + Test { one: Some(1), two: Some(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1)?.single()?) }; let bytes: Vec = serialize(&expected).unwrap(); let actual = deserialize::(&(bytes)).unwrap(); assert_eq!(expected, actual); + Ok(()) } From de66bf2f1a41167160012db566c58adf9ed8ec02 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 09:39:59 +0200 Subject: [PATCH 34/54] feature check --- src/error.rs | 32 ++++++++++++++++++++++++++------ src/naive/date.rs | 1 - src/offset/mod.rs | 4 ++-- src/round.rs | 4 ---- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/error.rs b/src/error.rs index 4b2da3420b..dcb0370de7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,6 +2,7 @@ // See README.md and LICENSE.txt for details. use core::fmt; +#[cfg(feature = "std")] use std::time::SystemTimeError; /// Chrono error @@ -55,35 +56,52 @@ pub 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 + #[cfg(feature = "std")] Io(std::io::ErrorKind), + /// Out of range error OutOfRange(&'static str), + /// Integer parsing error ParseInt(core::num::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 + #[cfg(feature = "std")] Utf8(core::str::Utf8Error), /// Error when tryint to convert from int @@ -139,6 +157,8 @@ impl fmt::Display for Error { Error::InvalidSlice(error) => error.fmt(f), Error::InvalidTzString(error) => write!(f, "invalid TZ string: {}", error), Error::InvalidTzFile(error) => error.fmt(f), + + #[cfg(feature = "std")] Error::Io(error) => error.fmt(f), Error::OutOfRange(error) => error.fmt(f), Error::ParseInt(error) => error.fmt(f), @@ -148,6 +168,8 @@ impl fmt::Display for 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), + + #[cfg(feature = "std")] Error::Utf8(error) => error.fmt(f), Error::TryFromIntError => write!(f, "failed to convert int"), @@ -178,6 +200,7 @@ impl std::error::Error for Error { } } +#[cfg(feature = "std")] impl From for Error { fn from(_: std::string::FromUtf8Error) -> Self { Error::FromUtf8Error @@ -190,6 +213,7 @@ impl From for Error { } } +#[cfg(feature = "std")] impl From for Error { fn from(error: std::io::Error) -> Self { Error::Io(error.kind()) @@ -202,21 +226,17 @@ impl From for Error { } } +#[cfg(feature = "std")] impl From for Error { fn from(_: SystemTimeError) -> Self { Error::SystemTime } } +#[cfg(feature = "std")] impl From for Error { fn from(error: core::str::Utf8Error) -> Self { Error::Utf8(error) } } -#[cfg(feature = "serde")] -impl From for Error { - fn from(_: serde_json::Error) -> Self { - Error::SerializationError - } -} diff --git a/src/naive/date.rs b/src/naive/date.rs index be169bf406..cba91a30fe 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -788,7 +788,6 @@ impl NaiveDate { } /// 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) } diff --git a/src/offset/mod.rs b/src/offset/mod.rs index 0eb274cee2..c8102b8f1d 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -300,8 +300,8 @@ pub trait TimeZone: Sized + Clone { #[allow(clippy::wrong_self_convention)] #[allow(deprecated)] fn from_local_date(&self, local: &NaiveDate) -> Result>, Error> { - // TODO: This might be total nonsense, but the functionality is required at quite a few places - // Is the default time of a day midnight or noon? + // TODO: The functionality is required at quite a few places + // As seen in other instances, midnight is assumed to be the default time Ok(self .offset_from_local_date(local)? .map(|offset| Date::from_utc((local.and_midnight() - offset.fix()).date(), offset))) diff --git a/src/round.rs b/src/round.rs index 70cce5a755..b877ac836d 100644 --- a/src/round.rs +++ b/src/round.rs @@ -101,10 +101,6 @@ const fn span_for_digits(digits: u16) -> u32 { /// `TimeDelta` or the `DateTime` are too big to represented as nanoseconds. They /// will also fail if the `TimeDelta` is bigger than the timestamp. pub trait DurationRound: Sized { - /// Error that can occur in rounding or truncating - #[cfg(not(any(feature = "std", test)))] - type Err: fmt::Debug + fmt::Display; - /// Return a copy rounded by TimeDelta. /// /// # Example From d7f03746fff0289ef124afe99b548fe092c081f4 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 09:52:56 +0200 Subject: [PATCH 35/54] serde error handling --- src/datetime/mod.rs | 1 - src/error.rs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 6beed9a000..25116198dc 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1280,7 +1280,6 @@ where FUtc: Fn(&DateTime) -> Result, FFixed: Fn(&DateTime) -> Result, E: ::core::fmt::Debug, - crate::Error: From, { assert_eq!( to_string_utc(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6)?.single()?).ok(), diff --git a/src/error.rs b/src/error.rs index dcb0370de7..82fc145bdc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -168,7 +168,7 @@ impl fmt::Display for 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), - + #[cfg(feature = "std")] Error::Utf8(error) => error.fmt(f), @@ -239,4 +239,3 @@ impl From for Error { Error::Utf8(error) } } - From 246e33233628e0637d0c5e7433696e3730ef74e8 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 10:00:23 +0200 Subject: [PATCH 36/54] wasm --- src/offset/fixed.rs | 4 ++-- src/offset/local/mod.rs | 21 ++++++++++----------- src/offset/utc.rs | 4 +--- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index d1e80f41ef..144a0f0d7f 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -19,8 +19,8 @@ use crate::{DateTime, Error, LocalResult, Timelike}; /// /// Using the [`TimeZone`](./trait.TimeZone.html) methods /// on a `FixedOffset` struct is the preferred way to construct -/// `DateTime` instances. See the [`east_opt`](#method.east_opt) and -/// [`west_opt`](#method.west_opt) methods for examples. +/// `DateTime` instances. See the [`east`](#method.east) and +/// [`west`](#method.west) methods for examples. #[derive(PartialEq, Eq, Hash, Copy, Clone)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] pub struct FixedOffset { diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 628caa532f..0612b580e0 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -133,14 +133,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( @@ -166,15 +167,13 @@ 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)) } // TODO: A local time from a UTC timestamp is never ambiguous, - // but this still returns `Result`. If it reall is not ambiguous, + // but this still returns `Result`. If it really is not ambiguous, // make sure that `inner::naive_to_local` returns `T` first. #[cfg(not(all( target_arch = "wasm32", diff --git a/src/offset/utc.rs b/src/offset/utc.rs index 6a26713cdc..3ed97fdbd4 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -76,10 +76,8 @@ impl Utc { not(any(target_os = "emscripten", target_os = "wasi")) ))] pub fn now() -> Result, Error> { - use std::convert::TryFrom; - let now = js_sys::Date::new_0(); - DateTime::::try_from(now) + Ok(DateTime::::from(now)) } } From eda476aa01e8cd93f3f345dbdacd92d83d16959f Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 17:22:08 +0200 Subject: [PATCH 37/54] remove vscode config --- .vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e32e912475..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rust-analyzer.linkedProjects": [ - "/Cargo.toml" - ] -} \ No newline at end of file From 816df27f0d4e07324102dd0142c3c14086ff6100 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 19:42:36 +0200 Subject: [PATCH 38/54] ymd gone --- README.md | 2 +- src/datetime/serde.rs | 40 ++++++++++++++++++++-------------------- src/lib.rs | 6 +++--- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index afe65820be..81cae758a2 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ if you want. Chrono inherently does not support an inaccurate or partial date and time representation. 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(2014, 1, 30).with_month(2)` returns `Err(chrono::Error)`. +and consequently `NaiveDate::from_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/src/datetime/serde.rs b/src/datetime/serde.rs index 867b36689f..aa9af3ad5c 100644 --- a/src/datetime/serde.rs +++ b/src/datetime/serde.rs @@ -118,7 +118,7 @@ impl<'de> de::Deserialize<'de> for DateTime { /// time: DateTime /// } /// -/// let time = NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?.and_local_timezone(Utc).ok(); +/// let time = NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?.and_local_timezone(Utc)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -153,7 +153,7 @@ pub mod ts_nanoseconds { /// } /// /// let my_s = S { - /// time: NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?.and_local_timezone(Utc).ok(), + /// time: NaiveDate::from_ymd(2018, 5, 17)?.and_hms_nano(02, 04, 59, 918355733)?.and_local_timezone(Utc)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); @@ -365,7 +365,7 @@ pub mod ts_nanoseconds_option { /// time: DateTime /// } /// -/// let time = Utc.ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?; +/// let time = NaiveDate::from_ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?.and_local_timezone(Utc)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -400,7 +400,7 @@ pub mod ts_microseconds { /// } /// /// let my_s = S { - /// time: Utc.ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?, + /// time: NaiveDate::from_ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?.and_local_timezone(Utc)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); @@ -484,7 +484,7 @@ pub mod ts_microseconds { /// time: Option> /// } /// -/// let time = Some(Utc.ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?); +/// let time = Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?.and_local_timezone(Utc)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -519,7 +519,7 @@ pub mod ts_microseconds_option { /// } /// /// let my_s = S { - /// time: Some(Utc.ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?), + /// time: Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_micro(02, 04, 59, 918355)?.and_local_timezone(Utc)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); @@ -612,7 +612,7 @@ pub mod ts_microseconds_option { /// time: DateTime /// } /// -/// let time = Utc.ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?; +/// let time = NaiveDate::from_ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?.and_local_timezone(Utc)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -647,7 +647,7 @@ pub mod ts_milliseconds { /// } /// /// let my_s = S { - /// time: Utc.ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?, + /// time: NaiveDate::from_ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?.and_local_timezone(Utc)?, /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); @@ -730,7 +730,7 @@ pub mod ts_milliseconds { /// time: Option> /// } /// -/// let time = Some(Utc.ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?); +/// let time = Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?.and_local_timezone(Utc)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -765,7 +765,7 @@ pub mod ts_milliseconds_option { /// } /// /// let my_s = S { - /// time: Some(Utc.ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?), + /// time: Some(NaiveDate::from_ymd(2018, 5, 17)?.and_hms_milli(02, 04, 59, 918)?.and_local_timezone(Utc)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); @@ -862,7 +862,7 @@ pub mod ts_milliseconds_option { /// # Example: /// /// ```rust -/// # use chrono::{TimeZone, DateTime, Utc}; +/// # use chrono::{TimeZone, NaiveDate, DateTime, Utc}; /// # use serde_derive::{Deserialize, Serialize}; /// use chrono::serde::ts_seconds; /// #[derive(Deserialize, Serialize)] @@ -871,7 +871,7 @@ pub mod ts_milliseconds_option { /// time: DateTime /// } /// -/// let time = Utc.ymd(2015, 5, 15)?.and_hms(10, 0, 0)?; +/// let time = NaiveDate::from_ymd(2015, 5, 15)?.and_hms(10, 0, 0)?.and_local_timezone(Utc)?; /// let my_s = S { /// time: time.clone(), /// }; @@ -896,7 +896,7 @@ pub mod ts_seconds { /// # Example: /// /// ```rust - /// # use chrono::{TimeZone, DateTime, Utc}; + /// # use chrono::{TimeZone, NaiveDate, DateTime, Utc}; /// # use serde_derive::Serialize; /// use chrono::serde::ts_seconds::serialize as to_ts; /// #[derive(Serialize)] @@ -906,11 +906,11 @@ pub mod ts_seconds { /// } /// /// let my_s = S { - /// time: Utc.ymd(2015, 5, 15)?.and_hms(10, 0, 0)?, + /// time: NaiveDate::from_ymd(2015, 5, 15)?.and_hms(10, 0, 0)?.and_local_timezone(Utc)?, /// }; - /// let as_string = serde_json::to_string(&my_s)?; + /// let as_string = serde_json::to_string(&my_s).unwrap(); /// assert_eq!(as_string, r#"{"time":1431684000}"#); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -979,7 +979,7 @@ pub mod ts_seconds { /// # Example: /// /// ```rust -/// # use chrono::{TimeZone, DateTime, Utc}; +/// # use chrono::{NaiveDate, TimeZone, DateTime, Utc}; /// # use serde_derive::{Deserialize, Serialize}; /// use chrono::serde::ts_seconds_option; /// #[derive(Deserialize, Serialize)] @@ -988,7 +988,7 @@ pub mod ts_seconds { /// time: Option> /// } /// -/// let time = Some(Utc.ymd(2015, 5, 15)?.and_hms(10, 0, 0)?); +/// let time = Some(NaiveDate::from_ymd(2015, 5, 15)?.and_hms(10, 0, 0)?.and_local_timezone(Utc)?); /// let my_s = S { /// time: time.clone(), /// }; @@ -1013,7 +1013,7 @@ pub mod ts_seconds_option { /// # Example: /// /// ```rust - /// # use chrono::{TimeZone, DateTime, Utc}; + /// # use chrono::{NaiveDate, TimeZone, DateTime, Utc}; /// # use serde_derive::Serialize; /// use chrono::serde::ts_seconds_option::serialize as to_tsopt; /// #[derive(Serialize)] @@ -1023,7 +1023,7 @@ pub mod ts_seconds_option { /// } /// /// let my_s = S { - /// time: Some(Utc.ymd(2015, 5, 15)?.and_hms(10, 0, 0)?), + /// time: Some(NaiveDate::from_ymd(2015, 5, 15)?.and_hms(10, 0, 0)?.and_local_timezone(Utc)?), /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1431684000}"#); diff --git a/src/lib.rs b/src/lib.rs index 72350d1571..55587a8666 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,7 +215,7 @@ //! //! # #[cfg(feature = "unstable-locales")] //! # fn main() -> Result<(), chrono::Error> { -//! let dt = Utc.ymd(2014, 11, 28)?.and_hms(12, 0, 9)?; +//! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9)?.single()?; //! 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"); @@ -227,7 +227,7 @@ //! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z"); //! //! // Note that milli/nanoseconds are only printed if they are non-zero -//! let dt_nano = Utc.ymd(2014, 11, 28)?.and_hms_nano(12, 0, 9, 1)?; +//! let dt_nano = NaiveDate::from_ymd(2014, 11, 28)?.and_hms_nano(12, 0, 9, 1)?.and_local_timezone(Utc)?; //! assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z"); //! # Ok(()) } //! # #[cfg(not(feature = "unstable-locales"))] @@ -382,7 +382,7 @@ //! Chrono inherently does not support an inaccurate or partial date and time representation. //! 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(2014, 1, 30)?.with_month(2)?` returns `Err(chrono::Error)`. +//! and consequently `NaiveDate::from_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) From 4d4197ed07039f4b94895b8dd50fa98182974623 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 19:49:17 +0200 Subject: [PATCH 39/54] serde error --- src/datetime/mod.rs | 18 ++--- src/datetime/serde.rs | 66 ++++++++--------- src/month.rs | 4 +- src/naive/date.rs | 124 ++++++++++++++++---------------- src/naive/datetime/mod.rs | 138 ++++++++++++++++++------------------ src/naive/datetime/serde.rs | 16 ++--- src/naive/isoweek.rs | 12 ++-- src/naive/time/mod.rs | 90 +++++++++++------------ src/offset/fixed.rs | 4 +- src/offset/local/mod.rs | 2 +- src/offset/mod.rs | 2 +- src/offset/utc.rs | 2 +- src/round.rs | 8 +-- src/traits.rs | 2 +- 14 files changed, 244 insertions(+), 244 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 25116198dc..9d5699f67b 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -104,7 +104,7 @@ impl DateTime { /// /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0)?, Utc); /// assert_eq!(Utc.timestamp(61, 0).unwrap(), dt); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` // // note: this constructor is purposely not named to `new` to discourage the direct usage. @@ -136,7 +136,7 @@ impl DateTime { /// assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east)?); /// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)?); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { @@ -207,7 +207,7 @@ impl DateTime { /// /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_milli(1, 46, 40, 555)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_millis(&self) -> i64 { @@ -231,7 +231,7 @@ impl DateTime { /// /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_micro(1, 46, 40, 555)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_micros(&self) -> i64 { @@ -255,7 +255,7 @@ impl DateTime { /// /// let dt = NaiveDate::from_ymd(2001, 9, 9)?.and_hms_nano(1, 46, 40, 555)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_nanos(&self) -> i64 { @@ -542,7 +542,7 @@ impl DateTime { /// DateTime::::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(), /// FixedOffset::east(0)?.with_ymd_and_hms(2015, 2, 18, 23, 16, 9)?.single()? /// ); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// [RFC 2822 Appendix A.5]: https://www.rfc-editor.org/rfc/rfc2822#appendix-A.5 @@ -593,7 +593,7 @@ impl DateTime { /// assert_eq!(dt, FixedOffset::east(0)?.from_local_datetime( /// &NaiveDate::from_ymd(1983, 4, 13)?.and_hms_milli(12, 9, 14, 274)? /// )?.single()?); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> Result, Error> { let mut parsed = Parsed::new(); @@ -652,7 +652,7 @@ impl DateTime { /// let dt = DateTime::::parse_from_str( /// "1983 Apr 13 12:09:14.274 +0100", "%Y %b %d %H:%M:%S%.3f %z")?; /// assert_eq!(dt, NaiveDate::from_ymd(1983, 4, 13)?.and_hms_milli(11, 9, 14, 274)?.and_local_timezone(Utc)?); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> Result, Error> { DateTime::::parse_from_str(s, fmt).map(|result| result.into()) @@ -706,7 +706,7 @@ where /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd(2018, 1, 26)?.and_hms_micro(10, 30, 9, 453_829)?)?.single()?; /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), /// "2018-01-26T10:30:09+08:00"); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] diff --git a/src/datetime/serde.rs b/src/datetime/serde.rs index aa9af3ad5c..9265ae3ad1 100644 --- a/src/datetime/serde.rs +++ b/src/datetime/serde.rs @@ -125,9 +125,9 @@ impl<'de> de::Deserialize<'de> for DateTime { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<_, Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_nanoseconds { use core::fmt; @@ -157,7 +157,7 @@ pub mod ts_nanoseconds { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -183,7 +183,7 @@ pub mod ts_nanoseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -243,9 +243,9 @@ pub mod ts_nanoseconds { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<_, Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_nanoseconds_option { use core::fmt; @@ -276,7 +276,7 @@ pub mod ts_nanoseconds_option { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -304,8 +304,8 @@ pub mod ts_nanoseconds_option { /// time: Option> /// } /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// # Ok::<_, Box>(()) + /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#).unwrap(); + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where @@ -372,9 +372,9 @@ pub mod ts_nanoseconds_option { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<_, Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_microseconds { use core::fmt; @@ -404,7 +404,7 @@ pub mod ts_microseconds { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -430,7 +430,7 @@ pub mod ts_microseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -491,9 +491,9 @@ pub mod ts_microseconds { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<_, Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_microseconds_option { use core::fmt; @@ -523,7 +523,7 @@ pub mod ts_microseconds_option { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -552,7 +552,7 @@ pub mod ts_microseconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where @@ -619,9 +619,9 @@ pub mod ts_microseconds_option { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<_, Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_milliseconds { use core::fmt; @@ -651,7 +651,7 @@ pub mod ts_milliseconds { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -677,7 +677,7 @@ pub mod ts_milliseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -737,9 +737,9 @@ pub mod ts_milliseconds { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<_, Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_milliseconds_option { use core::fmt; @@ -769,7 +769,7 @@ pub mod ts_milliseconds_option { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -810,7 +810,7 @@ pub mod ts_milliseconds_option { /// 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::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where @@ -878,9 +878,9 @@ pub mod ts_milliseconds_option { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1431684000}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<_, Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_seconds { use core::fmt; @@ -936,7 +936,7 @@ pub mod ts_seconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -995,9 +995,9 @@ pub mod ts_seconds { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1431684000}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<_, Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_seconds_option { use core::fmt; @@ -1025,9 +1025,9 @@ pub mod ts_seconds_option { /// let my_s = S { /// time: Some(NaiveDate::from_ymd(2015, 5, 15)?.and_hms(10, 0, 0)?.and_local_timezone(Utc)?), /// }; - /// let as_string = serde_json::to_string(&my_s)?; + /// let as_string = serde_json::to_string(&my_s).unwrap(); /// assert_eq!(as_string, r#"{"time":1431684000}"#); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -1056,7 +1056,7 @@ pub mod ts_seconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where diff --git a/src/month.rs b/src/month.rs index e146057525..97338848d6 100644 --- a/src/month.rs +++ b/src/month.rs @@ -19,7 +19,7 @@ use crate::OutOfRange; /// // `2019-10-28T09:10:11Z` /// let month = Month::try_from(u8::try_from(date.month())?).ok(); /// assert_eq!(month, Some(Month::October)); -/// Ok::<(), chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Or from a Month to an integer usable by dates @@ -29,7 +29,7 @@ use crate::OutOfRange; /// let month = Month::January; /// let dt = NaiveDate::from_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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// Allows mapping from and to month, from 1-January to 12-December. /// Can be Serialized/Deserialized with serde diff --git a/src/naive/date.rs b/src/naive/date.rs index cba91a30fe..d9441dc30a 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -73,7 +73,7 @@ impl NaiveWeek { /// let date = NaiveDate::from_ymd(2022, 4, 18)?; /// let week = date.week(Weekday::Mon); /// assert!(week.first_day() <= date); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn first_day(&self) -> NaiveDate { @@ -93,7 +93,7 @@ impl NaiveWeek { /// let date = NaiveDate::from_ymd(2022, 4, 18)?; /// let week = date.week(Weekday::Mon); /// assert!(week.last_day() >= date); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn last_day(&self) -> NaiveDate { @@ -113,7 +113,7 @@ impl NaiveWeek { /// let week = date.week(Weekday::Mon); /// let days = week.days(); /// assert!(days.contains(&date)); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn days(&self) -> RangeInclusive { @@ -285,7 +285,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn from_ymd(year: i32, month: u32, day: u32) -> Result { let flags = YearFlags::from_year(year); @@ -322,7 +322,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn from_yo(year: i32, ordinal: u32) -> Result { let flags = YearFlags::from_year(year); @@ -351,7 +351,7 @@ impl NaiveDate { /// assert_eq!(d.day(), 14); /// assert_eq!(d.ordinal(), 73); // day of year /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Examples showcasing errors. @@ -367,7 +367,7 @@ impl NaiveDate { /// /// assert!(from_isoywd(400000, 10, Weekday::Fri).is_err()); /// assert!(from_isoywd(-400000, 10, Weekday::Sat).is_err()); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// The year number of ISO week date may differ from that of the calendar date. @@ -390,7 +390,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> Result { let flags = YearFlags::from_year(year); @@ -442,7 +442,7 @@ impl NaiveDate { /// assert_eq!(d.iso_week().year(), 2015); /// assert_eq!(d.iso_week().week(), 11); /// assert_eq!(d.weekday(), Weekday::Sat); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// While not directly supported by Chrono, @@ -473,7 +473,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn from_num_days_from_ce(days: i32) -> Result { @@ -507,7 +507,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn from_weekday_of_month( year: i32, @@ -539,7 +539,7 @@ impl NaiveDate { /// NaiveDate::from_ymd(2015, 9, 5)?); /// assert_eq!(parse_from_str("5sep2015", "%d%b%Y")?, /// NaiveDate::from_ymd(2015, 9, 5)?); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Time and offset is ignored for the purpose of parsing. @@ -549,7 +549,7 @@ impl 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")?, /// NaiveDate::from_ymd(2014, 5, 17)?); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Out-of-bound dates or insufficient fields are errors. @@ -590,7 +590,7 @@ impl NaiveDate { /// NaiveDate::from_ymd(2022, 7, 31)?.checked_add_months(Months::new(2)), /// Ok(NaiveDate::from_ymd(2022, 9, 30)?) /// ); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_add_months(self, months: Months) -> Result { if months.0 == 0 { @@ -620,7 +620,7 @@ impl NaiveDate { /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)) /// .is_err() /// ); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_sub_months(self, months: Months) -> Result { if months.0 == 0 { @@ -688,7 +688,7 @@ impl NaiveDate { /// NaiveDate::from_ymd(2022, 7, 31)?.checked_add_days(Days::new(2)), /// Ok(NaiveDate::from_ymd(2022, 8, 2)?) /// ); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_add_days(self, days: Days) -> Result { if days.0 == 0 { @@ -710,7 +710,7 @@ impl NaiveDate { /// NaiveDate::from_ymd(2022, 2, 20)?.checked_sub_days(Days::new(6)), /// Ok(NaiveDate::from_ymd(2022, 2, 14)?) /// ); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_sub_days(self, days: Days) -> Result { if days.0 == 0 { @@ -748,7 +748,7 @@ impl NaiveDate { /// let dt: NaiveDateTime = d.and_time(t); /// assert_eq!(dt.date(), d); /// assert_eq!(dt.time(), t); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime { @@ -779,7 +779,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> Result { @@ -819,7 +819,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn and_hms_milli( @@ -860,7 +860,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn and_hms_micro( @@ -901,7 +901,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn and_hms_nano( @@ -964,7 +964,7 @@ impl NaiveDate { /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3)?.succ()?, /// NaiveDate::from_ymd(2015, 6, 4)?); /// assert!(NaiveDate::MAX.succ().is_err()); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn succ(&self) -> Result { @@ -990,7 +990,7 @@ impl NaiveDate { /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3)?.pred()?, /// NaiveDate::from_ymd(2015, 6, 2)?); /// assert!(NaiveDate::MIN.pred().is_err()); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn pred(&self) -> Result { @@ -1017,7 +1017,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_add_signed(self, rhs: TimeDelta) -> Result { let year = self.year(); @@ -1051,7 +1051,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result { let year = self.year(); @@ -1089,7 +1089,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn signed_duration_since(self, rhs: NaiveDate) -> TimeDelta { let year1 = self.year(); @@ -1132,7 +1132,7 @@ impl NaiveDate { /// 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"); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -1143,7 +1143,7 @@ impl NaiveDate { /// # let fmt = StrftimeItems::new("%Y-%m-%d").clone(); /// # let d = NaiveDate::from_ymd(2015, 9, 5)?; /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05"); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -1178,7 +1178,7 @@ impl NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -1188,7 +1188,7 @@ impl NaiveDate { /// # 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -1253,7 +1253,7 @@ impl NaiveDate { /// count -= 1; /// assert_eq!(d, expected[count]); /// } - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn iter_days(&self) -> NaiveDateDaysIterator { @@ -1285,7 +1285,7 @@ impl NaiveDate { /// count -= 1; /// assert_eq!(d, expected[count]); /// } - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn iter_weeks(&self) -> NaiveDateWeeksIterator { @@ -1315,7 +1315,7 @@ impl Datelike for NaiveDate { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn year(&self) -> i32 { @@ -1333,7 +1333,7 @@ impl Datelike for NaiveDate { /// /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.month(), 9); /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.month(), 3); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn month(&self) -> u32 { @@ -1351,7 +1351,7 @@ impl Datelike for NaiveDate { /// /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.month0(), 8); /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.month0(), 2); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn month0(&self) -> u32 { @@ -1369,7 +1369,7 @@ impl Datelike for NaiveDate { /// /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.day(), 8); /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.day(), 14); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Combined with [`NaiveDate::pred`](#method.pred), @@ -1393,7 +1393,7 @@ impl Datelike for NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn day(&self) -> u32 { @@ -1411,7 +1411,7 @@ impl Datelike for NaiveDate { /// /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.day0(), 7); /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.day0(), 13); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn day0(&self) -> u32 { @@ -1429,7 +1429,7 @@ impl Datelike for NaiveDate { /// /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.ordinal(), 251); /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.ordinal(), 74); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Combined with [`NaiveDate::pred`](#method.pred), @@ -1452,7 +1452,7 @@ impl Datelike for NaiveDate { /// assert_eq!(ndays_in_year(2017)?, 365); /// assert_eq!(ndays_in_year(2000)?, 366); /// assert_eq!(ndays_in_year(2100)?, 365); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn ordinal(&self) -> u32 { @@ -1470,7 +1470,7 @@ impl Datelike for NaiveDate { /// /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8)?.ordinal0(), 250); /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14)?.ordinal0(), 73); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn ordinal0(&self) -> u32 { @@ -1486,7 +1486,7 @@ impl Datelike for NaiveDate { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn weekday(&self) -> Weekday { @@ -1509,7 +1509,7 @@ impl Datelike for NaiveDate { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// A leap day (February 29) is a good example that this method can return @@ -1519,7 +1519,7 @@ impl Datelike for NaiveDate { /// # use chrono::{NaiveDate, Datelike}; /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_year(&self, year: i32) -> Result { @@ -1545,7 +1545,7 @@ impl Datelike for NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_month(&self, month: u32) -> Result { @@ -1565,7 +1565,7 @@ impl Datelike for NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_month0(&self, month0: u32) -> Result { @@ -1584,7 +1584,7 @@ impl Datelike for NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_day(&self, day: u32) -> Result { @@ -1603,7 +1603,7 @@ impl Datelike for NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_day0(&self, day0: u32) -> Result { @@ -1627,7 +1627,7 @@ impl Datelike for NaiveDate { /// NaiveDate::from_ymd(2016, 2, 29)?); /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal(366)?, /// NaiveDate::from_ymd(2016, 12, 31)?); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_ordinal(&self, ordinal: u32) -> Result { @@ -1651,7 +1651,7 @@ impl Datelike for NaiveDate { /// NaiveDate::from_ymd(2016, 2, 29)?); /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1)?.with_ordinal0(365)?, /// NaiveDate::from_ymd(2016, 12, 31)?); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_ordinal0(&self, ordinal0: u32) -> Result { @@ -1680,7 +1680,7 @@ impl Datelike for NaiveDate { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Add for NaiveDate { type Output = NaiveDate; @@ -1720,7 +1720,7 @@ impl Add for NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` fn add(self, months: Months) -> Self::Output { self.checked_add_months(months).unwrap() @@ -1746,7 +1746,7 @@ impl Sub for NaiveDate { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` fn sub(self, months: Months) -> Self::Output { self.checked_sub_months(months).unwrap() @@ -1791,7 +1791,7 @@ impl Sub for NaiveDate { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Sub for NaiveDate { type Output = NaiveDate; @@ -1832,7 +1832,7 @@ impl SubAssign for NaiveDate { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Sub for NaiveDate { type Output = TimeDelta; @@ -1935,7 +1935,7 @@ impl DoubleEndedIterator for NaiveDateWeeksIterator { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. @@ -1944,7 +1944,7 @@ impl DoubleEndedIterator for NaiveDateWeeksIterator { /// # use chrono::NaiveDate; /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(-1, 1, 1)?), "-0001-01-01"); /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31)?), "+10000-12-31"); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl fmt::Debug for NaiveDate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1981,7 +1981,7 @@ impl fmt::Debug for NaiveDate { /// assert_eq!(format!("{}", NaiveDate::from_ymd(2015, 9, 5)?), "2015-09-05"); /// assert_eq!(format!("{}", NaiveDate::from_ymd(0, 1, 1)?), "0000-01-01"); /// assert_eq!(format!("{}", NaiveDate::from_ymd(9999, 12, 31)?), "9999-12-31"); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. @@ -1990,7 +1990,7 @@ impl fmt::Debug for NaiveDate { /// # use chrono::NaiveDate; /// assert_eq!(format!("{}", NaiveDate::from_ymd(-1, 1, 1)?), "-0001-01-01"); /// assert_eq!(format!("{}", NaiveDate::from_ymd(10000, 12, 31)?), "+10000-12-31"); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl fmt::Display for NaiveDate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -2013,7 +2013,7 @@ impl fmt::Display for NaiveDate { /// assert_eq!("+12345-6-7".parse::()?, d); /// /// assert!("foo".parse::().is_err()); -/// # Ok::<_, Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl str::FromStr for NaiveDate { type Err = Error; @@ -2042,7 +2042,7 @@ impl str::FromStr for NaiveDate { /// /// let default_date = NaiveDate::default(); /// assert_eq!(default_date, NaiveDate::from_ymd(1970, 1, 1)?); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Default for NaiveDate { fn default() -> Self { diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 16fb5dd937..1c27b20b80 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -61,7 +61,7 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX; /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8)?.and_hms(9, 10, 11)?; /// # let _ = dt; -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// You can use typical [date-like](../trait.Datelike.html) and @@ -75,7 +75,7 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX; /// /// assert_eq!(dt.weekday(), Weekday::Fri); /// assert_eq!(dt.num_seconds_from_midnight(), 33011); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` #[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -130,7 +130,7 @@ impl NaiveDateTime { /// let dt = NaiveDateTime::new(d, t); /// assert_eq!(dt.date(), d); /// assert_eq!(dt.time(), t); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn new(date: NaiveDate, time: NaiveTime) -> NaiveDateTime { @@ -155,7 +155,7 @@ impl NaiveDateTime { /// let timestamp_millis: i64 = -2208936075000; //Mon Jan 01 1900 14:38:45 GMT+0000 /// let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis); /// assert_eq!(timestamp_millis, naive_datetime?.timestamp_millis()); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn from_timestamp_millis(millis: i64) -> Result { @@ -180,7 +180,7 @@ impl NaiveDateTime { /// let timestamp_micros: i64 = -2208936075000000; //Mon Jan 01 1900 14:38:45 GMT+0000 /// let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros); /// assert_eq!(timestamp_micros, naive_datetime?.timestamp_micros()); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn from_timestamp_micros(micros: i64) -> Result { @@ -221,7 +221,7 @@ impl NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn from_timestamp(secs: i64, nsecs: u32) -> Result { @@ -251,7 +251,7 @@ impl NaiveDateTime { /// Ok(NaiveDate::from_ymd(2015, 9, 5)?.and_hms(23, 56, 4)?)); /// assert_eq!(parse_from_str("5sep2015pm012345.6789", "%d%b%Y%p%I%M%S%.f"), /// Ok(NaiveDate::from_ymd(2015, 9, 5)?.and_hms_micro(13, 23, 45, 678_900)?)); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Offset is ignored for the purpose of parsing. @@ -261,7 +261,7 @@ impl NaiveDateTime { /// # let parse_from_str = NaiveDateTime::parse_from_str; /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), /// Ok(NaiveDate::from_ymd(2014, 5, 17)?.and_hms(12, 34, 56)?)); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// [Leap seconds](./struct.NaiveTime.html#leap-second-handling) are correctly handled by @@ -273,7 +273,7 @@ impl NaiveDateTime { /// # let parse_from_str = NaiveDateTime::parse_from_str; /// assert_eq!(parse_from_str("2015-07-01 08:59:60.123", "%Y-%m-%d %H:%M:%S%.f"), /// Ok(NaiveDate::from_ymd(2015, 7, 1)?.and_hms_milli(8, 59, 59, 1_123)?)); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Missing seconds are assumed to be zero, @@ -289,7 +289,7 @@ impl NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// All parsed fields should be consistent to each other, otherwise it's an error. @@ -326,7 +326,7 @@ impl NaiveDateTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn date(&self) -> NaiveDate { @@ -342,7 +342,7 @@ impl NaiveDateTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn time(&self) -> NaiveTime { @@ -370,7 +370,7 @@ impl NaiveDateTime { /// /// let dt = NaiveDate::from_ymd(-1, 1, 1)?.and_hms(0, 0, 0)?; /// assert_eq!(dt.timestamp(), -62198755200); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp(&self) -> i64 { @@ -403,7 +403,7 @@ impl NaiveDateTime { /// /// let dt = NaiveDate::from_ymd(1969, 12, 31)?.and_hms_milli(23, 59, 59, 100)?; /// assert_eq!(dt.timestamp_millis(), -900); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_millis(&self) -> i64 { @@ -431,7 +431,7 @@ impl NaiveDateTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_micros(&self) -> i64 { @@ -471,7 +471,7 @@ impl NaiveDateTime { /// dt, /// NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32)? /// ); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_nanos(&self) -> i64 { @@ -494,7 +494,7 @@ impl NaiveDateTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_subsec_millis(&self) -> u32 { @@ -516,7 +516,7 @@ impl NaiveDateTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_subsec_micros(&self) -> u32 { @@ -538,7 +538,7 @@ impl NaiveDateTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn timestamp_subsec_nanos(&self) -> u32 { @@ -578,7 +578,7 @@ impl NaiveDateTime { /// Ok(hmsm(3, 5, 8, 430)?)); /// /// assert!(NaiveDate::from_ymd(2016, 7, 8)?.and_hms(3, 5, 7)?.checked_add_signed(TimeDelta::days(1_000_000_000)).is_err()); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, @@ -603,7 +603,7 @@ impl NaiveDateTime { /// Ok(hmsm(3, 5, 50, 300)?)); /// assert_eq!(leap.checked_add_signed(TimeDelta::days(1)), /// Ok(from_ymd(2016, 7, 9)?.and_hms_milli(3, 5, 59, 300)?)); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_add_signed(self, rhs: TimeDelta) -> Result { let (time, rhs) = self.time.overflowing_add_signed(rhs); @@ -638,7 +638,7 @@ impl NaiveDateTime { /// .checked_add_months(Months::new(core::i32::MAX as u32 + 1)) /// .is_err() /// ); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_add_months(self, rhs: Months) -> Result { Ok(Self { date: self.date.checked_add_months(rhs)?, time: self.time }) @@ -676,7 +676,7 @@ impl NaiveDateTime { /// /// let dt = NaiveDate::from_ymd(2016, 7, 8)?.and_hms(3, 5, 7)?; /// assert!(dt.checked_sub_signed(TimeDelta::days(1_000_000_000)).is_err()); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that it is the @@ -697,7 +697,7 @@ impl NaiveDateTime { /// Ok(hmsm(3, 5, 0, 300)?)); /// assert_eq!(leap.checked_sub_signed(TimeDelta::days(1)), /// Ok(from_ymd(2016, 7, 7)?.and_hms_milli(3, 6, 0, 300)?)); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_sub_signed(self, rhs: TimeDelta) -> Result { let (time, rhs) = self.time.overflowing_sub_signed(rhs); @@ -731,7 +731,7 @@ impl NaiveDateTime { /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)) /// .is_err() /// ); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn checked_sub_months(self, rhs: Months) -> Result { Ok(Self { date: self.date.checked_sub_months(rhs)?, time: self.time }) @@ -775,7 +775,7 @@ impl NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that @@ -789,7 +789,7 @@ impl NaiveDateTime { /// TimeDelta::seconds(3600) + TimeDelta::milliseconds(500)); /// 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>(()) + /// # 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) @@ -811,7 +811,7 @@ impl NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -822,7 +822,7 @@ impl NaiveDateTime { /// # let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S").clone(); /// # 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -857,7 +857,7 @@ impl NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -867,7 +867,7 @@ impl NaiveDateTime { /// # 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -893,7 +893,7 @@ impl NaiveDateTime { /// use chrono::{NaiveDate, Utc}; /// let dt = NaiveDate::from_ymd(2015, 9, 5)?.and_hms(23, 56, 4)?.and_local_timezone(Utc)?; /// assert_eq!(dt.timezone(), Utc); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn and_local_timezone(&self, tz: Tz) -> Result, Error> { tz.from_local_datetime(self)?.single() @@ -953,7 +953,7 @@ impl Datelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.year(), 2015); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn year(&self) -> i32 { @@ -973,7 +973,7 @@ impl Datelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.month(), 9); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn month(&self) -> u32 { @@ -993,7 +993,7 @@ impl Datelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.month0(), 8); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn month0(&self) -> u32 { @@ -1013,7 +1013,7 @@ impl Datelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.day(), 25); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn day(&self) -> u32 { @@ -1033,7 +1033,7 @@ impl Datelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.day0(), 24); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn day0(&self) -> u32 { @@ -1053,7 +1053,7 @@ impl Datelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.ordinal(), 268); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn ordinal(&self) -> u32 { @@ -1073,7 +1073,7 @@ impl Datelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.ordinal0(), 267); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn ordinal0(&self) -> u32 { @@ -1091,7 +1091,7 @@ impl Datelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25)?.and_hms(12, 34, 56)?; /// assert_eq!(dt.weekday(), Weekday::Fri); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn weekday(&self) -> Weekday { @@ -1115,7 +1115,7 @@ impl Datelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_year(&self, year: i32) -> Result { @@ -1136,7 +1136,7 @@ impl Datelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_month(&self, month: u32) -> Result { @@ -1157,7 +1157,7 @@ impl Datelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_month0(&self, month0: u32) -> Result { @@ -1177,7 +1177,7 @@ impl Datelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_day(&self, day: u32) -> Result { @@ -1197,7 +1197,7 @@ impl Datelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_day0(&self, day0: u32) -> Result { @@ -1224,7 +1224,7 @@ impl Datelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_ordinal(&self, ordinal: u32) -> Result { @@ -1251,7 +1251,7 @@ impl Datelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_ordinal0(&self, ordinal0: u32) -> Result { @@ -1272,7 +1272,7 @@ impl Timelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.hour(), 12); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn hour(&self) -> u32 { @@ -1290,7 +1290,7 @@ impl Timelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.minute(), 34); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn minute(&self) -> u32 { @@ -1308,7 +1308,7 @@ impl Timelike for NaiveDateTime { /// /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8)?.and_hms_milli(12, 34, 56, 789)?; /// assert_eq!(dt.second(), 56); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn second(&self) -> u32 { @@ -1328,7 +1328,7 @@ impl Timelike for NaiveDateTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn nanosecond(&self) -> u32 { @@ -1350,7 +1350,7 @@ impl Timelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_hour(&self, hour: u32) -> Result { @@ -1374,7 +1374,7 @@ impl Timelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_minute(&self, min: u32) -> Result { @@ -1397,7 +1397,7 @@ impl Timelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_second(&self, sec: u32) -> Result { @@ -1422,7 +1422,7 @@ impl Timelike for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_nanosecond(&self, nano: u32) -> Result { @@ -1459,7 +1459,7 @@ impl Timelike for NaiveDateTime { /// /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, @@ -1478,7 +1478,7 @@ impl Timelike for NaiveDateTime { /// assert_eq!(leap + TimeDelta::seconds(-10), hmsm(3, 5, 50, 300)?); /// assert_eq!(leap + TimeDelta::days(1), /// from_ymd(2016, 7, 9)?.and_hms_milli(3, 5, 59, 300)?); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Add for NaiveDateTime { type Output = NaiveDateTime; @@ -1535,7 +1535,7 @@ impl Add for NaiveDateTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` fn add(self, rhs: Months) -> Self::Output { Self { date: self.date.checked_add_months(rhs).unwrap(), time: self.time } @@ -1573,7 +1573,7 @@ impl Add for NaiveDateTime { /// /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, @@ -1590,7 +1590,7 @@ impl Add for NaiveDateTime { /// assert_eq!(leap - TimeDelta::seconds(60), hmsm(3, 5, 0, 300)?); /// assert_eq!(leap - TimeDelta::days(1), /// from_ymd(2016, 7, 7)?.and_hms_milli(3, 6, 0, 300)?); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Sub for NaiveDateTime { type Output = NaiveDateTime; @@ -1632,7 +1632,7 @@ impl SubAssign for NaiveDateTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Sub for NaiveDateTime { type Output = NaiveDateTime; @@ -1665,7 +1665,7 @@ impl Sub for NaiveDateTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that no other leap @@ -1680,7 +1680,7 @@ impl Sub for NaiveDateTime { /// /// assert_eq!(NaiveDate::from_ymd(2015, 7, 1)?.and_hms(1, 0, 0)? - leap, /// TimeDelta::seconds(3600) - TimeDelta::milliseconds(500)); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Sub for NaiveDateTime { type Output = TimeDelta; @@ -1725,7 +1725,7 @@ impl Sub for NaiveDateTime { /// /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds may also be used. @@ -1734,7 +1734,7 @@ impl Sub for NaiveDateTime { /// # use chrono::NaiveDate; /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl fmt::Debug for NaiveDateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1760,7 +1760,7 @@ impl fmt::Debug for NaiveDateTime { /// /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds may also be used. @@ -1769,7 +1769,7 @@ impl fmt::Debug for NaiveDateTime { /// # use chrono::NaiveDate; /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl fmt::Display for NaiveDateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1794,7 +1794,7 @@ impl fmt::Display for NaiveDateTime { /// assert_eq!("+12345-6-7T7:59:60.5".parse::(), Ok(dt)); /// /// assert!("foo".parse::().is_err()); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl str::FromStr for NaiveDateTime { type Err = Error; @@ -1837,7 +1837,7 @@ impl str::FromStr for NaiveDateTime { /// /// let default_date = NaiveDateTime::default(); /// assert_eq!(default_date, NaiveDateTime::from_timestamp(0, 0)?); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Default for NaiveDateTime { fn default() -> Self { diff --git a/src/naive/datetime/serde.rs b/src/naive/datetime/serde.rs index a841f76c51..caf01947e2 100644 --- a/src/naive/datetime/serde.rs +++ b/src/naive/datetime/serde.rs @@ -75,7 +75,7 @@ impl<'de> de::Deserialize<'de> for NaiveDateTime { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); /// # Ok::<(), Box>(()) /// ``` @@ -194,7 +194,7 @@ pub mod ts_nanoseconds { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); /// # Ok::<(), Box>(()) /// ``` @@ -320,7 +320,7 @@ pub mod ts_nanoseconds_option { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); /// # Ok::<(), Box>(()) /// ``` @@ -439,7 +439,7 @@ pub mod ts_microseconds { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); /// # Ok::<(), Box>(()) /// ``` @@ -565,7 +565,7 @@ pub mod ts_microseconds_option { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); /// # Ok::<(), Box>(()) /// ``` @@ -684,7 +684,7 @@ pub mod ts_milliseconds { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); /// # Ok::<(), Box>(()) /// ``` @@ -810,7 +810,7 @@ pub mod ts_milliseconds_option { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1431684000}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); /// # Ok::<(), Box>(()) /// ``` @@ -924,7 +924,7 @@ pub mod ts_seconds { /// /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699}"#); -/// let my_s: S = serde_json::from_str(&as_string)?; +/// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); /// # Ok::<(), Box>(()) /// ``` diff --git a/src/naive/isoweek.rs b/src/naive/isoweek.rs index 9ed2e1ac7b..94eae1f8c0 100644 --- a/src/naive/isoweek.rs +++ b/src/naive/isoweek.rs @@ -60,7 +60,7 @@ impl IsoWeek { /// /// let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon)?; /// assert_eq!(d.iso_week().year(), 2015); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// This year number might not match the calendar year number. @@ -71,7 +71,7 @@ impl IsoWeek { /// # let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon)?; /// assert_eq!(d.year(), 2014); /// assert_eq!(d, NaiveDate::from_ymd(2014, 12, 29)?); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn year(&self) -> i32 { @@ -89,7 +89,7 @@ impl IsoWeek { /// /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon)?; /// assert_eq!(d.iso_week().week(), 15); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn week(&self) -> u32 { @@ -107,7 +107,7 @@ impl IsoWeek { /// /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon)?; /// assert_eq!(d.iso_week().week0(), 14); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn week0(&self) -> u32 { @@ -127,7 +127,7 @@ impl IsoWeek { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. @@ -136,7 +136,7 @@ impl IsoWeek { /// # use chrono::{NaiveDate, Datelike}; /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(0, 1, 2)?.iso_week()), "-0001-W52"); /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31)?.iso_week()), "+10000-W52"); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl fmt::Debug for IsoWeek { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 08afd0a10e..3e1eb62ef6 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -162,7 +162,7 @@ mod tests; /// /// let dt = NaiveDate::from_ymd(2015, 6, 30)?.and_hms_milli(23, 59, 59, 1_000)?.and_local_timezone(Utc)?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60Z"); -/// Ok::<(), chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// There are hypothetical leap seconds not on the minute boundary @@ -181,7 +181,7 @@ mod tests; /// let dt = Utc.with_ymd_and_hms(2015, 6, 30, 23, 56, 5)?.single()?; /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z"); /// assert_eq!(DateTime::::parse_from_rfc3339("2015-06-30T23:56:05Z")?, dt); -/// Ok::<(), chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Since Chrono alone cannot determine any existence of leap seconds, @@ -233,7 +233,7 @@ impl NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn from_hms(hour: u32, min: u32, sec: u32) -> Result { @@ -267,7 +267,7 @@ impl NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> Result { @@ -303,7 +303,7 @@ impl NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> Result { @@ -339,7 +339,7 @@ impl NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn from_hms_nano( @@ -382,7 +382,7 @@ impl NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub const fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> Result { @@ -407,7 +407,7 @@ impl NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Date and offset is ignored for the purpose of parsing. @@ -417,7 +417,7 @@ impl 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")?, /// NaiveTime::from_hms(12, 34, 56)?); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// [Leap seconds](#leap-second-handling) are correctly handled by @@ -429,7 +429,7 @@ impl NaiveTime { /// # let parse_from_str = NaiveTime::parse_from_str; /// assert_eq!(parse_from_str("08:59:60.123", "%H:%M:%S%.f")?, /// NaiveTime::from_hms_milli(8, 59, 59, 1_123)?); - /// # Ok::<_, Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Missing seconds are assumed to be zero, @@ -445,7 +445,7 @@ impl NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// All parsed fields should be consistent to each other, otherwise it's an error. @@ -481,7 +481,7 @@ impl NaiveTime { /// (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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn overflowing_add_signed(&self, mut rhs: TimeDelta) -> (NaiveTime, i64) { let mut secs = self.secs; @@ -564,7 +564,7 @@ impl NaiveTime { /// (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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] pub fn overflowing_sub_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) { @@ -606,7 +606,7 @@ impl NaiveTime { /// TimeDelta::seconds(-3600)); /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that @@ -626,7 +626,7 @@ impl NaiveTime { /// TimeDelta::seconds(1)); /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000)?, from_hmsm(2, 59, 59, 1_000)?), /// TimeDelta::seconds(61)); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn signed_duration_since(self, rhs: NaiveTime) -> TimeDelta { // | | :leap| | | | | | | :leap| | @@ -676,7 +676,7 @@ impl NaiveTime { /// 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"); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -687,7 +687,7 @@ impl NaiveTime { /// # let fmt = StrftimeItems::new("%H:%M:%S").clone(); /// # let t = NaiveTime::from_hms(23, 56, 4)?; /// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04"); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -723,7 +723,7 @@ impl NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -734,7 +734,7 @@ impl NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] @@ -765,7 +765,7 @@ impl Timelike for NaiveTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn hour(&self) -> u32 { @@ -781,7 +781,7 @@ impl Timelike for NaiveTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn minute(&self) -> u32 { @@ -797,7 +797,7 @@ impl Timelike for NaiveTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// This method never returns 60 even when it is a leap second. @@ -809,7 +809,7 @@ impl Timelike for NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn second(&self) -> u32 { @@ -827,7 +827,7 @@ impl Timelike for NaiveTime { /// /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds may have seemingly out-of-range return values. @@ -839,7 +839,7 @@ impl Timelike for NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn nanosecond(&self) -> u32 { @@ -858,7 +858,7 @@ impl Timelike for NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_hour(&self, hour: u32) -> Result { @@ -881,7 +881,7 @@ impl Timelike for NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_minute(&self, min: u32) -> Result { @@ -906,7 +906,7 @@ impl Timelike for NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_second(&self, sec: u32) -> Result { @@ -932,7 +932,7 @@ impl Timelike for NaiveTime { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds can theoretically follow *any* whole second. The following @@ -944,7 +944,7 @@ impl Timelike for NaiveTime { /// # use chrono::{NaiveTime, Timelike}; /// # let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?; /// assert_eq!(dt.with_nanosecond(1_333_333_333)?, NaiveTime::from_hms_nano(23, 56, 4, 1_333_333_333)?); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn with_nanosecond(&self, nano: u32) -> Result { @@ -964,7 +964,7 @@ impl Timelike for NaiveTime { /// assert_eq!(NaiveTime::from_hms(1, 2, 3)?.num_seconds_from_midnight(), 3723); /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678)?.num_seconds_from_midnight(), 86164); /// assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000)?.num_seconds_from_midnight(), 86399); - /// # Ok::<_, chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` #[inline] fn num_seconds_from_midnight(&self) -> u32 { @@ -995,7 +995,7 @@ impl Timelike for NaiveTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// The addition wraps around. @@ -1006,7 +1006,7 @@ impl Timelike for NaiveTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, but the addition assumes that it is the only leap second happened. @@ -1022,7 +1022,7 @@ impl Timelike for NaiveTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Add for NaiveTime { type Output = NaiveTime; @@ -1062,7 +1062,7 @@ impl AddAssign for NaiveTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// The subtraction wraps around. @@ -1072,7 +1072,7 @@ impl AddAssign for 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)?); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that it is the only leap second happened. @@ -1087,7 +1087,7 @@ impl AddAssign for NaiveTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Sub for NaiveTime { type Output = NaiveTime; @@ -1134,7 +1134,7 @@ impl SubAssign for NaiveTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds are handled, but the subtraction assumes that @@ -1150,7 +1150,7 @@ impl SubAssign for NaiveTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Sub for NaiveTime { type Output = TimeDelta; @@ -1181,7 +1181,7 @@ impl Sub for NaiveTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds may also be used. @@ -1189,7 +1189,7 @@ impl Sub for NaiveTime { /// ``` /// # use chrono::NaiveTime; /// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)?), "06:59:60.500"); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl fmt::Debug for NaiveTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1239,7 +1239,7 @@ impl fmt::Debug for NaiveTime { /// 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>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` /// /// Leap seconds may also be used. @@ -1247,7 +1247,7 @@ impl fmt::Debug for NaiveTime { /// ``` /// # use chrono::NaiveTime; /// assert_eq!(format!("{}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)?), "06:59:60.500"); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl fmt::Display for NaiveTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1273,7 +1273,7 @@ impl fmt::Display for NaiveTime { /// assert_eq!("23:59:60.23456789".parse::(), Ok(t)); /// /// assert!("foo".parse::().is_err()); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl str::FromStr for NaiveTime { type Err = Error; @@ -1303,7 +1303,7 @@ impl str::FromStr for NaiveTime { /// /// let default_time = NaiveTime::default(); /// assert_eq!(default_time, NaiveTime::from_hms(0, 0, 0)?); -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` impl Default for NaiveTime { fn default() -> Self { diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index 144a0f0d7f..d884d93b77 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -43,7 +43,7 @@ impl FixedOffset { /// let hour = 3600; /// let datetime = FixedOffset::east(5 * hour)?.with_ymd_and_hms(2016, 11, 08, 0, 0, 0)?.single()?; /// assert_eq!(datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00"); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub const fn east(secs: i32) -> Result { if -86_400 < secs && secs < 86_400 { @@ -64,7 +64,7 @@ impl FixedOffset { /// let hour = 3600; /// let datetime = FixedOffset::west(5 * hour)?.with_ymd_and_hms(2016, 11, 08, 0, 0, 0)?.single()?; /// assert_eq!(datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00"); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub const fn west(secs: i32) -> Result { if -86_400 < secs && secs < 86_400 { diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 0612b580e0..1f2fa8acbf 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -51,7 +51,7 @@ mod tz_info; /// /// let dt: DateTime = Local::now()?; /// let dt: DateTime = Local.timestamp(0, 0)?; -/// # Ok::<_, chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] diff --git a/src/offset/mod.rs b/src/offset/mod.rs index c8102b8f1d..07eafca2b5 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -255,7 +255,7 @@ pub trait TimeZone: Sized + Clone { /// use chrono::{Utc, TimeZone}; /// /// assert_eq!(Utc.timestamp_nanos(1431648000000000)?.timestamp(), 1431648); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` fn timestamp_nanos(&self, nanos: i64) -> Result, Error> { let (mut secs, mut nanos) = (nanos / 1_000_000_000, nanos % 1_000_000_000); diff --git a/src/offset/utc.rs b/src/offset/utc.rs index 3ed97fdbd4..a43f9411c1 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -40,7 +40,7 @@ use crate::{Error, LocalResult}; /// /// assert_eq!(dt, Utc.timestamp(61, 0)?); /// assert_eq!(dt, Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1)?.single()?); -/// Ok::<(), chrono::Error>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] diff --git a/src/round.rs b/src/round.rs index b877ac836d..ee1fc67bfe 100644 --- a/src/round.rs +++ b/src/round.rs @@ -28,7 +28,7 @@ pub trait SubsecRound { /// let dt = NaiveDate::from_ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?.and_local_timezone(Utc)?; /// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` fn round_subsecs(self, digits: u16) -> Self; @@ -41,7 +41,7 @@ pub trait SubsecRound { /// let dt = NaiveDate::from_ymd(2018, 1, 11)?.and_hms_milli(12, 0, 0, 154)?.and_local_timezone(Utc)?; /// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` fn trunc_subsecs(self, digits: u16) -> Self; } @@ -115,7 +115,7 @@ pub trait DurationRound: Sized { /// dt.duration_round(TimeDelta::days(1))?.to_string(), /// "2018-01-12 00:00:00 UTC" /// ); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` fn duration_round(self, duration: TimeDelta) -> Result; @@ -133,7 +133,7 @@ pub trait DurationRound: Sized { /// dt.duration_trunc(TimeDelta::days(1))?.to_string(), /// "2018-01-11 00:00:00 UTC" /// ); - /// Ok::<(), chrono::Error>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` fn duration_trunc(self, duration: TimeDelta) -> Result; } diff --git a/src/traits.rs b/src/traits.rs index f52e686d6c..69e8e197d2 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -99,7 +99,7 @@ pub trait Datelike: Sized { /// 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>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` fn num_days_from_ce(&self) -> i32 { // See test_num_days_from_ce_against_alternative_impl below for a more straightforward From b78a655433e0112f00cf3a240c4653ee7c5fb67b Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 20:34:16 +0200 Subject: [PATCH 40/54] From --- Cargo.toml | 2 +- src/error.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e4792d18b0..1a4f0c3bc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ __doctest = [] [dependencies] serde = { version = "1.0.99", default-features = false, optional = true } +serde_json = { version = "1" } pure-rust-locales = { version = "0.5.2", optional = true } criterion = { version = "0.4.0", optional = true } rkyv = {version = "0.7", optional = true} @@ -44,7 +45,6 @@ windows-sys = { version = "0.48.0", features = ["Win32_System_Time", "Win32_Foun iana-time-zone = { version = "0.1.45", optional = true, features = ["fallback"] } [dev-dependencies] -serde_json = { version = "1" } serde_derive = { version = "1", default-features = false } bincode = { version = "1.3.0" } num-iter = { version = "0.1.35", default-features = false } diff --git a/src/error.rs b/src/error.rs index 82fc145bdc..9b1cb23998 100644 --- a/src/error.rs +++ b/src/error.rs @@ -239,3 +239,11 @@ impl From for Error { Error::Utf8(error) } } + +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +impl From for Error { + fn from(_: serde_json::Error) -> Self { + Error::SerializationError + } +} From ca5276c502fe8954edc4f223f2e38dac104771ae Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 20:38:46 +0200 Subject: [PATCH 41/54] test returns --- src/format/mod.rs | 2 +- src/lib.rs | 4 ++-- src/naive/datetime/serde.rs | 48 ++++++++++++++++++------------------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/format/mod.rs b/src/format/mod.rs index 4d5bfa7282..223527899c 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -27,7 +27,7 @@ //! //! let parsed = Utc.datetime_from_str(&formatted, "%Y-%m-%d %H:%M:%S")?; //! assert_eq!(parsed, date_time); -//! # Ok::<_, Box>(()) +//! # Ok::<(), chrono::Error>(()) //! ``` #[cfg(feature = "alloc")] diff --git a/src/lib.rs b/src/lib.rs index 55587a8666..5bbf4ef31d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -289,7 +289,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>(()) +//! # Ok::<(), chrono::Error>(()) //! ``` //! //! Again : See [`format::strftime`](./format/strftime/index.html#specifiers) @@ -317,7 +317,7 @@ //! // Get epoch value from a datetime: //! let dt = DateTime::::parse_from_rfc2822("Fri, 14 Jul 2017 02:40:00 +0000")?; //! assert_eq!(dt.timestamp(), 1_500_000_000); -//! # Ok::<_, Box>(()) +//! # Ok::<(), chrono::Error>(()) //! ``` //! //! ### Individual date diff --git a/src/naive/datetime/serde.rs b/src/naive/datetime/serde.rs index caf01947e2..06ce3fe2df 100644 --- a/src/naive/datetime/serde.rs +++ b/src/naive/datetime/serde.rs @@ -77,7 +77,7 @@ impl<'de> de::Deserialize<'de> for NaiveDateTime { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<(), Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_nanoseconds { use core::fmt; @@ -106,7 +106,7 @@ pub mod ts_nanoseconds { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where @@ -132,7 +132,7 @@ pub mod ts_nanoseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result where @@ -196,7 +196,7 @@ pub mod ts_nanoseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<(), Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_nanoseconds_option { use core::fmt; @@ -226,7 +226,7 @@ pub mod ts_nanoseconds_option { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(opt: &Option, serializer: S) -> Result where @@ -255,7 +255,7 @@ pub mod ts_nanoseconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -322,7 +322,7 @@ pub mod ts_nanoseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<(), Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_microseconds { use core::fmt; @@ -351,7 +351,7 @@ pub mod ts_microseconds { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where @@ -377,7 +377,7 @@ pub mod ts_microseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result where @@ -441,7 +441,7 @@ pub mod ts_microseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<(), Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_microseconds_option { use core::fmt; @@ -471,7 +471,7 @@ pub mod ts_microseconds_option { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(opt: &Option, serializer: S) -> Result where @@ -500,7 +500,7 @@ pub mod ts_microseconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -567,7 +567,7 @@ pub mod ts_microseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<(), Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_milliseconds { use core::fmt; @@ -596,7 +596,7 @@ pub mod ts_milliseconds { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where @@ -622,7 +622,7 @@ pub mod ts_milliseconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result where @@ -686,7 +686,7 @@ pub mod ts_milliseconds { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<(), Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_milliseconds_option { use core::fmt; @@ -716,7 +716,7 @@ pub mod ts_milliseconds_option { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699918}"#); - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(opt: &Option, serializer: S) -> Result where @@ -745,7 +745,7 @@ pub mod ts_milliseconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -812,7 +812,7 @@ pub mod ts_milliseconds_option { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<(), Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_seconds { use core::fmt; @@ -841,7 +841,7 @@ pub mod ts_seconds { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1431684000}"#); - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where @@ -867,7 +867,7 @@ pub mod ts_seconds { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result where @@ -926,7 +926,7 @@ pub mod ts_seconds { /// assert_eq!(as_string, r#"{"time":1526522699}"#); /// let my_s: S = serde_json::from_str(&as_string).unwrap(); /// assert_eq!(my_s.time, time); -/// # Ok::<(), Box>(()) +/// # Ok::<(), chrono::Error>(()) /// ``` pub mod ts_seconds_option { use core::fmt; @@ -956,7 +956,7 @@ pub mod ts_seconds_option { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":1526522699}"#); - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn serialize(opt: &Option, serializer: S) -> Result where @@ -985,7 +985,7 @@ pub mod ts_seconds_option { /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; - /// # Ok::<(), Box>(()) + /// # Ok::<(), chrono::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where From b2f508f34858901bafd5c16e8d89e32ceee328c4 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 21:05:19 +0200 Subject: [PATCH 42/54] windows stuff --- ci/core-test/src/lib.rs | 2 +- src/date.rs | 11 ++++------- src/datetime/tests.rs | 8 +++----- src/offset/local/windows.rs | 7 +++---- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/ci/core-test/src/lib.rs b/ci/core-test/src/lib.rs index fc0405843e..63b60dc687 100644 --- a/ci/core-test/src/lib.rs +++ b/ci/core-test/src/lib.rs @@ -2,6 +2,6 @@ use chrono::{TimeZone, Utc}; -pub fn create_time() { +pub fn create_time() -> Result<(), chrono::Error> { let _ = Utc.with_ymd_and_hms(2019, 1, 1, 0, 0, 0)?.single()?; } diff --git a/src/date.rs b/src/date.rs index 8949298b6f..ba40d52227 100644 --- a/src/date.rs +++ b/src/date.rs @@ -27,17 +27,15 @@ use crate::{DateTime, Datelike, Error, Weekday}; /// You almost certainly want to be using a [`NaiveDate`] instead of this type. /// /// This type primarily exists to aid in the construction of DateTimes that -/// have a timezone by way of the [`TimeZone`] datelike constructors (e.g. -/// [`TimeZone::ymd`]). +/// have a timezone by way of the [`TimeZone`] datelike constructors. /// /// This type should be considered ambiguous at best, due to the inherent lack /// of precision required for the time zone resolution. /// /// There are some guarantees on the usage of `Date`: /// -/// - If properly constructed via [`TimeZone::ymd`] and others without an error, -/// the corresponding local date should exist for at least a moment. -/// (It may still have a gap from the offset changes.) +/// - If properly constructed without an error, the corresponding local date should +/// exist for at least a moment. (It may still have a gap from the offset changes.) /// /// - The `TimeZone` is free to assign *any* [`Offset`](crate::offset::Offset) to the /// local date, as long as that offset did occur in given day. @@ -47,8 +45,7 @@ use crate::{DateTime, Datelike, Error, Weekday}; /// but *not* `2015-03-08+00:00` and others. /// /// - Once constructed as a full `DateTime`, [`DateTime::date`] and other associated -/// methods should return those for the original `Date`. For example, if `dt = -/// tz.ymd_opt(y,m,d).unwrap().hms(h,n,s)` were valid, `dt.date() == tz.ymd_opt(y,m,d).unwrap()`. +/// methods should return those for the original `Date`. /// /// - The date is timezone-agnostic up to one day (i.e. practically always), /// so the local date and UTC date should be equal for most cases diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index e4061c2816..b2a1e24f9d 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1598,7 +1598,7 @@ fn test_from_system_time() -> Result<(), crate::Error> { #[test] #[cfg(target_os = "windows")] -fn test_from_system_time() { +fn test_from_system_time() -> Result<(), crate::Error> { use std::time::Duration; let nanos = 999_999_000; @@ -1624,8 +1624,7 @@ fn test_from_system_time() { SystemTime::from( Utc.from_local_datetime( &NaiveDate::from_ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() - ) - .unwrap() + )?.single()? ), UNIX_EPOCH + Duration::new(999_999_999, nanos) ); @@ -1633,8 +1632,7 @@ fn test_from_system_time() { SystemTime::from( Utc.from_local_datetime( &NaiveDate::from_ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1_000).unwrap() - ) - .unwrap() + )?.single()? ), UNIX_EPOCH - Duration::new(999_999_999, nanos) ); diff --git a/src/offset/local/windows.rs b/src/offset/local/windows.rs index d238144f18..728a27879d 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -11,7 +11,6 @@ use std::io; use std::mem; use std::ptr; -use std::ptr; use std::time::{SystemTime, UNIX_EPOCH}; use windows_sys::Win32::Foundation::FILETIME; @@ -23,7 +22,7 @@ use windows_sys::Win32::System::Time::SystemTimeToTzSpecificLocalTime; use windows_sys::Win32::System::Time::TzSpecificLocalTimeToSystemTime; use super::{FixedOffset, Local}; -use crate::error::{Error, ErrorKind}; +use crate::Error; use crate::offset::LocalResult; use crate::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; @@ -103,7 +102,7 @@ impl Timespec { fn now() -> Result { let st = SystemTime::now() .duration_since(UNIX_EPOCH) - .map_err(|_| ErrorKind::SystemTimeBeforeEpoch)?; + .map_err(|_| Error::SystemTimeBeforeEpoch)?; Ok(Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 }) } @@ -240,7 +239,7 @@ fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { macro_rules! call { ($name:ident($($arg:expr),*)) => { if $name($($arg),*) == 0 { - return Err(Error::new(ErrorKind::SystemError(io::Error::last_os_error()))) + return Err(io::Error::last_os_error()) } } } From 573535ddcb3fc05a522fff1e7acaf9c65d398c33 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 21:05:43 +0200 Subject: [PATCH 43/54] cargo fmt --- src/datetime/tests.rs | 6 ++++-- src/offset/local/windows.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index b2a1e24f9d..c5d6ea6e6e 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1624,7 +1624,8 @@ fn test_from_system_time() -> Result<(), crate::Error> { SystemTime::from( Utc.from_local_datetime( &NaiveDate::from_ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() - )?.single()? + )? + .single()? ), UNIX_EPOCH + Duration::new(999_999_999, nanos) ); @@ -1632,7 +1633,8 @@ fn test_from_system_time() -> Result<(), crate::Error> { SystemTime::from( Utc.from_local_datetime( &NaiveDate::from_ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1_000).unwrap() - )?.single()? + )? + .single()? ), UNIX_EPOCH - Duration::new(999_999_999, nanos) ); diff --git a/src/offset/local/windows.rs b/src/offset/local/windows.rs index 728a27879d..9e444f9a0b 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -22,8 +22,8 @@ use windows_sys::Win32::System::Time::SystemTimeToTzSpecificLocalTime; use windows_sys::Win32::System::Time::TzSpecificLocalTimeToSystemTime; use super::{FixedOffset, Local}; -use crate::Error; use crate::offset::LocalResult; +use crate::Error; use crate::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; pub(super) fn now() -> Result, Error> { From 4fb569660246382bcfae053afa654c562319593c Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 21:17:49 +0200 Subject: [PATCH 44/54] more windows --- ci/core-test/src/lib.rs | 1 + src/datetime/tests.rs | 14 +++++++------- src/offset/local/windows.rs | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ci/core-test/src/lib.rs b/ci/core-test/src/lib.rs index 63b60dc687..a4d4bdb549 100644 --- a/ci/core-test/src/lib.rs +++ b/ci/core-test/src/lib.rs @@ -4,4 +4,5 @@ use chrono::{TimeZone, Utc}; pub fn create_time() -> Result<(), chrono::Error> { let _ = Utc.with_ymd_and_hms(2019, 1, 1, 0, 0, 0)?.single()?; + Ok(()) } diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index c5d6ea6e6e..aae9a9d885 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1609,13 +1609,13 @@ fn test_from_system_time() -> Result<(), crate::Error> { 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(2001, 9, 9)?.and_hms_nano(1, 46, 39, nanos)?)? + Utc.from_local_datetime(&NaiveDate::from_ymd(2001, 9, 9)?.and_hms_nano(1, 46, 39, nanos)?)?.single()? ); assert_eq!( DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), Utc.from_local_datetime( &NaiveDate::from_ymd(1938, 4, 24)?.and_hms_nano(22, 13, 20, 1_000)? - )? + )?.single()? ); // DateTime -> SystemTime @@ -1623,7 +1623,7 @@ fn test_from_system_time() -> Result<(), crate::Error> { assert_eq!( SystemTime::from( Utc.from_local_datetime( - &NaiveDate::from_ymd(2001, 9, 9).unwrap().and_hms_nano(1, 46, 39, nanos).unwrap() + &NaiveDate::from_ymd(2001, 9, 9)?.and_hms_nano(1, 46, 39, nanos)? )? .single()? ), @@ -1632,7 +1632,7 @@ fn test_from_system_time() -> Result<(), crate::Error> { assert_eq!( SystemTime::from( Utc.from_local_datetime( - &NaiveDate::from_ymd(1938, 4, 24).unwrap().and_hms_nano(22, 13, 20, 1_000).unwrap() + &NaiveDate::from_ymd(1938, 4, 24)?.and_hms_nano(22, 13, 20, 1_000)? )? .single()? ), @@ -1642,14 +1642,14 @@ fn test_from_system_time() -> Result<(), crate::Error> { // 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)?), UNIX_EPOCH); } assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400).unwrap())), + SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400)?)), UNIX_EPOCH ); assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800).unwrap())), + SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800)?)), UNIX_EPOCH ); Ok(()) diff --git a/src/offset/local/windows.rs b/src/offset/local/windows.rs index 9e444f9a0b..9bf0f16b3c 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -22,8 +22,8 @@ use windows_sys::Win32::System::Time::SystemTimeToTzSpecificLocalTime; use windows_sys::Win32::System::Time::TzSpecificLocalTimeToSystemTime; use super::{FixedOffset, Local}; -use crate::offset::LocalResult; use crate::Error; +use crate::offset::LocalResult; use crate::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; pub(super) fn now() -> Result, Error> { @@ -239,7 +239,7 @@ fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { macro_rules! call { ($name:ident($($arg:expr),*)) => { if $name($($arg),*) == 0 { - return Err(io::Error::last_os_error()) + return Err(error::Error::SystemError(io::Error::last_os_error())) } } } From 7386f59acd09007ca6b77cb769f00d583fd5c1a6 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 21:19:08 +0200 Subject: [PATCH 45/54] cargo fmt --- src/datetime/tests.rs | 16 ++++++---------- src/offset/local/windows.rs | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index aae9a9d885..db9e8c73f8 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1609,13 +1609,15 @@ fn test_from_system_time() -> Result<(), crate::Error> { 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(2001, 9, 9)?.and_hms_nano(1, 46, 39, nanos)?)?.single()? + Utc.from_local_datetime(&NaiveDate::from_ymd(2001, 9, 9)?.and_hms_nano(1, 46, 39, nanos)?)? + .single()? ); assert_eq!( DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)), Utc.from_local_datetime( &NaiveDate::from_ymd(1938, 4, 24)?.and_hms_nano(22, 13, 20, 1_000)? - )?.single()? + )? + .single()? ); // DateTime -> SystemTime @@ -1644,14 +1646,8 @@ fn test_from_system_time() -> Result<(), crate::Error> { { assert_eq!(SystemTime::from(epoch.with_timezone(&Local)?), UNIX_EPOCH); } - assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400)?)), - UNIX_EPOCH - ); - assert_eq!( - SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800)?)), - UNIX_EPOCH - ); + assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400)?)), UNIX_EPOCH); + assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800)?)), UNIX_EPOCH); Ok(()) } diff --git a/src/offset/local/windows.rs b/src/offset/local/windows.rs index 9bf0f16b3c..563feab0ce 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -22,8 +22,8 @@ use windows_sys::Win32::System::Time::SystemTimeToTzSpecificLocalTime; use windows_sys::Win32::System::Time::TzSpecificLocalTimeToSystemTime; use super::{FixedOffset, Local}; -use crate::Error; use crate::offset::LocalResult; +use crate::Error; use crate::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; pub(super) fn now() -> Result, Error> { From d41abc1b0b018878bc69c8c3ad1489f3a295aedb Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Fri, 7 Apr 2023 21:25:45 +0200 Subject: [PATCH 46/54] more windows --- src/datetime/tests.rs | 6 +++--- src/error.rs | 2 +- src/naive/date.rs | 2 +- src/naive/datetime/tests.rs | 2 +- src/naive/time/tests.rs | 2 +- src/offset/local/windows.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index db9e8c73f8..079bc10dfa 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -790,7 +790,7 @@ fn test_parse_datetime_utc() { } // some invalid cases - // since `ParseErrorKind` is private, all we can do is to check if there was an error + // TODO: check the error type let invalid = [ "", // empty "Z", // missing data @@ -1646,8 +1646,8 @@ fn test_from_system_time() -> Result<(), crate::Error> { { assert_eq!(SystemTime::from(epoch.with_timezone(&Local)?), UNIX_EPOCH); } - assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400)?)), UNIX_EPOCH); - assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800)?)), UNIX_EPOCH); + assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400)?)?), UNIX_EPOCH); + assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800)?)?), UNIX_EPOCH); Ok(()) } diff --git a/src/error.rs b/src/error.rs index 9b1cb23998..ec063e82b4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -194,7 +194,7 @@ 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), + Error::SystemError(error) => Some(error), _ => None, } } diff --git a/src/naive/date.rs b/src/naive/date.rs index d9441dc30a..f3fca1d404 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -2775,7 +2775,7 @@ mod tests { } // some invalid cases - // since `ParseErrorKind` is private, all we can do is to check if there was an error + // TODO: check the error type let invalid = [ "", // empty "x", // invalid diff --git a/src/naive/datetime/tests.rs b/src/naive/datetime/tests.rs index e30c426da1..b0cff55e11 100644 --- a/src/naive/datetime/tests.rs +++ b/src/naive/datetime/tests.rs @@ -234,7 +234,7 @@ fn test_datetime_from_str() { } // some invalid cases - // since `ParseErrorKind` is private, all we can do is to check if there was an error + // TODO: check the error type let invalid = [ "", // empty "x", // invalid / missing data diff --git a/src/naive/time/tests.rs b/src/naive/time/tests.rs index 8d13ae23ec..c7dc0b8228 100644 --- a/src/naive/time/tests.rs +++ b/src/naive/time/tests.rs @@ -277,7 +277,7 @@ fn test_date_from_str() { } // some invalid cases - // since `ParseErrorKind` is private, all we can do is to check if there was an error + // TODO: check the error type let invalid = [ "", // empty "x", // invalid diff --git a/src/offset/local/windows.rs b/src/offset/local/windows.rs index 563feab0ce..3948cec20b 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -239,7 +239,7 @@ fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { macro_rules! call { ($name:ident($($arg:expr),*)) => { if $name($($arg),*) == 0 { - return Err(error::Error::SystemError(io::Error::last_os_error())) + return Err(Error::SystemError(io::Error::last_os_error())) } } } From 64bbb781b3936efe5e8b252540e730af7863af34 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sun, 9 Apr 2023 10:42:36 +0200 Subject: [PATCH 47/54] Removed SystemError --- src/error.rs | 17 ++-------------- src/offset/local/mod.rs | 44 ++++++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/error.rs b/src/error.rs index ec063e82b4..54179ceb86 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,8 +23,6 @@ pub enum Error { MissingDate, #[cfg(all(windows, feature = "clock"))] SystemTimeBeforeEpoch, - #[cfg(all(windows, feature = "clock"))] - SystemError(std::io::Error), /// Given field is out of permitted range. ParsingOutOfRange, @@ -139,10 +137,10 @@ impl fmt::Display for Error { 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"), @@ -189,17 +187,6 @@ impl fmt::Display for Error { } } -#[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"))] - Error::SystemError(error) => Some(error), - _ => None, - } - } -} - #[cfg(feature = "std")] impl From for Error { fn from(_: std::string::FromUtf8Error) -> Self { diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 1f2fa8acbf..9bd50c76de 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -238,7 +238,7 @@ mod tests { return Ok(()); } - let mut date = NaiveDate::from_ymd(1975, 1, 1).unwrap().and_hms(0, 0, 0).unwrap(); + let mut date = NaiveDate::from_ymd(1975, 1, 1)?.and_midnight(); while date.year() < 2078 { if (1975..=1977).contains(&date.year()) @@ -254,37 +254,38 @@ mod tests { } #[test] - fn verify_correct_offsets() { - 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(); + fn verify_correct_offsets() -> Result<(), Error> { + let now = Local::now()?; + let from_local = Local.from_local_datetime(&now.naive_local())?.single()?; + let from_utc = Local.from_utc_datetime(&now.naive_utc())?; 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()); assert_eq!(now, from_local); assert_eq!(now, from_utc); + Ok(()) } #[test] - fn verify_correct_offsets_distant_past() { - // let distant_past = Local::now() - Duration::days(365 * 100); - 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(); + fn verify_correct_offsets_distant_past() -> Result<(), Error> { + let distant_past = Local::now()? - TimeDelta::days(250 * 31); + let from_local = Local.from_local_datetime(&distant_past.naive_local())?.single()?; + let from_utc = Local.from_utc_datetime(&distant_past.naive_utc())?; 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()); assert_eq!(distant_past, from_local); assert_eq!(distant_past, from_utc); + Ok(()) } #[test] - fn verify_correct_offsets_distant_future() { - 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(); + fn verify_correct_offsets_distant_future() -> Result<(), Error> { + let distant_future = Local::now()? + TimeDelta::days(250 * 31); + let from_local = Local.from_local_datetime(&distant_future.naive_local())?.single()?; + let from_utc = Local.from_utc_datetime(&distant_future.naive_utc())?; assert_eq!( distant_future.offset().local_minus_utc(), @@ -294,34 +295,37 @@ mod tests { assert_eq!(distant_future, from_local); assert_eq!(distant_future, from_utc); + Ok(()) } #[test] - fn test_local_date_sanity_check() { + fn test_local_date_sanity_check() -> Result<(), Error> { // issue #27 assert_eq!( - Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0).unwrap().single().unwrap().day(), + Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0)?.single()?.day(), 28 ); + Ok(()) } #[test] - fn test_leap_second() { + fn test_leap_second() -> Result<(), Error> { // issue #123 - let today = Local::today().unwrap(); + let today = Local::today()?; - let dt = today.and_hms_milli(1, 2, 59, 1000).unwrap(); + let dt = today.and_hms_milli(1, 2, 59, 1000)?; let timestr = dt.time().to_string(); // the OS API may or may not support the leap second, // but there are only two sensible options. assert!(timestr == "01:02:60" || timestr == "01:03:00", "unexpected timestr {:?}", timestr); - let dt = today.and_hms_milli(1, 2, 3, 1234).unwrap(); + let dt = today.and_hms_milli(1, 2, 3, 1234)?; let timestr = dt.time().to_string(); assert!( timestr == "01:02:03.234" || timestr == "01:02:04.234", "unexpected timestr {:?}", timestr ); + Ok(()) } } From 79f21ca2d9f9e576d17879c4c56b6f3d1b31a1b7 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sun, 9 Apr 2023 10:43:15 +0200 Subject: [PATCH 48/54] cargo fmt... --- src/offset/local/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 9bd50c76de..5cdd29c3ab 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -301,10 +301,7 @@ mod tests { #[test] fn test_local_date_sanity_check() -> Result<(), Error> { // issue #27 - assert_eq!( - Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0)?.single()?.day(), - 28 - ); + assert_eq!(Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0)?.single()?.day(), 28); Ok(()) } From a46d79afcda104b99346032125ed1e7af2ab211c Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sun, 9 Apr 2023 10:47:42 +0200 Subject: [PATCH 49/54] IO direct --- src/offset/local/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/offset/local/windows.rs b/src/offset/local/windows.rs index 3948cec20b..9e444f9a0b 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -239,7 +239,7 @@ fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { macro_rules! call { ($name:ident($($arg:expr),*)) => { if $name($($arg),*) == 0 { - return Err(Error::SystemError(io::Error::last_os_error())) + return Err(io::Error::last_os_error()) } } } From ce5c11a0719e6ea5fbbdf21abf2bf70eb29befa1 Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sun, 9 Apr 2023 11:11:29 +0200 Subject: [PATCH 50/54] io error test --- src/error.rs | 12 ++++++++++++ src/offset/local/windows.rs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 54179ceb86..1a8709c53e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -234,3 +234,15 @@ impl From for Error { Error::SerializationError } } + +#[test] +#[cfg(feature = "std")] +fn test_io() -> Result<(), Error> { + + fn fail() -> Result<(), Error> { + Err(std::io::Error::last_os_error().into()) + } + + assert!(fail().is_err()); + Ok(()) +} diff --git a/src/offset/local/windows.rs b/src/offset/local/windows.rs index 9e444f9a0b..fcf7547125 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -239,7 +239,7 @@ fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { macro_rules! call { ($name:ident($($arg:expr),*)) => { if $name($($arg),*) == 0 { - return Err(io::Error::last_os_error()) + return Err(io::Error::last_os_error().into()) } } } From c7aa4635afdc263063afacefd0230cb6f413a17e Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sun, 9 Apr 2023 11:13:06 +0200 Subject: [PATCH 51/54] cargo fmt --- src/error.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index 1a8709c53e..f75a564253 100644 --- a/src/error.rs +++ b/src/error.rs @@ -238,11 +238,10 @@ impl From for Error { #[test] #[cfg(feature = "std")] fn test_io() -> Result<(), Error> { - fn fail() -> Result<(), Error> { Err(std::io::Error::last_os_error().into()) } - + assert!(fail().is_err()); Ok(()) } From 0e341c0c1895f642cd97411977d99c503c63a67c Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sun, 9 Apr 2023 11:29:50 +0200 Subject: [PATCH 52/54] serde_json only as test --- Cargo.toml | 2 +- src/error.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1a4f0c3bc8..e4792d18b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,6 @@ __doctest = [] [dependencies] serde = { version = "1.0.99", default-features = false, optional = true } -serde_json = { version = "1" } pure-rust-locales = { version = "0.5.2", optional = true } criterion = { version = "0.4.0", optional = true } rkyv = {version = "0.7", optional = true} @@ -45,6 +44,7 @@ windows-sys = { version = "0.48.0", features = ["Win32_System_Time", "Win32_Foun iana-time-zone = { version = "0.1.45", optional = true, features = ["fallback"] } [dev-dependencies] +serde_json = { version = "1" } serde_derive = { version = "1", default-features = false } bincode = { version = "1.3.0" } num-iter = { version = "0.1.35", default-features = false } diff --git a/src/error.rs b/src/error.rs index f75a564253..c2181785bb 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,17 +10,24 @@ use std::time::SystemTimeError; 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, + + /// Time before the the given epoch #[cfg(all(windows, feature = "clock"))] SystemTimeBeforeEpoch, @@ -227,6 +234,7 @@ impl From for Error { } } +#[cfg(test)] #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl From for Error { From 9e317ff4dc0384b50a3d0b43c8e866ca74d4719e Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sun, 9 Apr 2023 12:54:49 +0200 Subject: [PATCH 53/54] serde_json non-dev --- Cargo.toml | 2 +- src/error.rs | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e4792d18b0..af0eeb3739 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ __doctest = [] [dependencies] serde = { version = "1.0.99", default-features = false, optional = true } +serde_json = { version = "1", optional = true} pure-rust-locales = { version = "0.5.2", optional = true } criterion = { version = "0.4.0", optional = true } rkyv = {version = "0.7", optional = true} @@ -44,7 +45,6 @@ windows-sys = { version = "0.48.0", features = ["Win32_System_Time", "Win32_Foun iana-time-zone = { version = "0.1.45", optional = true, features = ["fallback"] } [dev-dependencies] -serde_json = { version = "1" } serde_derive = { version = "1", default-features = false } bincode = { version = "1.3.0" } num-iter = { version = "0.1.35", default-features = false } diff --git a/src/error.rs b/src/error.rs index c2181785bb..e2f9ff3e77 100644 --- a/src/error.rs +++ b/src/error.rs @@ -234,9 +234,7 @@ impl From for Error { } } -#[cfg(test)] #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl From for Error { fn from(_: serde_json::Error) -> Self { Error::SerializationError @@ -245,7 +243,7 @@ impl From for Error { #[test] #[cfg(feature = "std")] -fn test_io() -> Result<(), Error> { +fn test_error_io() -> Result<(), Error> { fn fail() -> Result<(), Error> { Err(std::io::Error::last_os_error().into()) } @@ -253,3 +251,14 @@ fn test_io() -> Result<(), Error> { assert!(fail().is_err()); Ok(()) } + +#[test] +#[cfg(feature = "serde")] +fn test_error_serde() -> Result<(), Error> { + fn fail() -> Result<(), Error> { + Err(serde_json::Error::from(serde::ser::Error::custom("serde error test")).into()) + } + + assert!(fail().is_err()); + Ok(()) +} From 74c975fa121e3f25f7f726e780bef0abcff6240b Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Sun, 9 Apr 2023 13:03:50 +0200 Subject: [PATCH 54/54] serde_json dependencies I know it's bad to have serde_json as package dependency, but I found no way around it. Many serde tests depend on serde_json and can throw an error. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index af0eeb3739..4fda1450e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ default = ["clock", "std", "wasmbind"] alloc = [] libc = [] std = [] +serde = ["dep:serde", "dep:serde_json"] clock = ["std", "windows-sys", "iana-time-zone"] wasmbind = ["wasm-bindgen", "js-sys"] unstable-locales = ["pure-rust-locales", "alloc"]