Add Years - jalalvandi/ParsiDate GitHub Wiki

Method add_years

Adds a specified number of years to this ParsiDate, returning a new ParsiDate instance, handling leap day adjustments when necessary.

Description

This method calculates a new date by adding (or subtracting) a given number of years to the current ParsiDate instance (self). The operation primarily adjusts the year component.

The month and day components generally remain unchanged, with one important exception: leap day handling. If the original date is Esfand 30th (the leap day, which only exists in Persian leap years) and the target year (calculated as self.year() + years_to_add) is not a leap year, then the day component of the resulting ParsiDate will be clamped down to 29 (the last day of Esfand in a non-leap year).

In all other situations, the month and day are preserved exactly:

  • If the original date is not Esfand 30th.
  • If the original date is Esfand 30th, and the target year is also a leap year.

The years_to_add argument can be positive to advance the date forward or negative to move the date backward in time.

Arguments

  • years_to_add: The number of years to add to the current date's year component (i32 or a similar signed integer type).
    • A positive value moves the date forward in years.
    • A negative value moves the date backward in years.
    • A value of zero results in a ParsiDate identical to the original.

Returns

  • Ok(ParsiDate): If the starting ParsiDate is valid and the resulting date (after potential day clamping for leap year transitions) has a year within the supported range [1, 9999], returns the new ParsiDate wrapped in Ok.
  • Err(DateError::InvalidDate): If the starting ParsiDate instance (self) represents an invalid date according to Persian calendar rules.
  • Err(DateError::ArithmeticOverflow): If adding years_to_add results in a year that falls outside the supported range [1, 9999].

Examples (Rust)

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

// --- Leap Day Handling Examples ---

// Start with Esfand 30th in a known leap year (1403 is leap)
let leap_day_1403 = ParsiDate::new(1403, 12, 30).unwrap();

// Add 1 year -> Target year 1404 (NOT leap). Day is clamped from 30 to 29.
let result1 = leap_day_1403.add_years(1);
assert_eq!(result1, Ok(ParsiDate::new(1404, 12, 29).unwrap()));

// Add 4 years -> Target year 1407 (IS leap). Day remains 30.
let result2 = leap_day_1403.add_years(4);
assert_eq!(result2, Ok(ParsiDate::new(1407, 12, 30).unwrap()));

// Subtract 4 years -> Target year 1399 (IS leap). Day remains 30.
let result3 = leap_day_1403.add_years(-4);
assert_eq!(result3, Ok(ParsiDate::new(1399, 12, 30).unwrap()));

// Subtract 3 years -> Target year 1400 (NOT leap). Day is clamped from 30 to 29.
let result4 = leap_day_1403.add_years(-3);
assert_eq!(result4, Ok(ParsiDate::new(1400, 12, 29).unwrap()));


// --- Non-Leap Day Examples ---

let common_date = ParsiDate::new(1403, 5, 15).unwrap(); // Mordad 15th

// Add 1 year. Month and day remain unchanged.
assert_eq!(common_date.add_years(1), Ok(ParsiDate::new(1404, 5, 15).unwrap()));

// Subtract 1 year. Month and day remain unchanged.
assert_eq!(common_date.add_years(-1), Ok(ParsiDate::new(1402, 5, 15).unwrap()));

// Start on Esfand 29th of a non-leap year (1402)
let esfand_29_common = ParsiDate::new(1402, 12, 29).unwrap();

// Add 1 year -> Target year 1403 (leap year). Day stays 29 (no clamping needed).
assert_eq!(esfand_29_common.add_years(1), Ok(ParsiDate::new(1403, 12, 29).unwrap()));


// --- Zero Years ---
assert_eq!(leap_day_1403.add_years(0), Ok(ParsiDate::new(1403, 12, 30).unwrap()));
assert_eq!(common_date.add_years(0), Ok(ParsiDate::new(1403, 5, 15).unwrap()));


// --- Error Case: Resulting Year Out of Range ---
let early_date = ParsiDate::new(1, 1, 1).unwrap();

// Try to subtract years to go before the supported year 1
let result_too_early = early_date.add_years(-1);
assert!(result_too_early.is_err());
assert_eq!(result_too_early, Err(DateError::ArithmeticOverflow));

let late_date = ParsiDate::new(9999, 6, 1).unwrap();
// Try to add years resulting in a year beyond the supported range (e.g., > 9999)
let result_too_late = late_date.add_years(1);
assert!(result_too_late.is_err());
assert_eq!(result_too_late, Err(DateError::ArithmeticOverflow));