Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// daylight saving time transition.
#[inline]
pub fn with_month(&self, month: u32) -> Option<DateTime<Tz>> {
map_local(self, |datetime| datetime.with_month(month))
map_local(self, |datetime| datetime.with_month(month).ok())
}

/// Makes a new `DateTime` with the month number (starting from 0) changed.
Expand All @@ -605,7 +605,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// daylight saving time transition.
#[inline]
pub fn with_month0(&self, month0: u32) -> Option<DateTime<Tz>> {
map_local(self, |datetime| datetime.with_month0(month0))
map_local(self, |datetime| datetime.with_month0(month0).ok())
}

/// Makes a new `DateTime` with the day of month (starting from 1) changed.
Expand All @@ -621,7 +621,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// daylight saving time transition.
#[inline]
pub fn with_day(&self, day: u32) -> Option<DateTime<Tz>> {
map_local(self, |datetime| datetime.with_day(day))
map_local(self, |datetime| datetime.with_day(day).ok())
}

/// Makes a new `DateTime` with the day of month (starting from 0) changed.
Expand All @@ -637,7 +637,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// daylight saving time transition.
#[inline]
pub fn with_day0(&self, day0: u32) -> Option<DateTime<Tz>> {
map_local(self, |datetime| datetime.with_day0(day0))
map_local(self, |datetime| datetime.with_day0(day0).ok())
}

/// Makes a new `DateTime` with the day of year (starting from 1) changed.
Expand Down
127 changes: 64 additions & 63 deletions src/naive/date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::format::{
};
use crate::month::Months;
use crate::naive::{Days, IsoWeek, NaiveDateTime, NaiveTime, NaiveWeek};
use crate::{expect, ok, try_err, try_opt};
use crate::{expect, ok, try_err, try_ok_or, try_opt};
use crate::{Datelike, Error, TimeDelta, Weekday};

use super::internals::{Mdf, YearFlags};
Expand Down Expand Up @@ -807,16 +807,16 @@ impl NaiveDate {

/// Makes a new `NaiveDate` with the packed month-day-flags changed.
///
/// Returns `None` when the resulting `NaiveDate` would be invalid.
/// # Errors
///
/// This method returns:
/// - [`Error::InvalidArgument`] if the `mdf` was created with `month == 0` or `day == 0`.
/// - [`Error::DoesNotExist`] if the given day does not exist in the given month.
#[inline]
const fn with_mdf(&self, mdf: Mdf) -> Option<NaiveDate> {
const fn with_mdf(&self, mdf: Mdf) -> Result<NaiveDate, Error> {
debug_assert!(self.year_flags().0 == mdf.year_flags().0);
match mdf.ordinal() {
Ok(ordinal) => {
Some(NaiveDate::from_yof((self.yof() & !ORDINAL_MASK) | (ordinal << 4) as i32))
}
Err(_) => None, // Non-existing date
}
let ordinal = try_err!(mdf.ordinal());
Ok(NaiveDate::from_yof((self.yof() & !ORDINAL_MASK) | (ordinal << 4) as i32))
}

/// Makes a new `NaiveDate` for the next calendar date.
Expand Down Expand Up @@ -1248,119 +1248,120 @@ impl NaiveDate {
///
/// # Errors
///
/// Returns `None` if:
/// - The resulting date does not exist (for example `month(4)` when day of the month is 31).
/// - The value for `month` is invalid.
/// This method returns:
/// - [`Error::DoesNotExist`] if the resulting date does not exist (for example `month(4)` when
/// day of the month is 31).
/// - [`Error::InvalidArgument`] if the value for `month` is invalid.
///
/// # Examples
///
/// ```
/// use chrono::NaiveDate;
/// use chrono::{Error, NaiveDate};
///
/// assert_eq!(
/// NaiveDate::from_ymd(2015, 9, 8).unwrap().with_month(10),
/// Some(NaiveDate::from_ymd(2015, 10, 8).unwrap())
/// );
/// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).unwrap().with_month(13), None); // No month 13
/// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).unwrap().with_month(2), None); // No Feb 30
/// let date = NaiveDate::from_ymd(2015, 9, 30)?;
/// assert_eq!(date.with_month(7), NaiveDate::from_ymd(2015, 7, 30));
/// assert_eq!(date.with_month(13), Err(Error::InvalidArgument)); // No month 13
/// assert_eq!(date.with_month(2), Err(Error::DoesNotExist)); // No February 30
/// # Ok::<(), Error>(())
/// ```
///
/// Don't combine multiple `Datelike::with_*` methods. The intermediate value may not exist.
/// Don't combine multiple `NaiveDate::with_*` methods. The intermediate value may not exist.
///
/// ```
/// use chrono::{Datelike, Error, NaiveDate};
///
/// fn with_year_month(date: NaiveDate, year: i32, month: u32) -> Option<NaiveDate> {
/// date.with_year(year).ok()?.with_month(month)
/// fn with_year_month(date: NaiveDate, year: i32, month: u32) -> Result<NaiveDate, Error> {
/// date.with_year(year)?.with_month(month)
/// }
/// let d = NaiveDate::from_ymd(2020, 2, 29).unwrap();
/// assert!(with_year_month(d, 2019, 1).is_none()); // fails because of invalid intermediate value
/// let d = NaiveDate::from_ymd(2020, 2, 29)?;
/// assert!(with_year_month(d, 2019, 1).is_err()); // fails because of invalid intermediate value
///
/// // Correct version:
/// fn with_year_month_fixed(date: NaiveDate, year: i32, month: u32) -> Result<NaiveDate, Error> {
/// NaiveDate::from_ymd(year, month, date.day())
/// }
/// let d = NaiveDate::from_ymd(2020, 2, 29).unwrap();
/// let d = NaiveDate::from_ymd(2020, 2, 29)?;
/// assert_eq!(with_year_month_fixed(d, 2019, 1), NaiveDate::from_ymd(2019, 1, 29));
/// # Ok::<(), Error>(())
/// ```
#[inline]
pub const fn with_month(&self, month: u32) -> Option<NaiveDate> {
self.with_mdf(try_opt!(ok!(self.mdf().with_month(month))))
pub const fn with_month(&self, month: u32) -> Result<NaiveDate, Error> {
self.with_mdf(try_err!(self.mdf().with_month(month)))
}

/// Makes a new `NaiveDate` with the month number (starting from 0) changed.
///
/// # Errors
///
/// Returns `None` if:
/// - The resulting date does not exist (for example `month0(3)` when day of the month is 31).
/// - The value for `month0` is invalid.
/// This method returns:
/// - [`Error::DoesNotExist`] if the resulting date does not exist (for example `month0(3)` when
/// day of the month is 31).
/// - [`Error::InvalidArgument`] if the value for `month0` is invalid.
///
/// # Example
///
/// ```
/// use chrono::NaiveDate;
/// use chrono::{Error, NaiveDate};
///
/// assert_eq!(
/// NaiveDate::from_ymd(2015, 9, 8).unwrap().with_month0(9),
/// Some(NaiveDate::from_ymd(2015, 10, 8).unwrap())
/// );
/// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).unwrap().with_month0(12), None); // No month 12
/// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).unwrap().with_month0(1), None); // No Feb 30
/// let date = NaiveDate::from_ymd(2015, 9, 30)?;
/// assert_eq!(date.with_month0(9), NaiveDate::from_ymd(2015, 10, 30));
/// assert_eq!(date.with_month0(12), Err(Error::InvalidArgument)); // No month 13
/// assert_eq!(date.with_month0(1), Err(Error::DoesNotExist)); // No February 30
/// # Ok::<(), Error>(())
/// ```
#[inline]
pub const fn with_month0(&self, month0: u32) -> Option<NaiveDate> {
let month = try_opt!(month0.checked_add(1));
self.with_mdf(try_opt!(ok!(self.mdf().with_month(month))))
pub const fn with_month0(&self, month0: u32) -> Result<NaiveDate, Error> {
let month = try_ok_or!(month0.checked_add(1), Error::InvalidArgument);
self.with_mdf(try_err!(self.mdf().with_month(month)))
}

/// Makes a new `NaiveDate` with the day of month (starting from 1) changed.
///
/// # Errors
///
/// Returns `None` if:
/// - The resulting date does not exist (for example `day(31)` in April).
/// - The value for `day` is invalid.
/// This method returns:
/// - [`Error::DoesNotExist`] if the resulting date does not exist (for example `day(31)` in
/// April).
/// - [`Error::InvalidArgument`] if the value for `day` is invalid.
///
/// # Example
///
/// ```
/// use chrono::NaiveDate;
/// use chrono::{Error, NaiveDate};
///
/// assert_eq!(
/// NaiveDate::from_ymd(2015, 9, 8).unwrap().with_day(30),
/// Some(NaiveDate::from_ymd(2015, 9, 30).unwrap())
/// );
/// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).unwrap().with_day(31), None); // no September 31
/// let date = NaiveDate::from_ymd(2015, 9, 8)?;
/// assert_eq!(date.with_day(30), NaiveDate::from_ymd(2015, 9, 30));
/// assert_eq!(date.with_day(31), Err(Error::DoesNotExist)); // No September 31
/// # Ok::<(), Error>(())
/// ```
#[inline]
pub const fn with_day(&self, day: u32) -> Option<NaiveDate> {
self.with_mdf(try_opt!(ok!(self.mdf().with_day(day))))
pub const fn with_day(&self, day: u32) -> Result<NaiveDate, Error> {
self.with_mdf(try_err!(self.mdf().with_day(day)))
}

/// Makes a new `NaiveDate` with the day of month (starting from 0) changed.
///
/// # Errors
///
/// Returns `None` if:
/// - The resulting date does not exist (for example `day(30)` in April).
/// - The value for `day0` is invalid.
/// This method returns:
/// - [`Error::DoesNotExist`] if the resulting date does not exist (for example `day0(30)` in
/// April).
/// - [`Error::InvalidArgument`] if the value for `day0` is invalid.
///
/// # Example
///
/// ```
/// use chrono::NaiveDate;
/// use chrono::{Error, NaiveDate};
///
/// assert_eq!(
/// NaiveDate::from_ymd(2015, 9, 8).unwrap().with_day0(29),
/// Some(NaiveDate::from_ymd(2015, 9, 30).unwrap())
/// );
/// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).unwrap().with_day0(30), None); // no September 31
/// let date = NaiveDate::from_ymd(2015, 9, 8)?;
/// assert_eq!(date.with_day0(29), NaiveDate::from_ymd(2015, 9, 30));
/// assert_eq!(date.with_day0(30), Err(Error::DoesNotExist)); // No September 31
/// # Ok::<(), Error>(())
/// ```
#[inline]
pub const fn with_day0(&self, day0: u32) -> Option<NaiveDate> {
let day = try_opt!(day0.checked_add(1));
self.with_mdf(try_opt!(ok!(self.mdf().with_day(day))))
pub const fn with_day0(&self, day0: u32) -> Result<NaiveDate, Error> {
let day = try_ok_or!(day0.checked_add(1), Error::InvalidArgument);
self.with_mdf(try_err!(self.mdf().with_day(day)))
}

/// Makes a new `NaiveDate` with the day of year (starting from 1) changed.
Expand Down
30 changes: 15 additions & 15 deletions src/naive/date/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,21 +377,21 @@ fn test_date_with_fields() {
assert_eq!(d.with_year(i32::MAX), Err(Error::OutOfRange));

let d = NaiveDate::from_ymd(2000, 4, 30).unwrap();
assert_eq!(d.with_month(0), None);
assert_eq!(d.with_month(1), Some(NaiveDate::from_ymd(2000, 1, 30).unwrap()));
assert_eq!(d.with_month(2), None);
assert_eq!(d.with_month(3), Some(NaiveDate::from_ymd(2000, 3, 30).unwrap()));
assert_eq!(d.with_month(4), Some(NaiveDate::from_ymd(2000, 4, 30).unwrap()));
assert_eq!(d.with_month(12), Some(NaiveDate::from_ymd(2000, 12, 30).unwrap()));
assert_eq!(d.with_month(13), None);
assert_eq!(d.with_month(u32::MAX), None);
assert_eq!(d.with_month(0), Err(Error::InvalidArgument));
assert_eq!(d.with_month(1), NaiveDate::from_ymd(2000, 1, 30));
assert_eq!(d.with_month(2), Err(Error::DoesNotExist));
assert_eq!(d.with_month(3), NaiveDate::from_ymd(2000, 3, 30));
assert_eq!(d.with_month(4), NaiveDate::from_ymd(2000, 4, 30));
assert_eq!(d.with_month(12), NaiveDate::from_ymd(2000, 12, 30));
assert_eq!(d.with_month(13), Err(Error::InvalidArgument));
assert_eq!(d.with_month(u32::MAX), Err(Error::InvalidArgument));

let d = NaiveDate::from_ymd(2000, 2, 8).unwrap();
assert_eq!(d.with_day(0), None);
assert_eq!(d.with_day(1), Some(NaiveDate::from_ymd(2000, 2, 1).unwrap()));
assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd(2000, 2, 29).unwrap()));
assert_eq!(d.with_day(30), None);
assert_eq!(d.with_day(u32::MAX), None);
assert_eq!(d.with_day(0), Err(Error::InvalidArgument));
assert_eq!(d.with_day(1), NaiveDate::from_ymd(2000, 2, 1));
assert_eq!(d.with_day(29), NaiveDate::from_ymd(2000, 2, 29));
assert_eq!(d.with_day(30), Err(Error::DoesNotExist));
assert_eq!(d.with_day(u32::MAX), Err(Error::InvalidArgument));
}

#[test]
Expand Down Expand Up @@ -750,8 +750,8 @@ fn test_weeks_from() {
#[test]
fn test_with_0_overflow() {
let dt = NaiveDate::from_ymd(2023, 4, 18).unwrap();
assert!(dt.with_month0(4294967295).is_none());
assert!(dt.with_day0(4294967295).is_none());
assert_eq!(dt.with_month0(u32::MAX), Err(Error::InvalidArgument));
assert_eq!(dt.with_day0(u32::MAX), Err(Error::InvalidArgument));
assert!(dt.with_ordinal0(4294967295).is_none());
}

Expand Down
Loading