Sub Duration (ParsiDateTime) - parsicore/parsidate GitHub Wiki

Method sub_duration (on ParsiDateTime)

Subtracts a chrono::Duration from this ParsiDateTime, returning a new ParsiDateTime.

Description

This method calculates a new ParsiDateTime by subtracting a specified chrono::Duration from the current instance. It correctly handles both date and time adjustments, including rollovers across seconds, minutes, hours, and days.

It functions as a convenience method, equivalent to calling add_duration with the duration negated (i.e., self.add_duration(-duration)). The underlying calculation typically involves conversions to/from chrono::NaiveDateTime to leverage chrono's robust duration arithmetic.

Arguments

  • duration: The chrono::Duration to subtract. Note that Duration itself can be negative, so subtracting a negative duration is equivalent to adding a positive one.

Returns

  • Ok(ParsiDateTime): If the starting ParsiDateTime is valid, the conversions succeed, and the arithmetic results in a valid ParsiDateTime within the supported range, returns the new ParsiDateTime wrapped in Ok.
  • Err(DateError::...): Returns an error under the same conditions as the add_duration method. This includes:
    • DateError::InvalidDate / DateError::InvalidTime: If the starting ParsiDateTime is invalid.
    • DateError::GregorianConversionError: If intermediate conversions to/from Gregorian fail.
    • DateError::ArithmeticOverflow: If the resulting date/time falls outside the supported range of chrono or ParsiDateTime.

Examples (Rust)

use parsidate::{ParsiDateTime, ParsiDate, DateError};
use chrono::Duration; // Make sure chrono is a dependency

// Example 1: Subtracting seconds that cross midnight backwards
let dt = ParsiDateTime::new(1403, 1, 1, 0, 0, 5).unwrap(); // Farvardin 1st, 5 seconds past midnight

// Subtract 10 seconds
let dt_prev_day_result = dt.sub_duration(Duration::seconds(10));
assert!(dt_prev_day_result.is_ok());
let dt_prev_day = dt_prev_day_result.unwrap();

// Expected: Goes back to the last second of the previous day.
// Previous day: 1402-12-29 (since 1403 is leap, 1402 is common, Esfand has 29 days).
// Time: 00:00:05 - 10s = wraps around to 23:59:55.
assert_eq!(dt_prev_day.date(), ParsiDate::new(1402, 12, 29).unwrap());
assert_eq!(dt_prev_day.time(), (23, 59, 55));


// Example 2: Subtracting hours
let dt2 = ParsiDateTime::new(1403, 5, 10, 2, 15, 0).unwrap(); // Mordad 10th, 02:15:00
// Subtract 4 hours
let dt_minus_4h = dt2.sub_duration(Duration::hours(4));
assert!(dt_minus_4h.is_ok());
let dt_minus_4h_unwrapped = dt_minus_4h.unwrap();
// Expected: Date goes back to Mordad 9th. Time wraps around (02:15 - 4h = -01:45 -> 22:15 prev day)
assert_eq!(dt_minus_4h_unwrapped.date(), ParsiDate::new(1403, 5, 9).unwrap());
assert_eq!(dt_minus_4h_unwrapped.time(), (22, 15, 0));


// Example 3: 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.sub_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)));