65 lines
2.1 KiB
Python
65 lines
2.1 KiB
Python
# holidays
|
|
# --------
|
|
# A fast, efficient Python library for generating country, province and state
|
|
# specific sets of holidays on the fly. It aims to make determining whether a
|
|
# specific date is a holiday as fast and flexible as possible.
|
|
#
|
|
# Authors: Vacanza Team and individual contributors (see CONTRIBUTORS file)
|
|
# dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
|
|
# ryanss <ryanssdev@icloud.com> (c) 2014-2017
|
|
# Website: https://github.com/vacanza/holidays
|
|
# License: MIT (see LICENSE file)
|
|
|
|
from datetime import date
|
|
from typing import Optional
|
|
|
|
from holidays.calendars.gregorian import _timedelta
|
|
|
|
|
|
class _Persian:
|
|
"""
|
|
Persian calendar (Solar Hijri) for 1901-2100 years.
|
|
|
|
https://en.wikipedia.org/wiki/Solar_Hijri_calendar
|
|
"""
|
|
|
|
START_YEAR = 1901
|
|
END_YEAR = 2100
|
|
|
|
def is_leap_year(self, year: int) -> bool:
|
|
"""
|
|
Is Persian year that begins in the specified Gregorian year a leap year.
|
|
"""
|
|
return (year % 33) in {3, 7, 11, 16, 20, 24, 28, 32}
|
|
|
|
def new_year_date(self, year: int) -> Optional[date]:
|
|
"""
|
|
Return Gregorian date of Persian new year (1 Farvardin) in a given Gregorian year.
|
|
"""
|
|
if year < _Persian.START_YEAR or year > _Persian.END_YEAR:
|
|
return None
|
|
|
|
day = 21
|
|
if (
|
|
(year % 4 == 1 and year >= 2029)
|
|
or (year % 4 == 2 and year >= 2062)
|
|
or (year % 4 == 3 and year >= 2095)
|
|
or (year % 4 == 0 and 1996 <= year <= 2096)
|
|
):
|
|
day = 20
|
|
elif (year % 4 == 2 and year <= 1926) or (year % 4 == 3 and year <= 1959):
|
|
day = 22
|
|
return date(year, 3, day)
|
|
|
|
def persian_to_gregorian(self, year: int, j_month: int, j_day: int) -> Optional[date]:
|
|
"""
|
|
Return Gregorian date of Persian day and month in a given Gregorian year.
|
|
"""
|
|
start_date = self.new_year_date(year)
|
|
if not start_date:
|
|
return None
|
|
|
|
m = j_month - 1
|
|
delta = (31 * m if m < 6 else 186 + 30 * (m - 6)) + j_day - 1
|
|
return _timedelta(start_date, delta)
|