Add Months (ParsiDateTime) - parsicore/parsidate GitHub Wiki

Method add_months (on ParsiDateTime)

Adds a specified number of months to the date part of this ParsiDateTime, returning a new ParsiDateTime with the same time component and potentially adjusted day.

Description

This method calculates a new ParsiDateTime by modifying only the date part (year, month, day) based on the number of months added or subtracted. The time part (hour, minute, second) of the original ParsiDateTime instance remains unchanged in the resulting instance.

The core date calculation, including adjusting the month and year, and handling day clamping, is delegated to the corresponding ParsiDate::add_months method. Day clamping means if the original day is invalid for the target month (e.g., day 31 when moving to Mehr), the day in the new date is adjusted to the last valid day of the target month. Please refer to the ParsiDate::add_months documentation for full details on this behavior.

Arguments

  • months: The number of months to add (i32 or similar signed integer type).
    • A positive value moves the date forward.
    • A negative value moves the date backward.

Returns

  • Ok(ParsiDateTime): If the starting ParsiDateTime is valid and the underlying ParsiDate::add_months call succeeds, returns the new ParsiDateTime instance (with updated date (potentially clamped day) and original time) wrapped in Ok.
  • Err(DateError::...): Returns an error if either of the following occurs:
    1. The starting ParsiDateTime instance itself holds invalid data (e.g., invalid date or time components, potentially from unsafe creation). An internal validity check might be performed first.
    2. The delegated call to ParsiDate::add_months fails. This propagates errors like DateError::InvalidDate (if the underlying date part was invalid) or DateError::ArithmeticOverflow (if the resulting date's year falls outside the supported range).

Examples (Rust)

use parsidate::{ParsiDateTime, ParsiDate, DateError}; // Assuming these types exist

// Example 1: Adding months resulting in day clamping
let dt1 = ParsiDateTime::new(1403, 6, 31, 12, 0, 0).unwrap(); // Shahrivar 31st, 12:00:00
// Add 1 month -> Target is Mehr (Month 7), which only has 30 days.
let dt_plus_1m = dt1.add_months(1);
assert!(dt_plus_1m.is_ok());
let dt_plus_1m_unwrapped = dt_plus_1m.unwrap();
// Check the date part: Day should be clamped from 31 to 30.
assert_eq!(dt_plus_1m_unwrapped.date(), ParsiDate::new(1403, 7, 30).unwrap()); // Expected date: 1403-07-30
// Check that the time part is unchanged
assert_eq!(dt_plus_1m_unwrapped.hour(), 12);
assert_eq!(dt_plus_1m_unwrapped.minute(), 0);
assert_eq!(dt_plus_1m_unwrapped.second(), 0);


// Example 2: Adding months without clamping
let dt2 = ParsiDateTime::new(1403, 7, 15, 9, 45, 30).unwrap(); // Mehr 15th, 09:45:30
// Add 2 months -> Target is Azar (Month 9), which has 30 days. Day 15 is valid.
let dt_plus_2m = dt2.add_months(2);
assert!(dt_plus_2m.is_ok());
let dt_plus_2m_unwrapped = dt_plus_2m.unwrap();
// Check the date part: Day should remain 15.
assert_eq!(dt_plus_2m_unwrapped.date(), ParsiDate::new(1403, 9, 15).unwrap()); // Expected date: 1403-09-15
// Check time part
assert_eq!(dt_plus_2m_unwrapped.time(), (9, 45, 30));


// Example 3: Subtracting months across year boundary
let dt3 = ParsiDateTime::new(1404, 2, 5, 18, 0, 0).unwrap(); // Ordibehesht 5th, 1404
// Subtract 3 months -> Target is Esfand (Month 12) of 1403. Day 5 is valid.
let dt_minus_3m = dt3.add_months(-3);
assert!(dt_minus_3m.is_ok());
let dt_minus_3m_unwrapped = dt_minus_3m.unwrap();
// Check the date part
assert_eq!(dt_minus_3m_unwrapped.date(), ParsiDate::new(1403, 12, 5).unwrap()); // Expected date: 1403-12-05
// Check time part
assert_eq!(dt_minus_3m_unwrapped.time(), (18, 0, 0));


// Example 4: Subtracting months resulting in clamping (leap day involved)
let dt4 = ParsiDateTime::new(1403, 12, 30, 10, 10, 10).unwrap(); // Esfand 30th, 1403 (leap)
// Subtract 12 months -> Target is Esfand (Month 12) of 1402. 1402 is common (29 days).
// Original day 30 > 29, so must clamp.
let dt_minus_12m = dt4.add_months(-12);
assert!(dt_minus_12m.is_ok());
let dt_minus_12m_unwrapped = dt_minus_12m.unwrap();
// Check the date part: Day clamped to 29
assert_eq!(dt_minus_12m_unwrapped.date(), ParsiDate::new(1402, 12, 29).unwrap()); // Expected date: 1402-12-29
// Check time part
assert_eq!(dt_minus_12m_unwrapped.time(), (10, 10, 10));


// Example 5: Error case (resulting year out of range)
let earliest_dt = ParsiDateTime::new(1, 1, 1, 0, 0, 0).unwrap();
let result = earliest_dt.add_months(-1); // Attempt to go before year 1
assert!(result.is_err());
// assert_eq!(result, Err(DateError::ArithmeticOverflow));