Add Days - parsicore/parsidate GitHub Wiki

Method add_days (on ParsiDate)

Adds a specified number of days to this ParsiDate, returning a new ParsiDate instance representing the result.

Description

This method calculates a new date by adding a given number of days to the current ParsiDate instance (self). The operation correctly handles transitions across month and year boundaries, including accounting for Persian leap years (specifically the length of Esfand).

The calculation is performed robustly by:

  1. Converting the ParsiDate instance (self) into its equivalent chrono::NaiveDate (Gregorian date).
  2. Using chrono's date arithmetic to add the specified number of days to the NaiveDate. This handles Gregorian leap years and month lengths correctly.
  3. Converting the resulting chrono::NaiveDate back into a ParsiDate.

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

Arguments

  • days: The number of days to add to the current date (i64 or a similar signed integer type compatible with chrono::Duration::days).
    • 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 starting ParsiDate is valid, the intermediate Gregorian calculations succeed, and the final resulting date falls within the supported range of ParsiDate (typically years 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::GregorianConversionError): If the conversion from ParsiDate to chrono::NaiveDate, or the conversion back from the calculated chrono::NaiveDate to ParsiDate, fails. This is generally unlikely for valid dates within the typical supported range but could occur in edge cases or if the underlying conversion logic encounters an unexpected issue.
  • Err(DateError::ArithmeticOverflow): If adding the days results in a chrono::NaiveDate that falls outside the representable range of chrono itself (very large positive or negative dates), or if the final calculated date, when converted back to ParsiDate, falls outside the supported year range (e.g., year 0 or year 10000+).

Examples (Rust)

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

// --- Basic Addition ---
let date = ParsiDate::new(1403, 12, 28).unwrap(); // 1403 is a leap year in Persian calendar

// Add days within the same month (Esfand, which has 30 days in 1403)
assert_eq!(date.add_days(1), Ok(ParsiDate::new(1403, 12, 29).unwrap()));
assert_eq!(date.add_days(2), Ok(ParsiDate::new(1403, 12, 30).unwrap())); // Hit the leap day

// Add days to cross into the next year (1404 is not a leap year)
assert_eq!(date.add_days(3), Ok(ParsiDate::new(1404, 1, 1).unwrap())); // From 1403/12/30 to 1404/01/01
assert_eq!(date.add_days(10), Ok(ParsiDate::new(1404, 1, 8).unwrap())); // 1403/12/28 + 10 days = 1404/01/08

// Add zero days
assert_eq!(date.add_days(0), Ok(ParsiDate::new(1403, 12, 28).unwrap()));


// --- Subtraction (Negative Days) ---
let date_start_of_1404 = ParsiDate::new(1404, 1, 1).unwrap();

// Subtract days to cross back into the previous year (1403 leap year)
assert_eq!(date_start_of_1404.add_days(-1), Ok(ParsiDate::new(1403, 12, 30).unwrap())); // Back to the leap day
assert_eq!(date_start_of_1404.add_days(-2), Ok(ParsiDate::new(1403, 12, 29).unwrap()));

// Subtract exactly one leap year's worth of days (366 for 1403)
assert_eq!(date_start_of_1404.add_days(-366), Ok(ParsiDate::new(1403, 1, 1).unwrap()));


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

// Try to subtract days to go before the supported year 1
let result_before_epoch = earliest_date.add_days(-1);
assert!(result_before_epoch.is_err());
// The specific error might be ArithmeticOverflow or GregorianConversionError depending on implementation details
// assert_eq!(result_before_epoch, Err(DateError::ArithmeticOverflow)); // Example assertion

// Try to add days resulting in a year beyond the supported range (e.g., > 9999)
// let latest_date = ParsiDate::new(9999, 10, 1).unwrap();
// let result_too_far = latest_date.add_days(365 * 2); // Add 2 years
// assert!(result_too_far.is_err());
// assert_eq!(result_too_far, Err(DateError::ArithmeticOverflow)); // Example assertion