Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  persian.rs

  Sprache: Rust
 

// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

use crate::calendar_arithmetic::ArithmeticDate;
use crate::calendar_arithmetic::DateFieldsResolver;
use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError};
use crate::options::DateFromFieldsOptions;
use crate::options::{DateAddOptions, DateDifferenceOptions};
use crate::types::DateFields;
use crate::{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)]
pub struct Persian;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]

/// The inner date type used for representing [`Date`]s of [`Persian`]. See [`Date`] and [`Persian`] for more details.
pub struct PersianDateInner(ArithmeticDate<Persian>);

impl DateFieldsResolver for Persian {
    type YearInfo = i32;

    fn days_in_provided_month(year: i32, month: u8) -> u8 {
        match month {
            1..=6 => 31,
            7..=11 => 30,
            12 if calendrical_calculations::persian::is_leap_year(year) => 30,
            12 => 29,
            _ => 0,
        }
    }

    fn months_in_provided_year(_: i32) -> u8 {
        12
    }

    #[inline]
    fn year_info_from_era(
        &self,
        era: &[u8],
        era_year: i32,
    ) -> Result<Self::YearInfo, UnknownEraError> {
        match era {
            b"ap" => Ok(era_year),
            _ => Err(UnknownEraError),
        }
    }

    #[inline]
    fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo {
        extended_year
    }

    #[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)
    }
}

impl crate::cal::scaffold::UnstableSealed for Persian {}
impl Calendar for Persian {
    type DateInner = PersianDateInner;
    type Year = types::EraYear;
    type DifferenceError = core::convert::Infallible;

    fn from_codes(
        &self,
        era: Option<&str>,
        year: i32,
        month_code: types::MonthCode,
        day: u8,
    ) -> Result<Self::DateInner, DateError> {
        ArithmeticDate::from_codes(era, year, month_code, day, self).map(PersianDateInner)
    }

    #[cfg(feature = "unstable")]
    fn from_fields(
        &self,
        fields: DateFields,
        options: DateFromFieldsOptions,
    ) -> Result<Self::DateInner, DateFromFieldsError> {
        ArithmeticDate::from_fields(fields, options, self).map(PersianDateInner)
    }

    fn from_rata_die(&self, rd: RataDie) -> Self::DateInner {
        PersianDateInner(
            match calendrical_calculations::persian::fast_persian_from_fixed(rd) {
                Err(I32CastError::BelowMin) => ArithmeticDate::new_unchecked(i32::MIN, 11),
                Err(I32CastError::AboveMax) => ArithmeticDate::new_unchecked(i32::MAX, 1229),
                Ok((year, month, day)) => ArithmeticDate::new_unchecked(year, month, day),
            },
        )
    }

    fn to_rata_die(&self, date: &Self::DateInner) -> RataDie {
        calendrical_calculations::persian::fixed_from_fast_persian(
            date.0.year,
            date.0.month,
            date.0.day,
        )
    }

    fn has_cheap_iso_conversion(&self) -> bool {
        false
    }

    fn months_in_year(&self, date: &Self::DateInner) -> u8 {
        Self::months_in_provided_year(date.0.year)
    }

    fn days_in_year(&self, date: &Self::DateInner) -> u16 {
        if self.is_in_leap_year(date) {
            366
        } else {
            365
        }
    }

    fn days_in_month(&self, date: &Self::DateInner) -> u8 {
        Self::days_in_provided_month(date.0.year, date.0.month)
    }

    #[cfg(feature = "unstable")]
    fn add(
        &self,
        date: &Self::DateInner,
        duration: types::DateDuration,
        options: DateAddOptions,
    ) -> Result<Self::DateInner, DateError> {
        date.0.added(duration, self, options).map(PersianDateInner)
    }

    #[cfg(feature = "unstable")]
    fn until(
        &self,
        date1: &Self::DateInner,
        date2: &Self::DateInner,
        options: DateDifferenceOptions,
    ) -> Result<types::DateDuration, Self::DifferenceError> {
        Ok(date1.0.until(&date2.0self, options))
    }

    fn year_info(&self, date: &Self::DateInner) -> Self::Year {
        let extended_year = date.0.year;
        types::EraYear {
            era: tinystr!(16"ap"),
            era_index: Some(0),
            year: extended_year,
            extended_year,
            ambiguity: types::YearAmbiguity::CenturyRequired,
        }
    }

    fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
        calendrical_calculations::persian::is_leap_year(date.0.year)
    }

    fn month(&self, date: &Self::DateInner) -> types::MonthInfo {
        types::MonthInfo::non_lunisolar(date.0.month)
    }

    fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
        types::DayOfMonth(date.0.day)
    }

    fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear {
        types::DayOfYear(
            (date.0.month as u16 - 1) * 31 - (date.0.month as u16 - 1).saturating_sub(6)
                + date.0.day as u16,
        )
    }

    fn debug_name(&self) -> &'static str {
        "Persian"
    }

    fn calendar_algorithm(&self) -> Option<crate::preferences::CalendarAlgorithm> {
        Some(crate::preferences::CalendarAlgorithm::Persian)
    }
}

impl Persian {
    /// Constructs a new Persian Calendar
    pub fn new() -> Self {
        Self
    }
}

impl Date<Persian> {
    /// Construct new Persian Date.
    ///
    /// Has no negative years, only era is the AH/AP.
    ///
    /// ```rust
    /// use icu::calendar::Date;
    ///
    /// let date_persian = Date::try_new_persian(1392, 4, 25)
    ///     .expect("Failed to initialize Persian Date instance.");
    ///
    /// assert_eq!(date_persian.era_year().year, 1392);
    /// assert_eq!(date_persian.month().ordinal, 4);
    /// assert_eq!(date_persian.day_of_month().0, 25);
    /// ```
    pub fn try_new_persian(year: i32, month: u8, day: u8) -> Result<Date<Persian>, RangeError> {
        ArithmeticDate::try_from_ymd(year, month, day)
            .map(PersianDateInner)
            .map(|inner| Date::from_raw(inner, Persian))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[derive(Debug)]
    struct DateCase {
        year: i32,
        month: u8,
        day: u8,
    }

    static TEST_RD: [i64; 21] = [
        656786664224671401694799702806704424708842709409709580727274728714,
        7393307393317443137634367634377646527751237754887754891317874,
    ];

    // 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() {
        let mut leap_years: [i32; 21] = [021];
        // These values were computed from the "Calendrical Calculations" reference code output
        let expected_values = [
            falsefalsetruefalsetruefalsefalsefalsefalsetruefalsetruefalse,
            falsetruefalsefalsefalsefalsetruetrue,
        ];

        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, 11).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, 11)
                    .unwrap()
                    .days_in_year(),
                (calendrical_calculations::persian::fixed_from_fast_persian(case.year + 111)
                    - calendrical_calculations::persian::fixed_from_fast_persian(case.year, 11))
                    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:?}"
            );
        }
    }

    // From https://calendar.ut.ac.ir/Fa/News/Data/Doc/KabiseShamsi1206-1498-new.pdf
    // Plain text version at https://github.com/roozbehp/persiancalendar/blob/main/kabise.txt
    static CALENDAR_UT_AC_IR_TEST_DATA: [(i32, bool, i32, u8, u8); 293] = [
        (1206false1827322),
        (1207false1828321),
        (1208false1829321),
        (1209false1830321),
        (1210true1831321),
        (1211false1832321),
        (1212false1833321),
        (1213false1834321),
        (1214true1835321),
        (1215false1836321),
        (1216false1837321),
        (1217false1838321),
        (1218true1839321),
        (1219false1840321),
        (1220false1841321),
        (1221false1842321),
        (1222true1843321),
        (1223false1844321),
        (1224false1845321),
        (1225false1846321),
        (1226true1847321),
        (1227false1848321),
        (1228false1849321),
        (1229false1850321),
        (1230true1851321),
        (1231false1852321),
        (1232false1853321),
        (1233false1854321),
        (1234true1855321),
        (1235false1856321),
        (1236false1857321),
        (1237false1858321),
        (1238true1859321),
        (1239false1860321),
        (1240false1861321),
        (1241false1862321),
        (1242false1863321),
        (1243true1864320),
        (1244false1865321),
        (1245false1866321),
        (1246false1867321),
        (1247true1868320),
        (1248false1869321),
        (1249false1870321),
        (1250false1871321),
        (1251true1872320),
        (1252false1873321),
        (1253false1874321),
        (1254false1875321),
        (1255true1876320),
        (1256false1877321),
        (1257false1878321),
        (1258false1879321),
        (1259true1880320),
        (1260false1881321),
        (1261false1882321),
        (1262false1883321),
        (1263true1884320),
        (1264false1885321),
        (1265false1886321),
        (1266false1887321),
        (1267true1888320),
        (1268false1889321),
        (1269false1890321),
        (1270false1891321),
        (1271true1892320),
        (1272false1893321),
        (1273false1894321),
        (1274false1895321),
        (1275false1896320),
        (1276true1897320),
        (1277false1898321),
        (1278false1899321),
        (1279false1900321),
        (1280true1901321),
        (1281false1902322),
        (1282false1903322),
        (1283false1904321),
        (1284true1905321),
        (1285false1906322),
        (1286false1907322),
        (1287false1908321),
        (1288true1909321),
        (1289false1910322),
        (1290false1911322),
        (1291false1912321),
        (1292true1913321),
        (1293false1914322),
        (1294false1915322),
        (1295false1916321),
        (1296true1917321),
        (1297false1918322),
        (1298false1919322),
        (1299false1920321),
        (1300true1921321),
        (1301false1922322),
        (1302false1923322),
        (1303false1924321),
        (1304true1925321),
        (1305false1926322),
        (1306false1927322),
        (1307false1928321),
        (1308false1929321),
        (1309true1930321),
        (1310false1931322),
        (1311false1932321),
        (1312false1933321),
        (1313true1934321),
        (1314false1935322),
        (1315false1936321),
        (1316false1937321),
        (1317true1938321),
        (1318false1939322),
        (1319false1940321),
        (1320false1941321),
        (1321true1942321),
        (1322false1943322),
        (1323false1944321),
        (1324false1945321),
        (1325true1946321),
        (1326false1947322),
        (1327false1948321),
        (1328false1949321),
        (1329true1950321),
        (1330false1951322),
        (1331false1952321),
        (1332false1953321),
        (1333true1954321),
        (1334false1955322),
        (1335false1956321),
        (1336false1957321),
        (1337true1958321),
        (1338false1959322),
        (1339false1960321),
        (1340false1961321),
        (1341false1962321),
        (1342true1963321),
        (1343false1964321),
        (1344false1965321),
        (1345false1966321),
        (1346true1967321),
        (1347false1968321),
        (1348false1969321),
        (1349false1970321),
        (1350true1971321),
        (1351false1972321),
        (1352false1973321),
        (1353false1974321),
        (1354true1975321),
        (1355false1976321),
        (1356false1977321),
        (1357false1978321),
        (1358true1979321),
        (1359false1980321),
        (1360false1981321),
        (1361false1982321),
        (1362true1983321),
        (1363false1984321),
        (1364false1985321),
        (1365false1986321),
        (1366true1987321),
        (1367false1988321),
        (1368false1989321),
        (1369false1990321),
        (1370true1991321),
        (1371false1992321),
        (1372false1993321),
        (1373false1994321),
        (1374false1995321),
        (1375true1996320),
        (1376false1997321),
        (1377false1998321),
        (1378false1999321),
        (1379true2000320),
        (1380false2001321),
        (1381false2002321),
        (1382false2003321),
        (1383true2004320),
        (1384false2005321),
        (1385false2006321),
        (1386false2007321),
        (1387true2008320),
        (1388false2009321),
        (1389false2010321),
        (1390false2011321),
        (1391true2012320),
        (1392false2013321),
        (1393false2014321),
        (1394false2015321),
        (1395true2016320),
        (1396false2017321),
        (1397false2018321),
        (1398false2019321),
        (1399true2020320),
        (1400false2021321),
        (1401false2022321),
        (1402false2023321),
        (1403true2024320),
        (1404false2025321),
        (1405false2026321),
        (1406false2027321),
        (1407false2028320),
        (1408true2029320),
        (1409false2030321),
        (1410false2031321),
        (1411false2032320),
        (1412true2033320),
        (1413false2034321),
        (1414false2035321),
        (1415false2036320),
        (1416true2037320),
        (1417false2038321),
        (1418false2039321),
        (1419false2040320),
        (1420true2041320),
        (1421false2042321),
        (1422false2043321),
        (1423false2044320),
        (1424true2045320),
        (1425false2046321),
        (1426false2047321),
        (1427false2048320),
        (1428true2049320),
        (1429false2050321),
        (1430false2051321),
        (1431false2052320),
        (1432true2053320),
        (1433false2054321),
        (1434false2055321),
        (1435false2056320),
        (1436true2057320),
        (1437false2058321),
        (1438false2059321),
        (1439false2060320),
        (1440false2061320),
        (1441true2062320),
        (1442false2063321),
        (1443false2064320),
        (1444false2065320),
        (1445true2066320),
        (1446false2067321),
        (1447false2068320),
        (1448false2069320),
        (1449true2070320),
        (1450false2071321),
        (1451false2072320),
        (1452false2073320),
        (1453true2074320),
        (1454false2075321),
        (1455false2076320),
        (1456false2077320),
        (1457true2078320),
        (1458false2079321),
        (1459false2080320),
        (1460false2081320),
        (1461true2082320),
        (1462false2083321),
        (1463false2084320),
        (1464false2085320),
        (1465true2086320),
        (1466false2087321),
        (1467false2088320),
        (1468false2089320),
        (1469true2090320),
        (1470false2091321),
        (1471false2092320),
        (1472false2093320),
        (1473false2094320),
        (1474true2095320),
        (1475false2096320),
        (1476false2097320),
        (1477false2098320),
        (1478true2099320),
        (1479false2100321),
        (1480false2101321),
        (1481false2102321),
        (1482true2103321),
        (1483false2104321),
        (1484false2105321),
        (1485false2106321),
        (1486true2107321),
        (1487false2108321),
        (1488false2109321),
        (1489false2110321),
        (1490true2111321),
        (1491false2112321),
        (1492false2113321),
        (1493false2114321),
        (1494true2115321),
        (1495false2116321),
        (1496false2117321),
        (1497false2118321),
        (1498true2119321),
    ];

    #[test]
    fn test_calendar_ut_ac_ir_data() {
        for &(p_year, leap, iso_year, iso_month, iso_day) in CALENDAR_UT_AC_IR_TEST_DATA.iter() {
            let persian_date = Date::try_new_persian(p_year, 11).unwrap();
            assert_eq!(persian_date.is_in_leap_year(), leap);
            let iso_date = persian_date.to_iso();
            assert_eq!(iso_date.era_year().year, iso_year);
            assert_eq!(iso_date.month().ordinal, iso_month);
            assert_eq!(iso_date.day_of_month().0, iso_day);
        }
    }
}

Messung V0.5 in Prozent
C=89 H=100 G=94

¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002