Package: uposatha
API for the Thai Lunar CalendarThis package provides a simple API for working with the seasons, moon days and holidays of the Thai calendar. Some use cases might include creating a printable calendar or sending a notification when there is an upcoming holiday.Example: Rains Retreat 2017fromuposatha.calendarimportCalendarfromuposatha.elementsimportHolidayName,SeasonNamecal=Calendar()rainy_season=[seasonforseasonincal.seasonsifseason.name==SeasonName.RAINYandseason.first_day.year==2017][0]pavarana=[holidayforholidayinrainy_season.holidaysifholiday.name==HolidayName.PAVARANA][0]start=rainy_season.first_day.strftime("%d/%m/%y")end=pavarana.uposatha.falls_on.strftime("%d/%m/%y")print(f"Rains 2017:{start}to{end}")Prints:Rains 2017: 09/07/17 to 05/10/17The Calendar ClassMost users of the package will start like so:fromuposatha.calendarimportCalendarcal=Calendar()This covers a specific range of dates as we need to know when years have extra months and days provided. You can see the calender range:>>>cal.start_datedatetime.date(2010,3,1)>>>cal.end_datedatetime.date(2030,11,10)When created, the calendar will generate a tuple of all seasons:>>>len(cal.seasons)62There are two helper functions:cal.next_uposatha()cal.current_season()These return instances of the classes described below.The Season ClassSeasonis defined in theuposatha.elementsmodule:>>>season=cal.seasons[0]>>>season.first_daydatetime.date(2010,3,1)>>>season.last_daydatetime.date(2010,7,26)>>>season.name<SeasonName.HOT:'Hot'>>>>season.type<SeasonType.EXTRA_MONTH:'Extra Month'>SeasonNameandSeasonTypeareEnumclasses defined inuposatha.elements.The Uposatha ClassEach season has a tuple of Uposathas:>>>uposatha=season.uposathas[0]>>>uposatha.falls_ondatetime.date(2010,3,15)You can combine this information with the season:>>>f"Uposatha{uposatha.number_in_season}of{len(season.uposathas)}"'Uposatha 1 of 10'And we have another enum -MoonPhase:>>>uposatha.moon_phase<MoonPhase.NEW:'New'>The Holiday ClassThere are four holidays:Vesak DayMagha PujaAsalha PujaPavarana DayHolidayinstances can be found in two ways:>>>vesak=season.holidays[0]>>>no_holiday=uposatha.holidayNote that when we createduposathait was not a holiday.no_holidayisNone. Holidays also have a reference to their uposatha:>>>vesak.uposatha.number_in_season6The enumHolidayNameis inuposatha.elements:>>>vesak.name<HolidayName.VESAK:'Vesak Day'>The HalfMoon ClassThere is a tuple of half moons in each season. Each is just a date and moon phase.>>>half_moon=season.half_moons[0]>>>half_moon.moon_phase<MoonPhase.WANING:'Waning'>>>>half_moon.falls_ondatetime.date(2010,3,8)Calendar ConfigurationIn order to generate the calendar some information is needed. This includes:Start dateStart seasonEnd SeasonEnd yearYears with extra month added.Years with extra day added.This information is specified in theconfiguremodule and is available via the calendar object:>>>cal.config.start_datedatetime.date(2010,2,28)>>>cal.config.extra_day_years[2016,2020,2025,2030]NB: If anyone knows this information beyond 2030, let me know!AcknowledgementsThe starting point of this project was theForest Sangha calendars. They in turn provide a link to anicalfile for importing into various calendar applications. The code for generating this file is available at thesplendidmoons github page. This is written in Go and does not provide a licence so I began by parsing the file in python. You can see the code athttps://github.com/jhanarato/uposatha-icalLeveraging that, I went back and wrote the uposatha package from scratch, testing with the data fromuposatha-ical. Thanks to the Forest Sangha and the Splendid Moons developers!