1use 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#[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
46pub 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 pub fn new() -> Self {
202 Self
203 }
204}
205
206impl Date<Persian> {
207 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 static CASES: [DateCase; 21] = [
247 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 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 DateCase {
306 year: 1403,
307 month: 12,
308 day: 30,
309 },
310 DateCase {
312 year: 1404,
313 month: 1,
314 day: 1,
315 },
316 DateCase {
317 year: 1417,
318 month: 8,
319 day: 19,
320 },
321 DateCase {
323 year: 1469,
324 month: 12,
325 day: 30,
326 },
327 DateCase {
329 year: 1470,
330 month: 1,
331 day: 1,
332 },
333 DateCase {
334 year: 1473,
335 month: 4,
336 day: 28,
337 },
338 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 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 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}