Sub Months (ParsiDateTime) - parsicore/parsidate GitHub Wiki

Method sub_months (on ParsiDateTime)

Subtracts a specified number of months from 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 subtracted. The time part (hour, minute, second) of the original ParsiDateTime instance remains unchanged in the resulting instance.

It functions as a convenient alternative to calling add_months with a negative value (i.e., self.add_months(-months)).

The core date calculation, including adjusting the month and year, and handling day clamping, is delegated to the corresponding ParsiDate::sub_months method (or equivalently, ParsiDate::add_months with a negative value). 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 method documentation for full details on this behavior.

Arguments

  • months: The non-negative number of months (u32 or similar unsigned integer type) to subtract from the current date part.

Returns

  • Ok(ParsiDateTime): If the starting ParsiDateTime is valid and the underlying ParsiDate::sub_months (or equivalent) call succeeds, returns the new ParsiDateTime instance (with updated date (potentially clamped day) and original time) wrapped in Ok.
  • Err(DateError::...): Returns an error under the same conditions as the add_months method when called with a negative value. This occurs if:
    1. The starting ParsiDateTime instance itself holds invalid data.
    2. The delegated call to ParsiDate::sub_months (or add_months) fails. This propagates errors like DateError::InvalidDate 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: Subtracting months without clamping
let dt = ParsiDateTime::new(1403, 1, 31, 9, 0, 0).unwrap(); // Farvardin 31st, 09:00:00
// Subtract 7 months.
// Target: 1403-01 minus 7 months = Month -6 -> wraps to Month (12 - 6) = 6 of previous year (1402).
// Target date: 1402-06-31 (Shahrivar 31st). Shahrivar has 31 days, so day 31 is valid. No clamping.
let dt_minus_7m = dt.sub_months(7);
assert!(dt_minus_7m.is_ok());
let dt_minus_7m_unwrapped = dt_minus_7m.unwrap();
// Check the date part
assert_eq!(dt_minus_7m_unwrapped.date(), ParsiDate::new(1402, 6, 31).unwrap()); // Expected: 1402-06-31
// Check that the time part is unchanged
assert_eq!(dt_minus_7m_unwrapped.hour(), 9);
assert_eq!(dt_minus_7m_unwrapped.minute(), 0);
assert_eq!(dt_minus_7m_unwrapped.second(), 0);


// Example 2: Subtracting months resulting in clamping
let dt2 = ParsiDateTime::new(1403, 3, 31, 14, 15, 16).unwrap(); // Khordad 31st, 1403
// Subtract 3 months -> Target is Esfand (Month 12) of 1402.
// Assume 1402 is a common year (Esfand has 29 days). Original day 31 > 29 -> clamp.
let dt_minus_3m = dt2.sub_months(3);
assert!(dt_minus_3m.is_ok());
let dt_minus_3m_unwrapped = dt_minus_3m.unwrap();
// Check the date part: Day clamped to 29
assert_eq!(dt_minus_3m_unwrapped.date(), ParsiDate::new(1402, 12, 29).unwrap()); // Expected: 1402-12-29
// Check time part
assert_eq!(dt_minus_3m_unwrapped.time(), (14, 15, 16));


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