Refactoring core classes

* Refactoring the core ``Calendar`` classes / mixins for better understanding. Only one ``Calendar`` subclass should be imported / used in calendar classes, the rest (when possible) should be ``Mixins`` (related to #511).
* Fixed Belarus holidays related to the Orthodox calendar
* Fixed Algeria week-end days
This commit is contained in:
Bruno Bord 2020-06-12 18:09:10 +02:00
parent 21ab4044c8
commit b347472334
No known key found for this signature in database
GPG Key ID: 9499EA6788BF80A1
74 changed files with 758 additions and 665 deletions

View File

@ -2,7 +2,11 @@
## master (unreleased)
Nothing here yet.
- Refactoring the core ``Calendar`` classes / mixins for better understanding. Only one ``Calendar`` subclass should be imported / used in calendar classes, the rest (when possible) should be ``Mixins`` (related to #511).
- Fixed `contributing.md` documentation with the new class/mixin organization.
- Bugfix -- Belarus: removing day after Radonitsa, which is apparently not a holiday.
- Bugfix -- Algeria: assigning the week-end days as FRI+SAT, as it's following a Islamic calendar.
## v10.2.0 (2020-06-26)

View File

@ -133,12 +133,12 @@ Now we've got 3 holidays out of 6.
#### Add religious holidays
Using `ChristianMixin` as a base to our `Zhraa` class will instantly add Christmas Day as a holiday. Now we can add Easter monday just by switching the correct flag.
Since we're using `WesternCalendar` (it inherits from `ChristianMixin`) as a base to our `Zhraa` class, it automatically adds Christmas Day as a holiday. Now we can add Easter monday just by switching the correct flag.
```python
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
class Zhraa(WesternCalendar, ChristianMixin):
class Zhraa(WesternCalendar):
include_easter_monday = True
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
@ -152,7 +152,7 @@ Almost there, 5 holidays out of 6.
There are many static methods that will grant you a clean access to variable days computation. It's very easy to add days like the "Birthday of the Founder":
```python
class Zhraa(WesternCalendar, ChristianMixin):
class Zhraa(WesternCalendar):
include_easter_monday = True
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
@ -184,7 +184,7 @@ To register, add the following:
from ..registry_tools import iso_register
@iso_register('ZK')
class Zhraa(WesternCalendar, ChristianMixin):
class Zhraa(WesternCalendar):
# The rest of your code...
```

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, IslamicMixin
from ..core import IslamicCalendar, NewYearsDayMixin
from ..registry_tools import iso_register
@iso_register('DZ')
class Algeria(WesternCalendar, IslamicMixin):
class Algeria(NewYearsDayMixin, IslamicCalendar):
"Algeria"
# Islamic holidays
include_prophet_birthday = True
@ -11,12 +11,13 @@ class Algeria(WesternCalendar, IslamicMixin):
include_day_of_sacrifice = True
include_islamic_new_year = True
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
(7, 5, "Independence Day"),
(11, 1, "Anniversary of the revolution"),
)
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + \
IslamicCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
(7, 5, "Independence Day"),
(11, 1, "Anniversary of the revolution"),
)
ISLAMIC_HOLIDAYS = IslamicMixin.ISLAMIC_HOLIDAYS + (
ISLAMIC_HOLIDAYS = IslamicCalendar.ISLAMIC_HOLIDAYS + (
(1, 10, "Ashura"),
)

View File

@ -1,11 +1,10 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('AO')
class Angola(WesternCalendar, ChristianMixin):
class Angola(WesternCalendar):
"Angola"
include_fat_tuesday = True
fat_tuesday_label = "Dia de Carnaval"
include_good_friday = True

View File

@ -1,10 +1,11 @@
from ..core import WesternCalendar, IslamicMixin, ChristianMixin
from ..core import NewYearsDayMixin, IslamoWesternCalendar, SAT, SUN
from ..registry_tools import iso_register
@iso_register('BJ')
class Benin(WesternCalendar, IslamicMixin, ChristianMixin):
class Benin(NewYearsDayMixin, IslamoWesternCalendar):
"Benin"
# Christian holidays
include_easter_monday = True
include_ascension = True
include_whit_monday = True
@ -16,10 +17,13 @@ class Benin(WesternCalendar, IslamicMixin, ChristianMixin):
include_day_of_sacrifice = True
include_day_of_sacrifice_label = "Tabaski"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + (
(1, 10, "Traditional Day"),
(5, 1, "Labour Day"),
(8, 1, "Independence Day"),
(10, 26, "Armed Forces Day"),
(11, 30, "National Day"),
)
# Explicitely assign these WE days, Benin has adopted the western workweek
WEEKEND_DAYS = (SAT, SUN)

View File

@ -1,22 +1,27 @@
from ..core import WesternCalendar, IslamicMixin, ChristianMixin
from ..core import NewYearsDayMixin, IslamoWesternCalendar, SAT, SUN
from ..registry_tools import iso_register
@iso_register('CI')
class IvoryCoast(WesternCalendar, ChristianMixin, IslamicMixin):
class IvoryCoast(NewYearsDayMixin, IslamoWesternCalendar):
"Ivory Coast"
# Christian holidays
include_easter_monday = True
include_ascension = True
include_whit_monday = True
include_assumption = True
include_all_saints = True
# Islamic holidays
include_day_after_prophet_birthday = True
include_eid_al_fitr = True
include_day_of_sacrifice = True
include_day_of_sacrifice_label = "Feast of the Sacrifice"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
(8, 7, "Independence Day"),
(11, 15, "National Peace Day"),
)
# Ivory Coast has adopted the "western" workweek.
WEEKEND_DAYS = (SAT, SUN)

View File

@ -1,13 +1,14 @@
from copy import copy
from datetime import timedelta, date
from ..core import WesternCalendar, IslamicMixin, ChristianMixin, SUN
from ..core import NewYearsDayMixin, IslamoWesternCalendar, SAT, SUN
from ..registry_tools import iso_register
@iso_register('KE')
class Kenya(WesternCalendar, IslamicMixin, ChristianMixin):
class Kenya(NewYearsDayMixin, IslamoWesternCalendar):
"Kenya"
# Christian holidays
include_good_friday = True
include_easter_monday = True
# Islamic holidays
@ -15,7 +16,10 @@ class Kenya(WesternCalendar, IslamicMixin, ChristianMixin):
include_day_of_sacrifice = True
shift_sunday_holidays = True
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
# Explicitely assign these WE days, Kenya has adopted the western workweek
WEEKEND_DAYS = (SAT, SUN)
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
(6, 1, "Madaraka Day"),
(10, 20, "Mashujaa Day"),

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('MG')
class Madagascar(WesternCalendar, ChristianMixin):
class Madagascar(WesternCalendar):
"Madagascar"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(3, 29, "Martyrs' Day"),

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('ST')
class SaoTomeAndPrincipe(WesternCalendar, ChristianMixin):
class SaoTomeAndPrincipe(WesternCalendar):
"São Tomé and Príncipe"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(2, 3, "Martyr's Day"),

View File

@ -1,14 +1,12 @@
from datetime import timedelta, date
from ..core import WesternCalendar
from ..core import SUN, MON, FRI
from ..core import ChristianMixin
from ..core import WesternCalendar, SUN, MON, FRI
from ..exceptions import CalendarError
from ..registry_tools import iso_register
@iso_register('ZA')
class SouthAfrica(WesternCalendar, ChristianMixin):
class SouthAfrica(WesternCalendar):
"South Africa"
include_good_friday = True
include_christmas = True

View File

@ -1,13 +1,10 @@
from datetime import timedelta, date
from ..core import (
WesternCalendar, ChristianMixin,
MON, TUE, WED, THU, FRI, SAT
)
from ..core import WesternCalendar, MON, TUE, WED, THU, FRI, SAT
from ..registry_tools import iso_register
@iso_register('AR')
class Argentina(WesternCalendar, ChristianMixin):
class Argentina(WesternCalendar):
'Argentina'
include_fat_tuesday = True

View File

@ -1,13 +1,12 @@
from datetime import timedelta
from copy import copy
from ..core import WesternCalendar, ChristianMixin
from ..core import SUN, MON
from ..core import WesternCalendar, SUN, MON
from ..registry_tools import iso_register
@iso_register("BB")
class Barbados(WesternCalendar, ChristianMixin):
class Barbados(WesternCalendar):
"Barbados"
include_good_friday = True

View File

@ -1,12 +1,11 @@
from datetime import timedelta, date
from ..core import WesternCalendar, ChristianMixin
from ..core import MON, SAT, SUN
from ..core import WesternCalendar, MON, SAT, SUN
from ..registry_tools import iso_register
@iso_register('BR')
class Brazil(WesternCalendar, ChristianMixin):
class Brazil(WesternCalendar):
"Brazil"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(4, 21, "Tiradentes' Day"),

View File

@ -1,12 +1,11 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin, Calendar
from ..core import SUN, MON, SAT
from ..core import WesternCalendar, SUN, MON, SAT
from ..registry_tools import iso_register
@iso_register('CA')
class Canada(WesternCalendar, ChristianMixin):
class Canada(WesternCalendar):
"Canada"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(7, 1, "Canada Day"),
@ -31,14 +30,14 @@ class Canada(WesternCalendar, ChristianMixin):
return days
class LateFamilyDayMixin(Calendar):
class LateFamilyDayMixin:
"3rd Monday of February"
def get_family_day(self, year, label="Family Day"):
return (self.get_nth_weekday_in_month(year, 2, MON, 3), label)
class VictoriaDayMixin(Calendar):
class VictoriaDayMixin:
"Monday preceding the 25th of May"
def get_victoria_day(self, year):
@ -47,14 +46,14 @@ class VictoriaDayMixin(Calendar):
return (date(year, 5, day), "Victoria Day")
class AugustCivicHolidayMixin(Calendar):
class AugustCivicHolidayMixin:
"1st Monday of August; different names depending on location"
def get_civic_holiday(self, year, label="Civic Holiday"):
return (self.get_nth_weekday_in_month(year, 8, MON), label)
class ThanksgivingMixin(Calendar):
class ThanksgivingMixin:
"2nd Monday of October"
def get_thanksgiving(self, year):
@ -62,7 +61,7 @@ class ThanksgivingMixin(Calendar):
return (thanksgiving, "Thanksgiving")
class BoxingDayMixin(Calendar):
class BoxingDayMixin:
"26th of December; shift to next working day"
def get_boxing_day(self, year):
@ -78,7 +77,7 @@ class BoxingDayMixin(Calendar):
return days
class StJeanBaptisteMixin(Calendar):
class StJeanBaptisteMixin:
"24th of June; shift to next working day"
def get_st_jean(self, year):
@ -92,7 +91,7 @@ class StJeanBaptisteMixin(Calendar):
return days
class RemembranceDayShiftMixin(Calendar):
class RemembranceDayShiftMixin:
"11th of November; shift to next day"
def get_remembrance_day(self, year):
remembranceday = date(year, 11, 11)
@ -106,8 +105,9 @@ class RemembranceDayShiftMixin(Calendar):
@iso_register('CA-ON')
class Ontario(Canada, BoxingDayMixin, ThanksgivingMixin, VictoriaDayMixin,
LateFamilyDayMixin, AugustCivicHolidayMixin):
class Ontario(BoxingDayMixin, ThanksgivingMixin, VictoriaDayMixin,
LateFamilyDayMixin, AugustCivicHolidayMixin,
Canada):
"Ontario"
include_good_friday = True
@ -125,7 +125,7 @@ class Ontario(Canada, BoxingDayMixin, ThanksgivingMixin, VictoriaDayMixin,
@iso_register('CA-QC')
class Quebec(Canada, VictoriaDayMixin, StJeanBaptisteMixin, ThanksgivingMixin):
class Quebec(VictoriaDayMixin, StJeanBaptisteMixin, ThanksgivingMixin, Canada):
"Quebec"
include_easter_monday = True
@ -140,8 +140,8 @@ class Quebec(Canada, VictoriaDayMixin, StJeanBaptisteMixin, ThanksgivingMixin):
@iso_register('CA-BC')
class BritishColumbia(Canada, VictoriaDayMixin, AugustCivicHolidayMixin,
ThanksgivingMixin):
class BritishColumbia(VictoriaDayMixin, AugustCivicHolidayMixin,
ThanksgivingMixin, Canada):
"British Columbia"
include_good_friday = True
@ -176,7 +176,7 @@ class BritishColumbia(Canada, VictoriaDayMixin, AugustCivicHolidayMixin,
@iso_register('CA-AB')
class Alberta(Canada, LateFamilyDayMixin, VictoriaDayMixin, ThanksgivingMixin):
class Alberta(LateFamilyDayMixin, VictoriaDayMixin, ThanksgivingMixin, Canada):
"Alberta"
include_good_friday = True
@ -195,9 +195,9 @@ class Alberta(Canada, LateFamilyDayMixin, VictoriaDayMixin, ThanksgivingMixin):
@iso_register('CA-SK')
class Saskatchewan(Canada, LateFamilyDayMixin, VictoriaDayMixin,
class Saskatchewan(LateFamilyDayMixin, VictoriaDayMixin,
RemembranceDayShiftMixin, AugustCivicHolidayMixin,
ThanksgivingMixin):
ThanksgivingMixin, Canada):
"Saskatchewan"
include_good_friday = True
@ -214,8 +214,9 @@ class Saskatchewan(Canada, LateFamilyDayMixin, VictoriaDayMixin,
@iso_register('CA-MB')
class Manitoba(Canada, LateFamilyDayMixin, VictoriaDayMixin,
AugustCivicHolidayMixin, ThanksgivingMixin):
class Manitoba(LateFamilyDayMixin, VictoriaDayMixin,
AugustCivicHolidayMixin, ThanksgivingMixin,
Canada):
"Manitoba"
include_good_friday = True
@ -231,7 +232,7 @@ class Manitoba(Canada, LateFamilyDayMixin, VictoriaDayMixin,
@iso_register('CA-NB')
class NewBrunswick(Canada, AugustCivicHolidayMixin):
class NewBrunswick(AugustCivicHolidayMixin, Canada):
"New Brunswick"
FIXED_HOLIDAYS = Canada.FIXED_HOLIDAYS + (
@ -247,7 +248,7 @@ class NewBrunswick(Canada, AugustCivicHolidayMixin):
@iso_register('CA-NS')
class NovaScotia(Canada, RemembranceDayShiftMixin, LateFamilyDayMixin):
class NovaScotia(RemembranceDayShiftMixin, LateFamilyDayMixin, Canada):
"Nova Scotia"
include_good_friday = True
@ -261,7 +262,7 @@ class NovaScotia(Canada, RemembranceDayShiftMixin, LateFamilyDayMixin):
@iso_register('CA-PE')
class PrinceEdwardIsland(Canada, LateFamilyDayMixin, RemembranceDayShiftMixin):
class PrinceEdwardIsland(LateFamilyDayMixin, RemembranceDayShiftMixin, Canada):
"Prince Edward Island"
include_good_friday = True
@ -280,7 +281,7 @@ class Newfoundland(Canada):
@iso_register('CA-YT')
class Yukon(Canada, VictoriaDayMixin, ThanksgivingMixin):
class Yukon(VictoriaDayMixin, ThanksgivingMixin, Canada):
"Yukon"
FIXED_HOLIDAYS = Canada.FIXED_HOLIDAYS + (
@ -300,8 +301,8 @@ class Yukon(Canada, VictoriaDayMixin, ThanksgivingMixin):
@iso_register('CA-NT')
class NorthwestTerritories(Canada, RemembranceDayShiftMixin, VictoriaDayMixin,
ThanksgivingMixin):
class NorthwestTerritories(RemembranceDayShiftMixin, VictoriaDayMixin,
ThanksgivingMixin, Canada):
"Northwest Territories"
FIXED_HOLIDAYS = Canada.FIXED_HOLIDAYS + (
@ -321,8 +322,8 @@ class NorthwestTerritories(Canada, RemembranceDayShiftMixin, VictoriaDayMixin,
@iso_register('CA-NU')
class Nunavut(Canada, VictoriaDayMixin, ThanksgivingMixin,
RemembranceDayShiftMixin):
class Nunavut(VictoriaDayMixin, ThanksgivingMixin, RemembranceDayShiftMixin,
Canada):
"Nunavut"
include_good_friday = True

View File

@ -1,12 +1,11 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin
from ..core import MON, TUE, WED, FRI
from ..core import WesternCalendar, MON, TUE, WED, FRI
from ..registry_tools import iso_register
@iso_register('CL')
class Chile(WesternCalendar, ChristianMixin):
class Chile(WesternCalendar):
"Chile"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),

View File

@ -1,11 +1,11 @@
from datetime import timedelta, date
from ..core import WesternCalendar, ChristianMixin, MON
from ..core import WesternCalendar, MON
from ..registry_tools import iso_register
@iso_register('CO')
class Colombia(WesternCalendar, ChristianMixin):
class Colombia(WesternCalendar):
"Colombia"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),

View File

@ -1,12 +1,11 @@
from datetime import date, timedelta
from ..core import WesternCalendar, ChristianMixin
from ..core import SUN, MON, SAT
from ..core import WesternCalendar, SUN, MON, SAT
from ..registry_tools import iso_register
@iso_register('MX')
class Mexico(WesternCalendar, ChristianMixin):
class Mexico(WesternCalendar):
"Mexico"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),

View File

@ -1,11 +1,11 @@
from datetime import timedelta
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('PA')
class Panama(WesternCalendar, ChristianMixin):
class Panama(WesternCalendar):
"Panama"
include_good_friday = True
include_easter_saturday = True

View File

@ -1,11 +1,11 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('PY')
class Paraguay(WesternCalendar, ChristianMixin):
class Paraguay(WesternCalendar):
"Paraguay"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),

View File

@ -1,7 +1,7 @@
from datetime import date
import warnings
from ..core import ChineseNewYearCalendar, WesternCalendar
from ..core import ChineseNewYearCalendar, NewYearsDayMixin
from ..registry_tools import iso_register
from ..exceptions import CalendarError
@ -56,12 +56,12 @@ workdays = {
@iso_register('CN')
class China(ChineseNewYearCalendar, WesternCalendar):
class China(NewYearsDayMixin, ChineseNewYearCalendar):
"China"
# WARNING: Support 2018, 2019 currently, need update every year.
# National Days, 10.1 - 10.7
national_days = [(10, i, "National Day") for i in range(1, 8)]
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + tuple(national_days)
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + tuple(national_days)
include_chinese_new_year_eve = True

View File

@ -1,7 +1,7 @@
from datetime import date, timedelta
from ..core import (
ChineseNewYearCalendar, WesternCalendar, ChristianMixin,
ChineseNewYearCalendar, NewYearsDayMixin, WesternMixin,
SUN, SAT
)
from ..astronomy import solar_term
@ -9,7 +9,7 @@ from ..registry_tools import iso_register
@iso_register('HK')
class HongKong(WesternCalendar, ChineseNewYearCalendar, ChristianMixin):
class HongKong(NewYearsDayMixin, WesternMixin, ChineseNewYearCalendar):
"Hong Kong"
include_good_friday = True
include_easter_saturday = True
@ -18,7 +18,7 @@ class HongKong(WesternCalendar, ChineseNewYearCalendar, ChristianMixin):
WEEKEND_DAYS = (SUN,)
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
(7, 1, "SAR Establishment Day"),
(10, 1, "National Day"),

View File

@ -1,16 +1,18 @@
from datetime import date
from ..core import MON
from ..core import WesternCalendar
from ..core import NewYearsDayMixin, Calendar, MON, SAT, SUN
from ..astronomy import calculate_equinoxes
from ..registry_tools import iso_register
@iso_register('JP')
class Japan(WesternCalendar):
class Japan(NewYearsDayMixin, Calendar):
"Japan"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
# Japan uses the "western" workweek
WEEKEND_DAYS = (SAT, SUN)
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + (
(2, 11, "Foundation Day"),
(4, 29, "Showa Day"),
(5, 3, "Constitution Memorial Day"),

View File

@ -1,12 +1,14 @@
from datetime import date
from ..core import ChineseNewYearCalendar, WesternCalendar
from ..core import IslamicMixin
from ..core import (
NewYearsDayMixin, IslamicMixin, ChineseNewYearCalendar,
SAT, SUN
)
from ..registry_tools import iso_register
@iso_register('MY')
class Malaysia(ChineseNewYearCalendar, WesternCalendar, IslamicMixin):
class Malaysia(NewYearsDayMixin, IslamicMixin, ChineseNewYearCalendar):
"Malaysia"
include_nuzul_al_quran = True
include_eid_al_fitr = True
@ -17,7 +19,11 @@ class Malaysia(ChineseNewYearCalendar, WesternCalendar, IslamicMixin):
include_islamic_new_year = True
include_prophet_birthday = True
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
# Most of th Malaysian territory uses these Week-end days
WEEKEND_DAYS = (SAT, SUN)
# TODO: Add calendar exceptions
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + (
(2, 1, "Federal Territory Day"),
(5, 1, "Workers' Day"),
(8, 31, "National Day"),

View File

@ -1,12 +1,10 @@
from ..core import Calendar
from ..core import FRI, SAT, IslamicMixin
from ..core import IslamicCalendar
from ..registry_tools import iso_register
@iso_register('QA')
class Qatar(IslamicMixin, Calendar):
class Qatar(IslamicCalendar):
"Qatar"
WEEKEND_DAYS = (FRI, SAT)
FIXED_HOLIDAYS = (
(12, 18, "National Day"),

View File

@ -1,26 +1,33 @@
from datetime import date
from ..core import (
ChineseNewYearCalendar, WesternCalendar, ChristianMixin, IslamicMixin
NewYearsDayMixin, WesternMixin, IslamicMixin, ChineseNewYearCalendar,
SAT, SUN
)
from ..registry_tools import iso_register
@iso_register('SG')
class Singapore(WesternCalendar,
ChineseNewYearCalendar, ChristianMixin, IslamicMixin):
class Singapore(NewYearsDayMixin, WesternMixin, IslamicMixin,
ChineseNewYearCalendar):
"Singapore"
# Christian holiday
include_good_friday = True
# Islamic holidays
include_eid_al_fitr = True
eid_al_fitr_label = "Hari Raya Puasa"
include_day_of_sacrifice = True
day_of_sacrifice_label = "Hari Raya Haji"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),
(8, 9, "National Day"),
)
# Explicitely assign these WE days, Singapore calendar is too much of a mix
WEEKEND_DAYS = (SAT, SUN)
# Diwali/Deepavali is sometimes celebrated on a different day to India
# so this can't be put into a HinduMixin
DEEPAVALI = {

View File

@ -1,11 +1,11 @@
from ..core import ChineseNewYearCalendar, WesternCalendar
from ..core import NewYearsDayMixin, ChineseNewYearCalendar
from ..registry_tools import iso_register
@iso_register('KR')
class SouthKorea(WesternCalendar, ChineseNewYearCalendar):
class SouthKorea(NewYearsDayMixin, ChineseNewYearCalendar):
"South Korea"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + (
(3, 1, "Independence Day"),
(5, 5, "Children's Day"),
(6, 6, "Memorial Day"),

View File

@ -1,13 +1,13 @@
from ..core import ChineseNewYearCalendar, WesternCalendar
from ..core import NewYearsDayMixin, ChineseNewYearCalendar
from ..astronomy import solar_term
from ..registry_tools import iso_register
@iso_register('TW')
class Taiwan(ChineseNewYearCalendar, WesternCalendar):
class Taiwan(NewYearsDayMixin, ChineseNewYearCalendar):
"Taiwan (Republic of China)"
FIXED_HOLIDAYS = (
WesternCalendar.FIXED_HOLIDAYS +
NewYearsDayMixin.FIXED_HOLIDAYS +
(
(2, 28, "228 Peace Memorial Day"),
(4, 4, "Combination of Women's Day and Children's Day"),

View File

@ -42,7 +42,451 @@ def cleaned_date(day, keep_datetime=False):
return day
class Calendar:
class NewYearsDayMixin:
FIXED_HOLIDAYS = (
(1, 1, 'New year'),
)
shift_new_years_day = False
def get_variable_days(self, year):
days = super().get_variable_days(year)
new_year = date(year, 1, 1)
if self.shift_new_years_day:
if new_year.weekday() in self.get_weekend_days():
days.append((
self.find_following_working_day(new_year),
"New Year shift"))
return days
class ChristianMixin:
EASTER_METHOD = None # to be assigned in the inherited mixin
include_epiphany = False
include_clean_monday = False
include_annunciation = False
include_fat_tuesday = False
# Fat tuesday forced to `None` to make sure this value is always set
# We've seen that there was a wide variety of labels.
fat_tuesday_label = None
include_ash_wednesday = False
ash_wednesday_label = "Ash Wednesday"
include_palm_sunday = False
include_holy_thursday = False
include_good_friday = False
good_friday_label = "Good Friday"
include_easter_monday = False
include_easter_saturday = False
include_easter_sunday = False
include_all_saints = False
include_immaculate_conception = False
immaculate_conception_label = "Immaculate Conception"
include_christmas = True
include_christmas_eve = False
include_ascension = False
include_assumption = False
include_whit_sunday = False
whit_sunday_label = 'Whit Sunday'
include_whit_monday = False
whit_monday_label = 'Whit Monday'
include_corpus_christi = False
include_boxing_day = False
boxing_day_label = "Boxing Day"
include_all_souls = False
def get_fat_tuesday(self, year):
if not self.fat_tuesday_label:
raise CalendarError(
"Improperly configured: please provide a "
"`fat_tuesday_label` value")
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=47)
def get_ash_wednesday(self, year):
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=46)
def get_palm_sunday(self, year):
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=7)
def get_holy_thursday(self, year):
"Return the date of the last thursday before easter"
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=3)
def get_good_friday(self, year):
"Return the date of the last friday before easter"
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=2)
def get_clean_monday(self, year):
"Return the clean monday date"
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=48)
def get_easter_saturday(self, year):
"Return the Easter Saturday date"
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=1)
def get_easter_sunday(self, year):
"Return the date of the easter (sunday) -- following the easter method"
return easter.easter(year, self.EASTER_METHOD)
def get_easter_monday(self, year):
"Return the date of the monday after easter"
sunday = self.get_easter_sunday(year)
return sunday + timedelta(days=1)
def get_ascension_thursday(self, year):
easter = self.get_easter_sunday(year)
return easter + timedelta(days=39)
def get_whit_monday(self, year):
easter = self.get_easter_sunday(year)
return easter + timedelta(days=50)
def get_whit_sunday(self, year):
easter = self.get_easter_sunday(year)
return easter + timedelta(days=49)
def get_corpus_christi(self, year):
return self.get_easter_sunday(year) + timedelta(days=60)
def shift_christmas_boxing_days(self, year):
""" When Christmas and/or Boxing Day falls on a weekend, it is rolled
forward to the next weekday.
"""
christmas = date(year, 12, 25)
boxing_day = date(year, 12, 26)
boxing_day_label = "{} Shift".format(self.boxing_day_label)
results = []
if christmas.weekday() in self.get_weekend_days():
shift = self.find_following_working_day(christmas)
results.append((shift, "Christmas Shift"))
results.append((shift + timedelta(days=1), boxing_day_label))
elif boxing_day.weekday() in self.get_weekend_days():
shift = self.find_following_working_day(boxing_day)
results.append((shift, boxing_day_label))
return results
def get_variable_days(self, year): # noqa
"Return the christian holidays list according to the mixin"
days = super().get_variable_days(year)
if self.include_epiphany:
days.append((date(year, 1, 6), "Epiphany"))
if self.include_clean_monday:
days.append((self.get_clean_monday(year), "Clean Monday"))
if self.include_annunciation:
days.append((date(year, 3, 25), "Annunciation"))
if self.include_fat_tuesday:
days.append(
(self.get_fat_tuesday(year), self.fat_tuesday_label)
)
if self.include_ash_wednesday:
days.append(
(self.get_ash_wednesday(year), self.ash_wednesday_label)
)
if self.include_palm_sunday:
days.append((self.get_palm_sunday(year), "Palm Sunday"))
if self.include_holy_thursday:
days.append((self.get_holy_thursday(year), "Holy Thursday"))
if self.include_good_friday:
days.append((self.get_good_friday(year), self.good_friday_label))
if self.include_easter_saturday:
days.append((self.get_easter_saturday(year), "Easter Saturday"))
if self.include_easter_sunday:
days.append((self.get_easter_sunday(year), "Easter Sunday"))
if self.include_easter_monday:
days.append((self.get_easter_monday(year), "Easter Monday"))
if self.include_assumption:
days.append((date(year, 8, 15), "Assumption of Mary to Heaven"))
if self.include_all_saints:
days.append((date(year, 11, 1), "All Saints Day"))
if self.include_all_souls:
days.append((date(year, 11, 2), "All Souls Day"))
if self.include_immaculate_conception:
days.append((date(year, 12, 8), self.immaculate_conception_label))
if self.include_christmas:
days.append((date(year, 12, 25), "Christmas Day"))
if self.include_christmas_eve:
days.append((date(year, 12, 24), "Christmas Eve"))
if self.include_boxing_day:
days.append((date(year, 12, 26), self.boxing_day_label))
if self.include_ascension:
days.append((
self.get_ascension_thursday(year), "Ascension Thursday"))
if self.include_whit_monday:
days.append((self.get_whit_monday(year), self.whit_monday_label))
if self.include_whit_sunday:
days.append((self.get_whit_sunday(year), self.whit_sunday_label))
if self.include_corpus_christi:
days.append((self.get_corpus_christi(year), "Corpus Christi"))
return days
class WesternMixin(ChristianMixin):
"""
General usage calendar for Western countries.
(chiefly Europe and Northern America)
"""
EASTER_METHOD = easter.EASTER_WESTERN
WEEKEND_DAYS = (SAT, SUN)
class OrthodoxMixin(ChristianMixin):
EASTER_METHOD = easter.EASTER_ORTHODOX
WEEKEND_DAYS = (SAT, SUN)
class LunarMixin:
"""
Calendar ready to compute luncar calendar days
"""
@staticmethod
def lunar(year, month, day):
return LunarDate(year, month, day).toSolarDate()
class ChineseNewYearMixin(LunarMixin):
"""
Calendar including toolsets to compute the Chinese New Year holidays.
"""
include_chinese_new_year_eve = False
chinese_new_year_eve_label = "Chinese New Year's eve"
# Chinese New Year will be included by default
include_chinese_new_year = True
chinese_new_year_label = 'Chinese New Year'
# Some countries include the 2nd lunar day as a holiday
include_chinese_second_day = False
chinese_second_day_label = "Chinese New Year (2nd day)"
include_chinese_third_day = False
chinese_third_day_label = "Chinese New Year (3rd day)"
shift_sunday_holidays = False
# Some calendars roll a starting Sunday CNY to Sat
shift_start_cny_sunday = False
def get_chinese_new_year(self, year):
"""
Compute Chinese New Year days. To return a list of holidays.
By default, it'll at least return the Chinese New Year holidays chosen
using the following options:
* ``include_chinese_new_year_eve``
* ``include_chinese_new_year`` (on by default)
* ``include_chinese_second_day``
If the ``shift_sunday_holidays`` option is on, the rules are the
following.
* If the CNY1 falls on MON-FRI, there's not shift.
* If the CNY1 falls on SAT, the CNY2 is shifted to the Monday after.
* If the CNY1 falls on SUN, the CNY1 is shifted to the Monday after,
and CNY2 is shifted to the Tuesday after.
"""
days = []
lunar_first_day = ChineseNewYearMixin.lunar(year, 1, 1)
# Chinese new year's eve
if self.include_chinese_new_year_eve:
days.append((
lunar_first_day - timedelta(days=1),
self.chinese_new_year_eve_label
))
# Chinese new year (is included by default)
if self.include_chinese_new_year:
days.append((lunar_first_day, self.chinese_new_year_label))
if self.include_chinese_second_day:
lunar_second_day = lunar_first_day + timedelta(days=1)
days.append((
lunar_second_day,
self.chinese_second_day_label
))
if self.include_chinese_third_day:
lunar_third_day = lunar_first_day + timedelta(days=2)
days.append((
lunar_third_day,
self.chinese_third_day_label
))
if self.shift_sunday_holidays:
if lunar_first_day.weekday() == SUN:
if self.shift_start_cny_sunday:
days.append(
(lunar_first_day - timedelta(days=1),
"Chinese Lunar New Year shift"),
)
else:
if self.include_chinese_third_day:
shift_day = lunar_third_day
else:
shift_day = lunar_second_day
days.append(
(shift_day + timedelta(days=1),
"Chinese Lunar New Year shift"),
)
if (lunar_second_day.weekday() == SUN
and self.include_chinese_third_day):
days.append(
(lunar_third_day + timedelta(days=1),
"Chinese Lunar New Year shift"),
)
return days
def get_variable_days(self, year):
days = super().get_variable_days(year)
days.extend(self.get_chinese_new_year(year))
return days
def get_shifted_holidays(self, dates):
"""
Taking a list of existing holidays, yield a list of 'shifted' days if
the holiday falls on SUN.
"""
for holiday, label in dates:
if holiday.weekday() == SUN:
yield (
holiday + timedelta(days=1),
label + ' shift'
)
def get_calendar_holidays(self, year):
"""
Take into account the eventual shift to the next MON if any holiday
falls on SUN.
"""
# Unshifted days are here:
days = super().get_calendar_holidays(year)
if self.shift_sunday_holidays:
days_to_inspect = copy(days)
for day_shifted in self.get_shifted_holidays(days_to_inspect):
days.append(day_shifted)
return days
class CalverterMixin:
conversion_method = None
ISLAMIC_HOLIDAYS = ()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.calverter = Calverter()
if self.conversion_method is None:
raise NotImplementedError
def converted(self, year):
conversion_method = getattr(
self.calverter, 'jd_to_%s' % self.conversion_method)
current = date(year, 1, 1)
days = []
while current.year == year:
julian_day = self.calverter.gregorian_to_jd(
current.year,
current.month,
current.day)
days.append(conversion_method(julian_day))
current = current + timedelta(days=1)
return days
def calverted_years(self, year):
converted = self.converted(year)
generator = (y for y, m, d in converted)
return sorted(list(set(generator)))
def get_islamic_holidays(self):
return self.ISLAMIC_HOLIDAYS
def get_delta_islamic_holidays(self, year):
"""
Return the delta to add/substract according to the year or customs.
By default, to return None or timedelta(days=0)
"""
return None
def get_variable_days(self, year):
warnings.warn('Please take note that, due to arbitrary decisions, '
'this Islamic calendar computation may be wrong.')
days = super().get_variable_days(year)
years = self.calverted_years(year)
conversion_method = getattr(
self.calverter, '%s_to_jd' % self.conversion_method)
for month, day, label in self.get_islamic_holidays():
for y in years:
jd = conversion_method(y, month, day)
g_year, g_month, g_day = self.calverter.jd_to_gregorian(jd)
holiday = date(g_year, g_month, g_day)
# Only add a delta if necessary
delta = self.get_delta_islamic_holidays(year)
if delta:
holiday += delta
if holiday.year == year:
days.append((holiday, label))
return days
class IslamicMixin(CalverterMixin):
WEEKEND_DAYS = (FRI, SAT)
conversion_method = 'islamic'
include_prophet_birthday = False
include_day_after_prophet_birthday = False
include_start_ramadan = False
include_eid_al_fitr = False
length_eid_al_fitr = 1
eid_al_fitr_label = "Eid al-Fitr"
include_eid_al_adha = False
length_eid_al_adha = 1
include_day_of_sacrifice = False
day_of_sacrifice_label = "Eid al-Adha"
include_islamic_new_year = False
include_laylat_al_qadr = False
include_nuzul_al_quran = False
def get_islamic_holidays(self):
"""Return a list of Islamic (month, day, label) for islamic holidays.
Please take note that these dates must be expressed using the Islamic
Calendar"""
days = list(super().get_islamic_holidays())
if self.include_islamic_new_year:
days.append((1, 1, "Islamic New Year"))
if self.include_prophet_birthday:
days.append((3, 12, "Prophet's Birthday"))
if self.include_day_after_prophet_birthday:
days.append((3, 13, "Day after Prophet's Birthday"))
if self.include_start_ramadan:
days.append((9, 1, "Start of ramadan"))
if self.include_nuzul_al_quran:
days.append((9, 17, "Nuzul Al-Qur'an"))
if self.include_eid_al_fitr:
for x in range(self.length_eid_al_fitr):
days.append((10, x + 1, self.eid_al_fitr_label))
if self.include_eid_al_adha:
for x in range(self.length_eid_al_adha):
days.append((12, x + 10, "Eid al-Adha"))
if self.include_day_of_sacrifice:
days.append((12, 10, self.day_of_sacrifice_label))
if self.include_laylat_al_qadr:
warnings.warn("The Islamic holiday named Laylat al-Qadr is decided"
" by the religious authorities. It is not possible"
" to compute it. You'll have to add it manually.")
return tuple(days)
class JalaliMixin(CalverterMixin):
conversion_method = 'jalali'
class CoreCalendar:
FIXED_HOLIDAYS = ()
WEEKEND_DAYS = ()
@ -368,438 +812,40 @@ class Calendar:
return count
class ChristianMixin(Calendar):
EASTER_METHOD = None # to be assigned in the inherited mixin
include_epiphany = False
include_clean_monday = False
include_annunciation = False
include_fat_tuesday = False
# Fat tuesday forced to `None` to make sure this value is always set
# We've seen that there was a wide variety of labels.
fat_tuesday_label = None
include_ash_wednesday = False
ash_wednesday_label = "Ash Wednesday"
include_palm_sunday = False
include_holy_thursday = False
include_good_friday = False
good_friday_label = "Good Friday"
include_easter_monday = False
include_easter_saturday = False
include_easter_sunday = False
include_all_saints = False
include_immaculate_conception = False
immaculate_conception_label = "Immaculate Conception"
include_christmas = True
include_christmas_eve = False
include_ascension = False
include_assumption = False
include_whit_sunday = False
whit_sunday_label = 'Whit Sunday'
include_whit_monday = False
whit_monday_label = 'Whit Monday'
include_corpus_christi = False
include_boxing_day = False
boxing_day_label = "Boxing Day"
include_all_souls = False
def get_fat_tuesday(self, year):
if not self.fat_tuesday_label:
raise CalendarError(
"Improperly configured: please provide a "
"`fat_tuesday_label` value")
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=47)
def get_ash_wednesday(self, year):
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=46)
def get_palm_sunday(self, year):
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=7)
def get_holy_thursday(self, year):
"Return the date of the last thursday before easter"
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=3)
def get_good_friday(self, year):
"Return the date of the last friday before easter"
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=2)
def get_clean_monday(self, year):
"Return the clean monday date"
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=48)
def get_easter_saturday(self, year):
"Return the Easter Saturday date"
sunday = self.get_easter_sunday(year)
return sunday - timedelta(days=1)
def get_easter_sunday(self, year):
"Return the date of the easter (sunday) -- following the easter method"
return easter.easter(year, self.EASTER_METHOD)
def get_easter_monday(self, year):
"Return the date of the monday after easter"
sunday = self.get_easter_sunday(year)
return sunday + timedelta(days=1)
def get_ascension_thursday(self, year):
easter = self.get_easter_sunday(year)
return easter + timedelta(days=39)
def get_whit_monday(self, year):
easter = self.get_easter_sunday(year)
return easter + timedelta(days=50)
def get_whit_sunday(self, year):
easter = self.get_easter_sunday(year)
return easter + timedelta(days=49)
def get_corpus_christi(self, year):
return self.get_easter_sunday(year) + timedelta(days=60)
def shift_christmas_boxing_days(self, year):
""" When Christmas and/or Boxing Day falls on a weekend, it is rolled
forward to the next weekday.
"""
christmas = date(year, 12, 25)
boxing_day = date(year, 12, 26)
boxing_day_label = "{} Shift".format(self.boxing_day_label)
results = []
if christmas.weekday() in self.get_weekend_days():
shift = self.find_following_working_day(christmas)
results.append((shift, "Christmas Shift"))
results.append((shift + timedelta(days=1), boxing_day_label))
elif boxing_day.weekday() in self.get_weekend_days():
shift = self.find_following_working_day(boxing_day)
results.append((shift, boxing_day_label))
return results
def get_variable_days(self, year): # noqa
"Return the christian holidays list according to the mixin"
days = super().get_variable_days(year)
if self.include_epiphany:
days.append((date(year, 1, 6), "Epiphany"))
if self.include_clean_monday:
days.append((self.get_clean_monday(year), "Clean Monday"))
if self.include_annunciation:
days.append((date(year, 3, 25), "Annunciation"))
if self.include_fat_tuesday:
days.append(
(self.get_fat_tuesday(year), self.fat_tuesday_label)
)
if self.include_ash_wednesday:
days.append(
(self.get_ash_wednesday(year), self.ash_wednesday_label)
)
if self.include_palm_sunday:
days.append((self.get_palm_sunday(year), "Palm Sunday"))
if self.include_holy_thursday:
days.append((self.get_holy_thursday(year), "Holy Thursday"))
if self.include_good_friday:
days.append((self.get_good_friday(year), self.good_friday_label))
if self.include_easter_saturday:
days.append((self.get_easter_saturday(year), "Easter Saturday"))
if self.include_easter_sunday:
days.append((self.get_easter_sunday(year), "Easter Sunday"))
if self.include_easter_monday:
days.append((self.get_easter_monday(year), "Easter Monday"))
if self.include_assumption:
days.append((date(year, 8, 15), "Assumption of Mary to Heaven"))
if self.include_all_saints:
days.append((date(year, 11, 1), "All Saints Day"))
if self.include_all_souls:
days.append((date(year, 11, 2), "All Souls Day"))
if self.include_immaculate_conception:
days.append((date(year, 12, 8), self.immaculate_conception_label))
if self.include_christmas:
days.append((date(year, 12, 25), "Christmas Day"))
if self.include_christmas_eve:
days.append((date(year, 12, 24), "Christmas Eve"))
if self.include_boxing_day:
days.append((date(year, 12, 26), self.boxing_day_label))
if self.include_ascension:
days.append((
self.get_ascension_thursday(year), "Ascension Thursday"))
if self.include_whit_monday:
days.append((self.get_whit_monday(year), self.whit_monday_label))
if self.include_whit_sunday:
days.append((self.get_whit_sunday(year), self.whit_sunday_label))
if self.include_corpus_christi:
days.append((self.get_corpus_christi(year), "Corpus Christi"))
return days
class Calendar(CoreCalendar):
pass
class WesternCalendar(Calendar):
class WesternCalendar(NewYearsDayMixin, WesternMixin, Calendar):
"""
General usage calendar for Western countries.
(chiefly Europe and Northern America)
A Christian calendar using Western definition for Easter.
"""
EASTER_METHOD = easter.EASTER_WESTERN
class OrthodoxCalendar(NewYearsDayMixin, OrthodoxMixin, Calendar):
"""
A Christian calendar using Orthodox definition for Easter.
"""
class ChineseNewYearCalendar(ChineseNewYearMixin, Calendar):
"""
Chinese Calendar, using Chinese New Year computation.
"""
# There are regional exceptions to those week-end days, to define locally.
WEEKEND_DAYS = (SAT, SUN)
shift_new_years_day = False
FIXED_HOLIDAYS = (
(1, 1, 'New year'),
)
def get_variable_days(self, year):
days = super().get_variable_days(year)
new_year = date(year, 1, 1)
if self.shift_new_years_day:
if new_year.weekday() in self.get_weekend_days():
days.append((
self.find_following_working_day(new_year),
"New Year shift"))
return days
class OrthodoxMixin(ChristianMixin):
EASTER_METHOD = easter.EASTER_ORTHODOX
class LunarCalendar(Calendar):
class IslamicCalendar(IslamicMixin, Calendar):
"""
Calendar ready to compute luncar calendar days
Islamic calendar
"""
@staticmethod
def lunar(year, month, day):
return LunarDate(year, month, day).toSolarDate()
class ChineseNewYearCalendar(LunarCalendar):
class IslamoWesternCalendar(IslamicMixin, WesternMixin, Calendar):
"""
Calendar including toolsets to compute the Chinese New Year holidays.
Mix of Islamic and Western calendars.
When countries have both Islamic and Western-Christian holidays.
"""
include_chinese_new_year_eve = False
chinese_new_year_eve_label = "Chinese New Year's eve"
# Chinese New Year will be included by default
include_chinese_new_year = True
chinese_new_year_label = 'Chinese New Year'
# Some countries include the 2nd lunar day as a holiday
include_chinese_second_day = False
chinese_second_day_label = "Chinese New Year (2nd day)"
include_chinese_third_day = False
chinese_third_day_label = "Chinese New Year (3rd day)"
shift_sunday_holidays = False
# Some calendars roll a starting Sunday CNY to Sat
shift_start_cny_sunday = False
def get_chinese_new_year(self, year):
"""
Compute Chinese New Year days. To return a list of holidays.
By default, it'll at least return the Chinese New Year holidays chosen
using the following options:
* ``include_chinese_new_year_eve``
* ``include_chinese_new_year`` (on by default)
* ``include_chinese_second_day``
If the ``shift_sunday_holidays`` option is on, the rules are the
following.
* If the CNY1 falls on MON-FRI, there's not shift.
* If the CNY1 falls on SAT, the CNY2 is shifted to the Monday after.
* If the CNY1 falls on SUN, the CNY1 is shifted to the Monday after,
and CNY2 is shifted to the Tuesday after.
"""
days = []
lunar_first_day = ChineseNewYearCalendar.lunar(year, 1, 1)
# Chinese new year's eve
if self.include_chinese_new_year_eve:
days.append((
lunar_first_day - timedelta(days=1),
self.chinese_new_year_eve_label
))
# Chinese new year (is included by default)
if self.include_chinese_new_year:
days.append((lunar_first_day, self.chinese_new_year_label))
if self.include_chinese_second_day:
lunar_second_day = lunar_first_day + timedelta(days=1)
days.append((
lunar_second_day,
self.chinese_second_day_label
))
if self.include_chinese_third_day:
lunar_third_day = lunar_first_day + timedelta(days=2)
days.append((
lunar_third_day,
self.chinese_third_day_label
))
if self.shift_sunday_holidays:
if lunar_first_day.weekday() == SUN:
if self.shift_start_cny_sunday:
days.append(
(lunar_first_day - timedelta(days=1),
"Chinese Lunar New Year shift"),
)
else:
if self.include_chinese_third_day:
shift_day = lunar_third_day
else:
shift_day = lunar_second_day
days.append(
(shift_day + timedelta(days=1),
"Chinese Lunar New Year shift"),
)
if (lunar_second_day.weekday() == SUN
and self.include_chinese_third_day):
days.append(
(lunar_third_day + timedelta(days=1),
"Chinese Lunar New Year shift"),
)
return days
def get_variable_days(self, year):
days = super().get_variable_days(year)
days.extend(self.get_chinese_new_year(year))
return days
def get_shifted_holidays(self, dates):
"""
Taking a list of existing holidays, yield a list of 'shifted' days if
the holiday falls on SUN.
"""
for holiday, label in dates:
if holiday.weekday() == SUN:
yield (
holiday + timedelta(days=1),
label + ' shift'
)
def get_calendar_holidays(self, year):
"""
Take into account the eventual shift to the next MON if any holiday
falls on SUN.
"""
# Unshifted days are here:
days = super().get_calendar_holidays(year)
if self.shift_sunday_holidays:
days_to_inspect = copy(days)
for day_shifted in self.get_shifted_holidays(days_to_inspect):
days.append(day_shifted)
return days
class CalverterMixin(Calendar):
conversion_method = None
ISLAMIC_HOLIDAYS = ()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.calverter = Calverter()
if self.conversion_method is None:
raise NotImplementedError
def converted(self, year):
conversion_method = getattr(
self.calverter, 'jd_to_%s' % self.conversion_method)
current = date(year, 1, 1)
days = []
while current.year == year:
julian_day = self.calverter.gregorian_to_jd(
current.year,
current.month,
current.day)
days.append(conversion_method(julian_day))
current = current + timedelta(days=1)
return days
def calverted_years(self, year):
converted = self.converted(year)
generator = (y for y, m, d in converted)
return sorted(list(set(generator)))
def get_islamic_holidays(self):
return self.ISLAMIC_HOLIDAYS
def get_delta_islamic_holidays(self, year):
"""
Return the delta to add/substract according to the year or customs.
By default, to return None or timedelta(days=0)
"""
return None
def get_variable_days(self, year):
warnings.warn('Please take note that, due to arbitrary decisions, '
'this Islamic calendar computation may be wrong.')
days = super().get_variable_days(year)
years = self.calverted_years(year)
conversion_method = getattr(
self.calverter, '%s_to_jd' % self.conversion_method)
for month, day, label in self.get_islamic_holidays():
for y in years:
jd = conversion_method(y, month, day)
g_year, g_month, g_day = self.calverter.jd_to_gregorian(jd)
holiday = date(g_year, g_month, g_day)
# Only add a delta if necessary
delta = self.get_delta_islamic_holidays(year)
if delta:
holiday += delta
if holiday.year == year:
days.append((holiday, label))
return days
class IslamicMixin(CalverterMixin):
conversion_method = 'islamic'
include_prophet_birthday = False
include_day_after_prophet_birthday = False
include_start_ramadan = False
include_eid_al_fitr = False
length_eid_al_fitr = 1
eid_al_fitr_label = "Eid al-Fitr"
include_eid_al_adha = False
length_eid_al_adha = 1
include_day_of_sacrifice = False
day_of_sacrifice_label = "Eid al-Adha"
include_islamic_new_year = False
include_laylat_al_qadr = False
include_nuzul_al_quran = False
def get_islamic_holidays(self):
"""Return a list of Islamic (month, day, label) for islamic holidays.
Please take note that these dates must be expressed using the Islamic
Calendar"""
days = list(super().get_islamic_holidays())
if self.include_islamic_new_year:
days.append((1, 1, "Islamic New Year"))
if self.include_prophet_birthday:
days.append((3, 12, "Prophet's Birthday"))
if self.include_day_after_prophet_birthday:
days.append((3, 13, "Day after Prophet's Birthday"))
if self.include_start_ramadan:
days.append((9, 1, "Start of ramadan"))
if self.include_nuzul_al_quran:
days.append((9, 17, "Nuzul Al-Qur'an"))
if self.include_eid_al_fitr:
for x in range(self.length_eid_al_fitr):
days.append((10, x + 1, self.eid_al_fitr_label))
if self.include_eid_al_adha:
for x in range(self.length_eid_al_adha):
days.append((12, x + 10, "Eid al-Adha"))
if self.include_day_of_sacrifice:
days.append((12, 10, self.day_of_sacrifice_label))
if self.include_laylat_al_qadr:
warnings.warn("The Islamic holiday named Laylat al-Qadr is decided"
" by the religious authorities. It is not possible"
" to compute it. You'll have to add it manually.")
return tuple(days)
class JalaliMixin(CalverterMixin):
conversion_method = 'jalali'
FIXED_HOLIDAYS = Calendar.FIXED_HOLIDAYS

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('AT')
class Austria(WesternCalendar, ChristianMixin):
class Austria(WesternCalendar):
'Austria'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (

View File

@ -1,16 +1,16 @@
from datetime import timedelta
from ..core import WesternCalendar, OrthodoxMixin
from ..core import OrthodoxCalendar
from ..registry_tools import iso_register
@iso_register('BY')
class Belarus(WesternCalendar, OrthodoxMixin):
class Belarus(OrthodoxCalendar):
'Belarus'
"as of http://president.gov.by/en/holidays_en/"
include_christmas = False
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = OrthodoxCalendar.FIXED_HOLIDAYS + (
(1, 2, "Day After New Year"),
(1, 7, "Christmas (Orthodox)"),
(3, 8, "International Women's Day"),
@ -24,15 +24,10 @@ class Belarus(WesternCalendar, OrthodoxMixin):
# https://en.wikipedia.org/wiki/Radonitsa
def get_radonitsa(self, year):
# Second Monday after easter sunday
return self.get_easter_sunday(year) + timedelta(days=15)
def get_day_after_radonitsa(self, year):
# one day after the Radonsista Monday
return self.get_radonitsa(year) + timedelta(days=1)
# 9 Days after the Orthodox easter sunday
return self.get_easter_sunday(year) + timedelta(days=9)
def get_variable_days(self, year):
days = super().get_variable_days(year)
days.append((self.get_radonitsa(year), "Radonista"))
days.append((self.get_day_after_radonitsa(year), "Radonista Holiday"))
days.append((self.get_radonitsa(year), "Radonitsa"))
return days

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('BE')
class Belgium(WesternCalendar, ChristianMixin):
class Belgium(WesternCalendar):
'Belgium'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('BG')
class Bulgaria(WesternCalendar, ChristianMixin):
class Bulgaria(WesternCalendar):
'Bulgaria'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (

View File

@ -1,6 +1,6 @@
from datetime import date, timedelta
from ..core import WesternCalendar, ChristianMixin, MON, SAT
from ..core import WesternCalendar, MON, SAT
from ..registry_tools import iso_register
@ -11,7 +11,7 @@ QUEENS_BIRTHDAY_EXCEPTIONS = {
@iso_register('KY')
class CaymanIslands(WesternCalendar, ChristianMixin):
class CaymanIslands(WesternCalendar):
"Cayman Islands"
include_ash_wednesday = True
include_good_friday = True

View File

@ -1,11 +1,11 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('HR')
class Croatia(WesternCalendar, ChristianMixin):
class Croatia(WesternCalendar):
'Croatia'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (

View File

@ -1,10 +1,10 @@
from datetime import timedelta
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('CY')
class Cyprus(WesternCalendar, ChristianMixin):
class Cyprus(WesternCalendar):
'Cyprus'
include_epiphany = True

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('CZ')
class CzechRepublic(WesternCalendar, ChristianMixin):
class CzechRepublic(WesternCalendar):
'Czech Republic'
include_easter_monday = True

View File

@ -1,10 +1,10 @@
from datetime import timedelta
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('DK')
class Denmark(WesternCalendar, ChristianMixin):
class Denmark(WesternCalendar):
'Denmark'
include_holy_thursday = True

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('EE')
class Estonia(WesternCalendar, ChristianMixin):
class Estonia(WesternCalendar):
'Estonia'
include_good_friday = True

View File

@ -1,7 +1,7 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
class EuropeanCentralBank(WesternCalendar, ChristianMixin):
class EuropeanCentralBank(WesternCalendar):
"European Central Bank"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(5, 1, "Labour Day"),

View File

@ -1,10 +1,10 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin, FRI, SAT
from ..core import WesternCalendar, FRI, SAT
from ..registry_tools import iso_register
@iso_register('FI')
class Finland(WesternCalendar, ChristianMixin):
class Finland(WesternCalendar):
'Finland'
include_epiphany = True

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('FR')
class France(WesternCalendar, ChristianMixin):
class France(WesternCalendar):
'France'
include_easter_monday = True

View File

@ -1,10 +1,10 @@
from datetime import date, timedelta
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('DE')
class Germany(WesternCalendar, ChristianMixin):
class Germany(WesternCalendar):
'Germany'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (

View File

@ -1,12 +1,12 @@
from ..core import WesternCalendar, OrthodoxMixin
from ..core import OrthodoxCalendar
from ..registry_tools import iso_register
@iso_register('GR')
class Greece(OrthodoxMixin, WesternCalendar):
class Greece(OrthodoxCalendar):
'Greece'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = OrthodoxCalendar.FIXED_HOLIDAYS + (
(3, 25, "Independence Day"),
(5, 1, "Labour Day"),
(10, 28, "Ohi Day"),

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('HU')
class Hungary(WesternCalendar, ChristianMixin):
class Hungary(WesternCalendar):
'Hungary'
include_easter_sunday = True

View File

@ -1,10 +1,10 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin, THU, MON
from ..core import WesternCalendar, THU, MON
from ..registry_tools import iso_register
@iso_register('IS')
class Iceland(WesternCalendar, ChristianMixin):
class Iceland(WesternCalendar):
'Iceland'
include_holy_thursday = True

View File

@ -1,10 +1,10 @@
from datetime import date, timedelta
from ..core import WesternCalendar, ChristianMixin, MON
from ..core import WesternCalendar, MON
from ..registry_tools import iso_register
@iso_register('IE')
class Ireland(WesternCalendar, ChristianMixin):
class Ireland(WesternCalendar):
'Ireland'
include_easter_monday = True

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('IT')
class Italy(WesternCalendar, ChristianMixin):
class Italy(WesternCalendar):
'Italy'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (

View File

@ -1,10 +1,10 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('LV')
class Latvia(WesternCalendar, ChristianMixin):
class Latvia(WesternCalendar):
'Latvia'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin, SUN
from ..core import WesternCalendar, SUN
from ..registry_tools import iso_register
@iso_register('LT')
class Lithuania(WesternCalendar, ChristianMixin):
class Lithuania(WesternCalendar):
'Lithuania'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (

View File

@ -1,10 +1,10 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('LU')
class Luxembourg(WesternCalendar, ChristianMixin):
class Luxembourg(WesternCalendar):
'Luxembourg'
include_easter_monday = True

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('MT')
class Malta(WesternCalendar, ChristianMixin):
class Malta(WesternCalendar):
'Malta'
include_good_friday = True

View File

@ -1,10 +1,10 @@
from datetime import date, timedelta
from ..core import WesternCalendar, ChristianMixin, SUN
from ..core import WesternCalendar, SUN
from ..registry_tools import iso_register
@iso_register('NL')
class Netherlands(WesternCalendar, ChristianMixin):
class Netherlands(WesternCalendar):
'Netherlands'
include_good_friday = True

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('NO')
class Norway(WesternCalendar, ChristianMixin):
class Norway(WesternCalendar):
'Norway'
include_holy_thursday = True

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('PL')
class Poland(WesternCalendar, ChristianMixin):
class Poland(WesternCalendar):
'Poland'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (

View File

@ -1,10 +1,10 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('PT')
class Portugal(WesternCalendar, ChristianMixin):
class Portugal(WesternCalendar):
'Portugal'
include_good_friday = True

View File

@ -1,14 +1,14 @@
from datetime import date
from ..core import WesternCalendar, OrthodoxMixin
from ..core import OrthodoxCalendar
from ..registry_tools import iso_register
@iso_register('RO')
class Romania(OrthodoxMixin, WesternCalendar):
class Romania(OrthodoxCalendar):
'Romania'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(1, 2, "Day After New Years"),
FIXED_HOLIDAYS = OrthodoxCalendar.FIXED_HOLIDAYS + (
(1, 2, "Day After New Year"),
(1, 24, "Union Day"),
(5, 1, "Labour Day"),
(8, 15, "Dormition of the Theotokos"),

View File

@ -1,14 +1,14 @@
from ..core import WesternCalendar
from ..core import OrthodoxCalendar
from ..registry_tools import iso_register
@iso_register('RU')
class Russia(WesternCalendar):
class Russia(OrthodoxCalendar):
'Russia'
shift_new_years_day = True
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = OrthodoxCalendar.FIXED_HOLIDAYS + (
(1, 2, "Day After New Year"),
(1, 7, "Christmas"),
(2, 23, "Defendence of the Fatherland"),

View File

@ -24,7 +24,7 @@ FIXME:
# necessary to split this module and associated tests
from datetime import date, timedelta
import warnings
from ...core import WesternCalendar, ChristianMixin, MON, THU, FRI
from ...core import WesternCalendar, MON, THU, FRI
from .mixins import (
SpringHolidayFirstMondayApril,
SpringHolidaySecondMondayApril,
@ -51,7 +51,7 @@ from .mixins import (
)
class Scotland(WesternCalendar, ChristianMixin):
class Scotland(WesternCalendar):
"Scotland"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(1, 2, "New Year Holiday"),

View File

@ -1,12 +1,12 @@
from ..core import WesternCalendar, OrthodoxMixin
from ..core import OrthodoxCalendar
from ..registry_tools import iso_register
@iso_register('RS')
class Serbia(OrthodoxMixin, WesternCalendar):
class Serbia(OrthodoxCalendar):
'Serbia'
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = OrthodoxCalendar.FIXED_HOLIDAYS + (
(1, 2, "Day After New Year"),
(1, 7, "Christmas"),
(2, 15, "Statehood Day"),

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('SK')
class Slovakia(WesternCalendar, ChristianMixin):
class Slovakia(WesternCalendar):
'Slovakia'
include_epiphany = True

View File

@ -1,10 +1,10 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('SI')
class Slovenia(WesternCalendar, ChristianMixin):
class Slovenia(WesternCalendar):
'Slovenia'
include_easter_sunday = True

View File

@ -1,9 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..registry_tools import iso_register
@iso_register('ES')
class Spain(WesternCalendar, ChristianMixin):
class Spain(WesternCalendar):
'Spain'
include_epiphany = True

View File

@ -1,10 +1,10 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin, FRI, SAT
from ..core import WesternCalendar, FRI, SAT
from ..registry_tools import iso_register
@iso_register('SE')
class Sweden(WesternCalendar, ChristianMixin):
class Sweden(WesternCalendar):
'Sweden'
include_epiphany = True

View File

@ -1,10 +1,10 @@
from datetime import date, timedelta
from ..core import WesternCalendar, ChristianMixin, SUN
from ..core import WesternCalendar, SUN
from ..registry_tools import iso_register
@iso_register('CH')
class Switzerland(WesternCalendar, ChristianMixin):
class Switzerland(WesternCalendar):
'Switzerland'
# ChristianMixin entries common to (most) cantons - opt out

View File

@ -1,13 +1,14 @@
from datetime import timedelta
from ..core import WesternCalendar, IslamicMixin
from ..core import NewYearsDayMixin, IslamicCalendar, SAT, SUN
from ..registry_tools import iso_register
@iso_register('TR')
class Turkey(WesternCalendar, IslamicMixin):
class Turkey(NewYearsDayMixin, IslamicCalendar):
'Turkey'
shift_new_years_day = True
# Even though they're using an islamic calendar, the work week is MON->FRI
WEEKEND_DAYS = (SAT, SUN)
# Islamic Holidays
include_eid_al_fitr = True
@ -15,7 +16,7 @@ class Turkey(WesternCalendar, IslamicMixin):
include_eid_al_adha = True
length_eid_al_adha = 4
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = NewYearsDayMixin.FIXED_HOLIDAYS + (
(4, 23, "National Sovereignty and Children's Day"),
(5, 1, "Labor and Solidarity Day"),
(5, 19, "Commemoration of Atatürk, Youth and Sports Day"),

View File

@ -1,16 +1,16 @@
from datetime import date
from ..core import WesternCalendar, OrthodoxMixin
from ..core import OrthodoxCalendar
from ..registry_tools import iso_register
@iso_register('UA')
class Ukraine(OrthodoxMixin, WesternCalendar):
class Ukraine(OrthodoxCalendar):
'Ukraine'
shift_sunday_holidays = True
shift_new_years_day = True
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
FIXED_HOLIDAYS = OrthodoxCalendar.FIXED_HOLIDAYS + (
(3, 8, "International Womens Day"),
(5, 1, "Workers Solidarity Day"),
(5, 9, "Victory Day"),

View File

@ -1,10 +1,10 @@
from datetime import date
from ..core import WesternCalendar, ChristianMixin, MON
from ..core import WesternCalendar, MON
from ..registry_tools import iso_register
@iso_register('GB')
class UnitedKingdom(WesternCalendar, ChristianMixin):
class UnitedKingdom(WesternCalendar):
'United Kingdom'
include_good_friday = True

View File

@ -1,12 +1,11 @@
from datetime import date, timedelta
from ..core import WesternCalendar, ChristianMixin
from ..core import MON, TUE, SAT, SUN
from ..core import WesternCalendar, MON, TUE, SAT, SUN
from ..registry_tools import iso_register
@iso_register('AU')
class Australia(WesternCalendar, ChristianMixin):
class Australia(WesternCalendar):
"Australia"
include_good_friday = True
include_easter_monday = True

View File

@ -1,10 +1,9 @@
from ..core import WesternCalendar, ChristianMixin
from ..core import FRI
from ..core import WesternCalendar, FRI
from ..registry_tools import iso_register
@iso_register('MH')
class MarshallIslands(WesternCalendar, ChristianMixin):
class MarshallIslands(WesternCalendar):
"Marshall Islands"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
(3, 3, "Remembrance Day"),

View File

@ -1,11 +1,11 @@
from datetime import date, timedelta
from ..core import WesternCalendar, ChristianMixin, MON, SAT, SUN
from ..core import WesternCalendar, MON, SAT, SUN
from ..registry_tools import iso_register
@iso_register("NZ")
class NewZealand(WesternCalendar, ChristianMixin):
class NewZealand(WesternCalendar):
"New Zealand"
include_good_friday = True
include_easter_monday = True

View File

@ -5,11 +5,26 @@ from unittest import TestCase
from ..core import Calendar
class GenericCalendarTest(TestCase):
class CoreCalendarTest(TestCase):
cal_class = Calendar
def setUp(self):
super().setUp()
warnings.simplefilter('ignore')
self.year = date.today().year
self.cal = self.cal_class()
class GenericCalendarTest(CoreCalendarTest):
def setUp(self):
super().setUp()
warnings.simplefilter('ignore')
def test_weekend_days(self):
class_name = self.cal_class.__name__
if class_name in ('Calendar',):
return
try:
self.cal.get_weekend_days()
except NotImplementedError:
assert False, (self.cal, class_name)

View File

@ -4,16 +4,16 @@ from unittest import TestCase
import pandas
from . import GenericCalendarTest
from . import CoreCalendarTest
from ..core import (
MON, TUE, THU, FRI, WED, SAT, SUN,
Calendar, LunarCalendar, WesternCalendar,
IslamicMixin, JalaliMixin, ChristianMixin
Calendar, LunarMixin, WesternCalendar,
IslamicMixin, JalaliMixin
)
from ..exceptions import UnsupportedDateType
class CalendarTest(GenericCalendarTest):
class CalendarTest(CoreCalendarTest):
def test_private_variables(self):
self.assertTrue(hasattr(self.cal, '_holidays'))
@ -104,12 +104,11 @@ class CalendarTest(GenericCalendarTest):
)
class LunarCalendarTest(GenericCalendarTest):
cal_class = LunarCalendar
class LunarCalendarTest(TestCase):
def test_new_year(self):
def test_lunar_new_year(self):
self.assertEquals(
self.cal.lunar(2014, 1, 1),
LunarMixin.lunar(2014, 1, 1),
date(2014, 1, 31)
)
@ -126,7 +125,7 @@ class MockCalendar(Calendar):
return [] # no week-end, yes, it's sad
class MockCalendarTest(GenericCalendarTest):
class MockCalendarTest(CoreCalendarTest):
cal_class = MockCalendar
def test_holidays_set(self):
@ -239,7 +238,7 @@ class MockCalendarTest(GenericCalendarTest):
)
class IslamicMixinTest(GenericCalendarTest):
class IslamicMixinTest(CoreCalendarTest):
cal_class = IslamicMixin
def test_year_conversion(self):
@ -247,7 +246,7 @@ class IslamicMixinTest(GenericCalendarTest):
self.assertEquals(len(days), 365)
class JalaliMixinTest(GenericCalendarTest):
class JalaliMixinTest(CoreCalendarTest):
cal_class = JalaliMixin
def test_year_conversion(self):
@ -255,11 +254,12 @@ class JalaliMixinTest(GenericCalendarTest):
self.assertEquals(len(days), 365)
class MockChristianCalendar(WesternCalendar, ChristianMixin):
class MockChristianCalendar(WesternCalendar):
# WesternCalendar inherits from ChristianMixin
pass
class MockChristianCalendarTest(GenericCalendarTest):
class MockChristianCalendarTest(CoreCalendarTest):
cal_class = MockChristianCalendar
def test_year_2014(self):
@ -297,7 +297,7 @@ class NoWeekendCalendar(Calendar):
"""
class NoWeekendCalendarTest(GenericCalendarTest):
class NoWeekendCalendarTest(CoreCalendarTest):
cal_class = NoWeekendCalendar
def test_weekend(self):
@ -317,7 +317,7 @@ class WeekendOnWednesdayCalendar(Calendar):
WEEKEND_DAYS = (WED,)
class WeekendOnWednesdayCalendarTest(GenericCalendarTest):
class WeekendOnWednesdayCalendarTest(CoreCalendarTest):
cal_class = WeekendOnWednesdayCalendar
def test_weekend(self):
@ -337,7 +337,7 @@ class OverwriteGetWeekendDaysCalendar(Calendar):
return (WED,)
class OverwriteGetWeekendDaysCalendarTest(GenericCalendarTest):
class OverwriteGetWeekendDaysCalendarTest(CoreCalendarTest):
cal_class = OverwriteGetWeekendDaysCalendar
def test_weekend(self):
@ -487,7 +487,7 @@ class CalendarClassName(TestCase):
)
class TestAcceptableDateTypes(GenericCalendarTest):
class TestAcceptableDateTypes(CoreCalendarTest):
"""
Test cases about accepted date and datetime types.
"""
@ -642,7 +642,7 @@ class TestAcceptableDateTypes(GenericCalendarTest):
self.cal.get_holiday_label(datetime(2014, 1, 2)))
class PandasTimestampTest(GenericCalendarTest):
class PandasTimestampTest(CoreCalendarTest):
cal_class = MockCalendar
def test_panda_type_is_working_day(self):

View File

@ -72,8 +72,7 @@ class BelarusTest(GenericCalendarTest):
self.assertIn(date(2019, 1, 7), holidays) # Christmas (Orthodox)
self.assertIn(date(2019, 3, 8), holidays) # International Women's Day
self.assertIn(date(2019, 5, 1), holidays) # Labour Day
self.assertIn(date(2019, 5, 6), holidays) # Radonista
self.assertIn(date(2019, 5, 7), holidays) # Radonista Holiday
self.assertIn(date(2019, 5, 7), holidays) # Radonitsa
self.assertIn(date(2019, 5, 9), holidays) # Victory Day
self.assertIn(date(2019, 7, 3), holidays) # Republic Day
self.assertIn(date(2019, 11, 7), holidays) # October Revolution Day
@ -85,8 +84,7 @@ class BelarusTest(GenericCalendarTest):
self.assertIn(date(2020, 1, 2), holidays) # Day after NYE
self.assertIn(date(2020, 1, 7), holidays) # Christmas (Orthodox)
self.assertIn(date(2020, 3, 8), holidays) # International Women's Day
self.assertIn(date(2020, 4, 27), holidays) # Radonista
self.assertIn(date(2020, 4, 28), holidays) # Radonista Holiday
self.assertIn(date(2020, 4, 28), holidays) # Radonitsa
self.assertIn(date(2020, 5, 1), holidays) # Labour Day
self.assertIn(date(2020, 5, 9), holidays) # Victory Day
self.assertIn(date(2020, 7, 3), holidays) # Republic Day
@ -569,6 +567,24 @@ class GreeceTest(GenericCalendarTest):
self.assertIn(date(2013, 12, 25), holidays) # XMas
self.assertIn(date(2013, 12, 26), holidays) # Glorifying mother of God
def test_year_2020(self):
holidays = self.cal.holidays_set(2020)
self.assertIn(date(2020, 1, 1), holidays) # new year
self.assertIn(date(2020, 1, 6), holidays) # epiphany
self.assertIn(date(2020, 3, 2), holidays) # Clean monday
# Annunciation & Independence day
self.assertIn(date(2020, 3, 25), holidays)
self.assertIn(date(2020, 4, 17), holidays) # good friday
self.assertIn(date(2020, 4, 19), holidays) # easter
self.assertIn(date(2020, 4, 20), holidays) # easter monday
self.assertIn(date(2020, 5, 1), holidays) # labour day
self.assertIn(date(2020, 6, 7), holidays) # pentecost sunday
self.assertIn(date(2020, 6, 8), holidays) # whit monday
self.assertIn(date(2020, 8, 15), holidays) # Assumption
self.assertIn(date(2020, 10, 28), holidays) # Ochi Day
self.assertIn(date(2020, 12, 25), holidays) # XMas
self.assertIn(date(2020, 12, 26), holidays) # Glorifying mother of God
class HungaryTest(GenericCalendarTest):
cal_class = Hungary

View File

@ -1,12 +1,12 @@
from datetime import date, timedelta
from ..core import WesternCalendar, ChristianMixin
from ..core import WesternCalendar
from ..core import SUN, MON, TUE, WED, THU, FRI, SAT
from ..registry_tools import iso_register
@iso_register('US')
class UnitedStates(WesternCalendar, ChristianMixin):
class UnitedStates(WesternCalendar):
"United States of America"
FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (