Add Months - jalalvandi/ParsiDate GitHub Wiki
add_months
Method Adds a specified number of months to this ParsiDate
, returning a new ParsiDate
instance, handling day clamping when necessary.
Description
This method calculates a new date by adding (or subtracting) a given number of months to the current ParsiDate
instance (self
). The operation correctly adjusts the month and, if necessary, the year.
A key feature of this method is day clamping. If the day component of the original date (self.day()
) is greater than the number of days in the resulting month (after adding months_to_add
), the day of the new ParsiDate
will be adjusted ("clamped") down to the last valid day of that target month. For example, adding one month to Farvardin 31st (which has 31 days) results in Ordibehesht 31st (which also has 31 days, so no clamping occurs). However, adding six months to Farvardin 31st targets Mehr (which has 30 days), so the result will be clamped to Mehr 30th. This logic also correctly handles the varying length of Esfand (29 or 30 days) in leap years.
The months_to_add
argument can be positive to advance the date forward or negative to move the date backward in time.
Arguments
months_to_add
: The number of months to add to the current date (i32
or a similar signed integer type).- A positive value moves the date forward.
- A negative value moves the date backward.
- A value of zero results in a
ParsiDate
identical to the original.
Returns
Ok(ParsiDate)
: If the startingParsiDate
is valid and the resulting date (after potential day clamping and year adjustment) falls within the supported range ofParsiDate
(typically years 1-9999), returns the newParsiDate
wrapped inOk
.Err(DateError::InvalidDate)
: If the startingParsiDate
instance (self
) represents an invalid date according to Persian calendar rules.Err(DateError::ArithmeticOverflow)
: If addingmonths_to_add
results in a year that falls outside the supported range (e.g., year 0 or year 10000+), or if an internal overflow occurs during the month/year calculation.
Examples (Rust)
use parsidate::{ParsiDate, DateError}; // Assuming these types exist
// --- Addition Examples ---
let date1 = ParsiDate::new(1403, 1, 31).unwrap(); // Farvardin 31st (Month 1 has 31 days)
// Add 1 month -> Ordibehesht 31st (Month 2 has 31 days, no clamping)
assert_eq!(date1.add_months(1), Ok(ParsiDate::new(1403, 2, 31).unwrap()));
// Add 6 months -> Mehr 30th (Month 7 has 30 days, day clamped from 31)
assert_eq!(date1.add_months(6), Ok(ParsiDate::new(1403, 7, 30).unwrap()));
// Add 8 months -> Azar 30th (Month 9 has 30 days, day clamped from 31)
assert_eq!(date1.add_months(8), Ok(ParsiDate::new(1403, 9, 30).unwrap()));
// Add 11 months -> Esfand 30th (1403 is a leap year, Month 12 has 30 days, day clamped from 31)
assert_eq!(date1.add_months(11), Ok(ParsiDate::new(1403, 12, 30).unwrap()));
// Add 12 months -> Farvardin 31st of next year (Year rollover)
assert_eq!(date1.add_months(12), Ok(ParsiDate::new(1404, 1, 31).unwrap()));
// Add 13 months -> Ordibehesht 31st of next year (1404 Month 2 has 31 days)
assert_eq!(date1.add_months(13), Ok(ParsiDate::new(1404, 2, 31).unwrap()));
// Add 23 months -> Esfand 29th of 1404 (1404 is NOT leap, Month 12 has 29 days, day clamped from 31)
assert_eq!(date1.add_months(23), Ok(ParsiDate::new(1404, 12, 29).unwrap()));
// Add zero months
assert_eq!(date1.add_months(0), Ok(ParsiDate::new(1403, 1, 31).unwrap()));
// --- Subtraction Examples ---
let date2 = ParsiDate::new(1403, 5, 31).unwrap(); // Mordad 31st (Month 5 has 31 days)
// Subtract 1 month -> Tir 31st (Month 4 has 31 days, no clamping)
assert_eq!(date2.add_months(-1), Ok(ParsiDate::new(1403, 4, 31).unwrap()));
// Subtract 5 months -> Esfand 30th, 1402 (1402 NOT leap, Month 12 has 29 days, day clamped from 31)
// Let's recheck the date math: 1403/05/31 - 5 months = 1402/12/31 -> Clamp to 1402/12/29
assert_eq!(date2.add_months(-5), Ok(ParsiDate::new(1402, 12, 29).unwrap()));
// Subtract 12 months -> Mordad 31st of previous year
assert_eq!(date2.add_months(-12), Ok(ParsiDate::new(1402, 5, 31).unwrap()));
let date3 = ParsiDate::new(1403, 1, 15).unwrap(); // Farvardin 15th
// Subtract 1 month -> Esfand 15th, 1402 (1402 NOT leap)
assert_eq!(date3.add_months(-1), Ok(ParsiDate::new(1402, 12, 15).unwrap()));
// --- Error Case: Resulting Year Out of Range ---
let early_date = ParsiDate::new(1, 1, 1).unwrap();
// Try to subtract months to go before the supported year 1
let result_too_early = early_date.add_months(-1);
assert!(result_too_early.is_err());
// The specific error might be ArithmeticOverflow or InvalidDate depending on implementation
// assert_eq!(result_too_early, Err(DateError::ArithmeticOverflow)); // Example assertion
let late_date = ParsiDate::new(9999, 12, 1).unwrap();
// Try to add months resulting in a year beyond the supported range (e.g., > 9999)
let result_too_late = late_date.add_months(1);
assert!(result_too_late.is_err());
// assert_eq!(result_too_late, Err(DateError::ArithmeticOverflow)); // Example assertion