Add Duration (ParsiDateTime) - jalalvandi/ParsiDate GitHub Wiki
add_duration
(on ParsiDateTime)
Method Adds a chrono::Duration
to this ParsiDateTime
, returning a new ParsiDateTime
.
Description
This method calculates a new ParsiDateTime
by adding a specified chrono::Duration
to the current instance. It handles both date and time adjustments, including rollovers across seconds, minutes, hours, and days, leveraging the robust arithmetic capabilities of the chrono
library.
The operation follows these steps:
- Validates the starting
ParsiDateTime
instance. - Converts the
ParsiDateTime
to its equivalent Gregorianchrono::NaiveDateTime
. - Adds the provided
chrono::Duration
to thechrono::NaiveDateTime
. - Converts the resulting
chrono::NaiveDateTime
back to aParsiDateTime
.
This conversion strategy ensures accurate handling of complex time arithmetic across calendar systems.
Arguments
duration
: Thechrono::Duration
to add. This can be positive to move time forward or negative to move time backward. It can represent durations from nanoseconds up to days or weeks (though typically used for sub-day durations when combined withadd_days
).
Returns
Ok(ParsiDateTime)
: If the startingParsiDateTime
is valid, the conversions succeed, and the arithmetic results in a validParsiDateTime
within the supported range, returns the newParsiDateTime
wrapped inOk
.Err(DateError::...)
: Returns an error if any step fails:DateError::InvalidDate
orDateError::InvalidTime
: If the startingParsiDateTime
instance (self
) fails its internal validity check.DateError::GregorianConversionError
: If either the initial conversion tochrono::NaiveDateTime
or the final conversion back toParsiDateTime
fails (e.g., due to dates outside supported epochs).DateError::ArithmeticOverflow
: If the addition of theduration
results in achrono::NaiveDateTime
outside the range supported bychrono
, or if the final convertedParsiDateTime
falls outside the library's supported year range [1, 9999].
Examples (Rust)
use parsidate::{ParsiDateTime, ParsiDate, DateError};
use chrono::Duration; // Make sure chrono is a dependency
// Example 1: Adding seconds that cross midnight
let dt1 = ParsiDateTime::new(1403, 1, 1, 23, 59, 58).unwrap(); // Near end of Farvardin 1st
// Add 3 seconds
let dt_next_day = dt1.add_duration(Duration::seconds(3));
assert!(dt_next_day.is_ok());
let dt_next_day_unwrapped = dt_next_day.unwrap();
// Date should advance to Farvardin 2nd
assert_eq!(dt_next_day_unwrapped.date(), ParsiDate::new(1403, 1, 2).unwrap());
// Time should roll over to 00:00:01
assert_eq!(dt_next_day_unwrapped.hour(), 0);
assert_eq!(dt_next_day_unwrapped.minute(), 0);
assert_eq!(dt_next_day_unwrapped.second(), 1);
// Example 2: Adding hours that cross midnight and advance the day
let dt2 = ParsiDateTime::new(1403, 5, 10, 22, 30, 0).unwrap(); // Mordad 10th, 22:30:00
// Add 4 hours
let dt_plus_4h = dt2.add_duration(Duration::hours(4));
assert!(dt_plus_4h.is_ok());
let dt_plus_4h_unwrapped = dt_plus_4h.unwrap();
// Date should advance to Mordad 11th
assert_eq!(dt_plus_4h_unwrapped.date(), ParsiDate::new(1403, 5, 11).unwrap());
// Time should be 02:30:00 (22:30 + 4h = 26:30 -> 02:30 next day)
assert_eq!(dt_plus_4h_unwrapped.hour(), 2);
assert_eq!(dt_plus_4h_unwrapped.minute(), 30);
assert_eq!(dt_plus_4h_unwrapped.second(), 0);
// Example 3: Adding a larger duration (25 hours)
let dt3 = ParsiDateTime::new(1403, 1, 1, 23, 59, 58).unwrap(); // Use dt1 again for comparison
// Add 25 hours (1 day + 1 hour)
let dt_plus_25h = dt3.add_duration(Duration::hours(25));
assert!(dt_plus_25h.is_ok());
let dt_plus_25h_unwrapped = dt_plus_25h.unwrap();
// Date should advance by 1 day (to Farvardin 2nd) PLUS the day rollover from the time part. -> Farvardin 3rd
assert_eq!(dt_plus_25h_unwrapped.date(), ParsiDate::new(1403, 1, 3).unwrap());
// Time should be 23:59:58 + 1 hour -> 00:59:58
assert_eq!(dt_plus_25h_unwrapped.hour(), 0);
assert_eq!(dt_plus_25h_unwrapped.minute(), 59);
assert_eq!(dt_plus_25h_unwrapped.second(), 58);
// Example 4: Subtracting a duration
let dt4 = ParsiDateTime::new(1403, 1, 2, 0, 0, 5).unwrap(); // Farvardin 2nd, 00:00:05
// Subtract 10 seconds
let dt_minus_10s = dt4.add_duration(Duration::seconds(-10));
assert!(dt_minus_10s.is_ok());
let dt_minus_10s_unwrapped = dt_minus_10s.unwrap();
// Date should go back to Farvardin 1st
assert_eq!(dt_minus_10s_unwrapped.date(), ParsiDate::new(1403, 1, 1).unwrap());
// Time should be 23:59:55 (00:00:05 - 10s)
assert_eq!(dt_minus_10s_unwrapped.hour(), 23);
assert_eq!(dt_minus_10s_unwrapped.minute(), 59);
assert_eq!(dt_minus_10s_unwrapped.second(), 55);
// Example 5: Error case (potential) - subtracting large duration
let earliest_dt = ParsiDateTime::new(1, 1, 1, 0, 0, 0).unwrap();
let very_long_ago = Duration::days(-500 * 365); // Approx 500 years
let result = earliest_dt.add_duration(very_long_ago);
// This will likely fail due to going before the supported epoch
assert!(result.is_err());
// assert!(matches!(result, Err(DateError::GregorianConversionError) | Err(DateError::ArithmeticOverflow)));