holidays 0.47__py3-none-any.whl → 0.49__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- holidays/__init__.py +1 -1
- holidays/calendars/gregorian.py +31 -7
- holidays/calendars/persian.py +3 -2
- holidays/calendars/thai.py +24 -20
- holidays/countries/__init__.py +1 -0
- holidays/countries/angola.py +2 -2
- holidays/countries/aruba.py +2 -3
- holidays/countries/australia.py +1 -3
- holidays/countries/belgium.py +1 -2
- holidays/countries/bolivia.py +1 -2
- holidays/countries/brazil.py +1 -2
- holidays/countries/cambodia.py +7 -8
- holidays/countries/canada.py +2 -1
- holidays/countries/chile.py +6 -6
- holidays/countries/colombia.py +1 -2
- holidays/countries/curacao.py +3 -4
- holidays/countries/cyprus.py +1 -2
- holidays/countries/denmark.py +1 -2
- holidays/countries/finland.py +3 -3
- holidays/countries/france.py +1 -2
- holidays/countries/greece.py +11 -6
- holidays/countries/hongkong.py +398 -133
- holidays/countries/israel.py +13 -13
- holidays/countries/italy.py +2 -4
- holidays/countries/japan.py +17 -6
- holidays/countries/jersey.py +2 -2
- holidays/countries/laos.py +7 -23
- holidays/countries/madagascar.py +2 -3
- holidays/countries/malaysia.py +545 -235
- holidays/countries/moldova.py +1 -2
- holidays/countries/netherlands.py +2 -3
- holidays/countries/new_zealand.py +10 -11
- holidays/countries/palau.py +127 -0
- holidays/countries/portugal.py +2 -6
- holidays/countries/saudi_arabia.py +2 -3
- holidays/countries/south_korea.py +18 -5
- holidays/countries/sweden.py +2 -3
- holidays/countries/switzerland.py +2 -3
- holidays/countries/timor_leste.py +23 -1
- holidays/countries/united_states.py +1 -1
- holidays/countries/uruguay.py +3 -4
- holidays/financial/__init__.py +1 -0
- holidays/financial/ice_futures_europe.py +47 -0
- holidays/financial/ny_stock_exchange.py +17 -4
- holidays/groups/chinese.py +2 -3
- holidays/groups/christian.py +18 -19
- holidays/groups/international.py +10 -0
- holidays/groups/islamic.py +2 -2
- holidays/groups/persian.py +2 -2
- holidays/helpers.py +9 -3
- holidays/holiday_base.py +133 -66
- holidays/locale/en_US/LC_MESSAGES/MY.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/MY.po +250 -0
- holidays/locale/ms_MY/LC_MESSAGES/MY.mo +0 -0
- holidays/locale/ms_MY/LC_MESSAGES/MY.po +250 -0
- holidays/mixins.py +31 -0
- holidays/observed_holiday_base.py +25 -13
- holidays/registry.py +2 -0
- {holidays-0.47.dist-info → holidays-0.49.dist-info}/METADATA +29 -21
- {holidays-0.47.dist-info → holidays-0.49.dist-info}/RECORD +64 -57
- {holidays-0.47.dist-info → holidays-0.49.dist-info}/AUTHORS +0 -0
- {holidays-0.47.dist-info → holidays-0.49.dist-info}/LICENSE +0 -0
- {holidays-0.47.dist-info → holidays-0.49.dist-info}/WHEEL +0 -0
- {holidays-0.47.dist-info → holidays-0.49.dist-info}/top_level.txt +0 -0
holidays/groups/christian.py
CHANGED
|
@@ -11,11 +11,10 @@
|
|
|
11
11
|
# License: MIT (see LICENSE file)
|
|
12
12
|
|
|
13
13
|
from datetime import date
|
|
14
|
-
from datetime import timedelta as td
|
|
15
14
|
|
|
16
15
|
from dateutil.easter import EASTER_ORTHODOX, EASTER_WESTERN, easter
|
|
17
16
|
|
|
18
|
-
from holidays.calendars.gregorian import GREGORIAN_CALENDAR, JAN, DEC
|
|
17
|
+
from holidays.calendars.gregorian import GREGORIAN_CALENDAR, JAN, DEC, _timedelta
|
|
19
18
|
from holidays.calendars.julian import JULIAN_CALENDAR
|
|
20
19
|
from holidays.calendars.julian_revised import JULIAN_REVISED_CALENDAR
|
|
21
20
|
|
|
@@ -123,7 +122,7 @@ class ChristianHolidays:
|
|
|
123
122
|
Day, or sometimes Holy Thursday.
|
|
124
123
|
https://en.wikipedia.org/wiki/Feast_of_the_Ascension
|
|
125
124
|
"""
|
|
126
|
-
return self._add_holiday(name, self._easter_sunday +
|
|
125
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, +39))
|
|
127
126
|
|
|
128
127
|
def _add_ash_monday(self, name) -> date:
|
|
129
128
|
"""
|
|
@@ -133,7 +132,7 @@ class ChristianHolidays:
|
|
|
133
132
|
or Green Monday. The first day of Great Lent.
|
|
134
133
|
https://en.wikipedia.org/wiki/Clean_Monday
|
|
135
134
|
"""
|
|
136
|
-
return self._add_holiday(name, self._easter_sunday
|
|
135
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, -48))
|
|
137
136
|
|
|
138
137
|
def _add_ash_wednesday(self, name) -> date:
|
|
139
138
|
"""
|
|
@@ -142,7 +141,7 @@ class ChristianHolidays:
|
|
|
142
141
|
A holy day of prayer and fasting. It marks the beginning of Lent.
|
|
143
142
|
https://en.wikipedia.org/wiki/Ash_Wednesday
|
|
144
143
|
"""
|
|
145
|
-
return self._add_holiday(name, self._easter_sunday
|
|
144
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, -46))
|
|
146
145
|
|
|
147
146
|
def _add_assumption_of_mary_day(self, name, calendar=None) -> date:
|
|
148
147
|
"""
|
|
@@ -182,7 +181,7 @@ class ChristianHolidays:
|
|
|
182
181
|
the liturgical season of Lent.
|
|
183
182
|
https://en.wikipedia.org/wiki/Carnival
|
|
184
183
|
"""
|
|
185
|
-
return self._add_holiday(name, self._easter_sunday
|
|
184
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, -48))
|
|
186
185
|
|
|
187
186
|
def _add_carnival_tuesday(self, name) -> date:
|
|
188
187
|
"""
|
|
@@ -192,7 +191,7 @@ class ChristianHolidays:
|
|
|
192
191
|
the liturgical season of Lent.
|
|
193
192
|
https://en.wikipedia.org/wiki/Carnival
|
|
194
193
|
"""
|
|
195
|
-
return self._add_holiday(name, self._easter_sunday
|
|
194
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, -47))
|
|
196
195
|
|
|
197
196
|
def _add_christmas_day(self, name, calendar=None) -> date:
|
|
198
197
|
"""
|
|
@@ -212,7 +211,7 @@ class ChristianHolidays:
|
|
|
212
211
|
https://en.wikipedia.org/wiki/Boxing_Day
|
|
213
212
|
https://en.wikipedia.org/wiki/Christmas
|
|
214
213
|
"""
|
|
215
|
-
return self._add_holiday(name, self.__get_christmas_day(calendar) +
|
|
214
|
+
return self._add_holiday(name, _timedelta(self.__get_christmas_day(calendar), +1))
|
|
216
215
|
|
|
217
216
|
def _add_christmas_day_three(self, name, calendar=None) -> date:
|
|
218
217
|
"""
|
|
@@ -221,7 +220,7 @@ class ChristianHolidays:
|
|
|
221
220
|
A holiday celebrated 2 days after Christmas Day (in some countries).
|
|
222
221
|
https://en.wikipedia.org/wiki/Christmas
|
|
223
222
|
"""
|
|
224
|
-
return self._add_holiday(name, self.__get_christmas_day(calendar) +
|
|
223
|
+
return self._add_holiday(name, _timedelta(self.__get_christmas_day(calendar), +2))
|
|
225
224
|
|
|
226
225
|
def _add_christmas_eve(self, name, calendar=None) -> date:
|
|
227
226
|
"""
|
|
@@ -231,7 +230,7 @@ class ChristianHolidays:
|
|
|
231
230
|
the festival commemorating the birth of Jesus Christ.
|
|
232
231
|
https://en.wikipedia.org/wiki/Christmas_Eve
|
|
233
232
|
"""
|
|
234
|
-
return self._add_holiday(name, self.__get_christmas_day(calendar)
|
|
233
|
+
return self._add_holiday(name, _timedelta(self.__get_christmas_day(calendar), -1))
|
|
235
234
|
|
|
236
235
|
def _add_corpus_christi_day(self, name) -> date:
|
|
237
236
|
"""
|
|
@@ -243,7 +242,7 @@ class ChristianHolidays:
|
|
|
243
242
|
of Jesus Christ in the elements of the Eucharist.
|
|
244
243
|
https://en.wikipedia.org/wiki/Feast_of_Corpus_Christi
|
|
245
244
|
"""
|
|
246
|
-
return self._add_holiday(name, self._easter_sunday +
|
|
245
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, +60))
|
|
247
246
|
|
|
248
247
|
def _add_easter_monday(self, name, calendar=None) -> date:
|
|
249
248
|
"""
|
|
@@ -254,7 +253,7 @@ class ChristianHolidays:
|
|
|
254
253
|
some countries.
|
|
255
254
|
https://en.wikipedia.org/wiki/Easter_Monday
|
|
256
255
|
"""
|
|
257
|
-
return self._add_holiday(name, self.__get_easter_sunday(calendar) +
|
|
256
|
+
return self._add_holiday(name, _timedelta(self.__get_easter_sunday(calendar), +1))
|
|
258
257
|
|
|
259
258
|
def _add_easter_sunday(self, name, calendar=None) -> date:
|
|
260
259
|
"""
|
|
@@ -294,7 +293,7 @@ class ChristianHolidays:
|
|
|
294
293
|
Great Friday, Great and Holy Friday.
|
|
295
294
|
https://en.wikipedia.org/wiki/Good_Friday
|
|
296
295
|
"""
|
|
297
|
-
return self._add_holiday(name, self.__get_easter_sunday(calendar)
|
|
296
|
+
return self._add_holiday(name, _timedelta(self.__get_easter_sunday(calendar), -2))
|
|
298
297
|
|
|
299
298
|
def _add_holy_saturday(self, name) -> date:
|
|
300
299
|
"""
|
|
@@ -303,7 +302,7 @@ class ChristianHolidays:
|
|
|
303
302
|
Great and Holy Saturday is a day between Good Friday and Easter Sunday.
|
|
304
303
|
https://en.wikipedia.org/wiki/Holy_Saturday
|
|
305
304
|
"""
|
|
306
|
-
return self._add_holiday(name, self._easter_sunday
|
|
305
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, -1))
|
|
307
306
|
|
|
308
307
|
def _add_holy_thursday(self, name) -> date:
|
|
309
308
|
"""
|
|
@@ -314,7 +313,7 @@ class ChristianHolidays:
|
|
|
314
313
|
Jesus Christ with the Apostles, as described in the canonical gospels.
|
|
315
314
|
https://en.wikipedia.org/wiki/Maundy_Thursday
|
|
316
315
|
"""
|
|
317
|
-
return self._add_holiday(name, self._easter_sunday
|
|
316
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, -3))
|
|
318
317
|
|
|
319
318
|
def _add_immaculate_conception_day(self, name) -> date:
|
|
320
319
|
"""
|
|
@@ -345,7 +344,7 @@ class ChristianHolidays:
|
|
|
345
344
|
Palm Sunday marks the first day of Holy Week.
|
|
346
345
|
https://en.wikipedia.org/wiki/Palm_Sunday
|
|
347
346
|
"""
|
|
348
|
-
return self._add_holiday(name, self._easter_sunday
|
|
347
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, -7))
|
|
349
348
|
|
|
350
349
|
def _add_rejoicing_day(self, name) -> date:
|
|
351
350
|
"""
|
|
@@ -356,7 +355,7 @@ class ChristianHolidays:
|
|
|
356
355
|
Pascha (Easter).In Ukrainian tradition it is called Provody.
|
|
357
356
|
https://en.wikipedia.org/wiki/Radonitsa
|
|
358
357
|
"""
|
|
359
|
-
return self._add_holiday(name, self._easter_sunday +
|
|
358
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, +9))
|
|
360
359
|
|
|
361
360
|
def _add_saint_georges_day(self, name) -> date:
|
|
362
361
|
"""
|
|
@@ -418,7 +417,7 @@ class ChristianHolidays:
|
|
|
418
417
|
https://en.wikipedia.org/wiki/Pentecost
|
|
419
418
|
https://en.wikipedia.org/wiki/Whit_Monday
|
|
420
419
|
"""
|
|
421
|
-
return self._add_holiday(name, self._easter_sunday +
|
|
420
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, +50))
|
|
422
421
|
|
|
423
422
|
def _add_whit_sunday(self, name) -> date:
|
|
424
423
|
"""
|
|
@@ -430,4 +429,4 @@ class ChristianHolidays:
|
|
|
430
429
|
Feast of Weeks.
|
|
431
430
|
https://en.wikipedia.org/wiki/Pentecost
|
|
432
431
|
"""
|
|
433
|
-
return self._add_holiday(name, self._easter_sunday +
|
|
432
|
+
return self._add_holiday(name, _timedelta(self._easter_sunday, +49))
|
holidays/groups/international.py
CHANGED
|
@@ -194,3 +194,13 @@ class InternationalHolidays:
|
|
|
194
194
|
https://en.wikipedia.org/wiki/Victory_Day_(9_May)
|
|
195
195
|
"""
|
|
196
196
|
return self._add_holiday_may_9(name)
|
|
197
|
+
|
|
198
|
+
def _add_united_nations_day(self, name):
|
|
199
|
+
"""
|
|
200
|
+
Add United Nations Day (Oct 24th)
|
|
201
|
+
|
|
202
|
+
United Nations Day is an annual commemorative day, reflecting the
|
|
203
|
+
official creation of the United Nations on 24 October 1945.
|
|
204
|
+
https://en.wikipedia.org/wiki/United_Nations_Day
|
|
205
|
+
"""
|
|
206
|
+
return self._add_holiday_oct_24(name)
|
holidays/groups/islamic.py
CHANGED
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
# License: MIT (see LICENSE file)
|
|
12
12
|
|
|
13
13
|
from datetime import date
|
|
14
|
-
from datetime import timedelta as td
|
|
15
14
|
from typing import Iterable, Set, Tuple
|
|
16
15
|
|
|
17
16
|
from holidays.calendars import _IslamicLunar
|
|
17
|
+
from holidays.calendars.gregorian import _timedelta
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class IslamicHolidays:
|
|
@@ -264,7 +264,7 @@ class IslamicHolidays:
|
|
|
264
264
|
estimated_label = getattr(self, "estimated_label", "%s (estimated)")
|
|
265
265
|
for dt, is_estimated in dates:
|
|
266
266
|
if days_delta != 0:
|
|
267
|
-
dt
|
|
267
|
+
dt = _timedelta(dt, days_delta)
|
|
268
268
|
|
|
269
269
|
dt = self._add_holiday(
|
|
270
270
|
self.tr(estimated_label) % self.tr(name) if is_estimated else name, dt
|
holidays/groups/persian.py
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
# License: MIT (see LICENSE file)
|
|
12
12
|
|
|
13
13
|
from datetime import date
|
|
14
|
-
from datetime import timedelta as td
|
|
15
14
|
from typing import Optional
|
|
16
15
|
|
|
16
|
+
from holidays.calendars.gregorian import _timedelta
|
|
17
17
|
from holidays.calendars.persian import _Persian
|
|
18
18
|
|
|
19
19
|
|
|
@@ -142,5 +142,5 @@ class PersianCalendarHolidays:
|
|
|
142
142
|
if dt is None:
|
|
143
143
|
return None
|
|
144
144
|
if days_delta != 0:
|
|
145
|
-
dt
|
|
145
|
+
dt = _timedelta(dt, days_delta)
|
|
146
146
|
return self._add_holiday(name, dt)
|
holidays/helpers.py
CHANGED
|
@@ -24,13 +24,19 @@ def _normalize_arguments(cls, value):
|
|
|
24
24
|
A set created from `value` argument.
|
|
25
25
|
|
|
26
26
|
"""
|
|
27
|
+
if value is None:
|
|
28
|
+
return set()
|
|
29
|
+
|
|
27
30
|
if isinstance(value, cls):
|
|
28
31
|
return {value}
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
try:
|
|
34
|
+
return {v if isinstance(v, cls) else cls(v) for v in value}
|
|
35
|
+
except TypeError: # non-iterable
|
|
36
|
+
return {value if isinstance(value, cls) else cls(value)}
|
|
31
37
|
|
|
32
38
|
|
|
33
|
-
def _normalize_tuple(
|
|
39
|
+
def _normalize_tuple(value):
|
|
34
40
|
"""Normalize tuple.
|
|
35
41
|
|
|
36
42
|
:param data:
|
|
@@ -40,4 +46,4 @@ def _normalize_tuple(data):
|
|
|
40
46
|
An unchanged object for tuple of tuples, e.g., ((JAN, 10), (DEC, 31)).
|
|
41
47
|
An object put into a tuple otherwise, e.g., ((JAN, 10),).
|
|
42
48
|
"""
|
|
43
|
-
return
|
|
49
|
+
return value if not value or isinstance(value[0], tuple) else (value,)
|
holidays/holiday_base.py
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
__all__ = ("DateLike", "HolidayBase", "HolidaySum")
|
|
14
14
|
|
|
15
15
|
import copy
|
|
16
|
-
import re
|
|
17
16
|
import warnings
|
|
18
17
|
from calendar import isleap
|
|
19
18
|
from datetime import date, datetime, timedelta, timezone
|
|
@@ -24,7 +23,6 @@ from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, Union, cast
|
|
|
24
23
|
|
|
25
24
|
from dateutil.parser import parse
|
|
26
25
|
|
|
27
|
-
from holidays.calendars import gregorian
|
|
28
26
|
from holidays.calendars.gregorian import (
|
|
29
27
|
MON,
|
|
30
28
|
TUE,
|
|
@@ -33,8 +31,12 @@ from holidays.calendars.gregorian import (
|
|
|
33
31
|
FRI,
|
|
34
32
|
SAT,
|
|
35
33
|
SUN,
|
|
34
|
+
_timedelta,
|
|
36
35
|
_get_nth_weekday_from,
|
|
37
36
|
_get_nth_weekday_of_month,
|
|
37
|
+
DAYS,
|
|
38
|
+
MONTHS,
|
|
39
|
+
WEEKDAYS,
|
|
38
40
|
)
|
|
39
41
|
from holidays.constants import HOLIDAY_NAME_DELIMITER, PUBLIC
|
|
40
42
|
from holidays.helpers import _normalize_arguments, _normalize_tuple
|
|
@@ -230,6 +232,8 @@ class HolidayBase(Dict[date, str]):
|
|
|
230
232
|
ones."""
|
|
231
233
|
weekend: Set[int] = {SAT, SUN}
|
|
232
234
|
"""Country weekend days."""
|
|
235
|
+
weekend_workdays: Set[date] = set()
|
|
236
|
+
"""Working days moved to weekends."""
|
|
233
237
|
default_category: str = PUBLIC
|
|
234
238
|
"""The entity category used by default."""
|
|
235
239
|
default_language: Optional[str] = None
|
|
@@ -353,6 +357,7 @@ class HolidayBase(Dict[date, str]):
|
|
|
353
357
|
self.language = language.lower() if language else None
|
|
354
358
|
self.observed = observed
|
|
355
359
|
self.subdiv = subdiv
|
|
360
|
+
self.weekend_workdays = set()
|
|
356
361
|
|
|
357
362
|
supported_languages = set(self.supported_languages)
|
|
358
363
|
self.tr = (
|
|
@@ -427,77 +432,107 @@ class HolidayBase(Dict[date, str]):
|
|
|
427
432
|
except AttributeError as e:
|
|
428
433
|
# This part is responsible for _add_holiday_* syntactic sugar support.
|
|
429
434
|
add_holiday_prefix = "_add_holiday_"
|
|
430
|
-
# Raise early if prefix doesn't match to avoid
|
|
435
|
+
# Raise early if prefix doesn't match to avoid patterns checks.
|
|
431
436
|
if name[: len(add_holiday_prefix)] != add_holiday_prefix:
|
|
432
437
|
raise e
|
|
433
438
|
|
|
439
|
+
tokens = name.split("_")
|
|
440
|
+
|
|
434
441
|
# Handle <month> <day> patterns (e.g., _add_holiday_jun_15()).
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
month
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
+
if len(tokens) == 5:
|
|
443
|
+
*_, month, day = tokens
|
|
444
|
+
if month in MONTHS and day in DAYS:
|
|
445
|
+
return lambda name: self._add_holiday(
|
|
446
|
+
name,
|
|
447
|
+
date(self._year, MONTHS[month], int(day)),
|
|
448
|
+
)
|
|
442
449
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
450
|
+
elif len(tokens) == 7:
|
|
451
|
+
# Handle <last/nth> <weekday> of <month> patterns (e.g.,
|
|
452
|
+
# _add_holiday_last_mon_of_aug() or _add_holiday_3rd_fri_of_aug()).
|
|
453
|
+
*_, number, weekday, of, month = tokens
|
|
454
|
+
if (
|
|
455
|
+
of == "of"
|
|
456
|
+
and (number == "last" or number[0].isdigit())
|
|
457
|
+
and month in MONTHS
|
|
458
|
+
and weekday in WEEKDAYS
|
|
459
|
+
):
|
|
460
|
+
return lambda name: self._add_holiday(
|
|
461
|
+
name,
|
|
462
|
+
_get_nth_weekday_of_month(
|
|
463
|
+
-1 if number == "last" else int(number[0]),
|
|
464
|
+
WEEKDAYS[weekday],
|
|
465
|
+
MONTHS[month],
|
|
466
|
+
self._year,
|
|
467
|
+
),
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# Handle <n> days <past/prior> easter patterns (e.g.,
|
|
471
|
+
# _add_holiday_8_days_past_easter() or
|
|
472
|
+
# _add_holiday_5_days_prior_easter()).
|
|
473
|
+
*_, days, unit, delta_direction, easter = tokens
|
|
474
|
+
if (
|
|
475
|
+
unit in {"day", "days"}
|
|
476
|
+
and delta_direction in {"past", "prior"}
|
|
477
|
+
and easter == "easter"
|
|
478
|
+
and len(days) < 3
|
|
479
|
+
and days.isdigit()
|
|
480
|
+
):
|
|
481
|
+
return lambda name: self._add_holiday(
|
|
482
|
+
name,
|
|
483
|
+
_timedelta(
|
|
484
|
+
self._easter_sunday,
|
|
485
|
+
+int(days) if delta_direction == "past" else -int(days),
|
|
486
|
+
),
|
|
487
|
+
)
|
|
459
488
|
|
|
460
489
|
# Handle <n> day(s) <past/prior> <last/<nth> <weekday> of <month> patterns (e.g.,
|
|
461
490
|
# _add_holiday_1_day_past_1st_fri_of_aug() or
|
|
462
491
|
# _add_holiday_5_days_prior_last_fri_of_aug()).
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
days
|
|
470
|
-
|
|
471
|
-
number
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
)
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
492
|
+
elif len(tokens) == 10:
|
|
493
|
+
*_, days, unit, delta_direction, number, weekday, of, month = tokens
|
|
494
|
+
if (
|
|
495
|
+
unit in {"day", "days"}
|
|
496
|
+
and delta_direction in {"past", "prior"}
|
|
497
|
+
and of == "of"
|
|
498
|
+
and len(days) < 3
|
|
499
|
+
and days.isdigit()
|
|
500
|
+
and (number == "last" or number[0].isdigit())
|
|
501
|
+
and month in MONTHS
|
|
502
|
+
and weekday in WEEKDAYS
|
|
503
|
+
):
|
|
504
|
+
return lambda name: self._add_holiday(
|
|
505
|
+
name,
|
|
506
|
+
_timedelta(
|
|
507
|
+
_get_nth_weekday_of_month(
|
|
508
|
+
-1 if number == "last" else int(number[0]),
|
|
509
|
+
WEEKDAYS[weekday],
|
|
510
|
+
MONTHS[month],
|
|
511
|
+
self._year,
|
|
512
|
+
),
|
|
513
|
+
+int(days) if delta_direction == "past" else -int(days),
|
|
514
|
+
),
|
|
482
515
|
)
|
|
483
|
-
+ timedelta(days=+int(days) if delta_direction == "past" else -int(days)),
|
|
484
|
-
)
|
|
485
516
|
|
|
486
517
|
# Handle <nth> <weekday> <before/from> <month> <day> patterns (e.g.,
|
|
487
518
|
# _add_holiday_1st_mon_before_jun_15() or _add_holiday_1st_mon_from_jun_15()).
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
519
|
+
elif len(tokens) == 8:
|
|
520
|
+
*_, number, weekday, date_direction, month, day = tokens
|
|
521
|
+
if (
|
|
522
|
+
date_direction in {"before", "from"}
|
|
523
|
+
and number[0].isdigit()
|
|
524
|
+
and month in MONTHS
|
|
525
|
+
and weekday in WEEKDAYS
|
|
526
|
+
and day in DAYS
|
|
527
|
+
):
|
|
528
|
+
return lambda name: self._add_holiday(
|
|
529
|
+
name,
|
|
530
|
+
_get_nth_weekday_from(
|
|
531
|
+
-int(number[0]) if date_direction == "before" else +int(number[0]),
|
|
532
|
+
WEEKDAYS[weekday],
|
|
533
|
+
date(self._year, MONTHS[month], int(day)),
|
|
534
|
+
),
|
|
535
|
+
)
|
|
501
536
|
|
|
502
537
|
raise e # No match.
|
|
503
538
|
|
|
@@ -527,7 +562,7 @@ class HolidayBase(Dict[date, str]):
|
|
|
527
562
|
|
|
528
563
|
days_in_range = []
|
|
529
564
|
for delta_days in range(0, date_diff.days, step):
|
|
530
|
-
day = start
|
|
565
|
+
day = _timedelta(start, delta_days)
|
|
531
566
|
if day in self:
|
|
532
567
|
days_in_range.append(day)
|
|
533
568
|
|
|
@@ -676,9 +711,13 @@ class HolidayBase(Dict[date, str]):
|
|
|
676
711
|
.lower()
|
|
677
712
|
)
|
|
678
713
|
|
|
679
|
-
@
|
|
714
|
+
@property
|
|
680
715
|
def _sorted_categories(self):
|
|
681
|
-
return
|
|
716
|
+
return (
|
|
717
|
+
[self.default_category] + sorted(self.categories - {self.default_category})
|
|
718
|
+
if self.default_category in self.categories
|
|
719
|
+
else sorted(self.categories)
|
|
720
|
+
)
|
|
682
721
|
|
|
683
722
|
@classmethod
|
|
684
723
|
def get_subdivision_aliases(cls) -> Dict[str, List]:
|
|
@@ -724,14 +763,14 @@ class HolidayBase(Dict[date, str]):
|
|
|
724
763
|
)
|
|
725
764
|
else: # Substituted holidays.
|
|
726
765
|
to_month, to_day, from_month, from_day, *optional = data
|
|
766
|
+
from_date = date(optional[0] if optional else self._year, from_month, from_day)
|
|
727
767
|
self._add_holiday(
|
|
728
768
|
self.tr(self.substituted_label)
|
|
729
|
-
%
|
|
730
|
-
optional[0] if optional else self._year, from_month, from_day
|
|
731
|
-
).strftime(self.tr(self.substituted_date_format)),
|
|
769
|
+
% from_date.strftime(self.tr(self.substituted_date_format)),
|
|
732
770
|
to_month,
|
|
733
771
|
to_day,
|
|
734
772
|
)
|
|
773
|
+
self.weekend_workdays.add(from_date)
|
|
735
774
|
|
|
736
775
|
def _check_weekday(self, weekday: int, *args) -> bool:
|
|
737
776
|
"""
|
|
@@ -922,6 +961,34 @@ class HolidayBase(Dict[date, str]):
|
|
|
922
961
|
|
|
923
962
|
raise AttributeError(f"Unknown lookup type: {lookup}")
|
|
924
963
|
|
|
964
|
+
def get_nth_workday(self, key: DateLike, n: int) -> date:
|
|
965
|
+
"""Return n-th working day from provided date (if n is positive)
|
|
966
|
+
or n-th working day before provided date (if n is negative).
|
|
967
|
+
"""
|
|
968
|
+
direction = +1 if n > 0 else -1
|
|
969
|
+
dt = self.__keytransform__(key)
|
|
970
|
+
for _ in range(abs(n)):
|
|
971
|
+
dt = _timedelta(dt, direction)
|
|
972
|
+
while not self.is_workday(dt):
|
|
973
|
+
dt = _timedelta(dt, direction)
|
|
974
|
+
return dt
|
|
975
|
+
|
|
976
|
+
def get_workdays_number(self, key1: DateLike, key2: DateLike) -> int:
|
|
977
|
+
"""Return the number of working days between two dates (not including the start date)."""
|
|
978
|
+
dt1 = self.__keytransform__(key1)
|
|
979
|
+
dt2 = self.__keytransform__(key2)
|
|
980
|
+
if dt1 == dt2:
|
|
981
|
+
return 0
|
|
982
|
+
if dt1 > dt2:
|
|
983
|
+
dt1, dt2 = dt2, dt1
|
|
984
|
+
|
|
985
|
+
return sum(self.is_workday(_timedelta(dt1, n)) for n in range(1, (dt2 - dt1).days + 1))
|
|
986
|
+
|
|
987
|
+
def is_workday(self, key: DateLike) -> bool:
|
|
988
|
+
"""Return True if date is a working day (not a holiday or a weekend)."""
|
|
989
|
+
dt = self.__keytransform__(key)
|
|
990
|
+
return dt in self.weekend_workdays if self._is_weekend(dt) else dt not in self
|
|
991
|
+
|
|
925
992
|
def pop(self, key: DateLike, default: Union[str, Any] = None) -> Union[str, Any]:
|
|
926
993
|
"""If date is a holiday, remove it and return its date, else return
|
|
927
994
|
default.
|
|
Binary file
|