diff options
Diffstat (limited to 'vendor/chrono/src/naive/date.rs')
-rw-r--r-- | vendor/chrono/src/naive/date.rs | 281 |
1 files changed, 199 insertions, 82 deletions
diff --git a/vendor/chrono/src/naive/date.rs b/vendor/chrono/src/naive/date.rs index 64af978f3..b9404a15f 100644 --- a/vendor/chrono/src/naive/date.rs +++ b/vendor/chrono/src/naive/date.rs @@ -5,12 +5,9 @@ #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; -use core::convert::TryFrom; use core::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign}; use core::{fmt, str}; -use num_integer::div_mod_floor; -use num_traits::ToPrimitive; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; @@ -20,8 +17,10 @@ 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::{Item, Numeric, Pad}; +use crate::format::{ + parse, parse_and_remainder, write_hundreds, Item, Numeric, Pad, ParseError, ParseResult, + Parsed, StrftimeItems, +}; use crate::month::Months; use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime}; use crate::oldtime::Duration as OldDuration; @@ -77,11 +76,15 @@ impl NaiveWeek { /// assert!(week.first_day() <= date); /// ``` #[inline] + #[must_use] pub fn first_day(&self) -> NaiveDate { - let start = self.start.num_days_from_monday(); - let end = self.date.weekday().num_days_from_monday(); - let days = if start > end { 7 - start + end } else { end - start }; - self.date - Duration::days(days.into()) + let start = self.start.num_days_from_monday() as i32; + let ref_day = self.date.weekday().num_days_from_monday() as i32; + // Calculate the number of days to subtract from `self.date`. + // Do not construct an intermediate date beyond `self.date`, because that may be out of + // range if `date` is close to `NaiveDate::MAX`. + let days = start - ref_day - if start > ref_day { 7 } else { 0 }; + self.date.diff_days(days as i64).unwrap() } /// Returns a date representing the last day of the week. @@ -96,8 +99,15 @@ impl NaiveWeek { /// assert!(week.last_day() >= date); /// ``` #[inline] + #[must_use] pub fn last_day(&self) -> NaiveDate { - self.first_day() + Duration::days(6) + let end = self.start.pred().num_days_from_monday() as i32; + let ref_day = self.date.weekday().num_days_from_monday() as i32; + // Calculate the number of days to add to `self.date`. + // Do not construct an intermediate date before `self.date` (like with `first_day()`), + // because that may be out of range if `date` is close to `NaiveDate::MIN`. + let days = end - ref_day + if end < ref_day { 7 } else { 0 }; + self.date.diff_days(days as i64).unwrap() } /// Returns a [`RangeInclusive<T>`] representing the whole week bounded by @@ -115,6 +125,7 @@ impl NaiveWeek { /// assert!(days.contains(&date)); /// ``` #[inline] + #[must_use] pub fn days(&self) -> RangeInclusive<NaiveDate> { self.first_day()..=self.last_day() } @@ -137,8 +148,7 @@ impl Days { } /// ISO 8601 calendar date without timezone. -/// Allows for every [proleptic Gregorian date](#calendar-date) -/// from Jan 1, 262145 BCE to Dec 31, 262143 CE. +/// Allows for every [proleptic Gregorian date] from Jan 1, 262145 BCE to Dec 31, 262143 CE. /// Also supports the conversion from ISO 8601 ordinal and week date. /// /// # Calendar Date @@ -184,6 +194,8 @@ impl Days { /// The year number is the same as that of the [calendar date](#calendar-date). /// /// This is currently the internal format of Chrono's date types. +/// +/// [proleptic Gregorian date]: crate::NaiveDate#calendar-date #[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] pub struct NaiveDate { @@ -239,19 +251,35 @@ 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<NaiveDate> { - if (MIN_YEAR..=MAX_YEAR).contains(&year) && of.valid() { - let Of(of) = of; - Some(NaiveDate { ymdf: (year << 13) | (of as DateImpl) }) - } else { - None + + /// Makes a new `NaiveDate` from year, ordinal and flags. + /// Does not check whether the flags are correct for the provided year. + const fn from_ordinal_and_flags( + year: i32, + ordinal: u32, + flags: YearFlags, + ) -> Option<NaiveDate> { + if year < MIN_YEAR || year > MAX_YEAR { + return None; // Out-of-range + } + // Enable debug check once the MSRV >= 1.57 (panicking in const feature) + // debug_assert!(YearFlags::from_year(year).0 == flags.0); + match Of::new(ordinal, flags) { + Some(of) => Some(NaiveDate { ymdf: (year << 13) | (of.inner() as DateImpl) }), + None => None, // Invalid: Ordinal outside of the nr of days in a year with those flags. } } - /// Makes a new `NaiveDate` from year and packed month-day-flags, with a verification. - fn from_mdf(year: i32, mdf: Mdf) -> Option<NaiveDate> { - NaiveDate::from_of(year, mdf.to_of()) + /// Makes a new `NaiveDate` from year and packed month-day-flags. + /// Does not check whether the flags are correct for the provided year. + const fn from_mdf(year: i32, mdf: Mdf) -> Option<NaiveDate> { + if year < MIN_YEAR || year > MAX_YEAR { + return None; // Out-of-range + } + match mdf.to_of() { + Some(of) => Some(NaiveDate { ymdf: (year << 13) | (of.inner() as DateImpl) }), + None => None, // Non-existing date + } } /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) @@ -259,6 +287,7 @@ impl NaiveDate { /// /// Panics on the out-of-range date, invalid month and/or day. #[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")] + #[must_use] 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") } @@ -282,6 +311,7 @@ impl NaiveDate { /// assert!(from_ymd_opt(400000, 1, 1).is_none()); /// assert!(from_ymd_opt(-400000, 1, 1).is_none()); /// ``` + #[must_use] pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> { let flags = YearFlags::from_year(year); NaiveDate::from_mdf(year, Mdf::new(month, day, flags)?) @@ -292,6 +322,7 @@ impl NaiveDate { /// /// Panics on the out-of-range date and/or invalid day of year. #[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")] + #[must_use] pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate { NaiveDate::from_yo_opt(year, ordinal).expect("invalid or out-of-range date") } @@ -316,9 +347,10 @@ impl NaiveDate { /// assert!(from_yo_opt(400000, 1).is_none()); /// assert!(from_yo_opt(-400000, 1).is_none()); /// ``` + #[must_use] pub fn from_yo_opt(year: i32, ordinal: u32) -> Option<NaiveDate> { let flags = YearFlags::from_year(year); - NaiveDate::from_of(year, Of::new(ordinal, flags)?) + NaiveDate::from_ordinal_and_flags(year, ordinal, flags) } /// Makes a new `NaiveDate` from the [ISO week date](#week-date) @@ -327,6 +359,7 @@ impl NaiveDate { /// /// Panics on the out-of-range date and/or invalid week number. #[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")] + #[must_use] 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") } @@ -342,7 +375,7 @@ impl NaiveDate { /// ``` /// use chrono::{NaiveDate, Weekday}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// let from_isoywd_opt = NaiveDate::from_isoywd_opt; /// /// assert_eq!(from_isoywd_opt(2015, 0, Weekday::Sun), None); @@ -358,7 +391,7 @@ impl NaiveDate { /// /// ``` /// # use chrono::{NaiveDate, Weekday}; - /// # let from_ymd = NaiveDate::from_ymd; + /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let from_isoywd_opt = NaiveDate::from_isoywd_opt; /// // Mo Tu We Th Fr Sa Su /// // 2014-W52 22 23 24 25 26 27 28 has 4+ days of new year, @@ -375,6 +408,7 @@ impl NaiveDate { /// 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))); /// ``` + #[must_use] pub fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option<NaiveDate> { let flags = YearFlags::from_year(year); let nweeks = flags.nisoweeks(); @@ -385,20 +419,21 @@ impl NaiveDate { if weekord <= delta { // ordinal < 1, previous year let prevflags = YearFlags::from_year(year - 1); - NaiveDate::from_of( + NaiveDate::from_ordinal_and_flags( year - 1, - Of::new(weekord + prevflags.ndays() - delta, prevflags)?, + weekord + prevflags.ndays() - delta, + prevflags, ) } else { let ordinal = weekord - delta; let ndays = flags.ndays(); if ordinal <= ndays { // this year - NaiveDate::from_of(year, Of::new(ordinal, flags)?) + NaiveDate::from_ordinal_and_flags(year, ordinal, flags) } else { // ordinal > ndays, next year let nextflags = YearFlags::from_year(year + 1); - NaiveDate::from_of(year + 1, Of::new(ordinal - ndays, nextflags)?) + NaiveDate::from_ordinal_and_flags(year + 1, ordinal - ndays, nextflags) } } } else { @@ -412,6 +447,7 @@ impl NaiveDate { /// Panics if the date is out of range. #[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")] #[inline] + #[must_use] pub fn from_num_days_from_ce(days: i32) -> NaiveDate { NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date") } @@ -436,12 +472,13 @@ impl NaiveDate { /// assert_eq!(from_ndays_opt(100_000_000), None); /// assert_eq!(from_ndays_opt(-100_000_000), None); /// ``` + #[must_use] pub fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> { - let days = days + 365; // make December 31, 1 BCE equal to day 0 + let days = days.checked_add(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); 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)?) + NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags) } /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week @@ -455,6 +492,7 @@ impl NaiveDate { /// /// `n` is 1-indexed. Passing `n=0` will cause a panic. #[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")] + #[must_use] 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") } @@ -471,6 +509,7 @@ impl NaiveDate { /// /// 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`. + #[must_use] pub fn from_weekday_of_month_opt( year: i32, month: u32, @@ -534,6 +573,28 @@ impl NaiveDate { parsed.to_naive_date() } + /// Parses a string from a user-specified format into a new `NaiveDate` value, and a slice with + /// the remaining portion of the string. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// Similar to [`parse_from_str`](#method.parse_from_str). + /// + /// # Example + /// + /// ```rust + /// # use chrono::{NaiveDate}; + /// let (date, remainder) = NaiveDate::parse_and_remainder( + /// "2015-02-18 trailing text", "%Y-%m-%d").unwrap(); + /// assert_eq!(date, NaiveDate::from_ymd_opt(2015, 2, 18).unwrap()); + /// assert_eq!(remainder, " trailing text"); + /// ``` + pub fn parse_and_remainder<'a>(s: &'a str, fmt: &str) -> ParseResult<(NaiveDate, &'a str)> { + let mut parsed = Parsed::new(); + let remainder = parse_and_remainder(&mut parsed, s, StrftimeItems::new(fmt))?; + parsed.to_naive_date().map(|d| (d, remainder)) + } + /// Add a duration in [`Months`] to the date /// /// If the day would be out of range for the resulting month, use the last day for that month. @@ -551,6 +612,7 @@ impl NaiveDate { /// Some(NaiveDate::from_ymd_opt(2022, 9, 30).unwrap()) /// ); /// ``` + #[must_use] pub fn checked_add_months(self, months: Months) -> Option<Self> { if months.0 == 0 { return Some(self); @@ -581,6 +643,7 @@ impl NaiveDate { /// None /// ); /// ``` + #[must_use] pub fn checked_sub_months(self, months: Months) -> Option<Self> { if months.0 == 0 { return Some(self); @@ -654,6 +717,7 @@ impl NaiveDate { /// None /// ); /// ``` + #[must_use] pub fn checked_add_days(self, days: Days) -> Option<Self> { if days.0 == 0 { return Some(self); @@ -677,6 +741,7 @@ impl NaiveDate { /// None /// ); /// ``` + #[must_use] pub fn checked_sub_days(self, days: Days) -> Option<Self> { if days.0 == 0 { return Some(self); @@ -708,6 +773,7 @@ impl NaiveDate { /// assert_eq!(dt.time(), t); /// ``` #[inline] + #[must_use] pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime { NaiveDateTime::new(*self, time) } @@ -720,6 +786,7 @@ impl NaiveDate { /// Panics on invalid hour, minute and/or second. #[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")] #[inline] + #[must_use] pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime { self.and_hms_opt(hour, min, sec).expect("invalid time") } @@ -743,6 +810,7 @@ impl NaiveDate { /// assert!(d.and_hms_opt(24, 34, 56).is_none()); /// ``` #[inline] + #[must_use] pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<NaiveDateTime> { NaiveTime::from_hms_opt(hour, min, sec).map(|time| self.and_time(time)) } @@ -755,6 +823,7 @@ impl NaiveDate { /// Panics on invalid hour, minute, second and/or millisecond. #[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")] #[inline] + #[must_use] 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") } @@ -780,6 +849,7 @@ impl NaiveDate { /// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none()); /// ``` #[inline] + #[must_use] pub fn and_hms_milli_opt( &self, hour: u32, @@ -804,7 +874,7 @@ impl NaiveDate { /// /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); /// - /// let dt: NaiveDateTime = d.and_hms_micro(12, 34, 56, 789_012); + /// let dt: NaiveDateTime = d.and_hms_micro_opt(12, 34, 56, 789_012).unwrap(); /// assert_eq!(dt.year(), 2015); /// assert_eq!(dt.weekday(), Weekday::Wed); /// assert_eq!(dt.second(), 56); @@ -812,6 +882,7 @@ impl NaiveDate { /// ``` #[deprecated(since = "0.4.23", note = "use `and_hms_micro_opt()` instead")] #[inline] + #[must_use] 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") } @@ -837,6 +908,7 @@ impl NaiveDate { /// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none()); /// ``` #[inline] + #[must_use] pub fn and_hms_micro_opt( &self, hour: u32, @@ -855,6 +927,7 @@ impl NaiveDate { /// Panics on invalid hour, minute, second and/or nanosecond. #[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")] #[inline] + #[must_use] 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") } @@ -880,6 +953,7 @@ impl NaiveDate { /// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none()); /// ``` #[inline] + #[must_use] pub fn and_hms_nano_opt( &self, hour: u32, @@ -899,7 +973,7 @@ impl NaiveDate { /// Returns the packed ordinal-flags. #[inline] const fn of(&self) -> Of { - Of((self.ymdf & 0b1_1111_1111_1111) as u32) + Of::from_date_impl(self.ymdf) } /// Makes a new `NaiveDate` with the packed month-day-flags changed. @@ -907,20 +981,16 @@ impl NaiveDate { /// Returns `None` when the resulting `NaiveDate` would be invalid. #[inline] fn with_mdf(&self, mdf: Mdf) -> Option<NaiveDate> { - self.with_of(mdf.to_of()) + Some(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. + /// Does not check if the year flags match the year. #[inline] - fn with_of(&self, of: Of) -> Option<NaiveDate> { - if of.valid() { - let Of(of) = of; - Some(NaiveDate { ymdf: (self.ymdf & !0b1_1111_1111_1111) | of as DateImpl }) - } else { - None - } + const fn with_of(&self, of: Of) -> NaiveDate { + NaiveDate { ymdf: (self.ymdf & !0b1_1111_1111_1111) | of.inner() as DateImpl } } /// Makes a new `NaiveDate` for the next calendar date. @@ -928,6 +998,7 @@ impl NaiveDate { /// Panics when `self` is the last representable date. #[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")] #[inline] + #[must_use] pub fn succ(&self) -> NaiveDate { self.succ_opt().expect("out of bound") } @@ -946,8 +1017,12 @@ impl NaiveDate { /// assert_eq!(NaiveDate::MAX.succ_opt(), None); /// ``` #[inline] + #[must_use] pub fn succ_opt(&self) -> Option<NaiveDate> { - self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1)) + match self.of().succ() { + Some(of) => Some(self.with_of(of)), + None => NaiveDate::from_ymd_opt(self.year() + 1, 1, 1), + } } /// Makes a new `NaiveDate` for the previous calendar date. @@ -955,6 +1030,7 @@ impl NaiveDate { /// Panics when `self` is the first representable date. #[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")] #[inline] + #[must_use] pub fn pred(&self) -> NaiveDate { self.pred_opt().expect("out of bound") } @@ -973,8 +1049,12 @@ impl NaiveDate { /// assert_eq!(NaiveDate::MIN.pred_opt(), None); /// ``` #[inline] + #[must_use] pub fn pred_opt(&self) -> Option<NaiveDate> { - self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31)) + match self.of().pred() { + Some(of) => Some(self.with_of(of)), + None => NaiveDate::from_ymd_opt(self.year() - 1, 12, 31), + } } /// Adds the `days` part of given `Duration` to the current date. @@ -995,17 +1075,18 @@ impl NaiveDate { /// assert_eq!(d.checked_add_signed(Duration::days(-1_000_000_000)), None); /// assert_eq!(NaiveDate::MAX.checked_add_signed(Duration::days(1)), None); /// ``` + #[must_use] pub fn checked_add_signed(self, rhs: OldDuration) -> Option<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 = (cycle as i32).checked_add(rhs.num_days().to_i32()?)?; + let cycle = (cycle as i32).checked_add(i32::try_from(rhs.num_days()).ok()?)?; 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)?) + NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags) } /// Subtracts the `days` part of given `Duration` from the current date. @@ -1026,17 +1107,18 @@ impl NaiveDate { /// assert_eq!(d.checked_sub_signed(Duration::days(-1_000_000_000)), None); /// assert_eq!(NaiveDate::MIN.checked_sub_signed(Duration::days(1)), None); /// ``` + #[must_use] pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<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 = (cycle as i32).checked_sub(rhs.num_days().to_i32()?)?; + let cycle = (cycle as i32).checked_sub(i32::try_from(rhs.num_days()).ok()?)?; 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)?) + NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags) } /// Subtracts another `NaiveDate` from the current date. @@ -1050,7 +1132,7 @@ impl NaiveDate { /// ``` /// use chrono::{Duration, NaiveDate}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// let since = NaiveDate::signed_duration_since; /// /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 1)), Duration::zero()); @@ -1061,6 +1143,7 @@ impl NaiveDate { /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), Duration::days(365*4 + 1)); /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), Duration::days(365*400 + 97)); /// ``` + #[must_use] pub fn signed_duration_since(self, rhs: NaiveDate) -> OldDuration { let year1 = self.year(); let year2 = rhs.year(); @@ -1074,6 +1157,7 @@ impl NaiveDate { } /// Returns the number of whole years from the given `base` until `self`. + #[must_use] pub fn years_since(&self, base: Self) -> Option<u32> { let mut years = self.year() - base.year(); if (self.month(), self.day()) < (base.month(), base.day()) { @@ -1116,6 +1200,7 @@ impl NaiveDate { #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> where I: Iterator<Item = B> + Clone, @@ -1159,6 +1244,7 @@ impl NaiveDate { #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { self.format_with_items(StrftimeItems::new(fmt)) } @@ -1167,6 +1253,7 @@ impl NaiveDate { #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[inline] + #[must_use] pub fn format_localized_with_items<'a, I, B>( &self, items: I, @@ -1186,6 +1273,7 @@ impl NaiveDate { #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[inline] + #[must_use] pub fn format_localized<'a>( &self, fmt: &'a str, @@ -1345,7 +1433,7 @@ impl Datelike for NaiveDate { /// let d = NaiveDate::from_ymd_opt(y, m, 1).unwrap(); /// /// // ...is preceded by the last day of the original month - /// d.pred().day() + /// d.pred_opt().unwrap().day() /// } /// /// assert_eq!(ndays_in_month(2015, 8), 31); @@ -1401,7 +1489,7 @@ impl Datelike for NaiveDate { /// let d = NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap(); /// /// // ...is preceded by the last day of the original year - /// d.pred().ordinal() + /// d.pred_opt().unwrap().ordinal() /// } /// /// assert_eq!(ndays_in_year(2015), 365); @@ -1521,7 +1609,8 @@ impl Datelike for NaiveDate { /// ``` #[inline] fn with_month0(&self, month0: u32) -> Option<NaiveDate> { - self.with_mdf(self.mdf().with_month(month0 + 1)?) + let month = month0.checked_add(1)?; + self.with_mdf(self.mdf().with_month(month)?) } /// Makes a new `NaiveDate` with the day of month (starting from 1) changed. @@ -1559,7 +1648,8 @@ impl Datelike for NaiveDate { /// ``` #[inline] fn with_day0(&self, day0: u32) -> Option<NaiveDate> { - self.with_mdf(self.mdf().with_day(day0 + 1)?) + let day = day0.checked_add(1)?; + self.with_mdf(self.mdf().with_day(day)?) } /// Makes a new `NaiveDate` with the day of year (starting from 1) changed. @@ -1583,7 +1673,7 @@ impl Datelike for NaiveDate { /// ``` #[inline] fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDate> { - self.with_of(self.of().with_ordinal(ordinal)?) + self.of().with_ordinal(ordinal).map(|of| self.with_of(of)) } /// Makes a new `NaiveDate` with the day of year (starting from 0) changed. @@ -1607,22 +1697,22 @@ impl Datelike for NaiveDate { /// ``` #[inline] fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDate> { - self.with_of(self.of().with_ordinal(ordinal0 + 1)?) + let ordinal = ordinal0.checked_add(1)?; + self.with_ordinal(ordinal) } } /// An addition of `Duration` to `NaiveDate` discards the fractional days, /// rounding to the closest integral number of days towards `Duration::zero()`. /// -/// Panics on underflow or overflow. -/// Use [`NaiveDate::checked_add_signed`](#method.checked_add_signed) to detect that. +/// Panics on underflow or overflow. Use [`NaiveDate::checked_add_signed`] to detect that. /// /// # Example /// /// ``` /// use chrono::{Duration, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// assert_eq!(from_ymd(2014, 1, 1) + Duration::zero(), from_ymd(2014, 1, 1)); /// assert_eq!(from_ymd(2014, 1, 1) + Duration::seconds(86399), from_ymd(2014, 1, 1)); @@ -1633,6 +1723,8 @@ impl Datelike for NaiveDate { /// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*4 + 1), from_ymd(2018, 1, 1)); /// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*400 + 97), from_ymd(2414, 1, 1)); /// ``` +/// +/// [`NaiveDate::checked_add_signed`]: crate::NaiveDate::checked_add_signed impl Add<OldDuration> for NaiveDate { type Output = NaiveDate; @@ -1661,9 +1753,9 @@ impl Add<Months> for NaiveDate { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate, Months}; + /// use chrono::{NaiveDate, Months}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// 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)); @@ -1689,9 +1781,9 @@ impl Sub<Months> for NaiveDate { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate, Months}; + /// use chrono::{NaiveDate, Months}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// 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)); @@ -1722,15 +1814,14 @@ impl Sub<Days> for NaiveDate { /// rounding to the closest integral number of days towards `Duration::zero()`. /// It is the same as the addition with a negated `Duration`. /// -/// Panics on underflow or overflow. -/// Use [`NaiveDate::checked_sub_signed`](#method.checked_sub_signed) to detect that. +/// Panics on underflow or overflow. Use [`NaiveDate::checked_sub_signed`] to detect that. /// /// # Example /// /// ``` /// use chrono::{Duration, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// assert_eq!(from_ymd(2014, 1, 1) - Duration::zero(), from_ymd(2014, 1, 1)); /// assert_eq!(from_ymd(2014, 1, 1) - Duration::seconds(86399), from_ymd(2014, 1, 1)); @@ -1741,6 +1832,8 @@ impl Sub<Days> for NaiveDate { /// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*4 + 1), from_ymd(2010, 1, 1)); /// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*400 + 97), from_ymd(1614, 1, 1)); /// ``` +/// +/// [`NaiveDate::checked_sub_signed`]: crate::NaiveDate::checked_sub_signed impl Sub<OldDuration> for NaiveDate { type Output = NaiveDate; @@ -1771,7 +1864,7 @@ impl SubAssign<OldDuration> for NaiveDate { /// ``` /// use chrono::{Duration, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 1), Duration::zero()); /// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 12, 31), Duration::days(1)); @@ -1790,6 +1883,12 @@ impl Sub<NaiveDate> for NaiveDate { } } +impl From<NaiveDateTime> for NaiveDate { + fn from(naive_datetime: NaiveDateTime) -> Self { + naive_datetime.date() + } +} + /// Iterator over `NaiveDate` with a step size of one day. #[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)] pub struct NaiveDateDaysIterator { @@ -1993,6 +2092,10 @@ impl Default for NaiveDate { } } +fn div_mod_floor(val: i32, div: i32) -> (i32, i32) { + (val.div_euclid(div), val.rem_euclid(div)) +} + #[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] fn test_encodable_json<F, E>(to_string: F) where @@ -2183,10 +2286,7 @@ mod tests { }; use crate::oldtime::Duration; use crate::{Datelike, Weekday}; - use std::{ - convert::{TryFrom, TryInto}, - i32, u32, - }; + use std::{i32, u32}; #[test] fn diff_months() { @@ -2208,7 +2308,7 @@ mod tests { assert_eq!( NaiveDate::from_ymd_opt(2022, 8, 3) .unwrap() - .checked_sub_months(Months::new((i32::MIN as i64).abs() as u32 + 1)), + .checked_sub_months(Months::new(i32::MIN.unsigned_abs() + 1)), None ); @@ -2275,9 +2375,7 @@ mod tests { #[test] fn test_readme_doomsday() { - use num_iter::range_inclusive; - - for y in range_inclusive(NaiveDate::MIN.year(), NaiveDate::MAX.year()) { + for y in 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(); @@ -2459,6 +2557,9 @@ mod tests { 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(i32::MIN), None); + assert_eq!(from_ndays_from_ce(i32::MAX), None); } #[test] @@ -2915,24 +3016,32 @@ mod tests { fn test_naiveweek() { let date = NaiveDate::from_ymd_opt(2022, 5, 18).unwrap(); let asserts = vec![ - (Weekday::Mon, "2022-05-16", "2022-05-22"), - (Weekday::Tue, "2022-05-17", "2022-05-23"), - (Weekday::Wed, "2022-05-18", "2022-05-24"), - (Weekday::Thu, "2022-05-12", "2022-05-18"), - (Weekday::Fri, "2022-05-13", "2022-05-19"), - (Weekday::Sat, "2022-05-14", "2022-05-20"), - (Weekday::Sun, "2022-05-15", "2022-05-21"), + (Weekday::Mon, "Mon 2022-05-16", "Sun 2022-05-22"), + (Weekday::Tue, "Tue 2022-05-17", "Mon 2022-05-23"), + (Weekday::Wed, "Wed 2022-05-18", "Tue 2022-05-24"), + (Weekday::Thu, "Thu 2022-05-12", "Wed 2022-05-18"), + (Weekday::Fri, "Fri 2022-05-13", "Thu 2022-05-19"), + (Weekday::Sat, "Sat 2022-05-14", "Fri 2022-05-20"), + (Weekday::Sun, "Sun 2022-05-15", "Sat 2022-05-21"), ]; for (start, first_day, last_day) in asserts { let week = date.week(start); let days = week.days(); - assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%Y-%m-%d")); - assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%Y-%m-%d")); + assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%a %Y-%m-%d")); + assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%a %Y-%m-%d")); assert!(days.contains(&date)); } } #[test] + fn test_naiveweek_min_max() { + let date_max = NaiveDate::MAX; + assert!(date_max.week(Weekday::Mon).first_day() <= date_max); + let date_min = NaiveDate::MIN; + assert!(date_min.week(Weekday::Mon).last_day() >= date_min); + } + + #[test] fn test_weeks_from() { // tests per: https://github.com/chronotope/chrono/issues/961 // these internally use `weeks_from` via the parsing infrastructure @@ -2994,4 +3103,12 @@ mod tests { } } } + + #[test] + fn test_with_0_overflow() { + let dt = NaiveDate::from_ymd_opt(2023, 4, 18).unwrap(); + assert!(dt.with_month0(4294967295).is_none()); + assert!(dt.with_day0(4294967295).is_none()); + assert!(dt.with_ordinal0(4294967295).is_none()); + } } |