usecrate::calendar_arithmetic::ArithmeticDate; usecrate::calendar_arithmetic::DateFieldsResolver; usecrate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; usecrate::options::DateFromFieldsOptions; usecrate::options::{DateAddOptions, DateDifferenceOptions}; usecrate::types::DateFields; usecrate::{types, Calendar, Date, RangeError}; use ::tinystr::tinystr; use calendrical_calculations::helpers::I32CastError; use calendrical_calculations::rata_die::RataDie;
/// The [Persian Calendar](https://en.wikipedia.org/wiki/Solar_Hijri_calendar) /// /// The Persian Calendar is a solar calendar used officially by the countries of Iran and /// Afghanistan and many Persian-speaking regions. /// /// This implementation extends proleptically for dates before the calendar's creation /// in 458 AP (1079 CE). /// /// This corresponds to the `"persian"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// # Era codes /// /// This calendar uses a single era code `ap`, with Anno Persico/Anno Persarum starting the year of the Hijra. Dates before this era use negative years. /// /// # Months and days /// /// The 12 months are called Farvardin (`M01`, 31 days), Ordibehesht (`M02`, 31 days), /// Khordad (`M03`, 31 days), Tir (`M04`, 31 days), Mordad (`M05`, 31 days), Shahrivar (`M06`, 31 days), /// Mehr (`M07`, 30 days), Aban (`M08`, 30 days), Azar (`M09`, 30 days), /// Dey (`M10`, 30 days), Bahman (`M11`, 30 days), Esfand (`M12`, 29 days). /// /// In leap years (determined astronomically with respect to the vernal equinox), Esfand gains a 30th day. /// /// Standard years thus have 365 days, and leap years 366. /// /// # Calendar drift /// /// As leap years are determined with respect to the solar year, this calendar stays anchored /// to the seasons. #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord)] #[allow(clippy::exhaustive_structs)] pubstruct Persian;
/// The inner date type used for representing [`Date`]s of [`Persian`]. See [`Date`] and [`Persian`] for more details. pubstruct PersianDateInner(ArithmeticDate<Persian>);
impl DateFieldsResolver for Persian { type YearInfo = i32;
#[inline] fn reference_year_from_month_day(
&self,
month_code: types::ValidMonthCode,
day: u8,
) -> Result<Self::YearInfo, EcmaReferenceYearError> { let (ordinal_month, false) = month_code.to_tuple() else { return Err(EcmaReferenceYearError::MonthCodeNotInCalendar);
}; // December 31, 1972 occurs on 10th month, 10th day, 1351 AP let persian_year = if ordinal_month < 10 || (ordinal_month == 10 && day <= 10) { 1351
} else { // Note: 1350 is a leap year 1350
};
Ok(persian_year)
}
}
implcrate::cal::scaffold::UnstableSealed for Persian {} impl Calendar for Persian { type DateInner = PersianDateInner; type Year = types::EraYear; type DifferenceError = core::convert::Infallible;
// Test data are provided for the range 1178-3000 AP, for which // we know the 33-year rule, with the override table, matches the // astronomical calculations based on the 52.5 degrees east meridian. static CASES: [DateCase; 21] = [ // First year for which 33-year rule matches the astronomical calculation
DateCase {
year: 1178,
month: 1,
day: 1,
},
DateCase {
year: 1198,
month: 5,
day: 10,
},
DateCase {
year: 1218,
month: 1,
day: 7,
},
DateCase {
year: 1282,
month: 1,
day: 29,
}, // The beginning of the year the calendar was adopted
DateCase {
year: 1304,
month: 1,
day: 1,
},
DateCase {
year: 1308,
month: 6,
day: 3,
},
DateCase {
year: 1320,
month: 7,
day: 7,
},
DateCase {
year: 1322,
month: 1,
day: 29,
},
DateCase {
year: 1322,
month: 7,
day: 14,
},
DateCase {
year: 1370,
month: 12,
day: 27,
},
DateCase {
year: 1374,
month: 12,
day: 6,
}, // First day that the 2820-year rule fails
DateCase {
year: 1403,
month: 12,
day: 30,
}, // First Nowruz that the 2820-year rule fails
DateCase {
year: 1404,
month: 1,
day: 1,
},
DateCase {
year: 1417,
month: 8,
day: 19,
}, // First day the unmodified astronomical algorithm fails
DateCase {
year: 1469,
month: 12,
day: 30,
}, // First Nowruz the unmodified astronomical algorithm fails
DateCase {
year: 1470,
month: 1,
day: 1,
},
DateCase {
year: 1473,
month: 4,
day: 28,
}, // Last year the 33-year rule matches the modified astronomical calculation
DateCase {
year: 1501,
month: 12,
day: 29,
},
DateCase {
year: 1502,
month: 12,
day: 29,
},
DateCase {
year: 1503,
month: 1,
day: 1,
},
DateCase {
year: 2988,
month: 1,
day: 1,
},
];
#[test] fn test_persian_leap_year() { letmut leap_years: [i32; 21] = [0; 21]; // These values were computed from the "Calendrical Calculations" reference code output let expected_values = [ false, false, true, false, true, false, false, false, false, true, false, true, false, false, true, false, false, false, false, true, true,
];
for (index, case) in CASES.iter().enumerate() {
leap_years[index] = case.year;
} for (&year, &is_leap) in leap_years.iter().zip(expected_values.iter()) {
assert_eq!(
Date::try_new_persian(year, 1, 1).unwrap().is_in_leap_year(),
is_leap
);
}
}
#[test] fn days_in_provided_year_test() { for case in CASES.iter() {
assert_eq!(
Date::try_new_persian(case.year, 1, 1)
.unwrap()
.days_in_year(),
(calendrical_calculations::persian::fixed_from_fast_persian(case.year + 1, 1, 1)
- calendrical_calculations::persian::fixed_from_fast_persian(case.year, 1, 1)) as u16
);
}
}
#[test] fn test_rd_from_persian() { for (case, f_date) in CASES.iter().zip(TEST_RD.iter()) { let date = Date::try_new_persian(case.year, case.month, case.day).unwrap();
assert_eq!(date.to_rata_die().to_i64_date(), *f_date, "{case:?}");
}
} #[test] fn test_persian_from_rd() { for (case, f_date) in CASES.iter().zip(TEST_RD.iter()) { let date = Date::try_new_persian(case.year, case.month, case.day).unwrap();
assert_eq!(
Persian.from_rata_die(RataDie::new(*f_date)),
date.inner, "{case:?}"
);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.