Sub Months - jalalvandi/ParsiDate GitHub Wiki
sub_months
Method Subtracts a specified number of months from this ParsiDate
, returning a new ParsiDate
.
Description
This method provides a convenient way to calculate the date that occurs a given number of months before the current ParsiDate
instance.
It functions as a direct equivalent to calling the add_months
method with a negative value for the number of months (i.e., self.add_months(-months_to_sub)
if add_months
accepted negative values, or more likely, it uses the same internal logic adapted for subtraction).
The calculation involves adjusting the month and potentially the year components. A key behavior is day clamping: if the original day number is greater than the number of days in the resulting target month (after subtraction), the day is adjusted downwards to the last valid day of that target month.
Arguments
months_to_sub
: The non-negative number of months (u32
or similar unsigned integer type) to subtract from the current date.
Returns
Ok(ParsiDate)
: If the subtraction results in a valid date within the supported range of the library (typically years 1 to 9999), returns the newParsiDate
instance wrapped inOk
.Err(DateError::...)
: Returns an error under the same conditions as theadd_months
method (when performing the equivalent addition of a negative number). This primarily occurs if:- The resulting date falls outside the supported year range (e.g., subtracting months from an early date results in a year less than 1).
- An arithmetic overflow or other internal error occurs during the calculation. Refer to
add_months
documentation for specific error kinds likeDateError::ArithmeticOverflow
orDateError::InvalidDate
.
Day Clamping Behavior
When subtracting months, if the day of the month in the original date (self.day()
) is greater than the number of days in the calculated target month, the day in the resulting ParsiDate
will be "clamped" (adjusted down) to the last valid day of that target month.
- Example 1: Subtracting 1 month from
1403-01-31
(Farvardin 31st). The target month is Esfand of the previous year (1402-12
). If 1402 is a common year, Esfand has 29 days. Since 31 > 29, the day is clamped to 29, resulting in1402-12-29
. - Example 2: Subtracting 1 month from
1403-08-30
(Aban 30th). The target month is Mehr (1403-07
), which also has 30 days. No clamping is needed, resulting in1403-07-30
. - Example 3: Subtracting 3 months from
1403-03-31
(Khordad 31st). Target month is Esfand (1402-12
). If 1402 is common (29 days in Esfand), day 31 is clamped to 29 ->1402-12-29
.
Examples (Rust)
use parsidate::{ParsiDate, DateError}; // Assuming these types exist
// --- Example with Day Clamping and Year Rollover ---
let date1 = ParsiDate::new(1403, 3, 31).unwrap(); // Khordad 31st, 1403
// Subtract 3 months. Target is 1402-12 (Esfand).
// Assume 1402 is a common year (Esfand has 29 days).
// Day 31 is invalid for Esfand, so it clamps to 29.
assert_eq!(
date1.sub_months(3),
Ok(ParsiDate::new(1402, 12, 29).unwrap())
);
// --- Example with Year Rollover, No Clamping ---
let date2 = ParsiDate::new(1403, 2, 15).unwrap(); // Ordibehesht 15th, 1403
// Subtract 2 months. Target is 1402-12 (Esfand). Day 15 is valid.
assert_eq!(
date2.sub_months(2),
Ok(ParsiDate::new(1402, 12, 15).unwrap())
);
// --- Simple Subtraction, No Clamping, Same Year ---
let date3 = ParsiDate::new(1403, 7, 10).unwrap(); // Mehr 10th, 1403
// Subtract 2 months. Target is 1403-05 (Mordad). Day 10 is valid.
assert_eq!(
date3.sub_months(2),
Ok(ParsiDate::new(1403, 5, 10).unwrap())
);
// --- Subtracting 12 months (exactly one year) ---
let date4 = ParsiDate::new(1403, 5, 5).unwrap(); // Mordad 5th, 1403
assert_eq!(
date4.sub_months(12),
Ok(ParsiDate::new(1402, 5, 5).unwrap())
);
// --- Subtracting more than 12 months ---
let date5 = ParsiDate::new(1404, 1, 1).unwrap(); // Farvardin 1st, 1404
// Subtract 13 months -> Target is 1402-12 (Esfand). Day 1 is valid.
assert_eq!(
date5.sub_months(13),
Ok(ParsiDate::new(1402, 12, 1).unwrap())
);
// --- Example Resulting in Error (Going Below Year 1) ---
let early_date = ParsiDate::new(1, 2, 1).unwrap(); // Ordibehesht 1st, Year 1
// Subtracting 2 months results in Year 0, Month 12, which is outside the supported range.
let result = early_date.sub_months(2);
assert!(result.is_err());
// assert_eq!(result, Err(DateError::InvalidDate)); // Or similar error
let result_large = ParsiDate::new(1, 1, 1).unwrap().sub_months(1); // Subtracting from 1/1/1
assert!(result_large.is_err()); // Should also fail