fitnr / convertdate

Utils for converting between date formats and calculating holidays
MIT License
47 stars 26 forks source link

Add Islamic holidays and Chinese New Year to holidays #24

Open snoopyjc opened 4 years ago

snoopyjc commented 4 years ago

Enhancement request: Please add Islamic holidays and Chinese New Year to holidays module. Here is a list of them: https://icalendars.net/religion/islamism/

snoopyjc commented 4 years ago

Here is the code for Ramadan:

def ramadan(year):
    islamic_year = islamic.from_gregorian(year, 1, 1)[0]
    result = islamic.to_gregorian(islamic_year, 9, 1)
    if result[0] < year:
        result = islamic.to_gregorian(islamic_year+1, 9, 1)
    elif result[0] > year:
        result = islamic.to_gregorian(islamic_year-1, 9, 1)
    return date(*result)
snoopyjc commented 4 years ago

Here is the code for Chinese New Year:

from lunardate import LunarDate

_yot = ('Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake', 'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig')

def year_of_the(year):
    yr = (year - 2020) % len(_yot)
    return _yot[yr]

def chinese_new_year(year):
    """Returns a tuple of the (date, year_of_the: str)"""
    return (LunarDate(year, 1, 1).toSolarDate(), year_of_the(year))
fitnr commented 4 years ago

Islamic holidays raise an issue because they can occur twice in a Gregorian year. Should the function return a list of date tuples, which isn't in line with the other functions, or return only one of the holidays, which is incomplete behavior?

snoopyjc commented 4 years ago

Name them -1 and -2? Not sure as I don’t celebrate them.

I wound up coding my own function for Ramadan and Chinese New Year. I skipped the rest.

-joe Sent from my AT&T iPhone

On May 15, 2020, at 9:35 PM, Neil Freeman notifications@github.com wrote:

Islamic holidays raise an issue because they can occur twice in a Gregorian year. Should the function return a list of date tuples, which isn't in line with the other functions, or return only one of the holidays, which is incomplete behavior?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

uy-rrodriguez commented 1 year ago

Hi, have you got anywhere with this request? I think returning both Ramadan dates would be correct. Based on @snoopyjc 's proposal, something like below. The second condition was removed, given the Islamic calendar is strictly shorter than Gregorian, I don't think that can ever happen.

def ramadan(year):
    islamic_year = islamic.from_gregorian(year, 1, 1)[0]
    result_1 = islamic.to_gregorian(islamic_year, 9, 1)
    result_2 = islamic.to_gregorian(islamic_year + 1, 9, 1)

    # Ramadan falls towards the end of the Gregorian year
    if result_1[0] < year:
        return ( date(*result_2), )

    # Ramadan falls both at the beginning and end of the Gregorian year
    elif result_1[0] == result_2[0] and result_1 != result_2:
        return ( date(*result_1), date(*result_2) )

    return ( date(*result_1), )

Another option could be to return the "next" date for beginning of Ramadan.

def next_ramadan(year, month, day):
    islamic_date = islamic.from_gregorian(year, month, day)
    # Returns the given date if Islamic date is exactly the beginning of Ramadan
    if islamic_date[1] < 9 or islamic_date[1] == 9 and islamic_date[2] == 1:
        result = islamic.to_gregorian(islamic_date[0], 9, 1)
    else:
        result = islamic.to_gregorian(islamic_date[0] + 1, 9, 1)
    return date(*result)