Skip to content

Commit

Permalink
Add an undate converter to wire in hijri date parsing capability
Browse files Browse the repository at this point in the history
  • Loading branch information
rlskoeser committed Nov 21, 2024
1 parent 50f2331 commit 778c67b
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/undate/converters/calendars/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from undate.converters.calendars.hijri import HijriDateConverter

__all__ = ["HijriDateConverter"]
3 changes: 3 additions & 0 deletions src/undate/converters/calendars/hijri/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from undate.converters.calendars.hijri.converter import HijriDateConverter

__all__ = ["HijriDateConverter"]
48 changes: 48 additions & 0 deletions src/undate/converters/calendars/hijri/converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from typing import Union

from lark.exceptions import UnexpectedCharacters

from undate.converters.base import BaseDateConverter
from undate.converters.calendars.hijri.parser import hijri_parser
from undate.converters.calendars.hijri.transformer import HijriDateTransformer
from undate.undate import Undate, UndateInterval


class HijriDateConverter(BaseDateConverter):
"""
Converter for Hijri / Islamic calendar.
Support for parsing Hijri dates and converting to Undate and UndateInterval
objects in the Gregorian calendar.
"""

#: converter name: Hijri
name: str = "Hijri"
calendar_name: str = "Hijrī"

def __init__(self):
self.transformer = HijriDateTransformer()

def parse(self, value: str) -> Union[Undate, UndateInterval]:
"""
Parse a Hijri date string and return an :class:`~undate.undate.Undate` or
:class:`~undate.undate.UndateInterval` in Gregorian calendar.
The Hijri date string is preserved in the undate label
"""
if not value:
raise ValueError("Parsing empty string is not supported")

# parse the input string, then transform to undate object
try:
# parse the string with our Hijri date parser
parsetree = hijri_parser.parse(value)
# transform the parse tree into an undate or undate interval
undate_obj = self.transformer.transform(parsetree)
# set the original date as a label, with the calendar name
undate_obj.label = f"{value} {self.calendar_name}"
return undate_obj
except UnexpectedCharacters:
raise ValueError("Could not parse '%s' as a Hijri date" % value)

# do we need to support conversion the other direction?
# i.e., generate a Hijri date from an abitrary undate or undate interval?
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pytest
from undate.converters.calendars import HijriDateConverter
from undate.undate import Undate, UndateInterval


class TestHijriDateConverter:
def test_parse_(self):
# day
date_str = "7 Jumādā I 1243"
date = HijriDateConverter().parse(date_str)
assert date == Undate(1827, 11, 26)
assert date.label == f"{date_str} {HijriDateConverter.calendar_name}"

# month
date_str = "Rajab 495"
date = HijriDateConverter().parse(date_str)
assert date == UndateInterval(Undate(1102, 4, 28), Undate(1102, 5, 27))
assert date.label == f"{date_str} {HijriDateConverter.calendar_name}"

# year
date_str = "441"
date = HijriDateConverter().parse(date_str)
assert date == UndateInterval(Undate(1049, 6, 11), Undate(1050, 5, 31))
assert date.label == f"{date_str} {HijriDateConverter.calendar_name}"

def test_parse_error(self):
# a string we can't parse should raise an error
with pytest.raises(ValueError):
HijriDateConverter().parse("January 2, 1991")
# empty string should also error
with pytest.raises(ValueError):
HijriDateConverter().parse("")

0 comments on commit 778c67b

Please sign in to comment.