Skip to content

Commit

Permalink
Refactor and fix potential issues in JalaliDate class methods
Browse files Browse the repository at this point in the history
  • Loading branch information
majiidd committed Jun 28, 2024
1 parent 1f23708 commit 90922d8
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
85 changes: 84 additions & 1 deletion persiantools/jdatetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,22 @@


class JalaliDate:
"""
Represents a date in the Jalali (Persian) calendar.
Attributes:
year (int): The year of the Jalali date.
month (int): The month of the Jalali date.
day (int): The day of the Jalali date.
locale (str): The locale for the Jalali date ('en' or 'fa').
"""

__slots__ = "_year", "_month", "_day", "_locale", "_hashcode"

def __init__(self, year, month=None, day=None, locale="en"):
if locale not in ["en", "fa"]:
raise ValueError("locale must be 'en' or 'fa'")

if isinstance(year, JalaliDate) and month is None:
month = year.month
day = year.day
Expand Down Expand Up @@ -201,12 +214,35 @@ def is_leap(year):
If the result of this calculation is less than 683, the year is a leap year in the Persian calendar.
This is because there are 683 leap years in each 2820-year cycle of the Persian calendar.
Args:
year (int): The year to check.
Returns:
bool: True if the year is a leap year, False otherwise.
Raises:
ValueError: If the year is out of the valid range.
"""
assert MINYEAR <= year <= MAXYEAR
if not MINYEAR <= year <= MAXYEAR:
raise ValueError(f"Year must be between {MINYEAR} and {MAXYEAR}")
return ((year + 2346) * 683) % 2820 < 683

@classmethod
def days_in_month(cls, month, year):
"""
Get the number of days in a given month for a specified year.
Args:
month (int): The month (1-12).
year (int): The year.
Returns:
int: The number of days in the month.
Raises:
AssertionError: If the month is out of the valid range.
"""
assert 1 <= month <= 12, "month must be in 1..12"

if month == 12 and cls.is_leap(year):
Expand All @@ -216,6 +252,18 @@ def days_in_month(cls, month, year):

@staticmethod
def days_before_month(month):
"""
Get the number of days before the start of a given month.
Args:
month (int): The month (1-12).
Returns:
int: The number of days before the month.
Raises:
AssertionError: If the month is out of the valid range.
"""
assert 1 <= month <= 12, "month must be in 1..12"

return _MONTH_COUNT[month][2]
Expand Down Expand Up @@ -355,6 +403,19 @@ def to_gregorian(self):

@classmethod
def today(cls):
"""
Get the current date in the Jalali (Persian) calendar.
This method returns a JalaliDate object representing the current date,
based on the system's local time.
Returns:
JalaliDate: A JalaliDate object representing today's date.
Example:
>>> j_date = JalaliDate.today()
>>> print(j_date)
"""
return cls(date.today())

def timetuple(self):
Expand Down Expand Up @@ -485,6 +546,28 @@ def ctime(self):
return self.strftime("%c")

def strftime(self, fmt, locale=None):
"""
Format a Jalali date according to the given format string.
This method returns a string representing the Jalali date, controlled by an explicit format string.
It is similar to the `strftime` method used with `datetime` objects.
Args:
fmt (str): The format string.
locale (str, optional): The locale to use for formatting ('en' for English or 'fa' for Persian).
If None, the instance's locale is used.
Returns:
str: The formatted date string.
Example:
>>> j_date = JalaliDate(1400, 1, 1)
>>> j_date.strftime("%A, %d %B %Y")
'Yekshanbeh, 01 Farvardin 1400'
>>> j_date.strftime("%A, %d %B %Y", locale="fa")
'یکشنبه, ۰۱ فروردین ۱۴۰۰'
"""
if locale is None or locale not in ["fa", "en"]:
locale = self._locale

Expand Down
4 changes: 4 additions & 0 deletions tests/test_jalalidate.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ def test_format(self):
with pytest.raises(ValueError):
JalaliDate.fromisoformat("1367-02/14")

j_date = JalaliDate(1400, 1, 1)
self.assertEqual(j_date.strftime("%A, %d %B %Y"), "Yekshanbeh, 01 Farvardin 1400")
self.assertEqual(j_date.strftime("%A, %d %B %Y", locale="fa"), "یکشنبه, ۰۱ فروردین ۱۴۰۰")

def test_week(self):
self.assertEqual(JalaliDate(1394, 3, 30).week_of_year(), 14)
self.assertEqual(JalaliDate(1394, 7, 30).week_of_year(), 31)
Expand Down

0 comments on commit 90922d8

Please sign in to comment.