icu_calendar/cal/
persian.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5//! This module contains types and implementations for the Persian calendar.
6//!
7//! ```rust
8//! use icu::calendar::Date;
9//!
10//! let persian_date = Date::try_new_persian(1348, 10, 11)
11//!     .expect("Failed to initialize Persian Date instance.");
12//!
13//! assert_eq!(persian_date.era_year().year, 1348);
14//! assert_eq!(persian_date.month().ordinal, 10);
15//! assert_eq!(persian_date.day_of_month().0, 11);
16//! ```
17
18use crate::cal::iso::{Iso, IsoDateInner};
19use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic};
20use crate::error::DateError;
21use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError};
22use ::tinystr::tinystr;
23use calendrical_calculations::helpers::I32CastError;
24use calendrical_calculations::rata_die::RataDie;
25
26/// The [Persian Calendar](https://en.wikipedia.org/wiki/Solar_Hijri_calendar)
27///
28/// The Persian Calendar is a solar calendar used officially by the countries of Iran and Afghanistan and many Persian-speaking regions.
29/// It has 12 months and other similarities to the [`Gregorian`](super::Gregorian) Calendar.
30///
31/// This type can be used with [`Date`] to represent dates in this calendar.
32///
33/// # Era codes
34///
35/// This calendar uses a single era code `ap` (aliases `sh`, `hs`), with Anno Persico/Anno Persarum starting the year of the Hijra. Dates before this era use negative years.
36///
37/// # Month codes
38///
39/// This calendar supports 12 solar month codes (`"M01" - "M12"`)
40#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord)]
41#[allow(clippy::exhaustive_structs)]
42pub struct Persian;
43
44#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
45
46/// The inner date type used for representing [`Date`]s of [`Persian`]. See [`Date`] and [`Persian`] for more details.
47pub struct PersianDateInner(ArithmeticDate<Persian>);
48
49impl CalendarArithmetic for Persian {
50    type YearInfo = i32;
51
52    fn days_in_provided_month(year: i32, month: u8) -> u8 {
53        match month {
54            1..=6 => 31,
55            7..=11 => 30,
56            12 if Self::provided_year_is_leap(year) => 30,
57            12 => 29,
58            _ => 0,
59        }
60    }
61
62    fn months_in_provided_year(_: i32) -> u8 {
63        12
64    }
65
66    fn provided_year_is_leap(p_year: i32) -> bool {
67        calendrical_calculations::persian::is_leap_year(p_year)
68    }
69
70    fn days_in_provided_year(year: i32) -> u16 {
71        if Self::provided_year_is_leap(year) {
72            366
73        } else {
74            365
75        }
76    }
77
78    fn last_month_day_in_provided_year(year: i32) -> (u8, u8) {
79        if Self::provided_year_is_leap(year) {
80            (12, 30)
81        } else {
82            (12, 29)
83        }
84    }
85}
86
87impl crate::cal::scaffold::UnstableSealed for Persian {}
88impl Calendar for Persian {
89    type DateInner = PersianDateInner;
90    type Year = types::EraYear;
91
92    fn from_codes(
93        &self,
94        era: Option<&str>,
95        year: i32,
96        month_code: types::MonthCode,
97        day: u8,
98    ) -> Result<Self::DateInner, DateError> {
99        let year = match era {
100            Some("ap" | "sh" | "hs") | None => year,
101            Some(_) => return Err(DateError::UnknownEra),
102        };
103
104        ArithmeticDate::new_from_codes(self, year, month_code, day).map(PersianDateInner)
105    }
106
107    fn from_rata_die(&self, rd: RataDie) -> Self::DateInner {
108        PersianDateInner(
109            match calendrical_calculations::persian::fast_persian_from_fixed(rd) {
110                Err(I32CastError::BelowMin) => ArithmeticDate::min_date(),
111                Err(I32CastError::AboveMax) => ArithmeticDate::max_date(),
112                Ok((year, month, day)) => ArithmeticDate::new_unchecked(year, month, day),
113            },
114        )
115    }
116
117    fn to_rata_die(&self, date: &Self::DateInner) -> RataDie {
118        calendrical_calculations::persian::fixed_from_fast_persian(
119            date.0.year,
120            date.0.month,
121            date.0.day,
122        )
123    }
124
125    fn from_iso(&self, iso: IsoDateInner) -> PersianDateInner {
126        self.from_rata_die(Iso.to_rata_die(&iso))
127    }
128
129    fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner {
130        Iso.from_rata_die(self.to_rata_die(date))
131    }
132
133    fn months_in_year(&self, date: &Self::DateInner) -> u8 {
134        date.0.months_in_year()
135    }
136
137    fn days_in_year(&self, date: &Self::DateInner) -> u16 {
138        date.0.days_in_year()
139    }
140
141    fn days_in_month(&self, date: &Self::DateInner) -> u8 {
142        date.0.days_in_month()
143    }
144
145    fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) {
146        date.0.offset_date(offset, &())
147    }
148
149    #[allow(clippy::field_reassign_with_default)]
150    fn until(
151        &self,
152        date1: &Self::DateInner,
153        date2: &Self::DateInner,
154        _calendar2: &Self,
155        _largest_unit: DateDurationUnit,
156        _smallest_unit: DateDurationUnit,
157    ) -> DateDuration<Self> {
158        date1.0.until(date2.0, _largest_unit, _smallest_unit)
159    }
160
161    fn year_info(&self, date: &Self::DateInner) -> Self::Year {
162        types::EraYear {
163            era: tinystr!(16, "ap"),
164            era_index: Some(0),
165            year: self.extended_year(date),
166            ambiguity: types::YearAmbiguity::CenturyRequired,
167        }
168    }
169
170    fn extended_year(&self, date: &Self::DateInner) -> i32 {
171        date.0.extended_year()
172    }
173
174    fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
175        Self::provided_year_is_leap(date.0.year)
176    }
177
178    fn month(&self, date: &Self::DateInner) -> types::MonthInfo {
179        date.0.month()
180    }
181
182    fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
183        date.0.day_of_month()
184    }
185
186    fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear {
187        date.0.day_of_year()
188    }
189
190    fn debug_name(&self) -> &'static str {
191        "Persian"
192    }
193
194    fn calendar_algorithm(&self) -> Option<crate::preferences::CalendarAlgorithm> {
195        Some(crate::preferences::CalendarAlgorithm::Persian)
196    }
197}
198
199impl Persian {
200    /// Constructs a new Persian Calendar
201    pub fn new() -> Self {
202        Self
203    }
204}
205
206impl Date<Persian> {
207    /// Construct new Persian Date.
208    ///
209    /// Has no negative years, only era is the AH/AP.
210    ///
211    /// ```rust
212    /// use icu::calendar::Date;
213    ///
214    /// let date_persian = Date::try_new_persian(1392, 4, 25)
215    ///     .expect("Failed to initialize Persian Date instance.");
216    ///
217    /// assert_eq!(date_persian.era_year().year, 1392);
218    /// assert_eq!(date_persian.month().ordinal, 4);
219    /// assert_eq!(date_persian.day_of_month().0, 25);
220    /// ```
221    pub fn try_new_persian(year: i32, month: u8, day: u8) -> Result<Date<Persian>, RangeError> {
222        ArithmeticDate::new_from_ordinals(year, month, day)
223            .map(PersianDateInner)
224            .map(|inner| Date::from_raw(inner, Persian))
225    }
226}
227
228#[cfg(test)]
229mod tests {
230    use super::*;
231    #[derive(Debug)]
232    struct DateCase {
233        year: i32,
234        month: u8,
235        day: u8,
236    }
237
238    static TEST_RD: [i64; 21] = [
239        656786, 664224, 671401, 694799, 702806, 704424, 708842, 709409, 709580, 727274, 728714,
240        739330, 739331, 744313, 763436, 763437, 764652, 775123, 775488, 775489, 1317874,
241    ];
242
243    // Test data are provided for the range 1178-3000 AP, for which
244    // we know the 33-year rule, with the override table, matches the
245    // astronomical calculations based on the 52.5 degrees east meridian.
246    static CASES: [DateCase; 21] = [
247        // First year for which 33-year rule matches the astronomical calculation
248        DateCase {
249            year: 1178,
250            month: 1,
251            day: 1,
252        },
253        DateCase {
254            year: 1198,
255            month: 5,
256            day: 10,
257        },
258        DateCase {
259            year: 1218,
260            month: 1,
261            day: 7,
262        },
263        DateCase {
264            year: 1282,
265            month: 1,
266            day: 29,
267        },
268        // The beginning of the year the calendar was adopted
269        DateCase {
270            year: 1304,
271            month: 1,
272            day: 1,
273        },
274        DateCase {
275            year: 1308,
276            month: 6,
277            day: 3,
278        },
279        DateCase {
280            year: 1320,
281            month: 7,
282            day: 7,
283        },
284        DateCase {
285            year: 1322,
286            month: 1,
287            day: 29,
288        },
289        DateCase {
290            year: 1322,
291            month: 7,
292            day: 14,
293        },
294        DateCase {
295            year: 1370,
296            month: 12,
297            day: 27,
298        },
299        DateCase {
300            year: 1374,
301            month: 12,
302            day: 6,
303        },
304        // First day that the 2820-year rule fails
305        DateCase {
306            year: 1403,
307            month: 12,
308            day: 30,
309        },
310        // First Nowruz that the 2820-year rule fails
311        DateCase {
312            year: 1404,
313            month: 1,
314            day: 1,
315        },
316        DateCase {
317            year: 1417,
318            month: 8,
319            day: 19,
320        },
321        // First day the unmodified astronomical algorithm fails
322        DateCase {
323            year: 1469,
324            month: 12,
325            day: 30,
326        },
327        // First Nowruz the unmodified astronomical algorithm fails
328        DateCase {
329            year: 1470,
330            month: 1,
331            day: 1,
332        },
333        DateCase {
334            year: 1473,
335            month: 4,
336            day: 28,
337        },
338        // Last year the 33-year rule matches the modified astronomical calculation
339        DateCase {
340            year: 1501,
341            month: 12,
342            day: 29,
343        },
344        DateCase {
345            year: 1502,
346            month: 12,
347            day: 29,
348        },
349        DateCase {
350            year: 1503,
351            month: 1,
352            day: 1,
353        },
354        DateCase {
355            year: 2988,
356            month: 1,
357            day: 1,
358        },
359    ];
360
361    fn days_in_provided_year_core(year: i32) -> u16 {
362        let ny =
363            calendrical_calculations::persian::fixed_from_fast_persian(year, 1, 1).to_i64_date();
364        let next_ny = calendrical_calculations::persian::fixed_from_fast_persian(year + 1, 1, 1)
365            .to_i64_date();
366
367        (next_ny - ny) as u16
368    }
369
370    #[test]
371    fn test_persian_leap_year() {
372        let mut leap_years: [i32; 21] = [0; 21];
373        // These values were computed from the "Calendrical Calculations" reference code output
374        let expected_values = [
375            false, false, true, false, true, false, false, false, false, true, false, true, false,
376            false, true, false, false, false, false, true, true,
377        ];
378
379        for (index, case) in CASES.iter().enumerate() {
380            leap_years[index] = case.year;
381        }
382        for (year, bool) in leap_years.iter().zip(expected_values.iter()) {
383            assert_eq!(Persian::provided_year_is_leap(*year), *bool);
384        }
385    }
386
387    #[test]
388    fn days_in_provided_year_test() {
389        for case in CASES.iter() {
390            assert_eq!(
391                days_in_provided_year_core(case.year),
392                Persian::days_in_provided_year(case.year)
393            );
394        }
395    }
396
397    #[test]
398    fn test_rd_from_persian() {
399        for (case, f_date) in CASES.iter().zip(TEST_RD.iter()) {
400            let date = Date::try_new_persian(case.year, case.month, case.day).unwrap();
401
402            assert_eq!(date.to_rata_die().to_i64_date(), *f_date, "{case:?}");
403        }
404    }
405    #[test]
406    fn test_persian_from_rd() {
407        for (case, f_date) in CASES.iter().zip(TEST_RD.iter()) {
408            let date = Date::try_new_persian(case.year, case.month, case.day).unwrap();
409            assert_eq!(
410                Persian.from_rata_die(RataDie::new(*f_date)),
411                date.inner,
412                "{case:?}"
413            );
414        }
415    }
416
417    // From https://calendar.ut.ac.ir/Fa/News/Data/Doc/KabiseShamsi1206-1498-new.pdf
418    // Plain text version at https://github.com/roozbehp/persiancalendar/blob/main/kabise.txt
419    static CALENDAR_UT_AC_IR_TEST_DATA: [(i32, bool, i32, u8, u8); 293] = [
420        (1206, false, 1827, 3, 22),
421        (1207, false, 1828, 3, 21),
422        (1208, false, 1829, 3, 21),
423        (1209, false, 1830, 3, 21),
424        (1210, true, 1831, 3, 21),
425        (1211, false, 1832, 3, 21),
426        (1212, false, 1833, 3, 21),
427        (1213, false, 1834, 3, 21),
428        (1214, true, 1835, 3, 21),
429        (1215, false, 1836, 3, 21),
430        (1216, false, 1837, 3, 21),
431        (1217, false, 1838, 3, 21),
432        (1218, true, 1839, 3, 21),
433        (1219, false, 1840, 3, 21),
434        (1220, false, 1841, 3, 21),
435        (1221, false, 1842, 3, 21),
436        (1222, true, 1843, 3, 21),
437        (1223, false, 1844, 3, 21),
438        (1224, false, 1845, 3, 21),
439        (1225, false, 1846, 3, 21),
440        (1226, true, 1847, 3, 21),
441        (1227, false, 1848, 3, 21),
442        (1228, false, 1849, 3, 21),
443        (1229, false, 1850, 3, 21),
444        (1230, true, 1851, 3, 21),
445        (1231, false, 1852, 3, 21),
446        (1232, false, 1853, 3, 21),
447        (1233, false, 1854, 3, 21),
448        (1234, true, 1855, 3, 21),
449        (1235, false, 1856, 3, 21),
450        (1236, false, 1857, 3, 21),
451        (1237, false, 1858, 3, 21),
452        (1238, true, 1859, 3, 21),
453        (1239, false, 1860, 3, 21),
454        (1240, false, 1861, 3, 21),
455        (1241, false, 1862, 3, 21),
456        (1242, false, 1863, 3, 21),
457        (1243, true, 1864, 3, 20),
458        (1244, false, 1865, 3, 21),
459        (1245, false, 1866, 3, 21),
460        (1246, false, 1867, 3, 21),
461        (1247, true, 1868, 3, 20),
462        (1248, false, 1869, 3, 21),
463        (1249, false, 1870, 3, 21),
464        (1250, false, 1871, 3, 21),
465        (1251, true, 1872, 3, 20),
466        (1252, false, 1873, 3, 21),
467        (1253, false, 1874, 3, 21),
468        (1254, false, 1875, 3, 21),
469        (1255, true, 1876, 3, 20),
470        (1256, false, 1877, 3, 21),
471        (1257, false, 1878, 3, 21),
472        (1258, false, 1879, 3, 21),
473        (1259, true, 1880, 3, 20),
474        (1260, false, 1881, 3, 21),
475        (1261, false, 1882, 3, 21),
476        (1262, false, 1883, 3, 21),
477        (1263, true, 1884, 3, 20),
478        (1264, false, 1885, 3, 21),
479        (1265, false, 1886, 3, 21),
480        (1266, false, 1887, 3, 21),
481        (1267, true, 1888, 3, 20),
482        (1268, false, 1889, 3, 21),
483        (1269, false, 1890, 3, 21),
484        (1270, false, 1891, 3, 21),
485        (1271, true, 1892, 3, 20),
486        (1272, false, 1893, 3, 21),
487        (1273, false, 1894, 3, 21),
488        (1274, false, 1895, 3, 21),
489        (1275, false, 1896, 3, 20),
490        (1276, true, 1897, 3, 20),
491        (1277, false, 1898, 3, 21),
492        (1278, false, 1899, 3, 21),
493        (1279, false, 1900, 3, 21),
494        (1280, true, 1901, 3, 21),
495        (1281, false, 1902, 3, 22),
496        (1282, false, 1903, 3, 22),
497        (1283, false, 1904, 3, 21),
498        (1284, true, 1905, 3, 21),
499        (1285, false, 1906, 3, 22),
500        (1286, false, 1907, 3, 22),
501        (1287, false, 1908, 3, 21),
502        (1288, true, 1909, 3, 21),
503        (1289, false, 1910, 3, 22),
504        (1290, false, 1911, 3, 22),
505        (1291, false, 1912, 3, 21),
506        (1292, true, 1913, 3, 21),
507        (1293, false, 1914, 3, 22),
508        (1294, false, 1915, 3, 22),
509        (1295, false, 1916, 3, 21),
510        (1296, true, 1917, 3, 21),
511        (1297, false, 1918, 3, 22),
512        (1298, false, 1919, 3, 22),
513        (1299, false, 1920, 3, 21),
514        (1300, true, 1921, 3, 21),
515        (1301, false, 1922, 3, 22),
516        (1302, false, 1923, 3, 22),
517        (1303, false, 1924, 3, 21),
518        (1304, true, 1925, 3, 21),
519        (1305, false, 1926, 3, 22),
520        (1306, false, 1927, 3, 22),
521        (1307, false, 1928, 3, 21),
522        (1308, false, 1929, 3, 21),
523        (1309, true, 1930, 3, 21),
524        (1310, false, 1931, 3, 22),
525        (1311, false, 1932, 3, 21),
526        (1312, false, 1933, 3, 21),
527        (1313, true, 1934, 3, 21),
528        (1314, false, 1935, 3, 22),
529        (1315, false, 1936, 3, 21),
530        (1316, false, 1937, 3, 21),
531        (1317, true, 1938, 3, 21),
532        (1318, false, 1939, 3, 22),
533        (1319, false, 1940, 3, 21),
534        (1320, false, 1941, 3, 21),
535        (1321, true, 1942, 3, 21),
536        (1322, false, 1943, 3, 22),
537        (1323, false, 1944, 3, 21),
538        (1324, false, 1945, 3, 21),
539        (1325, true, 1946, 3, 21),
540        (1326, false, 1947, 3, 22),
541        (1327, false, 1948, 3, 21),
542        (1328, false, 1949, 3, 21),
543        (1329, true, 1950, 3, 21),
544        (1330, false, 1951, 3, 22),
545        (1331, false, 1952, 3, 21),
546        (1332, false, 1953, 3, 21),
547        (1333, true, 1954, 3, 21),
548        (1334, false, 1955, 3, 22),
549        (1335, false, 1956, 3, 21),
550        (1336, false, 1957, 3, 21),
551        (1337, true, 1958, 3, 21),
552        (1338, false, 1959, 3, 22),
553        (1339, false, 1960, 3, 21),
554        (1340, false, 1961, 3, 21),
555        (1341, false, 1962, 3, 21),
556        (1342, true, 1963, 3, 21),
557        (1343, false, 1964, 3, 21),
558        (1344, false, 1965, 3, 21),
559        (1345, false, 1966, 3, 21),
560        (1346, true, 1967, 3, 21),
561        (1347, false, 1968, 3, 21),
562        (1348, false, 1969, 3, 21),
563        (1349, false, 1970, 3, 21),
564        (1350, true, 1971, 3, 21),
565        (1351, false, 1972, 3, 21),
566        (1352, false, 1973, 3, 21),
567        (1353, false, 1974, 3, 21),
568        (1354, true, 1975, 3, 21),
569        (1355, false, 1976, 3, 21),
570        (1356, false, 1977, 3, 21),
571        (1357, false, 1978, 3, 21),
572        (1358, true, 1979, 3, 21),
573        (1359, false, 1980, 3, 21),
574        (1360, false, 1981, 3, 21),
575        (1361, false, 1982, 3, 21),
576        (1362, true, 1983, 3, 21),
577        (1363, false, 1984, 3, 21),
578        (1364, false, 1985, 3, 21),
579        (1365, false, 1986, 3, 21),
580        (1366, true, 1987, 3, 21),
581        (1367, false, 1988, 3, 21),
582        (1368, false, 1989, 3, 21),
583        (1369, false, 1990, 3, 21),
584        (1370, true, 1991, 3, 21),
585        (1371, false, 1992, 3, 21),
586        (1372, false, 1993, 3, 21),
587        (1373, false, 1994, 3, 21),
588        (1374, false, 1995, 3, 21),
589        (1375, true, 1996, 3, 20),
590        (1376, false, 1997, 3, 21),
591        (1377, false, 1998, 3, 21),
592        (1378, false, 1999, 3, 21),
593        (1379, true, 2000, 3, 20),
594        (1380, false, 2001, 3, 21),
595        (1381, false, 2002, 3, 21),
596        (1382, false, 2003, 3, 21),
597        (1383, true, 2004, 3, 20),
598        (1384, false, 2005, 3, 21),
599        (1385, false, 2006, 3, 21),
600        (1386, false, 2007, 3, 21),
601        (1387, true, 2008, 3, 20),
602        (1388, false, 2009, 3, 21),
603        (1389, false, 2010, 3, 21),
604        (1390, false, 2011, 3, 21),
605        (1391, true, 2012, 3, 20),
606        (1392, false, 2013, 3, 21),
607        (1393, false, 2014, 3, 21),
608        (1394, false, 2015, 3, 21),
609        (1395, true, 2016, 3, 20),
610        (1396, false, 2017, 3, 21),
611        (1397, false, 2018, 3, 21),
612        (1398, false, 2019, 3, 21),
613        (1399, true, 2020, 3, 20),
614        (1400, false, 2021, 3, 21),
615        (1401, false, 2022, 3, 21),
616        (1402, false, 2023, 3, 21),
617        (1403, true, 2024, 3, 20),
618        (1404, false, 2025, 3, 21),
619        (1405, false, 2026, 3, 21),
620        (1406, false, 2027, 3, 21),
621        (1407, false, 2028, 3, 20),
622        (1408, true, 2029, 3, 20),
623        (1409, false, 2030, 3, 21),
624        (1410, false, 2031, 3, 21),
625        (1411, false, 2032, 3, 20),
626        (1412, true, 2033, 3, 20),
627        (1413, false, 2034, 3, 21),
628        (1414, false, 2035, 3, 21),
629        (1415, false, 2036, 3, 20),
630        (1416, true, 2037, 3, 20),
631        (1417, false, 2038, 3, 21),
632        (1418, false, 2039, 3, 21),
633        (1419, false, 2040, 3, 20),
634        (1420, true, 2041, 3, 20),
635        (1421, false, 2042, 3, 21),
636        (1422, false, 2043, 3, 21),
637        (1423, false, 2044, 3, 20),
638        (1424, true, 2045, 3, 20),
639        (1425, false, 2046, 3, 21),
640        (1426, false, 2047, 3, 21),
641        (1427, false, 2048, 3, 20),
642        (1428, true, 2049, 3, 20),
643        (1429, false, 2050, 3, 21),
644        (1430, false, 2051, 3, 21),
645        (1431, false, 2052, 3, 20),
646        (1432, true, 2053, 3, 20),
647        (1433, false, 2054, 3, 21),
648        (1434, false, 2055, 3, 21),
649        (1435, false, 2056, 3, 20),
650        (1436, true, 2057, 3, 20),
651        (1437, false, 2058, 3, 21),
652        (1438, false, 2059, 3, 21),
653        (1439, false, 2060, 3, 20),
654        (1440, false, 2061, 3, 20),
655        (1441, true, 2062, 3, 20),
656        (1442, false, 2063, 3, 21),
657        (1443, false, 2064, 3, 20),
658        (1444, false, 2065, 3, 20),
659        (1445, true, 2066, 3, 20),
660        (1446, false, 2067, 3, 21),
661        (1447, false, 2068, 3, 20),
662        (1448, false, 2069, 3, 20),
663        (1449, true, 2070, 3, 20),
664        (1450, false, 2071, 3, 21),
665        (1451, false, 2072, 3, 20),
666        (1452, false, 2073, 3, 20),
667        (1453, true, 2074, 3, 20),
668        (1454, false, 2075, 3, 21),
669        (1455, false, 2076, 3, 20),
670        (1456, false, 2077, 3, 20),
671        (1457, true, 2078, 3, 20),
672        (1458, false, 2079, 3, 21),
673        (1459, false, 2080, 3, 20),
674        (1460, false, 2081, 3, 20),
675        (1461, true, 2082, 3, 20),
676        (1462, false, 2083, 3, 21),
677        (1463, false, 2084, 3, 20),
678        (1464, false, 2085, 3, 20),
679        (1465, true, 2086, 3, 20),
680        (1466, false, 2087, 3, 21),
681        (1467, false, 2088, 3, 20),
682        (1468, false, 2089, 3, 20),
683        (1469, true, 2090, 3, 20),
684        (1470, false, 2091, 3, 21),
685        (1471, false, 2092, 3, 20),
686        (1472, false, 2093, 3, 20),
687        (1473, false, 2094, 3, 20),
688        (1474, true, 2095, 3, 20),
689        (1475, false, 2096, 3, 20),
690        (1476, false, 2097, 3, 20),
691        (1477, false, 2098, 3, 20),
692        (1478, true, 2099, 3, 20),
693        (1479, false, 2100, 3, 21),
694        (1480, false, 2101, 3, 21),
695        (1481, false, 2102, 3, 21),
696        (1482, true, 2103, 3, 21),
697        (1483, false, 2104, 3, 21),
698        (1484, false, 2105, 3, 21),
699        (1485, false, 2106, 3, 21),
700        (1486, true, 2107, 3, 21),
701        (1487, false, 2108, 3, 21),
702        (1488, false, 2109, 3, 21),
703        (1489, false, 2110, 3, 21),
704        (1490, true, 2111, 3, 21),
705        (1491, false, 2112, 3, 21),
706        (1492, false, 2113, 3, 21),
707        (1493, false, 2114, 3, 21),
708        (1494, true, 2115, 3, 21),
709        (1495, false, 2116, 3, 21),
710        (1496, false, 2117, 3, 21),
711        (1497, false, 2118, 3, 21),
712        (1498, true, 2119, 3, 21),
713    ];
714
715    #[test]
716    fn test_calendar_ut_ac_ir_data() {
717        for (p_year, leap, iso_year, iso_month, iso_day) in CALENDAR_UT_AC_IR_TEST_DATA.iter() {
718            assert_eq!(Persian::provided_year_is_leap(*p_year), *leap);
719            let persian_date = Date::try_new_persian(*p_year, 1, 1).unwrap();
720            let iso_date = persian_date.to_calendar(Iso);
721            assert_eq!(iso_date.era_year().year, *iso_year);
722            assert_eq!(iso_date.month().ordinal, *iso_month);
723            assert_eq!(iso_date.day_of_month().0, *iso_day);
724        }
725    }
726}