holidays 0.68__py3-none-any.whl → 0.70__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/__init__.py +2 -1
- holidays/calendars/balinese_saka.py +112 -0
- holidays/calendars/buddhist.py +1 -1
- holidays/calendars/chinese.py +1 -1
- holidays/calendars/custom.py +1 -1
- holidays/calendars/gregorian.py +1 -1
- holidays/calendars/hebrew.py +1 -1
- holidays/calendars/hindu.py +866 -2
- holidays/calendars/islamic.py +161 -1
- holidays/calendars/julian.py +1 -1
- holidays/calendars/julian_revised.py +1 -1
- holidays/calendars/persian.py +1 -1
- holidays/calendars/sinhala.py +1 -1
- holidays/calendars/thai.py +309 -257
- holidays/constants.py +3 -1
- holidays/countries/__init__.py +7 -1
- holidays/countries/afghanistan.py +17 -7
- holidays/countries/albania.py +16 -7
- holidays/countries/algeria.py +14 -10
- holidays/countries/american_samoa.py +12 -6
- holidays/countries/andorra.py +5 -4
- holidays/countries/angola.py +15 -14
- holidays/countries/antigua_and_barbuda.py +145 -0
- holidays/countries/argentina.py +787 -169
- holidays/countries/armenia.py +5 -6
- holidays/countries/aruba.py +11 -9
- holidays/countries/australia.py +21 -20
- holidays/countries/austria.py +3 -1
- holidays/countries/azerbaijan.py +30 -19
- holidays/countries/bahamas.py +13 -11
- holidays/countries/bahrain.py +14 -7
- holidays/countries/bangladesh.py +5 -4
- holidays/countries/barbados.py +11 -9
- holidays/countries/belarus.py +15 -15
- holidays/countries/belgium.py +8 -6
- holidays/countries/belize.py +7 -6
- holidays/countries/bolivia.py +12 -11
- holidays/countries/bosnia_and_herzegovina.py +21 -11
- holidays/countries/botswana.py +8 -6
- holidays/countries/brazil.py +8 -7
- holidays/countries/brunei.py +56 -62
- holidays/countries/bulgaria.py +9 -10
- holidays/countries/burkina_faso.py +14 -5
- holidays/countries/burundi.py +17 -12
- holidays/countries/cambodia.py +15 -24
- holidays/countries/cameroon.py +16 -7
- holidays/countries/canada.py +13 -12
- holidays/countries/chad.py +15 -6
- holidays/countries/chile.py +29 -28
- holidays/countries/china.py +39 -38
- holidays/countries/colombia.py +15 -20
- holidays/countries/congo.py +6 -7
- holidays/countries/costa_rica.py +11 -10
- holidays/countries/croatia.py +8 -5
- holidays/countries/cuba.py +30 -27
- holidays/countries/curacao.py +6 -4
- holidays/countries/cyprus.py +4 -5
- holidays/countries/czechia.py +7 -6
- holidays/countries/denmark.py +5 -6
- holidays/countries/djibouti.py +11 -3
- holidays/countries/dominica.py +18 -16
- holidays/countries/dominican_republic.py +6 -4
- holidays/countries/ecuador.py +5 -4
- holidays/countries/egypt.py +10 -11
- holidays/countries/el_salvador.py +6 -5
- holidays/countries/estonia.py +3 -1
- holidays/countries/eswatini.py +6 -4
- holidays/countries/ethiopia.py +26 -11
- holidays/countries/fiji.py +183 -0
- holidays/countries/finland.py +11 -10
- holidays/countries/france.py +6 -9
- holidays/countries/gabon.py +17 -8
- holidays/countries/georgia.py +7 -7
- holidays/countries/germany.py +11 -11
- holidays/countries/ghana.py +14 -6
- holidays/countries/greece.py +4 -5
- holidays/countries/greenland.py +5 -6
- holidays/countries/guam.py +12 -6
- holidays/countries/guatemala.py +7 -9
- holidays/countries/guernsey.py +37 -34
- holidays/countries/guinea.py +182 -0
- holidays/countries/haiti.py +6 -5
- holidays/countries/honduras.py +8 -4
- holidays/countries/hongkong.py +49 -60
- holidays/countries/hungary.py +26 -23
- holidays/countries/iceland.py +5 -4
- holidays/countries/india.py +494 -174
- holidays/countries/indonesia.py +68 -108
- holidays/countries/iran.py +18 -9
- holidays/countries/ireland.py +5 -4
- holidays/countries/isle_of_man.py +2 -2
- holidays/countries/israel.py +4 -5
- holidays/countries/italy.py +5 -4
- holidays/countries/ivory_coast.py +156 -0
- holidays/countries/jamaica.py +6 -4
- holidays/countries/japan.py +5 -5
- holidays/countries/jersey.py +29 -26
- holidays/countries/jordan.py +13 -6
- holidays/countries/kazakhstan.py +72 -51
- holidays/countries/kenya.py +28 -18
- holidays/countries/kuwait.py +14 -7
- holidays/countries/kyrgyzstan.py +11 -6
- holidays/countries/laos.py +21 -29
- holidays/countries/latvia.py +7 -5
- holidays/countries/lesotho.py +6 -5
- holidays/countries/liechtenstein.py +5 -5
- holidays/countries/lithuania.py +4 -5
- holidays/countries/luxembourg.py +5 -3
- holidays/countries/macau.py +480 -0
- holidays/countries/madagascar.py +5 -4
- holidays/countries/malawi.py +6 -4
- holidays/countries/malaysia.py +30 -18
- holidays/countries/maldives.py +14 -7
- holidays/countries/malta.py +10 -19
- holidays/countries/marshall_islands.py +6 -4
- holidays/countries/mauritania.py +13 -6
- holidays/countries/mexico.py +8 -7
- holidays/countries/moldova.py +6 -4
- holidays/countries/monaco.py +6 -4
- holidays/countries/montenegro.py +16 -7
- holidays/countries/morocco.py +13 -8
- holidays/countries/mozambique.py +3 -1
- holidays/countries/namibia.py +7 -5
- holidays/countries/netherlands.py +6 -6
- holidays/countries/new_zealand.py +3 -1
- holidays/countries/nicaragua.py +6 -5
- holidays/countries/nigeria.py +13 -5
- holidays/countries/north_macedonia.py +13 -5
- holidays/countries/northern_mariana_islands.py +12 -6
- holidays/countries/norway.py +15 -15
- holidays/countries/pakistan.py +48 -18
- holidays/countries/palau.py +13 -11
- holidays/countries/panama.py +9 -8
- holidays/countries/papua_new_guinea.py +25 -21
- holidays/countries/paraguay.py +10 -9
- holidays/countries/peru.py +4 -5
- holidays/countries/philippines.py +32 -18
- holidays/countries/poland.py +7 -6
- holidays/countries/portugal.py +13 -15
- holidays/countries/puerto_rico.py +12 -6
- holidays/countries/qatar.py +172 -0
- holidays/countries/romania.py +6 -4
- holidays/countries/russia.py +6 -4
- holidays/countries/saint_kitts_and_nevis.py +24 -22
- holidays/countries/saint_lucia.py +8 -7
- holidays/countries/samoa.py +7 -6
- holidays/countries/san_marino.py +4 -3
- holidays/countries/saudi_arabia.py +15 -15
- holidays/countries/serbia.py +3 -4
- holidays/countries/seychelles.py +22 -26
- holidays/countries/singapore.py +33 -38
- holidays/countries/slovakia.py +6 -5
- holidays/countries/slovenia.py +7 -6
- holidays/countries/south_africa.py +8 -6
- holidays/countries/south_korea.py +25 -32
- holidays/countries/spain.py +31 -24
- holidays/countries/sri_lanka.py +52 -42
- holidays/countries/sweden.py +20 -19
- holidays/countries/switzerland.py +6 -5
- holidays/countries/taiwan.py +230 -31
- holidays/countries/tanzania.py +34 -27
- holidays/countries/thailand.py +134 -142
- holidays/countries/timor_leste.py +38 -17
- holidays/countries/tonga.py +46 -42
- holidays/countries/tunisia.py +9 -3
- holidays/countries/turkey.py +17 -9
- holidays/countries/tuvalu.py +12 -11
- holidays/countries/ukraine.py +54 -54
- holidays/countries/united_arab_emirates.py +43 -30
- holidays/countries/united_kingdom.py +7 -6
- holidays/countries/united_states.py +130 -86
- holidays/countries/united_states_minor_outlying_islands.py +12 -6
- holidays/countries/united_states_virgin_islands.py +12 -6
- holidays/countries/uruguay.py +10 -9
- holidays/countries/uzbekistan.py +16 -7
- holidays/countries/vanuatu.py +7 -5
- holidays/countries/vatican_city.py +16 -15
- holidays/countries/venezuela.py +11 -14
- holidays/countries/vietnam.py +15 -11
- holidays/countries/zambia.py +8 -6
- holidays/countries/zimbabwe.py +6 -4
- holidays/deprecations/v1_incompatibility.py +1 -1
- holidays/financial/__init__.py +1 -1
- holidays/financial/brasil_bolsa_balcao.py +14 -13
- holidays/financial/european_central_bank.py +7 -6
- holidays/financial/ice_futures_europe.py +7 -6
- holidays/financial/ny_stock_exchange.py +13 -10
- holidays/groups/__init__.py +2 -1
- holidays/groups/balinese_saka.py +45 -0
- holidays/groups/buddhist.py +1 -1
- holidays/groups/chinese.py +69 -4
- holidays/groups/christian.py +1 -1
- holidays/groups/custom.py +1 -1
- holidays/groups/eastern.py +1 -1
- holidays/groups/hebrew.py +1 -1
- holidays/groups/hindu.py +256 -1
- holidays/groups/international.py +1 -1
- holidays/groups/islamic.py +17 -3
- holidays/groups/persian.py +1 -1
- holidays/groups/sinhala.py +1 -1
- holidays/groups/thai.py +1 -7
- holidays/helpers.py +1 -1
- holidays/holiday_base.py +410 -273
- holidays/ical.py +228 -0
- holidays/locale/ar_QA/LC_MESSAGES/QA.mo +0 -0
- holidays/locale/de/LC_MESSAGES/PL.mo +0 -0
- holidays/locale/en_CI/LC_MESSAGES/CI.mo +0 -0
- holidays/locale/en_HK/LC_MESSAGES/HK.mo +0 -0
- holidays/locale/en_IN/LC_MESSAGES/IN.mo +0 -0
- holidays/locale/en_MO/LC_MESSAGES/MO.mo +0 -0
- holidays/locale/en_PK/LC_MESSAGES/PK.mo +0 -0
- holidays/locale/en_TL/LC_MESSAGES/TL.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/AR.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/CI.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/GN.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/HK.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/IN.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/MO.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/PK.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/QA.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/TL.mo +0 -0
- holidays/locale/en_US/LC_MESSAGES/TW.mo +0 -0
- holidays/locale/es/LC_MESSAGES/AR.mo +0 -0
- holidays/locale/fr/LC_MESSAGES/CI.mo +0 -0
- holidays/locale/fr/LC_MESSAGES/GN.mo +0 -0
- holidays/locale/hi/LC_MESSAGES/IN.mo +0 -0
- holidays/locale/pt_MO/LC_MESSAGES/MO.mo +0 -0
- holidays/locale/pt_TL/LC_MESSAGES/TL.mo +0 -0
- holidays/locale/tet/LC_MESSAGES/TL.mo +0 -0
- holidays/locale/th/LC_MESSAGES/HK.mo +0 -0
- holidays/locale/th/LC_MESSAGES/MO.mo +0 -0
- holidays/locale/th/LC_MESSAGES/TL.mo +0 -0
- holidays/locale/th/LC_MESSAGES/TW.mo +0 -0
- holidays/locale/uk/LC_MESSAGES/AR.mo +0 -0
- holidays/locale/ur_PK/LC_MESSAGES/PK.mo +0 -0
- holidays/locale/zh_CN/LC_MESSAGES/HK.mo +0 -0
- holidays/locale/zh_CN/LC_MESSAGES/MO.mo +0 -0
- holidays/locale/zh_CN/LC_MESSAGES/TW.mo +0 -0
- holidays/locale/zh_HK/LC_MESSAGES/HK.mo +0 -0
- holidays/locale/zh_MO/LC_MESSAGES/MO.mo +0 -0
- holidays/locale/zh_TW/LC_MESSAGES/TW.mo +0 -0
- holidays/mixins.py +2 -2
- holidays/observed_holiday_base.py +5 -2
- holidays/registry.py +7 -1
- holidays/utils.py +151 -151
- holidays/version.py +2 -2
- holidays-0.70.dist-info/METADATA +1404 -0
- {holidays-0.68.dist-info → holidays-0.70.dist-info}/RECORD +253 -222
- {holidays-0.68.dist-info → holidays-0.70.dist-info}/WHEEL +1 -1
- holidays-0.68.dist-info/AUTHORS → holidays-0.70.dist-info/licenses/AUTHORS.md +7 -2
- {holidays-0.68.dist-info → holidays-0.70.dist-info/licenses}/LICENSE +1 -1
- holidays-0.68.dist-info/METADATA +0 -1080
- {holidays-0.68.dist-info → holidays-0.70.dist-info}/top_level.txt +0 -0
holidays/holiday_base.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# specific sets of holidays on the fly. It aims to make determining whether a
|
|
5
5
|
# specific date is a holiday as fast and flexible as possible.
|
|
6
6
|
#
|
|
7
|
-
# Authors: Vacanza Team and individual contributors (see AUTHORS file)
|
|
7
|
+
# Authors: Vacanza Team and individual contributors (see AUTHORS.md file)
|
|
8
8
|
# dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
|
|
9
9
|
# ryanss <ryanssdev@icloud.com> (c) 2014-2017
|
|
10
10
|
# Website: https://github.com/vacanza/holidays
|
|
@@ -56,19 +56,19 @@ YearArg = Union[int, Iterable[int]]
|
|
|
56
56
|
|
|
57
57
|
class HolidayBase(dict[date, str]):
|
|
58
58
|
"""
|
|
59
|
-
A dict
|
|
60
|
-
province or state if so initiated); inherits the dict class (so behaves
|
|
61
|
-
similarly to a dict). Dates without a key in the Holiday object are not
|
|
59
|
+
A `dict`-like object containing the holidays for a specific country (and
|
|
60
|
+
province or state if so initiated); inherits the `dict` class (so behaves
|
|
61
|
+
similarly to a `dict`). Dates without a key in the Holiday object are not
|
|
62
62
|
holidays.
|
|
63
63
|
|
|
64
64
|
The key of the object is the date of the holiday and the value is the name
|
|
65
65
|
of the holiday itself. When passing the date as a key, the date can be
|
|
66
66
|
expressed as one of the following formats:
|
|
67
67
|
|
|
68
|
-
* datetime.datetime type;
|
|
69
|
-
* datetime.date types;
|
|
70
|
-
* a float representing a Unix timestamp;
|
|
71
|
-
* or a string of any format (recognized by
|
|
68
|
+
* `datetime.datetime` type;
|
|
69
|
+
* `datetime.date` types;
|
|
70
|
+
* a `float` representing a Unix timestamp;
|
|
71
|
+
* or a string of any format (recognized by `dateutil.parser.parse()`).
|
|
72
72
|
|
|
73
73
|
The key is always returned as a `datetime.date` object.
|
|
74
74
|
|
|
@@ -78,11 +78,12 @@ class HolidayBase(dict[date, str]):
|
|
|
78
78
|
holidays. To pre-populate holidays, instantiate the class with the years
|
|
79
79
|
argument:
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
us_holidays = holidays.US(years=2020)
|
|
82
82
|
|
|
83
|
-
It is generally instantiated using the
|
|
83
|
+
It is generally instantiated using the
|
|
84
|
+
[country_holidays()][holidays.utils.country_holidays] function.
|
|
84
85
|
|
|
85
|
-
The key of the
|
|
86
|
+
The key of the `dict`-like `HolidayBase` object is the
|
|
86
87
|
`date` of the holiday, and the value is the name of the holiday itself.
|
|
87
88
|
Dates where a key is not present are not public holidays (or, if
|
|
88
89
|
**observed** is False, days when a public holiday is observed).
|
|
@@ -90,12 +91,12 @@ class HolidayBase(dict[date, str]):
|
|
|
90
91
|
When passing the `date` as a key, the `date` can be expressed in one of the
|
|
91
92
|
following types:
|
|
92
93
|
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* a
|
|
96
|
-
* or a
|
|
94
|
+
* `datetime.date`,
|
|
95
|
+
* `datetime.datetime`,
|
|
96
|
+
* a `str` of any format recognized by `dateutil.parser.parse()`,
|
|
97
|
+
* or a `float` or `int` representing a POSIX timestamp.
|
|
97
98
|
|
|
98
|
-
The key is always returned as a
|
|
99
|
+
The key is always returned as a `datetime.date` object.
|
|
99
100
|
|
|
100
101
|
To maximize speed, the list of public holidays is built on the fly as
|
|
101
102
|
needed, one calendar year at a time. When the object is instantiated
|
|
@@ -108,70 +109,70 @@ class HolidayBase(dict[date, str]):
|
|
|
108
109
|
|
|
109
110
|
Example usage:
|
|
110
111
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
>>> from holidays import country_holidays
|
|
113
|
+
>>> us_holidays = country_holidays('US')
|
|
114
|
+
# For a specific subdivisions (e.g. state or province):
|
|
115
|
+
>>> california_holidays = country_holidays('US', subdiv='CA')
|
|
115
116
|
|
|
116
117
|
The below will cause 2015 holidays to be calculated on the fly:
|
|
117
118
|
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
>>> from datetime import date
|
|
120
|
+
>>> assert date(2015, 1, 1) in us_holidays
|
|
120
121
|
|
|
121
122
|
This will be faster because 2015 holidays are already calculated:
|
|
122
123
|
|
|
123
|
-
|
|
124
|
+
>>> assert date(2015, 1, 2) not in us_holidays
|
|
124
125
|
|
|
125
|
-
The
|
|
126
|
+
The `HolidayBase` class also recognizes strings of many formats
|
|
126
127
|
and numbers representing a POSIX timestamp:
|
|
127
128
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
>>> assert '2014-01-01' in us_holidays
|
|
130
|
+
>>> assert '1/1/2014' in us_holidays
|
|
131
|
+
>>> assert 1388597445 in us_holidays
|
|
131
132
|
|
|
132
133
|
Show the holiday's name:
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
>>> us_holidays.get('2014-01-01')
|
|
136
|
+
"New Year's Day"
|
|
136
137
|
|
|
137
138
|
Check a range:
|
|
138
139
|
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
>>> us_holidays['2014-01-01': '2014-01-03']
|
|
141
|
+
[datetime.date(2014, 1, 1)]
|
|
141
142
|
|
|
142
143
|
List all 2020 holidays:
|
|
143
144
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
145
|
+
>>> us_holidays = country_holidays('US', years=2020)
|
|
146
|
+
>>> for day in sorted(us_holidays.items()):
|
|
147
|
+
... print(day)
|
|
148
|
+
(datetime.date(2020, 1, 1), "New Year's Day")
|
|
149
|
+
(datetime.date(2020, 1, 20), 'Martin Luther King Jr. Day')
|
|
150
|
+
(datetime.date(2020, 2, 17), "Washington's Birthday")
|
|
151
|
+
(datetime.date(2020, 5, 25), 'Memorial Day')
|
|
152
|
+
(datetime.date(2020, 7, 3), 'Independence Day (observed)')
|
|
153
|
+
(datetime.date(2020, 7, 4), 'Independence Day')
|
|
154
|
+
(datetime.date(2020, 9, 7), 'Labor Day')
|
|
155
|
+
(datetime.date(2020, 10, 12), 'Columbus Day')
|
|
156
|
+
(datetime.date(2020, 11, 11), 'Veterans Day')
|
|
157
|
+
(datetime.date(2020, 11, 26), 'Thanksgiving Day')
|
|
158
|
+
(datetime.date(2020, 12, 25), 'Christmas Day')
|
|
158
159
|
|
|
159
160
|
Some holidays are only present in parts of a country:
|
|
160
161
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
>>> us_pr_holidays = country_holidays('US', subdiv='PR')
|
|
163
|
+
>>> assert '2018-01-06' not in us_holidays
|
|
164
|
+
>>> assert '2018-01-06' in us_pr_holidays
|
|
164
165
|
|
|
165
166
|
Append custom holiday dates by passing one of:
|
|
166
167
|
|
|
167
|
-
* a
|
|
168
|
-
|
|
169
|
-
* a list of dates (as a
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
* or a single date item (of one of the types above); ``'Holiday'`` will be
|
|
168
|
+
* a `dict` with date/name key/value pairs (e.g.
|
|
169
|
+
`{'2010-07-10': 'My birthday!'}`),
|
|
170
|
+
* a list of dates (as a `datetime.date`, `datetime.datetime`,
|
|
171
|
+
`str`, `int`, or `float`); `'Holiday'` will be used as a description,
|
|
172
|
+
* or a single date item (of one of the types above); `'Holiday'` will be
|
|
173
173
|
used as a description:
|
|
174
174
|
|
|
175
|
+
```python
|
|
175
176
|
>>> custom_holidays = country_holidays('US', years=2015)
|
|
176
177
|
>>> custom_holidays.update({'2015-01-01': "New Year's Day"})
|
|
177
178
|
>>> custom_holidays.update(['2015-07-01', '07/04/2015'])
|
|
@@ -179,11 +180,10 @@ class HolidayBase(dict[date, str]):
|
|
|
179
180
|
>>> assert date(2015, 1, 1) in custom_holidays
|
|
180
181
|
>>> assert date(2015, 1, 2) not in custom_holidays
|
|
181
182
|
>>> assert '12/25/2015' in custom_holidays
|
|
183
|
+
```
|
|
182
184
|
|
|
183
185
|
For special (one-off) country-wide holidays handling use
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
.. code-block:: python
|
|
186
|
+
`special_public_holidays`:
|
|
187
187
|
|
|
188
188
|
special_public_holidays = {
|
|
189
189
|
1977: ((JUN, 7, "Silver Jubilee of Elizabeth II"),),
|
|
@@ -204,7 +204,8 @@ class HolidayBase(dict[date, str]):
|
|
|
204
204
|
...
|
|
205
205
|
|
|
206
206
|
For more complex logic, like 4th Monday of January, you can inherit the
|
|
207
|
-
|
|
207
|
+
[HolidayBase][holidays.holiday_base.HolidayBase] class and define your own `_populate()`
|
|
208
|
+
method.
|
|
208
209
|
See documentation for examples.
|
|
209
210
|
"""
|
|
210
211
|
|
|
@@ -265,39 +266,40 @@ class HolidayBase(dict[date, str]):
|
|
|
265
266
|
categories: Optional[CategoryArg] = None,
|
|
266
267
|
) -> None:
|
|
267
268
|
"""
|
|
268
|
-
:
|
|
269
|
-
|
|
269
|
+
Args:
|
|
270
|
+
years:
|
|
271
|
+
The year(s) to pre-calculate public holidays for at instantiation.
|
|
270
272
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
273
|
+
expand:
|
|
274
|
+
Whether the entire year is calculated when one date from that year
|
|
275
|
+
is requested.
|
|
274
276
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
observed:
|
|
278
|
+
Whether to include the dates when public holiday are observed
|
|
279
|
+
(e.g. a holiday falling on a Sunday being observed the
|
|
280
|
+
following Monday). This doesn't work for all countries.
|
|
279
281
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
282
|
+
subdiv:
|
|
283
|
+
The subdivision (e.g. state or province) as a ISO 3166-2 code
|
|
284
|
+
or its alias; not implemented for all countries (see documentation).
|
|
283
285
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
+
prov:
|
|
287
|
+
*deprecated* use `subdiv` instead.
|
|
286
288
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
+
state:
|
|
290
|
+
*deprecated* use `subdiv` instead.
|
|
289
291
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
292
|
+
language:
|
|
293
|
+
The language which the returned holiday names will be translated
|
|
294
|
+
into. It must be an ISO 639-1 (2-letter) language code. If the
|
|
295
|
+
language translation is not supported the original holiday names
|
|
296
|
+
will be used.
|
|
295
297
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
+
categories:
|
|
299
|
+
Requested holiday categories.
|
|
298
300
|
|
|
299
|
-
:
|
|
300
|
-
A
|
|
301
|
+
Returns:
|
|
302
|
+
A `HolidayBase` object matching the **country** or **market**.
|
|
301
303
|
"""
|
|
302
304
|
super().__init__()
|
|
303
305
|
|
|
@@ -361,54 +363,29 @@ class HolidayBase(dict[date, str]):
|
|
|
361
363
|
self.expand = expand
|
|
362
364
|
self.has_special_holidays = getattr(self, "has_special_holidays", False)
|
|
363
365
|
self.has_substituted_holidays = has_substituted_holidays
|
|
364
|
-
self.language = language
|
|
366
|
+
self.language = language
|
|
365
367
|
self.observed = observed
|
|
366
368
|
self.subdiv = subdiv
|
|
367
369
|
self.weekend_workdays = getattr(self, "weekend_workdays", set())
|
|
368
|
-
|
|
369
|
-
supported_languages = set(self.supported_languages)
|
|
370
|
-
if self._entity_code is not None:
|
|
371
|
-
fallback = language not in supported_languages
|
|
372
|
-
languages = [language] if language in supported_languages else None
|
|
373
|
-
locale_directory = str(Path(__file__).with_name("locale"))
|
|
374
|
-
|
|
375
|
-
# Add entity native content translations.
|
|
376
|
-
entity_translation = translation(
|
|
377
|
-
self._entity_code,
|
|
378
|
-
fallback=fallback,
|
|
379
|
-
languages=languages,
|
|
380
|
-
localedir=locale_directory,
|
|
381
|
-
)
|
|
382
|
-
# Add a fallback if entity has parent translations.
|
|
383
|
-
if parent_entity := self.parent_entity:
|
|
384
|
-
entity_translation.add_fallback(
|
|
385
|
-
translation(
|
|
386
|
-
parent_entity.country or parent_entity.market,
|
|
387
|
-
fallback=fallback,
|
|
388
|
-
languages=languages,
|
|
389
|
-
localedir=locale_directory,
|
|
390
|
-
)
|
|
391
|
-
)
|
|
392
|
-
self.tr = entity_translation.gettext
|
|
393
|
-
else:
|
|
394
|
-
self.tr = gettext
|
|
395
|
-
|
|
396
370
|
self.years = _normalize_arguments(int, years)
|
|
397
371
|
|
|
372
|
+
# Configure l10n related attributes.
|
|
373
|
+
self._init_translation()
|
|
374
|
+
|
|
398
375
|
# Populate holidays.
|
|
399
376
|
for year in self.years:
|
|
400
377
|
self._populate(year)
|
|
401
378
|
|
|
402
379
|
def __add__(self, other: Union[int, "HolidayBase", "HolidaySum"]) -> "HolidayBase":
|
|
403
380
|
"""Add another dictionary of public holidays creating a
|
|
404
|
-
|
|
381
|
+
[HolidaySum][holidays.holiday_base.HolidaySum] object.
|
|
405
382
|
|
|
406
|
-
:
|
|
407
|
-
|
|
383
|
+
Args:
|
|
384
|
+
other:
|
|
385
|
+
The dictionary of public holiday to be added.
|
|
408
386
|
|
|
409
|
-
:
|
|
410
|
-
A
|
|
411
|
-
added, then :class:`self`.
|
|
387
|
+
Returns:
|
|
388
|
+
A `HolidayBase` object unless the other object cannot be added, then `self`.
|
|
412
389
|
"""
|
|
413
390
|
if isinstance(other, int) and other == 0:
|
|
414
391
|
# Required to sum() list of holidays
|
|
@@ -424,14 +401,21 @@ class HolidayBase(dict[date, str]):
|
|
|
424
401
|
return len(self) > 0
|
|
425
402
|
|
|
426
403
|
def __contains__(self, key: object) -> bool:
|
|
427
|
-
"""
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
|
|
434
|
-
* or a
|
|
404
|
+
"""Check if a given date is a holiday.
|
|
405
|
+
|
|
406
|
+
The method supports the following input types:
|
|
407
|
+
|
|
408
|
+
* `datetime.date`,
|
|
409
|
+
* `datetime.datetime`,
|
|
410
|
+
* a `str` of any format recognized by `dateutil.parser.parse()`,
|
|
411
|
+
* or a `float` or `int` representing a POSIX timestamp.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
key:
|
|
415
|
+
The date to check.
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
`True` if the date is a holiday, `False` otherwise.
|
|
435
419
|
"""
|
|
436
420
|
|
|
437
421
|
if not isinstance(key, (date, datetime, float, int, str)):
|
|
@@ -592,16 +576,28 @@ class HolidayBase(dict[date, str]):
|
|
|
592
576
|
|
|
593
577
|
return dict.__getitem__(self, self.__keytransform__(key))
|
|
594
578
|
|
|
579
|
+
def __getstate__(self) -> dict[str, Any]:
|
|
580
|
+
"""Return the object's state for serialization."""
|
|
581
|
+
state = self.__dict__.copy()
|
|
582
|
+
state.pop("tr", None)
|
|
583
|
+
return state
|
|
584
|
+
|
|
595
585
|
def __keytransform__(self, key: DateLike) -> date:
|
|
596
|
-
"""
|
|
586
|
+
"""Convert various date-like formats to `datetime.date`.
|
|
597
587
|
|
|
598
|
-
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
|
|
602
|
-
* or a
|
|
588
|
+
The method supports the following input types:
|
|
589
|
+
* `datetime.date`,
|
|
590
|
+
* `datetime.datetime`,
|
|
591
|
+
* a `str` of any format recognized by `dateutil.parser.parse()`,
|
|
592
|
+
* or a `float` or `int` representing a POSIX timestamp
|
|
603
593
|
|
|
604
|
-
|
|
594
|
+
Args:
|
|
595
|
+
key:
|
|
596
|
+
The date-like object to convert.
|
|
597
|
+
|
|
598
|
+
Returns:
|
|
599
|
+
The corresponding `datetime.date` representation.
|
|
600
|
+
"""
|
|
605
601
|
|
|
606
602
|
dt: Optional[date] = None
|
|
607
603
|
# Try to catch `date` and `str` type keys first.
|
|
@@ -699,6 +695,11 @@ class HolidayBase(dict[date, str]):
|
|
|
699
695
|
|
|
700
696
|
dict.__setitem__(self, self.__keytransform__(key), value)
|
|
701
697
|
|
|
698
|
+
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
699
|
+
"""Restore the object's state after deserialization."""
|
|
700
|
+
self.__dict__.update(state)
|
|
701
|
+
self._init_translation()
|
|
702
|
+
|
|
702
703
|
def __str__(self) -> str:
|
|
703
704
|
if self:
|
|
704
705
|
return super().__str__()
|
|
@@ -743,13 +744,46 @@ class HolidayBase(dict[date, str]):
|
|
|
743
744
|
|
|
744
745
|
@classmethod
|
|
745
746
|
def get_subdivision_aliases(cls) -> dict[str, list]:
|
|
746
|
-
"""Get subdivision aliases.
|
|
747
|
+
"""Get subdivision aliases.
|
|
748
|
+
|
|
749
|
+
Returns:
|
|
750
|
+
A dictionary mapping subdivision aliases to their official ISO 3166-2 codes.
|
|
751
|
+
"""
|
|
747
752
|
subdivision_aliases: dict[str, list[str]] = {s: [] for s in cls.subdivisions}
|
|
748
753
|
for alias, subdivision in cls.subdivisions_aliases.items():
|
|
749
754
|
subdivision_aliases[subdivision].append(alias)
|
|
750
755
|
|
|
751
756
|
return subdivision_aliases
|
|
752
757
|
|
|
758
|
+
def _init_translation(self) -> None:
|
|
759
|
+
"""Initialize translation function based on language settings."""
|
|
760
|
+
supported_languages = set(self.supported_languages)
|
|
761
|
+
if self._entity_code is not None:
|
|
762
|
+
fallback = self.language not in supported_languages
|
|
763
|
+
languages = [self.language] if self.language in supported_languages else None
|
|
764
|
+
locale_directory = str(Path(__file__).with_name("locale"))
|
|
765
|
+
|
|
766
|
+
# Add entity native content translations.
|
|
767
|
+
entity_translation = translation(
|
|
768
|
+
self._entity_code,
|
|
769
|
+
fallback=fallback,
|
|
770
|
+
languages=languages,
|
|
771
|
+
localedir=locale_directory,
|
|
772
|
+
)
|
|
773
|
+
# Add a fallback if entity has parent translations.
|
|
774
|
+
if parent_entity := self.parent_entity:
|
|
775
|
+
entity_translation.add_fallback(
|
|
776
|
+
translation(
|
|
777
|
+
parent_entity.country or parent_entity.market,
|
|
778
|
+
fallback=fallback,
|
|
779
|
+
languages=languages,
|
|
780
|
+
localedir=locale_directory,
|
|
781
|
+
)
|
|
782
|
+
)
|
|
783
|
+
self.tr = entity_translation.gettext
|
|
784
|
+
else:
|
|
785
|
+
self.tr = gettext
|
|
786
|
+
|
|
753
787
|
def _is_leap_year(self) -> bool:
|
|
754
788
|
"""
|
|
755
789
|
Returns True if the year is leap. Returns False otherwise.
|
|
@@ -841,13 +875,13 @@ class HolidayBase(dict[date, str]):
|
|
|
841
875
|
directly from outside.
|
|
842
876
|
To add holidays to an object, use the update() method.
|
|
843
877
|
|
|
844
|
-
:
|
|
845
|
-
The year to populate with holidays.
|
|
878
|
+
Args:
|
|
879
|
+
year: The year to populate with holidays.
|
|
846
880
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
881
|
+
>>> from holidays import country_holidays
|
|
882
|
+
>>> us_holidays = country_holidays('US', years=2020)
|
|
883
|
+
# to add new holidays to the object:
|
|
884
|
+
>>> us_holidays.update(country_holidays('US', years=2021))
|
|
851
885
|
"""
|
|
852
886
|
|
|
853
887
|
if year < self.start_year or year > self.end_year:
|
|
@@ -888,7 +922,16 @@ class HolidayBase(dict[date, str]):
|
|
|
888
922
|
)
|
|
889
923
|
|
|
890
924
|
def append(self, *args: Union[dict[DateLike, str], list[DateLike], DateLike]) -> None:
|
|
891
|
-
"""Alias for
|
|
925
|
+
"""Alias for [update()][holidays.holiday_base.HolidayBase.update] to mimic list type.
|
|
926
|
+
|
|
927
|
+
Args:
|
|
928
|
+
args:
|
|
929
|
+
Holiday data to add. Can be:
|
|
930
|
+
|
|
931
|
+
* A dictionary mapping dates to holiday names.
|
|
932
|
+
* A list of dates (without names).
|
|
933
|
+
* A single date.
|
|
934
|
+
"""
|
|
892
935
|
return self.update(*args)
|
|
893
936
|
|
|
894
937
|
def copy(self):
|
|
@@ -896,64 +939,73 @@ class HolidayBase(dict[date, str]):
|
|
|
896
939
|
return copy.copy(self)
|
|
897
940
|
|
|
898
941
|
def get(self, key: DateLike, default: Union[str, Any] = None) -> Union[str, Any]:
|
|
899
|
-
"""
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
942
|
+
"""Retrieve the holiday name(s) for a given date.
|
|
943
|
+
|
|
944
|
+
If the date is a holiday, returns the holiday name as a string.
|
|
945
|
+
If multiple holidays fall on the same date, their names are joined by a semicolon (`;`).
|
|
946
|
+
If the date is not a holiday, returns the provided `default` value (defaults to `None`).
|
|
947
|
+
|
|
948
|
+
Args:
|
|
949
|
+
key:
|
|
950
|
+
The date expressed in one of the following types:
|
|
951
|
+
|
|
952
|
+
* `datetime.date`,
|
|
953
|
+
* `datetime.datetime`,
|
|
954
|
+
* a `str` of any format recognized by `dateutil.parser.parse()`,
|
|
955
|
+
* or a `float` or `int` representing a POSIX timestamp.
|
|
956
|
+
|
|
957
|
+
default:
|
|
958
|
+
The default value to return if no value is found.
|
|
959
|
+
|
|
960
|
+
Returns:
|
|
961
|
+
The holiday name(s) as a string if the date is a holiday,
|
|
962
|
+
or the `default` value otherwise.
|
|
916
963
|
"""
|
|
917
964
|
return dict.get(self, self.__keytransform__(key), default)
|
|
918
965
|
|
|
919
966
|
def get_list(self, key: DateLike) -> list[str]:
|
|
920
|
-
"""
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
967
|
+
"""Retrieve all holiday names for a given date.
|
|
968
|
+
|
|
969
|
+
Args:
|
|
970
|
+
key:
|
|
971
|
+
The date expressed in one of the following types:
|
|
972
|
+
|
|
973
|
+
* `datetime.date`,
|
|
974
|
+
* `datetime.datetime`,
|
|
975
|
+
* a `str` of any format recognized by `dateutil.parser.parse()`,
|
|
976
|
+
* or a `float` or `int` representing a POSIX timestamp.
|
|
977
|
+
|
|
978
|
+
Returns:
|
|
979
|
+
A list of holiday names if the date is a holiday, otherwise an empty list.
|
|
932
980
|
"""
|
|
933
981
|
return [name for name in self.get(key, "").split(HOLIDAY_NAME_DELIMITER) if name]
|
|
934
982
|
|
|
935
983
|
def get_named(
|
|
936
|
-
self, holiday_name: str, lookup="icontains", split_multiple_names=True
|
|
984
|
+
self, holiday_name: str, lookup: str = "icontains", split_multiple_names: bool = True
|
|
937
985
|
) -> list[date]:
|
|
938
|
-
"""
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
:
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
986
|
+
"""Find all holiday dates matching a given name.
|
|
987
|
+
|
|
988
|
+
The search by default is case-insensitive and includes partial matches.
|
|
989
|
+
|
|
990
|
+
Args:
|
|
991
|
+
holiday_name:
|
|
992
|
+
The holiday's name to try to match.
|
|
993
|
+
|
|
994
|
+
lookup:
|
|
995
|
+
The holiday name lookup type:
|
|
996
|
+
|
|
997
|
+
* contains - case sensitive contains match;
|
|
998
|
+
* exact - case sensitive exact match;
|
|
999
|
+
* startswith - case sensitive starts with match;
|
|
1000
|
+
* icontains - case insensitive contains match;
|
|
1001
|
+
* iexact - case insensitive exact match;
|
|
1002
|
+
* istartswith - case insensitive starts with match;
|
|
1003
|
+
|
|
1004
|
+
split_multiple_names:
|
|
1005
|
+
Either use the exact name for each date or split it by holiday
|
|
1006
|
+
name delimiter.
|
|
1007
|
+
|
|
1008
|
+
Returns:
|
|
957
1009
|
A list of all holiday dates matching the provided holiday name.
|
|
958
1010
|
"""
|
|
959
1011
|
holiday_name_dates = (
|
|
@@ -991,10 +1043,23 @@ class HolidayBase(dict[date, str]):
|
|
|
991
1043
|
target_date: DateLike = None,
|
|
992
1044
|
direction: Literal["forward", "backward"] = "forward",
|
|
993
1045
|
) -> Optional[tuple[date, str]]:
|
|
994
|
-
"""
|
|
995
|
-
if direction is "forward" or the previous holiday if direction is "backward".
|
|
996
|
-
If target_date is not provided the current date will be used by default."""
|
|
1046
|
+
"""Find the closest holiday relative to a given date.
|
|
997
1047
|
|
|
1048
|
+
If `direction` is "forward", returns the next holiday after `target_date`.
|
|
1049
|
+
If `direction` is "backward", returns the previous holiday before `target_date`.
|
|
1050
|
+
If `target_date` is not provided, the current date is used.
|
|
1051
|
+
|
|
1052
|
+
Args:
|
|
1053
|
+
target_date:
|
|
1054
|
+
The reference date. If None, defaults to today.
|
|
1055
|
+
|
|
1056
|
+
direction:
|
|
1057
|
+
Search direction, either "forward" (next holiday) or
|
|
1058
|
+
"backward" (previous holiday).
|
|
1059
|
+
|
|
1060
|
+
Returns:
|
|
1061
|
+
A tuple containing the holiday date and its name, or None if no holiday is found.
|
|
1062
|
+
"""
|
|
998
1063
|
if direction not in {"backward", "forward"}:
|
|
999
1064
|
raise AttributeError(f"Unknown direction: {direction}")
|
|
1000
1065
|
|
|
@@ -1017,8 +1082,20 @@ class HolidayBase(dict[date, str]):
|
|
|
1017
1082
|
return None
|
|
1018
1083
|
|
|
1019
1084
|
def get_nth_working_day(self, key: DateLike, n: int) -> date:
|
|
1020
|
-
"""
|
|
1021
|
-
|
|
1085
|
+
"""Find the n-th working day from a given date.
|
|
1086
|
+
|
|
1087
|
+
Moves forward if n is positive, or backward if n is negative.
|
|
1088
|
+
|
|
1089
|
+
Args:
|
|
1090
|
+
key:
|
|
1091
|
+
The starting date.
|
|
1092
|
+
|
|
1093
|
+
n:
|
|
1094
|
+
The number of working days to move. Positive values move forward,
|
|
1095
|
+
negative values move backward.
|
|
1096
|
+
|
|
1097
|
+
Returns:
|
|
1098
|
+
The calculated working day after shifting by n working days.
|
|
1022
1099
|
"""
|
|
1023
1100
|
direction = +1 if n > 0 else -1
|
|
1024
1101
|
dt = self.__keytransform__(key)
|
|
@@ -1029,16 +1106,20 @@ class HolidayBase(dict[date, str]):
|
|
|
1029
1106
|
return dt
|
|
1030
1107
|
|
|
1031
1108
|
def get_working_days_count(self, start: DateLike, end: DateLike) -> int:
|
|
1032
|
-
"""
|
|
1109
|
+
"""Calculate the number of working days between two dates.
|
|
1033
1110
|
|
|
1034
1111
|
The date range works in a closed interval fashion [start, end] so both
|
|
1035
1112
|
endpoints are included.
|
|
1036
1113
|
|
|
1037
|
-
:
|
|
1038
|
-
|
|
1114
|
+
Args:
|
|
1115
|
+
start:
|
|
1116
|
+
The range start date.
|
|
1117
|
+
|
|
1118
|
+
end:
|
|
1119
|
+
The range end date.
|
|
1039
1120
|
|
|
1040
|
-
:
|
|
1041
|
-
The
|
|
1121
|
+
Returns:
|
|
1122
|
+
The total count of working days between the given dates.
|
|
1042
1123
|
"""
|
|
1043
1124
|
dt1 = self.__keytransform__(start)
|
|
1044
1125
|
dt2 = self.__keytransform__(end)
|
|
@@ -1048,55 +1129,83 @@ class HolidayBase(dict[date, str]):
|
|
|
1048
1129
|
return sum(self.is_working_day(_timedelta(dt1, n)) for n in range(days))
|
|
1049
1130
|
|
|
1050
1131
|
def is_working_day(self, key: DateLike) -> bool:
|
|
1051
|
-
"""
|
|
1132
|
+
"""Check if the given date is considered a working day.
|
|
1133
|
+
|
|
1134
|
+
Args:
|
|
1135
|
+
key:
|
|
1136
|
+
The date to check.
|
|
1137
|
+
|
|
1138
|
+
Returns:
|
|
1139
|
+
True if the date is a working day, False if it is a holiday or weekend.
|
|
1140
|
+
"""
|
|
1052
1141
|
dt = self.__keytransform__(key)
|
|
1053
1142
|
return dt in self.weekend_workdays if self._is_weekend(dt) else dt not in self
|
|
1054
1143
|
|
|
1055
1144
|
def pop(self, key: DateLike, default: Union[str, Any] = None) -> Union[str, Any]:
|
|
1056
|
-
"""
|
|
1057
|
-
|
|
1145
|
+
"""Remove a holiday for a given date and return its name.
|
|
1146
|
+
|
|
1147
|
+
If the specified date is a holiday, it will be removed, and its name will
|
|
1148
|
+
be returned. If the date is not a holiday, the provided `default` value
|
|
1149
|
+
will be returned instead.
|
|
1058
1150
|
|
|
1059
|
-
:
|
|
1060
|
-
|
|
1151
|
+
Args:
|
|
1152
|
+
key:
|
|
1153
|
+
The date expressed in one of the following types:
|
|
1061
1154
|
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
* or a :class:`float` or :class:`int` representing a POSIX
|
|
1067
|
-
timestamp.
|
|
1155
|
+
* `datetime.date`,
|
|
1156
|
+
* `datetime.datetime`,
|
|
1157
|
+
* a `str` of any format recognized by `dateutil.parser.parse()`,
|
|
1158
|
+
* or a `float` or `int` representing a POSIX timestamp.
|
|
1068
1159
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1160
|
+
default:
|
|
1161
|
+
The default value to return if no match is found.
|
|
1071
1162
|
|
|
1072
|
-
:
|
|
1073
|
-
The date
|
|
1163
|
+
Returns:
|
|
1164
|
+
The name of the removed holiday if the date was a holiday, otherwise
|
|
1165
|
+
the provided `default` value.
|
|
1074
1166
|
|
|
1075
|
-
:
|
|
1076
|
-
KeyError if date is not a holiday and default is not given.
|
|
1167
|
+
Raises:
|
|
1168
|
+
KeyError: if date is not a holiday and default is not given.
|
|
1077
1169
|
"""
|
|
1078
1170
|
if default is None:
|
|
1079
1171
|
return dict.pop(self, self.__keytransform__(key))
|
|
1080
1172
|
|
|
1081
1173
|
return dict.pop(self, self.__keytransform__(key), default)
|
|
1082
1174
|
|
|
1083
|
-
def pop_named(self,
|
|
1084
|
-
"""Remove
|
|
1085
|
-
|
|
1086
|
-
|
|
1175
|
+
def pop_named(self, holiday_name: str, lookup: str = "icontains") -> list[date]:
|
|
1176
|
+
"""Remove all holidays matching the given name.
|
|
1177
|
+
|
|
1178
|
+
This method removes all dates associated with a holiday name, so they are
|
|
1179
|
+
no longer considered holidays. The search by default is case-insensitive and
|
|
1180
|
+
includes partial matches.
|
|
1087
1181
|
|
|
1088
|
-
:
|
|
1089
|
-
|
|
1182
|
+
Args:
|
|
1183
|
+
holiday_name:
|
|
1184
|
+
The holiday's name to try to match.
|
|
1090
1185
|
|
|
1091
|
-
|
|
1186
|
+
lookup:
|
|
1187
|
+
The holiday name lookup type:
|
|
1188
|
+
|
|
1189
|
+
* contains - case sensitive contains match;
|
|
1190
|
+
* exact - case sensitive exact match;
|
|
1191
|
+
* startswith - case sensitive starts with match;
|
|
1192
|
+
* icontains - case insensitive contains match;
|
|
1193
|
+
* iexact - case insensitive exact match;
|
|
1194
|
+
* istartswith - case insensitive starts with match;
|
|
1195
|
+
|
|
1196
|
+
Returns:
|
|
1092
1197
|
A list of dates removed.
|
|
1093
1198
|
|
|
1094
|
-
:
|
|
1095
|
-
KeyError if date is not a holiday
|
|
1199
|
+
Raises:
|
|
1200
|
+
KeyError: if date is not a holiday.
|
|
1096
1201
|
"""
|
|
1097
|
-
use_exact_name = HOLIDAY_NAME_DELIMITER in
|
|
1098
|
-
if not (
|
|
1099
|
-
|
|
1202
|
+
use_exact_name = HOLIDAY_NAME_DELIMITER in holiday_name
|
|
1203
|
+
if not (
|
|
1204
|
+
dts := self.get_named(
|
|
1205
|
+
holiday_name, lookup=lookup, split_multiple_names=not use_exact_name
|
|
1206
|
+
)
|
|
1207
|
+
):
|
|
1208
|
+
raise KeyError(holiday_name)
|
|
1100
1209
|
|
|
1101
1210
|
popped = []
|
|
1102
1211
|
for dt in dts:
|
|
@@ -1105,38 +1214,55 @@ class HolidayBase(dict[date, str]):
|
|
|
1105
1214
|
popped.append(dt)
|
|
1106
1215
|
|
|
1107
1216
|
# Keep the rest of holidays falling on the same date.
|
|
1108
|
-
if
|
|
1109
|
-
|
|
1217
|
+
if use_exact_name:
|
|
1218
|
+
continue
|
|
1219
|
+
if lookup == "icontains":
|
|
1220
|
+
holiday_name_lower = holiday_name.lower()
|
|
1110
1221
|
holiday_names = [
|
|
1111
|
-
|
|
1112
|
-
for holiday_name in holiday_names
|
|
1113
|
-
if name_lower not in holiday_name.lower()
|
|
1222
|
+
name for name in holiday_names if holiday_name_lower not in name.lower()
|
|
1114
1223
|
]
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1224
|
+
elif lookup == "iexact":
|
|
1225
|
+
holiday_name_lower = holiday_name.lower()
|
|
1226
|
+
holiday_names = [
|
|
1227
|
+
name for name in holiday_names if holiday_name_lower != name.lower()
|
|
1228
|
+
]
|
|
1229
|
+
elif lookup == "istartswith":
|
|
1230
|
+
holiday_name_lower = holiday_name.lower()
|
|
1231
|
+
holiday_names = [
|
|
1232
|
+
name
|
|
1233
|
+
for name in holiday_names
|
|
1234
|
+
if holiday_name_lower != name[: len(holiday_name)].lower()
|
|
1235
|
+
]
|
|
1236
|
+
elif lookup == "contains":
|
|
1237
|
+
holiday_names = [name for name in holiday_names if holiday_name not in name]
|
|
1238
|
+
elif lookup == "exact":
|
|
1239
|
+
holiday_names = [name for name in holiday_names if holiday_name != name]
|
|
1240
|
+
else: # startswith
|
|
1241
|
+
holiday_names = [
|
|
1242
|
+
name for name in holiday_names if holiday_name != name[: len(holiday_name)]
|
|
1243
|
+
]
|
|
1244
|
+
if holiday_names:
|
|
1245
|
+
self[dt] = HOLIDAY_NAME_DELIMITER.join(holiday_names)
|
|
1118
1246
|
|
|
1119
1247
|
return popped
|
|
1120
1248
|
|
|
1121
1249
|
def update( # type: ignore[override]
|
|
1122
1250
|
self, *args: Union[dict[DateLike, str], list[DateLike], DateLike]
|
|
1123
1251
|
) -> None:
|
|
1124
|
-
# TODO: fix arguments; should not be *args (cannot properly Type hint)
|
|
1125
1252
|
"""Update the object, overwriting existing dates.
|
|
1126
1253
|
|
|
1127
|
-
:
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1254
|
+
Args:
|
|
1255
|
+
args:
|
|
1256
|
+
Either another dictionary object where keys are dates and values
|
|
1257
|
+
are holiday names, or a single date (or a list of dates) for which
|
|
1258
|
+
the value will be set to "Holiday".
|
|
1131
1259
|
|
|
1132
|
-
|
|
1260
|
+
Dates can be expressed in one or more of the following types:
|
|
1133
1261
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
* or a :class:`float` or :class:`int` representing a POSIX
|
|
1139
|
-
timestamp.
|
|
1262
|
+
* `datetime.date`,
|
|
1263
|
+
* `datetime.datetime`,
|
|
1264
|
+
* a `str` of any format recognized by `dateutil.parser.parse()`,
|
|
1265
|
+
* or a `float` or `int` representing a POSIX timestamp.
|
|
1140
1266
|
"""
|
|
1141
1267
|
for arg in args:
|
|
1142
1268
|
if isinstance(arg, dict):
|
|
@@ -1151,11 +1277,11 @@ class HolidayBase(dict[date, str]):
|
|
|
1151
1277
|
|
|
1152
1278
|
class HolidaySum(HolidayBase):
|
|
1153
1279
|
"""
|
|
1154
|
-
Returns a
|
|
1280
|
+
Returns a `dict`-like object resulting from the addition of two or
|
|
1155
1281
|
more individual dictionaries of public holidays. The original dictionaries
|
|
1156
|
-
are available as a
|
|
1157
|
-
|
|
1158
|
-
together and could become
|
|
1282
|
+
are available as a `list` in the attribute `holidays,` and
|
|
1283
|
+
`country` and `subdiv` attributes are added
|
|
1284
|
+
together and could become `list` s. Holiday names, when different,
|
|
1159
1285
|
are merged. All years are calculated (expanded) for all operands.
|
|
1160
1286
|
"""
|
|
1161
1287
|
|
|
@@ -1174,30 +1300,31 @@ class HolidaySum(HolidayBase):
|
|
|
1174
1300
|
self, h1: Union[HolidayBase, "HolidaySum"], h2: Union[HolidayBase, "HolidaySum"]
|
|
1175
1301
|
) -> None:
|
|
1176
1302
|
"""
|
|
1177
|
-
:
|
|
1178
|
-
|
|
1303
|
+
Args:
|
|
1304
|
+
h1:
|
|
1305
|
+
The first HolidayBase object to add.
|
|
1179
1306
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1307
|
+
h2:
|
|
1308
|
+
The other HolidayBase object to add.
|
|
1182
1309
|
|
|
1183
1310
|
Example:
|
|
1184
1311
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
country_holidays('CA') + country_holidays('MX')
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1312
|
+
>>> from holidays import country_holidays
|
|
1313
|
+
>>> nafta_holidays = country_holidays('US', years=2020) + \
|
|
1314
|
+
country_holidays('CA') + country_holidays('MX')
|
|
1315
|
+
>>> dates = sorted(nafta_holidays.items(), key=lambda x: x[0])
|
|
1316
|
+
>>> from pprint import pprint
|
|
1317
|
+
>>> pprint(dates[:10], width=72)
|
|
1318
|
+
[(datetime.date(2020, 1, 1), "Año Nuevo; New Year's Day"),
|
|
1319
|
+
(datetime.date(2020, 1, 20), 'Martin Luther King Jr. Day'),
|
|
1320
|
+
(datetime.date(2020, 2, 3), 'Día de la Constitución'),
|
|
1321
|
+
(datetime.date(2020, 2, 17), "Washington's Birthday"),
|
|
1322
|
+
(datetime.date(2020, 3, 16), 'Natalicio de Benito Juárez'),
|
|
1323
|
+
(datetime.date(2020, 4, 10), 'Good Friday'),
|
|
1324
|
+
(datetime.date(2020, 5, 1), 'Día del Trabajo'),
|
|
1325
|
+
(datetime.date(2020, 5, 25), 'Memorial Day'),
|
|
1326
|
+
(datetime.date(2020, 7, 1), 'Canada Day'),
|
|
1327
|
+
(datetime.date(2020, 7, 3), 'Independence Day (observed)')]
|
|
1201
1328
|
"""
|
|
1202
1329
|
# Store originals in the holidays attribute.
|
|
1203
1330
|
self.holidays = []
|
|
@@ -1245,8 +1372,18 @@ country_holidays('CA') + country_holidays('MX')
|
|
|
1245
1372
|
else:
|
|
1246
1373
|
setattr(self, attr, value)
|
|
1247
1374
|
|
|
1375
|
+
# Retain language if they match and are strings.
|
|
1376
|
+
# If language wasn't assigned, default_language acts as fallback.
|
|
1377
|
+
h1_language = h1.language or h1.default_language
|
|
1378
|
+
h2_language = h2.language or h2.default_language
|
|
1379
|
+
if isinstance(h1_language, str) and h1_language == h2_language:
|
|
1380
|
+
kwargs["language"] = h1_language
|
|
1381
|
+
|
|
1248
1382
|
HolidayBase.__init__(self, **kwargs)
|
|
1249
1383
|
|
|
1384
|
+
# supported_languages is used for iCalExporter language check as well.
|
|
1385
|
+
self.supported_languages = (h1_language,) if h1_language else ()
|
|
1386
|
+
|
|
1250
1387
|
def _populate(self, year):
|
|
1251
1388
|
for operand in self.holidays:
|
|
1252
1389
|
operand._populate(year)
|