mirror of
https://github.com/chronotope/chrono.git
synced 2025-09-29 22:11:59 +00:00
Use overflowing_naive_local
in checked_(add|sub)_months
This commit is contained in:
parent
e292d9bc90
commit
dd201649b5
@ -436,13 +436,17 @@ impl<Tz: TimeZone> DateTime<Tz> {
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - The resulting date would be out of range.
|
||||
/// - The local time at the resulting date does not exist or is ambiguous, for example during a
|
||||
/// daylight saving time transition.
|
||||
/// - The resulting UTC datetime would be out of range.
|
||||
/// - The resulting local datetime would be out of range (unless `months` is zero).
|
||||
#[must_use]
|
||||
pub fn checked_add_months(self, rhs: Months) -> Option<DateTime<Tz>> {
|
||||
self.naive_local()
|
||||
.checked_add_months(rhs)?
|
||||
pub fn checked_add_months(self, months: Months) -> Option<DateTime<Tz>> {
|
||||
// `NaiveDate::checked_add_months` has a fast path for `Months(0)` that does not validate
|
||||
// the resulting date, with which we can return `Some` even for an out of range local
|
||||
// datetime.
|
||||
self.overflowing_naive_local()
|
||||
.checked_add_months(months)?
|
||||
.and_local_timezone(Tz::from_offset(&self.offset))
|
||||
.single()
|
||||
}
|
||||
@ -469,13 +473,17 @@ impl<Tz: TimeZone> DateTime<Tz> {
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - The resulting date would be out of range.
|
||||
/// - The local time at the resulting date does not exist or is ambiguous, for example during a
|
||||
/// daylight saving time transition.
|
||||
/// - The resulting UTC datetime would be out of range.
|
||||
/// - The resulting local datetime would be out of range (unless `months` is zero).
|
||||
#[must_use]
|
||||
pub fn checked_sub_months(self, rhs: Months) -> Option<DateTime<Tz>> {
|
||||
self.naive_local()
|
||||
.checked_sub_months(rhs)?
|
||||
pub fn checked_sub_months(self, months: Months) -> Option<DateTime<Tz>> {
|
||||
// `NaiveDate::checked_sub_months` has a fast path for `Months(0)` that does not validate
|
||||
// the resulting date, with which we can return `Some` even for an out of range local
|
||||
// datetime.
|
||||
self.overflowing_naive_local()
|
||||
.checked_sub_months(months)?
|
||||
.and_local_timezone(Tz::from_offset(&self.offset))
|
||||
.single()
|
||||
}
|
||||
|
@ -1461,6 +1461,31 @@ fn test_min_max_setters() {
|
||||
assert_eq!(beyond_max.with_nanosecond(beyond_max.nanosecond()), Some(beyond_max));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_max_add_months() {
|
||||
let offset_min = FixedOffset::west_opt(2 * 60 * 60).unwrap();
|
||||
let beyond_min = offset_min.from_utc_datetime(&NaiveDateTime::MIN);
|
||||
let offset_max = FixedOffset::east_opt(2 * 60 * 60).unwrap();
|
||||
let beyond_max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);
|
||||
let max_time = NaiveTime::from_hms_nano_opt(23, 59, 59, 999_999_999).unwrap();
|
||||
|
||||
assert_eq!(beyond_min.checked_add_months(Months::new(0)), Some(beyond_min));
|
||||
assert_eq!(
|
||||
beyond_min.checked_add_months(Months::new(1)),
|
||||
Some(offset_min.from_utc_datetime(&(NaiveDate::MIN + Months(1)).and_time(NaiveTime::MIN)))
|
||||
);
|
||||
assert_eq!(beyond_min.checked_sub_months(Months::new(0)), Some(beyond_min));
|
||||
assert_eq!(beyond_min.checked_sub_months(Months::new(1)), None);
|
||||
|
||||
assert_eq!(beyond_max.checked_add_months(Months::new(0)), Some(beyond_max));
|
||||
assert_eq!(beyond_max.checked_add_months(Months::new(1)), None);
|
||||
assert_eq!(beyond_max.checked_sub_months(Months::new(0)), Some(beyond_max));
|
||||
assert_eq!(
|
||||
beyond_max.checked_sub_months(Months::new(1)),
|
||||
Some(offset_max.from_utc_datetime(&(NaiveDate::MAX - Months(1)).and_time(max_time)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_local_beyond_min_datetime() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user