Skip to content

Commit 43bc97b

Browse files
committed
Implement representative years for islamic calendar converter
1 parent e0bac94 commit 43bc97b

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

src/undate/converters/calendars/islamic/converter.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ class IslamicDateConverter(BaseCalendarConverter):
2121
name: str = "Islamic"
2222
calendar_name: str = "Islamic"
2323

24+
#: arbitrary known non-leap year
25+
NON_LEAP_YEAR: int = 1457
26+
#: arbitrary known leap year
27+
LEAP_YEAR: int = 1458
28+
2429
def __init__(self):
2530
self.transformer = IslamicDateTransformer()
2631

@@ -36,6 +41,32 @@ def max_month(self, year: int) -> int:
3641
"""maximum numeric month for this calendar"""
3742
return 12
3843

44+
def representative_years(self, years: None | list[int] = None) -> list[int]:
45+
"""Takes a list of years and returns a subset with one leap year and one non-leap year.
46+
If no years are specified, returns a known leap year and non-leap year.
47+
"""
48+
49+
# if years is unset or list is empty
50+
if not years:
51+
return [self.LEAP_YEAR, self.NON_LEAP_YEAR]
52+
found_leap = False
53+
found_non_leap = False
54+
rep_years = []
55+
for year in years:
56+
if islamic.leap(year):
57+
if not found_leap:
58+
found_leap = True
59+
rep_years.append(year)
60+
else:
61+
if not found_non_leap:
62+
found_non_leap = True
63+
rep_years.append(year)
64+
# stop as soon as we've found one example of each type of year
65+
if found_leap and found_non_leap:
66+
break
67+
68+
return rep_years
69+
3970
def to_gregorian(self, year: int, month: int, day: int) -> tuple[int, int, int]:
4071
"""Convert a Hijri date, specified by year, month, and day,
4172
to the Gregorian equivalent date. Returns a tuple of year, month, day.

tests/test_converters/test_calendars/test_islamic/test_islamic_converter.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,23 @@ def test_compare_across_calendars(self):
152152
)
153153
expected_gregorian_years = [33, 1049, 1350, 1479, 1495, 1995]
154154
assert [d.earliest.year for d in sorted_dates] == expected_gregorian_years
155+
156+
def test_representative_years(self):
157+
converter = IslamicDateConverter()
158+
# single year is not filtered
159+
# 1458 is a leap year; 1457 and 1459 are not
160+
assert converter.representative_years([1457]) == [1457]
161+
# multiple non-leap years, returns just the first
162+
assert converter.representative_years([1457, 1459]) == [1457]
163+
# next leap year is 2028; returns first leap year and first non-leap year, in input order
164+
assert converter.representative_years([1457, 1458, 1459]) == [1457, 1458]
165+
166+
# if no years are provided, returns a known leap year and non-leap years
167+
assert converter.representative_years() == [
168+
converter.LEAP_YEAR,
169+
converter.NON_LEAP_YEAR,
170+
]
171+
assert converter.representative_years([]) == [
172+
converter.LEAP_YEAR,
173+
converter.NON_LEAP_YEAR,
174+
]

0 commit comments

Comments
 (0)