With Year - jalalvandi/ParsiDate GitHub Wiki

Method with_year

Creates a new ParsiDate instance by replacing the year component, adjusting the day for leap day transitions if necessary.

Description

This method creates a new ParsiDate based on the current instance (self), but with the year component changed to the specified year value. The month and day components are initially copied from the original self instance.

A special handling logic is applied for the leap day (Esfand 30th):

  • If the original date (self) is Esfand 30th (which only exists in a leap year), and the target year is a common year, the day component in the new ParsiDate is automatically adjusted (clamped) down to 29. This ensures the resulting date is valid (as Esfand only has 29 days in a common year).
  • If the original date is Esfand 30th and the target year is also a leap year, the day remains 30.
  • If the original date is not Esfand 30th, the day component remains unchanged.

This method performs validation to ensure the starting ParsiDate is valid and the target year is within the acceptable range [1, 9999]. The final validity of the resulting date (after potential clamping) is ensured by the internal logic used for construction.

Arguments

  • year: The desired year for the new ParsiDate (i32 or similar integer type). Must be within the range [1, 9999].

Returns

  • Ok(ParsiDate): If the original ParsiDate (self) is valid and the target year is valid (1-9999), returns the new ParsiDate instance (with potentially clamped day for leap day transitions) wrapped in Ok.
  • Err(DateError::InvalidDate): Returns an error if either of the following conditions is met:
    1. The starting ParsiDate instance (self) is invalid (e.g., contains invalid month or day data, potentially from unsafe creation).
    2. The provided target year is outside the supported range [1, 9999].

Examples (Rust)

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

let date = ParsiDate::new(1403, 5, 2).unwrap(); // Mordad 2nd, 1403 (1403 is leap)

// --- Success Case: Simple Year Change ---
// Change year to 1404 (common year). Month/Day are not Esfand 30th, so no clamping.
let date_next_year = date.with_year(1404);
assert!(date_next_year.is_ok());
assert_eq!(date_next_year.unwrap(), ParsiDate::new(1404, 5, 2).unwrap());


// --- Success Cases: Leap Day Handling ---
let leap_day = ParsiDate::new(1403, 12, 30).unwrap(); // Esfand 30th, 1403 (leap)

// Change to a common year (1404). Original day is Esfand 30th. Must clamp day to 29.
let common_year_date = leap_day.with_year(1404);
assert!(common_year_date.is_ok());
assert_eq!(
    common_year_date.unwrap(),
    ParsiDate::new(1404, 12, 29).unwrap() // Note: Day is 29
);

// Change to another leap year (1408). Original day is Esfand 30th. Target allows Esfand 30th. No clamping.
// (Checking leap: 1408 % 33 = 22 -> leap)
let other_leap_year_date = leap_day.with_year(1408);
assert!(other_leap_year_date.is_ok());
assert_eq!(
    other_leap_year_date.unwrap(),
    ParsiDate::new(1408, 12, 30).unwrap() // Note: Day is 30
);


// --- Error Cases ---

// Target year 0 is out of range [1, 9999]
assert_eq!(
    date.with_year(0),
    Err(DateError::InvalidDate)
);

// Target year 10000 is out of range [1, 9999]
assert_eq!(
    date.with_year(10000),
    Err(DateError::InvalidDate)
);


// --- Error Case: Starting date is invalid ---
// Create an invalid date unsafely (e.g., invalid month 13)
let invalid_start = unsafe { ParsiDate::new_unchecked(1400, 13, 1) };
// Trying to change the year of an invalid date should fail validation
assert_eq!(
    invalid_start.with_year(1401),
    Err(DateError::InvalidDate) // Original date is invalid
);