holidays 0.69__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.
Files changed (236) hide show
  1. holidays/__init__.py +1 -1
  2. holidays/calendars/__init__.py +1 -1
  3. holidays/calendars/balinese_saka.py +3 -3
  4. holidays/calendars/buddhist.py +1 -1
  5. holidays/calendars/chinese.py +1 -1
  6. holidays/calendars/custom.py +1 -1
  7. holidays/calendars/gregorian.py +1 -1
  8. holidays/calendars/hebrew.py +1 -1
  9. holidays/calendars/hindu.py +1 -1
  10. holidays/calendars/islamic.py +161 -1
  11. holidays/calendars/julian.py +1 -1
  12. holidays/calendars/julian_revised.py +1 -1
  13. holidays/calendars/persian.py +1 -1
  14. holidays/calendars/sinhala.py +1 -1
  15. holidays/calendars/thai.py +309 -257
  16. holidays/constants.py +2 -1
  17. holidays/countries/__init__.py +6 -1
  18. holidays/countries/afghanistan.py +11 -7
  19. holidays/countries/albania.py +10 -7
  20. holidays/countries/algeria.py +10 -10
  21. holidays/countries/american_samoa.py +6 -4
  22. holidays/countries/andorra.py +5 -4
  23. holidays/countries/angola.py +15 -14
  24. holidays/countries/antigua_and_barbuda.py +145 -0
  25. holidays/countries/argentina.py +787 -169
  26. holidays/countries/armenia.py +5 -6
  27. holidays/countries/aruba.py +11 -9
  28. holidays/countries/australia.py +21 -20
  29. holidays/countries/austria.py +3 -1
  30. holidays/countries/azerbaijan.py +24 -19
  31. holidays/countries/bahamas.py +13 -11
  32. holidays/countries/bahrain.py +8 -7
  33. holidays/countries/bangladesh.py +5 -4
  34. holidays/countries/barbados.py +11 -9
  35. holidays/countries/belarus.py +15 -15
  36. holidays/countries/belgium.py +8 -6
  37. holidays/countries/belize.py +7 -6
  38. holidays/countries/bolivia.py +12 -11
  39. holidays/countries/bosnia_and_herzegovina.py +15 -11
  40. holidays/countries/botswana.py +8 -6
  41. holidays/countries/brazil.py +8 -7
  42. holidays/countries/brunei.py +50 -62
  43. holidays/countries/bulgaria.py +9 -10
  44. holidays/countries/burkina_faso.py +8 -5
  45. holidays/countries/burundi.py +13 -12
  46. holidays/countries/cambodia.py +15 -24
  47. holidays/countries/cameroon.py +10 -7
  48. holidays/countries/canada.py +13 -12
  49. holidays/countries/chad.py +9 -6
  50. holidays/countries/chile.py +29 -28
  51. holidays/countries/china.py +39 -38
  52. holidays/countries/colombia.py +15 -20
  53. holidays/countries/congo.py +6 -7
  54. holidays/countries/costa_rica.py +11 -10
  55. holidays/countries/croatia.py +8 -5
  56. holidays/countries/cuba.py +30 -27
  57. holidays/countries/curacao.py +6 -4
  58. holidays/countries/cyprus.py +4 -5
  59. holidays/countries/czechia.py +7 -6
  60. holidays/countries/denmark.py +5 -6
  61. holidays/countries/djibouti.py +7 -3
  62. holidays/countries/dominica.py +18 -16
  63. holidays/countries/dominican_republic.py +6 -4
  64. holidays/countries/ecuador.py +5 -4
  65. holidays/countries/egypt.py +6 -11
  66. holidays/countries/el_salvador.py +6 -5
  67. holidays/countries/estonia.py +3 -1
  68. holidays/countries/eswatini.py +6 -4
  69. holidays/countries/ethiopia.py +20 -11
  70. holidays/countries/fiji.py +183 -0
  71. holidays/countries/finland.py +11 -10
  72. holidays/countries/france.py +6 -9
  73. holidays/countries/gabon.py +11 -8
  74. holidays/countries/georgia.py +7 -7
  75. holidays/countries/germany.py +11 -11
  76. holidays/countries/ghana.py +10 -6
  77. holidays/countries/greece.py +4 -5
  78. holidays/countries/greenland.py +5 -6
  79. holidays/countries/guam.py +6 -4
  80. holidays/countries/guatemala.py +7 -9
  81. holidays/countries/guernsey.py +37 -34
  82. holidays/countries/guinea.py +182 -0
  83. holidays/countries/haiti.py +6 -5
  84. holidays/countries/honduras.py +8 -4
  85. holidays/countries/hongkong.py +11 -8
  86. holidays/countries/hungary.py +26 -23
  87. holidays/countries/iceland.py +5 -4
  88. holidays/countries/india.py +14 -10
  89. holidays/countries/indonesia.py +57 -53
  90. holidays/countries/iran.py +12 -9
  91. holidays/countries/ireland.py +5 -4
  92. holidays/countries/isle_of_man.py +2 -2
  93. holidays/countries/israel.py +4 -5
  94. holidays/countries/italy.py +5 -4
  95. holidays/countries/ivory_coast.py +156 -0
  96. holidays/countries/jamaica.py +6 -4
  97. holidays/countries/japan.py +5 -5
  98. holidays/countries/jersey.py +29 -26
  99. holidays/countries/jordan.py +9 -6
  100. holidays/countries/kazakhstan.py +66 -51
  101. holidays/countries/kenya.py +22 -18
  102. holidays/countries/kuwait.py +10 -7
  103. holidays/countries/kyrgyzstan.py +7 -6
  104. holidays/countries/laos.py +21 -29
  105. holidays/countries/latvia.py +7 -5
  106. holidays/countries/lesotho.py +6 -5
  107. holidays/countries/liechtenstein.py +5 -5
  108. holidays/countries/lithuania.py +4 -5
  109. holidays/countries/luxembourg.py +5 -3
  110. holidays/countries/macau.py +32 -26
  111. holidays/countries/madagascar.py +5 -4
  112. holidays/countries/malawi.py +6 -4
  113. holidays/countries/malaysia.py +24 -18
  114. holidays/countries/maldives.py +10 -7
  115. holidays/countries/malta.py +10 -19
  116. holidays/countries/marshall_islands.py +6 -4
  117. holidays/countries/mauritania.py +9 -6
  118. holidays/countries/mexico.py +8 -7
  119. holidays/countries/moldova.py +6 -4
  120. holidays/countries/monaco.py +6 -4
  121. holidays/countries/montenegro.py +10 -7
  122. holidays/countries/morocco.py +9 -8
  123. holidays/countries/mozambique.py +3 -1
  124. holidays/countries/namibia.py +7 -5
  125. holidays/countries/netherlands.py +6 -6
  126. holidays/countries/new_zealand.py +3 -1
  127. holidays/countries/nicaragua.py +6 -5
  128. holidays/countries/nigeria.py +9 -5
  129. holidays/countries/north_macedonia.py +9 -5
  130. holidays/countries/northern_mariana_islands.py +6 -4
  131. holidays/countries/norway.py +15 -15
  132. holidays/countries/pakistan.py +41 -17
  133. holidays/countries/palau.py +13 -11
  134. holidays/countries/panama.py +9 -8
  135. holidays/countries/papua_new_guinea.py +25 -21
  136. holidays/countries/paraguay.py +10 -9
  137. holidays/countries/peru.py +4 -5
  138. holidays/countries/philippines.py +25 -21
  139. holidays/countries/poland.py +6 -5
  140. holidays/countries/portugal.py +13 -15
  141. holidays/countries/puerto_rico.py +6 -4
  142. holidays/countries/qatar.py +172 -0
  143. holidays/countries/romania.py +6 -4
  144. holidays/countries/russia.py +6 -4
  145. holidays/countries/saint_kitts_and_nevis.py +24 -22
  146. holidays/countries/saint_lucia.py +8 -7
  147. holidays/countries/samoa.py +7 -6
  148. holidays/countries/san_marino.py +4 -3
  149. holidays/countries/saudi_arabia.py +11 -15
  150. holidays/countries/serbia.py +3 -4
  151. holidays/countries/seychelles.py +22 -26
  152. holidays/countries/singapore.py +29 -39
  153. holidays/countries/slovakia.py +6 -5
  154. holidays/countries/slovenia.py +7 -6
  155. holidays/countries/south_africa.py +8 -6
  156. holidays/countries/south_korea.py +25 -32
  157. holidays/countries/spain.py +25 -24
  158. holidays/countries/sri_lanka.py +46 -42
  159. holidays/countries/sweden.py +20 -19
  160. holidays/countries/switzerland.py +6 -5
  161. holidays/countries/taiwan.py +50 -48
  162. holidays/countries/tanzania.py +28 -27
  163. holidays/countries/thailand.py +134 -142
  164. holidays/countries/timor_leste.py +20 -18
  165. holidays/countries/tonga.py +46 -42
  166. holidays/countries/tunisia.py +5 -3
  167. holidays/countries/turkey.py +11 -9
  168. holidays/countries/tuvalu.py +12 -11
  169. holidays/countries/ukraine.py +54 -54
  170. holidays/countries/united_arab_emirates.py +37 -30
  171. holidays/countries/united_kingdom.py +7 -6
  172. holidays/countries/united_states.py +50 -55
  173. holidays/countries/united_states_minor_outlying_islands.py +6 -4
  174. holidays/countries/united_states_virgin_islands.py +6 -4
  175. holidays/countries/uruguay.py +10 -9
  176. holidays/countries/uzbekistan.py +10 -7
  177. holidays/countries/vanuatu.py +7 -5
  178. holidays/countries/vatican_city.py +16 -15
  179. holidays/countries/venezuela.py +11 -14
  180. holidays/countries/vietnam.py +15 -11
  181. holidays/countries/zambia.py +8 -6
  182. holidays/countries/zimbabwe.py +6 -4
  183. holidays/deprecations/v1_incompatibility.py +1 -1
  184. holidays/financial/__init__.py +1 -1
  185. holidays/financial/brasil_bolsa_balcao.py +14 -13
  186. holidays/financial/european_central_bank.py +7 -6
  187. holidays/financial/ice_futures_europe.py +7 -6
  188. holidays/financial/ny_stock_exchange.py +13 -10
  189. holidays/groups/__init__.py +1 -1
  190. holidays/groups/balinese_saka.py +1 -1
  191. holidays/groups/buddhist.py +1 -1
  192. holidays/groups/chinese.py +1 -1
  193. holidays/groups/christian.py +1 -1
  194. holidays/groups/custom.py +1 -1
  195. holidays/groups/eastern.py +1 -1
  196. holidays/groups/hebrew.py +1 -1
  197. holidays/groups/hindu.py +1 -1
  198. holidays/groups/international.py +1 -1
  199. holidays/groups/islamic.py +12 -1
  200. holidays/groups/persian.py +1 -1
  201. holidays/groups/sinhala.py +1 -1
  202. holidays/groups/thai.py +1 -7
  203. holidays/helpers.py +1 -1
  204. holidays/holiday_base.py +366 -244
  205. holidays/ical.py +228 -0
  206. holidays/locale/ar_QA/LC_MESSAGES/QA.mo +0 -0
  207. holidays/locale/en_CI/LC_MESSAGES/CI.mo +0 -0
  208. holidays/locale/en_PK/LC_MESSAGES/PK.mo +0 -0
  209. holidays/locale/en_TL/LC_MESSAGES/TL.mo +0 -0
  210. holidays/locale/en_US/LC_MESSAGES/AR.mo +0 -0
  211. holidays/locale/en_US/LC_MESSAGES/CI.mo +0 -0
  212. holidays/locale/en_US/LC_MESSAGES/GN.mo +0 -0
  213. holidays/locale/en_US/LC_MESSAGES/PK.mo +0 -0
  214. holidays/locale/en_US/LC_MESSAGES/QA.mo +0 -0
  215. holidays/locale/en_US/LC_MESSAGES/TL.mo +0 -0
  216. holidays/locale/es/LC_MESSAGES/AR.mo +0 -0
  217. holidays/locale/fr/LC_MESSAGES/CI.mo +0 -0
  218. holidays/locale/fr/LC_MESSAGES/GN.mo +0 -0
  219. holidays/locale/hi/LC_MESSAGES/IN.mo +0 -0
  220. holidays/locale/pt_TL/LC_MESSAGES/TL.mo +0 -0
  221. holidays/locale/tet/LC_MESSAGES/TL.mo +0 -0
  222. holidays/locale/th/LC_MESSAGES/TL.mo +0 -0
  223. holidays/locale/uk/LC_MESSAGES/AR.mo +0 -0
  224. holidays/locale/ur_PK/LC_MESSAGES/PK.mo +0 -0
  225. holidays/mixins.py +2 -2
  226. holidays/observed_holiday_base.py +5 -2
  227. holidays/registry.py +6 -1
  228. holidays/utils.py +151 -151
  229. holidays/version.py +2 -2
  230. holidays-0.70.dist-info/METADATA +1404 -0
  231. {holidays-0.69.dist-info → holidays-0.70.dist-info}/RECORD +235 -217
  232. {holidays-0.69.dist-info → holidays-0.70.dist-info}/WHEEL +1 -1
  233. holidays-0.69.dist-info/AUTHORS → holidays-0.70.dist-info/licenses/AUTHORS.md +6 -2
  234. {holidays-0.69.dist-info → holidays-0.70.dist-info/licenses}/LICENSE +1 -1
  235. holidays-0.69.dist-info/METADATA +0 -1085
  236. {holidays-0.69.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-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
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 datetime.parse).
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
- us_holidays = holidays.US(years=2020)
81
+ us_holidays = holidays.US(years=2020)
82
82
 
83
- It is generally instantiated using the :func:`country_holidays` function.
83
+ It is generally instantiated using the
84
+ [country_holidays()][holidays.utils.country_holidays] function.
84
85
 
85
- The key of the :class:`dict`-like :class:`HolidayBase` object is 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
- * :class:`datetime.date`,
94
- * :class:`datetime.datetime`,
95
- * a :class:`str` of any format recognized by :func:`dateutil.parser.parse`,
96
- * or a :class:`float` or :class:`int` representing a POSIX timestamp.
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 :class:`datetime.date` object.
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
- >>> from holidays import country_holidays
112
- >>> us_holidays = country_holidays('US')
113
- # For a specific subdivisions (e.g. state or province):
114
- >>> california_holidays = country_holidays('US', subdiv='CA')
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
- >>> from datetime import date
119
- >>> assert date(2015, 1, 1) in us_holidays
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
- >>> assert date(2015, 1, 2) not in us_holidays
124
+ >>> assert date(2015, 1, 2) not in us_holidays
124
125
 
125
- The :class:`HolidayBase` class also recognizes strings of many formats
126
+ The `HolidayBase` class also recognizes strings of many formats
126
127
  and numbers representing a POSIX timestamp:
127
128
 
128
- >>> assert '2014-01-01' in us_holidays
129
- >>> assert '1/1/2014' in us_holidays
130
- >>> assert 1388597445 in us_holidays
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
- >>> us_holidays.get('2014-01-01')
135
- "New Year's Day"
135
+ >>> us_holidays.get('2014-01-01')
136
+ "New Year's Day"
136
137
 
137
138
  Check a range:
138
139
 
139
- >>> us_holidays['2014-01-01': '2014-01-03']
140
- [datetime.date(2014, 1, 1)]
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
- >>> us_holidays = country_holidays('US', years=2020)
145
- >>> for day in us_holidays.items():
146
- ... print(day)
147
- (datetime.date(2020, 1, 1), "New Year's Day")
148
- (datetime.date(2020, 1, 20), 'Martin Luther King Jr. Day')
149
- (datetime.date(2020, 2, 17), "Washington's Birthday")
150
- (datetime.date(2020, 5, 25), 'Memorial Day')
151
- (datetime.date(2020, 7, 4), 'Independence Day')
152
- (datetime.date(2020, 7, 3), 'Independence Day (observed)')
153
- (datetime.date(2020, 9, 7), 'Labor Day')
154
- (datetime.date(2020, 10, 12), 'Columbus Day')
155
- (datetime.date(2020, 11, 11), 'Veterans Day')
156
- (datetime.date(2020, 11, 26), 'Thanksgiving')
157
- (datetime.date(2020, 12, 25), 'Christmas Day')
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
- >>> us_pr_holidays = country_holidays('US', subdiv='PR')
162
- >>> assert '2018-01-06' not in us_holidays
163
- >>> assert '2018-01-06' in us_pr_holidays
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 :class:`dict` with date/name key/value pairs (e.g.
168
- ``{'2010-07-10': 'My birthday!'}``),
169
- * a list of dates (as a :class:`datetime.date`, :class:`datetime.datetime`,
170
- :class:`str`, :class:`int`, or :class:`float`); ``'Holiday'`` will be
171
- used as a description,
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
- :attr:`special_public_holidays`:
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
- :class:`HolidayBase` class and define your own :meth:`_populate` method.
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
- :param years:
269
- The year(s) to pre-calculate public holidays for at instantiation.
269
+ Args:
270
+ years:
271
+ The year(s) to pre-calculate public holidays for at instantiation.
270
272
 
271
- :param expand:
272
- Whether the entire year is calculated when one date from that year
273
- is requested.
273
+ expand:
274
+ Whether the entire year is calculated when one date from that year
275
+ is requested.
274
276
 
275
- :param observed:
276
- Whether to include the dates when public holiday are observed
277
- (e.g. a holiday falling on a Sunday being observed the
278
- following Monday). This doesn't work for all countries.
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
- :param subdiv:
281
- The subdivision (e.g. state or province) as a ISO 3166-2 code
282
- or its alias; not implemented for all countries (see documentation).
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
- :param prov:
285
- *deprecated* use subdiv instead.
286
+ prov:
287
+ *deprecated* use `subdiv` instead.
286
288
 
287
- :param state:
288
- *deprecated* use subdiv instead.
289
+ state:
290
+ *deprecated* use `subdiv` instead.
289
291
 
290
- :param language:
291
- The language which the returned holiday names will be translated
292
- into. It must be an ISO 639-1 (2-letter) language code. If the
293
- language translation is not supported the original holiday names
294
- will be used.
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
- :param categories:
297
- Requested holiday categories.
298
+ categories:
299
+ Requested holiday categories.
298
300
 
299
- :return:
300
- A :class:`HolidayBase` object matching the **country**.
301
+ Returns:
302
+ A `HolidayBase` object matching the **country** or **market**.
301
303
  """
302
304
  super().__init__()
303
305
 
@@ -376,14 +378,14 @@ class HolidayBase(dict[date, str]):
376
378
 
377
379
  def __add__(self, other: Union[int, "HolidayBase", "HolidaySum"]) -> "HolidayBase":
378
380
  """Add another dictionary of public holidays creating a
379
- :class:`HolidaySum` object.
381
+ [HolidaySum][holidays.holiday_base.HolidaySum] object.
380
382
 
381
- :param other:
382
- The dictionary of public holiday to be added.
383
+ Args:
384
+ other:
385
+ The dictionary of public holiday to be added.
383
386
 
384
- :return:
385
- A :class:`HolidaySum` object unless the other object cannot be
386
- added, then :class:`self`.
387
+ Returns:
388
+ A `HolidayBase` object unless the other object cannot be added, then `self`.
387
389
  """
388
390
  if isinstance(other, int) and other == 0:
389
391
  # Required to sum() list of holidays
@@ -399,14 +401,21 @@ class HolidayBase(dict[date, str]):
399
401
  return len(self) > 0
400
402
 
401
403
  def __contains__(self, key: object) -> bool:
402
- """Return true if date is in self, false otherwise. Accepts a date in
403
- the following types:
404
-
405
- * :class:`datetime.date`,
406
- * :class:`datetime.datetime`,
407
- * a :class:`str` of any format recognized by
408
- :func:`dateutil.parser.parse`,
409
- * or a :class:`float` or :class:`int` representing a POSIX timestamp.
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.
410
419
  """
411
420
 
412
421
  if not isinstance(key, (date, datetime, float, int, str)):
@@ -574,15 +583,21 @@ class HolidayBase(dict[date, str]):
574
583
  return state
575
584
 
576
585
  def __keytransform__(self, key: DateLike) -> date:
577
- """Transforms the date from one of the following types:
586
+ """Convert various date-like formats to `datetime.date`.
578
587
 
579
- * :class:`datetime.date`,
580
- * :class:`datetime.datetime`,
581
- * a :class:`str` of any format recognized by
582
- :func:`dateutil.parser.parse`,
583
- * or a :class:`float` or :class:`int` representing a POSIX timestamp
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
584
593
 
585
- to :class:`datetime.date`, which is how it's stored by the class."""
594
+ Args:
595
+ key:
596
+ The date-like object to convert.
597
+
598
+ Returns:
599
+ The corresponding `datetime.date` representation.
600
+ """
586
601
 
587
602
  dt: Optional[date] = None
588
603
  # Try to catch `date` and `str` type keys first.
@@ -729,7 +744,11 @@ class HolidayBase(dict[date, str]):
729
744
 
730
745
  @classmethod
731
746
  def get_subdivision_aliases(cls) -> dict[str, list]:
732
- """Get subdivision aliases."""
747
+ """Get subdivision aliases.
748
+
749
+ Returns:
750
+ A dictionary mapping subdivision aliases to their official ISO 3166-2 codes.
751
+ """
733
752
  subdivision_aliases: dict[str, list[str]] = {s: [] for s in cls.subdivisions}
734
753
  for alias, subdivision in cls.subdivisions_aliases.items():
735
754
  subdivision_aliases[subdivision].append(alias)
@@ -856,13 +875,13 @@ class HolidayBase(dict[date, str]):
856
875
  directly from outside.
857
876
  To add holidays to an object, use the update() method.
858
877
 
859
- :param year:
860
- The year to populate with holidays.
878
+ Args:
879
+ year: The year to populate with holidays.
861
880
 
862
- >>> from holidays import country_holidays
863
- >>> us_holidays = country_holidays('US', years=2020)
864
- # to add new holidays to the object:
865
- >>> us_holidays.update(country_holidays('US', years=2021))
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))
866
885
  """
867
886
 
868
887
  if year < self.start_year or year > self.end_year:
@@ -903,7 +922,16 @@ class HolidayBase(dict[date, str]):
903
922
  )
904
923
 
905
924
  def append(self, *args: Union[dict[DateLike, str], list[DateLike], DateLike]) -> None:
906
- """Alias for :meth:`update` to mimic list type."""
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
+ """
907
935
  return self.update(*args)
908
936
 
909
937
  def copy(self):
@@ -911,64 +939,73 @@ class HolidayBase(dict[date, str]):
911
939
  return copy.copy(self)
912
940
 
913
941
  def get(self, key: DateLike, default: Union[str, Any] = None) -> Union[str, Any]:
914
- """Return the holiday name for a date if date is a holiday, else
915
- default. If default is not given, it defaults to None, so that this
916
- method never raises a KeyError. If more than one holiday is present,
917
- they are separated by a comma.
918
-
919
- :param key:
920
- The date expressed in one of the following types:
921
-
922
- * :class:`datetime.date`,
923
- * :class:`datetime.datetime`,
924
- * a :class:`str` of any format recognized by
925
- :func:`dateutil.parser.parse`,
926
- * or a :class:`float` or :class:`int` representing a POSIX
927
- timestamp.
928
-
929
- :param default:
930
- The default value to return if no value is found.
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.
931
963
  """
932
964
  return dict.get(self, self.__keytransform__(key), default)
933
965
 
934
966
  def get_list(self, key: DateLike) -> list[str]:
935
- """Return a list of all holiday names for a date if date is a holiday,
936
- else empty string.
937
-
938
- :param key:
939
- The date expressed in one of the following types:
940
-
941
- * :class:`datetime.date`,
942
- * :class:`datetime.datetime`,
943
- * a :class:`str` of any format recognized by
944
- :func:`dateutil.parser.parse`,
945
- * or a :class:`float` or :class:`int` representing a POSIX
946
- timestamp.
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.
947
980
  """
948
981
  return [name for name in self.get(key, "").split(HOLIDAY_NAME_DELIMITER) if name]
949
982
 
950
983
  def get_named(
951
- self, holiday_name: str, lookup="icontains", split_multiple_names=True
984
+ self, holiday_name: str, lookup: str = "icontains", split_multiple_names: bool = True
952
985
  ) -> list[date]:
953
- """Return a list of all holiday dates matching the provided holiday
954
- name. The match will be made case insensitively and partial matches
955
- will be included by default.
956
-
957
- :param holiday_name:
958
- The holiday's name to try to match.
959
- :param lookup:
960
- The holiday name lookup type:
961
- contains - case sensitive contains match;
962
- exact - case sensitive exact match;
963
- startswith - case sensitive starts with match;
964
- icontains - case insensitive contains match;
965
- iexact - case insensitive exact match;
966
- istartswith - case insensitive starts with match;
967
- :param split_multiple_names:
968
- Either use the exact name for each date or split it by holiday
969
- name delimiter.
970
-
971
- :return:
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:
972
1009
  A list of all holiday dates matching the provided holiday name.
973
1010
  """
974
1011
  holiday_name_dates = (
@@ -1006,10 +1043,23 @@ class HolidayBase(dict[date, str]):
1006
1043
  target_date: DateLike = None,
1007
1044
  direction: Literal["forward", "backward"] = "forward",
1008
1045
  ) -> Optional[tuple[date, str]]:
1009
- """Return the date and name of the next holiday for a target_date
1010
- if direction is "forward" or the previous holiday if direction is "backward".
1011
- If target_date is not provided the current date will be used by default."""
1046
+ """Find the closest holiday relative to a given date.
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).
1012
1059
 
1060
+ Returns:
1061
+ A tuple containing the holiday date and its name, or None if no holiday is found.
1062
+ """
1013
1063
  if direction not in {"backward", "forward"}:
1014
1064
  raise AttributeError(f"Unknown direction: {direction}")
1015
1065
 
@@ -1032,8 +1082,20 @@ class HolidayBase(dict[date, str]):
1032
1082
  return None
1033
1083
 
1034
1084
  def get_nth_working_day(self, key: DateLike, n: int) -> date:
1035
- """Return n-th working day from provided date (if n is positive)
1036
- or n-th working day before provided date (if n is negative).
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.
1037
1099
  """
1038
1100
  direction = +1 if n > 0 else -1
1039
1101
  dt = self.__keytransform__(key)
@@ -1044,16 +1106,20 @@ class HolidayBase(dict[date, str]):
1044
1106
  return dt
1045
1107
 
1046
1108
  def get_working_days_count(self, start: DateLike, end: DateLike) -> int:
1047
- """Return the number of working days between two dates.
1109
+ """Calculate the number of working days between two dates.
1048
1110
 
1049
1111
  The date range works in a closed interval fashion [start, end] so both
1050
1112
  endpoints are included.
1051
1113
 
1052
- :param start:
1053
- The range start date.
1114
+ Args:
1115
+ start:
1116
+ The range start date.
1117
+
1118
+ end:
1119
+ The range end date.
1054
1120
 
1055
- :param end:
1056
- The range end date.
1121
+ Returns:
1122
+ The total count of working days between the given dates.
1057
1123
  """
1058
1124
  dt1 = self.__keytransform__(start)
1059
1125
  dt2 = self.__keytransform__(end)
@@ -1063,55 +1129,83 @@ class HolidayBase(dict[date, str]):
1063
1129
  return sum(self.is_working_day(_timedelta(dt1, n)) for n in range(days))
1064
1130
 
1065
1131
  def is_working_day(self, key: DateLike) -> bool:
1066
- """Return True if date is a working day (not a holiday or a weekend)."""
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
+ """
1067
1141
  dt = self.__keytransform__(key)
1068
1142
  return dt in self.weekend_workdays if self._is_weekend(dt) else dt not in self
1069
1143
 
1070
1144
  def pop(self, key: DateLike, default: Union[str, Any] = None) -> Union[str, Any]:
1071
- """If date is a holiday, remove it and return its date, else return
1072
- default.
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.
1073
1150
 
1074
- :param key:
1075
- The date expressed in one of the following types:
1151
+ Args:
1152
+ key:
1153
+ The date expressed in one of the following types:
1076
1154
 
1077
- * :class:`datetime.date`,
1078
- * :class:`datetime.datetime`,
1079
- * a :class:`str` of any format recognized by
1080
- :func:`dateutil.parser.parse`,
1081
- * or a :class:`float` or :class:`int` representing a POSIX
1082
- 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.
1083
1159
 
1084
- :param default:
1085
- The default value to return if no match is found.
1160
+ default:
1161
+ The default value to return if no match is found.
1086
1162
 
1087
- :return:
1088
- The date removed.
1163
+ Returns:
1164
+ The name of the removed holiday if the date was a holiday, otherwise
1165
+ the provided `default` value.
1089
1166
 
1090
- :raise:
1091
- 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.
1092
1169
  """
1093
1170
  if default is None:
1094
1171
  return dict.pop(self, self.__keytransform__(key))
1095
1172
 
1096
1173
  return dict.pop(self, self.__keytransform__(key), default)
1097
1174
 
1098
- def pop_named(self, name: str) -> list[date]:
1099
- """Remove (no longer treat at as holiday) all dates matching the
1100
- provided holiday name. The match will be made case insensitively and
1101
- partial matches will be removed.
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.
1102
1181
 
1103
- :param name:
1104
- The holiday's name to try to match.
1182
+ Args:
1183
+ holiday_name:
1184
+ The holiday's name to try to match.
1105
1185
 
1106
- :return:
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:
1107
1197
  A list of dates removed.
1108
1198
 
1109
- :raise:
1110
- KeyError if date is not a holiday and default is not given.
1199
+ Raises:
1200
+ KeyError: if date is not a holiday.
1111
1201
  """
1112
- use_exact_name = HOLIDAY_NAME_DELIMITER in name
1113
- if not (dts := self.get_named(name, split_multiple_names=not use_exact_name)):
1114
- raise KeyError(name)
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)
1115
1209
 
1116
1210
  popped = []
1117
1211
  for dt in dts:
@@ -1120,38 +1214,55 @@ class HolidayBase(dict[date, str]):
1120
1214
  popped.append(dt)
1121
1215
 
1122
1216
  # Keep the rest of holidays falling on the same date.
1123
- if not use_exact_name:
1124
- name_lower = name.lower()
1217
+ if use_exact_name:
1218
+ continue
1219
+ if lookup == "icontains":
1220
+ holiday_name_lower = holiday_name.lower()
1125
1221
  holiday_names = [
1126
- holiday_name
1127
- for holiday_name in holiday_names
1128
- if name_lower not in holiday_name.lower()
1222
+ name for name in holiday_names if holiday_name_lower not in name.lower()
1129
1223
  ]
1130
-
1131
- if holiday_names:
1132
- self[dt] = HOLIDAY_NAME_DELIMITER.join(holiday_names)
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)
1133
1246
 
1134
1247
  return popped
1135
1248
 
1136
1249
  def update( # type: ignore[override]
1137
1250
  self, *args: Union[dict[DateLike, str], list[DateLike], DateLike]
1138
1251
  ) -> None:
1139
- # TODO: fix arguments; should not be *args (cannot properly Type hint)
1140
1252
  """Update the object, overwriting existing dates.
1141
1253
 
1142
- :param:
1143
- Either another dictionary object where keys are dates and values
1144
- are holiday names, or a single date (or a list of dates) for which
1145
- the value will be set to "Holiday".
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".
1146
1259
 
1147
- Dates can be expressed in one or more of the following types:
1260
+ Dates can be expressed in one or more of the following types:
1148
1261
 
1149
- * :class:`datetime.date`,
1150
- * :class:`datetime.datetime`,
1151
- * a :class:`str` of any format recognized by
1152
- :func:`dateutil.parser.parse`,
1153
- * or a :class:`float` or :class:`int` representing a POSIX
1154
- 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.
1155
1266
  """
1156
1267
  for arg in args:
1157
1268
  if isinstance(arg, dict):
@@ -1166,11 +1277,11 @@ class HolidayBase(dict[date, str]):
1166
1277
 
1167
1278
  class HolidaySum(HolidayBase):
1168
1279
  """
1169
- Returns a :class:`dict`-like object resulting from the addition of two or
1280
+ Returns a `dict`-like object resulting from the addition of two or
1170
1281
  more individual dictionaries of public holidays. The original dictionaries
1171
- are available as a :class:`list` in the attribute :attr:`holidays,` and
1172
- :attr:`country` and :attr:`subdiv` attributes are added
1173
- together and could become :class:`list` s. Holiday names, when different,
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,
1174
1285
  are merged. All years are calculated (expanded) for all operands.
1175
1286
  """
1176
1287
 
@@ -1189,30 +1300,31 @@ class HolidaySum(HolidayBase):
1189
1300
  self, h1: Union[HolidayBase, "HolidaySum"], h2: Union[HolidayBase, "HolidaySum"]
1190
1301
  ) -> None:
1191
1302
  """
1192
- :param h1:
1193
- The first HolidayBase object to add.
1303
+ Args:
1304
+ h1:
1305
+ The first HolidayBase object to add.
1194
1306
 
1195
- :param h2:
1196
- The other HolidayBase object to add.
1307
+ h2:
1308
+ The other HolidayBase object to add.
1197
1309
 
1198
1310
  Example:
1199
1311
 
1200
- >>> from holidays import country_holidays
1201
- >>> nafta_holidays = country_holidays('US', years=2020) + \
1202
- country_holidays('CA') + country_holidays('MX')
1203
- >>> dates = sorted(nafta_holidays.items(), key=lambda x: x[0])
1204
- >>> from pprint import pprint
1205
- >>> pprint(dates[:10], width=72)
1206
- [(datetime.date(2020, 1, 1), "Año Nuevo"),
1207
- (datetime.date(2020, 1, 20), 'Martin Luther King Jr. Day'),
1208
- (datetime.date(2020, 2, 3),
1209
- 'Día de la Constitución'),
1210
- (datetime.date(2020, 2, 17), "Washington's Birthday, Family Day"),
1211
- (datetime.date(2020, 3, 16),
1212
- "Natalicio de Benito Juárez"),
1213
- (datetime.date(2020, 4, 10), 'Good Friday'),
1214
- (datetime.date(2020, 5, 1), 'Día del Trabajo'),
1215
- (datetime.date(2020, 5, 18), 'Victoria Day')]
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)')]
1216
1328
  """
1217
1329
  # Store originals in the holidays attribute.
1218
1330
  self.holidays = []
@@ -1260,8 +1372,18 @@ country_holidays('CA') + country_holidays('MX')
1260
1372
  else:
1261
1373
  setattr(self, attr, value)
1262
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
+
1263
1382
  HolidayBase.__init__(self, **kwargs)
1264
1383
 
1384
+ # supported_languages is used for iCalExporter language check as well.
1385
+ self.supported_languages = (h1_language,) if h1_language else ()
1386
+
1265
1387
  def _populate(self, year):
1266
1388
  for operand in self.holidays:
1267
1389
  operand._populate(year)