To Gregorian - jalalvandi/ParsiDate GitHub Wiki
to_gregorian
Method Converts this Persian (Jalali) ParsiDate
instance to its equivalent Gregorian date represented by chrono::NaiveDate
.
Description
This method performs a conversion from the Persian (Hejri-Shamsi or Jalali) calendar system to the widely used Gregorian calendar system.
The process typically involves these steps:
- Validation: The method first checks if the current
ParsiDate
instance (self
) represents a valid date using its internalis_valid()
check. This guards against attempting conversion on potentially inconsistent data (e.g., created viaunsafe ParsiDate::new_unchecked
). - Conversion Algorithm: If the
ParsiDate
is valid, it proceeds with the conversion. A common algorithm involves calculating the total number of days that have elapsed since the defined epoch start of the Persian calendar (usually considered Farvardin 1st of year 1, corresponding to March 21st, 622 CE in the Julian calendar, often adjusted slightly for Gregorian). This day count (or an equivalent like a Julian Day Number) is then used as a basis to calculate the corresponding year, month, and day in the Gregorian calendar, often leveraging functionalities provided by thechrono
library itself.
The result is returned as a chrono::NaiveDate
, which represents a Gregorian date without any timezone information.
Returns
Ok(chrono::NaiveDate)
: If theParsiDate
is valid and the conversion is successful, returns the equivalent Gregorian date wrapped inOk
.Err(DateError::InvalidDate)
: If theParsiDate
instance (self
) fails the initialis_valid()
check (e.g., it contains month 0, day 32, or represents an impossible date like Esfand 30th in a common year, potentially created viaunsafe
).Err(DateError::GregorianConversionError)
: If the conversion calculation itself encounters an error after the initial validation passes. This is generally rare for dates within the supportedParsiDate
range but could theoretically occur due to:- Internal arithmetic overflows during the day count calculation (extremely unlikely with standard integer types for the supported year range).
- The calculated Gregorian date falling outside the range supported by
chrono::NaiveDate
(also highly unlikely ifParsiDate
's supported range is reasonable).
Examples (Rust)
use chrono::NaiveDate;
use parsidate::{ParsiDate, DateError}; // Assuming these types exist
// --- Successful Conversions ---
// Example 1: Convert a standard Persian date
let pd1 = ParsiDate::new(1403, 5, 2).unwrap(); // 2nd Mordad, 1403
// Expected Gregorian equivalent: July 23, 2024
let expected_g1 = NaiveDate::from_ymd_opt(2024, 7, 23).unwrap();
assert_eq!(pd1.to_gregorian(), Ok(expected_g1));
// Example 2: Convert the conventional start of the Persian epoch
let pd_epoch = ParsiDate::new(1, 1, 1).unwrap(); // 1st Farvardin, 1
// Expected Gregorian equivalent: March 21, 622 (Proleptic Gregorian)
// Note: The exact Gregorian date for the Hejri Shamsi epoch can vary slightly
// depending on the specific astronomical vs. algorithmic definition used.
// 622-03-21 is a common computational reference point.
let expected_epoch_gregorian = NaiveDate::from_ymd_opt(622, 3, 21).unwrap();
assert_eq!(pd_epoch.to_gregorian(), Ok(expected_epoch_gregorian));
// Example 3: Convert the last day of a Persian leap year
let pd_leap_end = ParsiDate::new(1403, 12, 30).unwrap(); // 30th Esfand, 1403 (leap year)
// Expected Gregorian equivalent: March 20, 2025
let expected_g_leap_end = NaiveDate::from_ymd_opt(2025, 3, 20).unwrap();
assert_eq!(pd_leap_end.to_gregorian(), Ok(expected_g_leap_end));
// Example 4: Convert the last day of a Persian common year
let pd_common_end = ParsiDate::new(1404, 12, 29).unwrap(); // 29th Esfand, 1404 (common year)
// Expected Gregorian equivalent: March 20, 2026
let expected_g_common_end = NaiveDate::from_ymd_opt(2026, 3, 20).unwrap();
assert_eq!(pd_common_end.to_gregorian(), Ok(expected_g_common_end));
// --- Error Case: Invalid Source Date ---
// Create an invalid ParsiDate (Esfand 30th in a common year 1404) unsafely
let invalid_pd = unsafe { ParsiDate::new_unchecked(1404, 12, 30) };
// Calling to_gregorian should detect the invalidity first
let result = invalid_pd.to_gregorian();
assert!(result.is_err());
assert_eq!(result, Err(DateError::InvalidDate));