Skip to content

Commit

Permalink
Convert NaiveDate::with_year to return Result
Browse files Browse the repository at this point in the history
  • Loading branch information
Zomtir authored and djc committed Mar 12, 2024
1 parent 2e4e6ed commit ceeb289
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 52 deletions.
2 changes: 1 addition & 1 deletion src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
pub fn with_year(&self, year: i32) -> Option<DateTime<Tz>> {
map_local(self, |dt| match dt.year() == year {
true => Some(dt),
false => dt.with_year(year),
false => dt.with_year(year).ok(),
})
}

Expand Down
47 changes: 21 additions & 26 deletions src/naive/date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1201,52 +1201,47 @@ impl NaiveDate {
///
/// # Errors
///
/// Returns `None` if:
/// - The resulting date does not exist (February 29 in a non-leap year).
/// - The year is out of range for a `NaiveDate`.
/// Returns:
/// - [`Error::DoesNotExist`] if the resulting date does not exist.
/// - [`Error::OutOfRange`] if `year` is out of range for a `NaiveDate`.
///
/// # Examples
///
/// ```
/// use chrono::NaiveDate;
///
/// assert_eq!(
/// NaiveDate::from_ymd(2015, 9, 8).unwrap().with_year(2016),
/// Some(NaiveDate::from_ymd(2016, 9, 8).unwrap())
/// );
/// assert_eq!(
/// NaiveDate::from_ymd(2015, 9, 8).unwrap().with_year(-308),
/// Some(NaiveDate::from_ymd(-308, 9, 8).unwrap())
/// );
/// # use chrono::{NaiveDate, Error};
/// 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::<(), Error>(())
/// ```
///
/// A leap day (February 29) is a case where this method can return `None`.
/// A leap day (February 29) in a non-leap year will return [`Err(Error::DoesNotExist)`].
///
/// ```
/// # use chrono::NaiveDate;
/// assert!(NaiveDate::from_ymd(2016, 2, 29).unwrap().with_year(2015).is_none());
/// assert!(NaiveDate::from_ymd(2016, 2, 29).unwrap().with_year(2020).is_some());
/// # use chrono::{NaiveDate, Error};
/// assert_eq!(NaiveDate::from_ymd(2016, 2, 29)?.with_year(2015), Err(Error::DoesNotExist));
/// assert!(NaiveDate::from_ymd(2016, 2, 29)?.with_year(2020).is_ok());
/// # Ok::<(), Error>(())
/// ```
///
/// Don't use `with_year` if you want the ordinal date to stay the same:
/// Don't use `with_year` if you want the ordinal date to stay the same.
///
/// ```
/// # use chrono::NaiveDate;
/// assert_ne!(
/// NaiveDate::from_yo(2020, 100).unwrap().with_year(2023).unwrap(),
/// NaiveDate::from_yo(2023, 100).unwrap() // result is 2023-101
/// );
/// # use chrono::{NaiveDate, Error};
/// let date = NaiveDate::from_yo(2020, 100)?.with_year(2023);
/// assert_ne!(date, NaiveDate::from_yo(2023, 100));
/// assert_eq!(date, NaiveDate::from_yo(2023, 99));
/// # Ok::<(), Error>(())
/// ```
#[inline]
pub const fn with_year(&self, year: i32) -> Option<NaiveDate> {
pub const fn with_year(&self, year: i32) -> Result<NaiveDate, Error> {
// we need to operate with `mdf` since we should keep the month and day number as is
let mdf = self.mdf();

// adjust the flags as needed
let flags = YearFlags::from_year(year);
let mdf = mdf.with_flags(flags);

ok!(NaiveDate::from_mdf(year, mdf))
NaiveDate::from_mdf(year, mdf)
}

/// Makes a new `NaiveDate` with the month number (starting from 1) changed.
Expand Down Expand Up @@ -1276,7 +1271,7 @@ impl NaiveDate {
/// use chrono::{Datelike, Error, NaiveDate};
///
/// fn with_year_month(date: NaiveDate, year: i32, month: u32) -> Option<NaiveDate> {
/// date.with_year(year)?.with_month(month)
/// date.with_year(year).ok()?.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
Expand Down
16 changes: 8 additions & 8 deletions src/naive/date/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,14 +367,14 @@ fn test_date_weekday() {
#[test]
fn test_date_with_fields() {
let d = NaiveDate::from_ymd(2000, 2, 29).unwrap();
assert_eq!(d.with_year(-400), Some(NaiveDate::from_ymd(-400, 2, 29).unwrap()));
assert_eq!(d.with_year(-100), None);
assert_eq!(d.with_year(1600), Some(NaiveDate::from_ymd(1600, 2, 29).unwrap()));
assert_eq!(d.with_year(1900), None);
assert_eq!(d.with_year(2000), Some(NaiveDate::from_ymd(2000, 2, 29).unwrap()));
assert_eq!(d.with_year(2001), None);
assert_eq!(d.with_year(2004), Some(NaiveDate::from_ymd(2004, 2, 29).unwrap()));
assert_eq!(d.with_year(i32::MAX), None);
assert_eq!(d.with_year(-400), NaiveDate::from_ymd(-400, 2, 29));
assert_eq!(d.with_year(-100), Err(Error::DoesNotExist));
assert_eq!(d.with_year(1600), NaiveDate::from_ymd(1600, 2, 29));
assert_eq!(d.with_year(1900), Err(Error::DoesNotExist));
assert_eq!(d.with_year(2000), NaiveDate::from_ymd(2000, 2, 29));
assert_eq!(d.with_year(2001), Err(Error::DoesNotExist));
assert_eq!(d.with_year(2004), NaiveDate::from_ymd(2004, 2, 29));
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);
Expand Down
28 changes: 11 additions & 17 deletions src/naive/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,28 +728,22 @@ impl NaiveDateTime {
///
/// # Errors
///
/// Returns `None` if:
/// - The resulting date does not exist (February 29 in a non-leap year).
/// - The year is out of range for a `NaiveDate`.
/// Returns:
/// - [`Error::DoesNotExist`] if the resulting date does not exist.
/// - [`Error::OutOfRange`] if `year` is out of range for a `NaiveDate`.
///
/// # Example
/// # Examples
///
/// ```
/// use chrono::{NaiveDate, NaiveDateTime};
///
/// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).unwrap().and_hms(12, 34, 56).unwrap();
/// assert_eq!(
/// dt.with_year(2016),
/// Some(NaiveDate::from_ymd(2016, 9, 25).unwrap().and_hms(12, 34, 56).unwrap())
/// );
/// assert_eq!(
/// dt.with_year(-308),
/// Some(NaiveDate::from_ymd(-308, 9, 25).unwrap().and_hms(12, 34, 56).unwrap())
/// );
/// # use chrono::{NaiveDate, NaiveDateTime, Error};
/// 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::<(), Error>(())
/// ```
#[inline]
pub const fn with_year(&self, year: i32) -> Option<NaiveDateTime> {
Some(NaiveDateTime { date: try_opt!(self.date.with_year(year)), ..*self })
pub const fn with_year(&self, year: i32) -> Result<NaiveDateTime, Error> {
Ok(NaiveDateTime { date: try_err!(self.date.with_year(year)), ..*self })
}

/// Makes a new `NaiveDateTime` with the month number (starting from 1) changed.
Expand Down

0 comments on commit ceeb289

Please sign in to comment.