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