holidays 0.69__py3-none-any.whl → 0.71__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 (249) 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 +10 -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 +7 -10
  73. holidays/countries/french_southern_territories.py +53 -0
  74. holidays/countries/gabon.py +11 -8
  75. holidays/countries/georgia.py +7 -7
  76. holidays/countries/germany.py +11 -11
  77. holidays/countries/ghana.py +10 -6
  78. holidays/countries/greece.py +4 -5
  79. holidays/countries/greenland.py +5 -6
  80. holidays/countries/guam.py +6 -4
  81. holidays/countries/guatemala.py +7 -9
  82. holidays/countries/guernsey.py +37 -34
  83. holidays/countries/guinea.py +182 -0
  84. holidays/countries/haiti.py +6 -5
  85. holidays/countries/honduras.py +8 -4
  86. holidays/countries/hongkong.py +11 -8
  87. holidays/countries/hungary.py +26 -23
  88. holidays/countries/iceland.py +5 -4
  89. holidays/countries/india.py +14 -10
  90. holidays/countries/indonesia.py +57 -53
  91. holidays/countries/iran.py +12 -9
  92. holidays/countries/ireland.py +5 -4
  93. holidays/countries/isle_of_man.py +2 -2
  94. holidays/countries/israel.py +4 -5
  95. holidays/countries/italy.py +5 -4
  96. holidays/countries/ivory_coast.py +156 -0
  97. holidays/countries/jamaica.py +6 -4
  98. holidays/countries/japan.py +5 -5
  99. holidays/countries/jersey.py +29 -26
  100. holidays/countries/jordan.py +9 -6
  101. holidays/countries/kazakhstan.py +66 -51
  102. holidays/countries/kenya.py +22 -18
  103. holidays/countries/kuwait.py +10 -7
  104. holidays/countries/kyrgyzstan.py +7 -6
  105. holidays/countries/laos.py +21 -29
  106. holidays/countries/latvia.py +7 -5
  107. holidays/countries/lesotho.py +6 -5
  108. holidays/countries/liechtenstein.py +5 -5
  109. holidays/countries/lithuania.py +4 -5
  110. holidays/countries/luxembourg.py +5 -3
  111. holidays/countries/macau.py +32 -26
  112. holidays/countries/madagascar.py +5 -4
  113. holidays/countries/malawi.py +6 -4
  114. holidays/countries/malaysia.py +29 -19
  115. holidays/countries/maldives.py +10 -7
  116. holidays/countries/malta.py +10 -19
  117. holidays/countries/marshall_islands.py +6 -4
  118. holidays/countries/mauritania.py +9 -6
  119. holidays/countries/mexico.py +8 -7
  120. holidays/countries/moldova.py +6 -4
  121. holidays/countries/monaco.py +6 -4
  122. holidays/countries/montenegro.py +10 -7
  123. holidays/countries/morocco.py +9 -8
  124. holidays/countries/mozambique.py +3 -1
  125. holidays/countries/namibia.py +7 -5
  126. holidays/countries/netherlands.py +6 -6
  127. holidays/countries/new_zealand.py +3 -1
  128. holidays/countries/nicaragua.py +6 -5
  129. holidays/countries/nigeria.py +9 -5
  130. holidays/countries/north_macedonia.py +9 -5
  131. holidays/countries/northern_mariana_islands.py +6 -4
  132. holidays/countries/norway.py +15 -15
  133. holidays/countries/oman.py +185 -0
  134. holidays/countries/pakistan.py +48 -17
  135. holidays/countries/palau.py +13 -11
  136. holidays/countries/panama.py +9 -8
  137. holidays/countries/papua_new_guinea.py +25 -21
  138. holidays/countries/paraguay.py +10 -9
  139. holidays/countries/peru.py +4 -5
  140. holidays/countries/philippines.py +25 -21
  141. holidays/countries/poland.py +6 -5
  142. holidays/countries/portugal.py +13 -15
  143. holidays/countries/puerto_rico.py +6 -4
  144. holidays/countries/qatar.py +172 -0
  145. holidays/countries/romania.py +6 -4
  146. holidays/countries/russia.py +6 -4
  147. holidays/countries/saint_kitts_and_nevis.py +24 -22
  148. holidays/countries/saint_lucia.py +8 -7
  149. holidays/countries/samoa.py +7 -6
  150. holidays/countries/san_marino.py +4 -3
  151. holidays/countries/saudi_arabia.py +11 -15
  152. holidays/countries/serbia.py +3 -4
  153. holidays/countries/seychelles.py +22 -26
  154. holidays/countries/sierra_leone.py +149 -0
  155. holidays/countries/singapore.py +29 -39
  156. holidays/countries/slovakia.py +6 -5
  157. holidays/countries/slovenia.py +7 -6
  158. holidays/countries/south_africa.py +8 -6
  159. holidays/countries/south_korea.py +39 -47
  160. holidays/countries/spain.py +25 -24
  161. holidays/countries/sri_lanka.py +46 -42
  162. holidays/countries/suriname.py +227 -0
  163. holidays/countries/sweden.py +20 -19
  164. holidays/countries/switzerland.py +6 -5
  165. holidays/countries/taiwan.py +52 -49
  166. holidays/countries/tanzania.py +28 -27
  167. holidays/countries/thailand.py +134 -142
  168. holidays/countries/timor_leste.py +20 -18
  169. holidays/countries/tonga.py +46 -42
  170. holidays/countries/tunisia.py +5 -3
  171. holidays/countries/turkey.py +11 -9
  172. holidays/countries/tuvalu.py +12 -11
  173. holidays/countries/ukraine.py +54 -54
  174. holidays/countries/united_arab_emirates.py +37 -30
  175. holidays/countries/united_kingdom.py +7 -6
  176. holidays/countries/united_states.py +50 -55
  177. holidays/countries/united_states_minor_outlying_islands.py +6 -4
  178. holidays/countries/united_states_virgin_islands.py +6 -4
  179. holidays/countries/uruguay.py +10 -9
  180. holidays/countries/uzbekistan.py +10 -7
  181. holidays/countries/vanuatu.py +7 -5
  182. holidays/countries/vatican_city.py +16 -15
  183. holidays/countries/venezuela.py +11 -14
  184. holidays/countries/vietnam.py +15 -11
  185. holidays/countries/zambia.py +8 -6
  186. holidays/countries/zimbabwe.py +6 -4
  187. holidays/deprecations/v1_incompatibility.py +1 -1
  188. holidays/financial/__init__.py +1 -1
  189. holidays/financial/brasil_bolsa_balcao.py +14 -13
  190. holidays/financial/european_central_bank.py +7 -6
  191. holidays/financial/ice_futures_europe.py +7 -6
  192. holidays/financial/ny_stock_exchange.py +13 -10
  193. holidays/groups/__init__.py +1 -1
  194. holidays/groups/balinese_saka.py +1 -1
  195. holidays/groups/buddhist.py +1 -1
  196. holidays/groups/chinese.py +1 -1
  197. holidays/groups/christian.py +1 -1
  198. holidays/groups/custom.py +1 -1
  199. holidays/groups/eastern.py +1 -1
  200. holidays/groups/hebrew.py +1 -1
  201. holidays/groups/hindu.py +1 -1
  202. holidays/groups/international.py +1 -1
  203. holidays/groups/islamic.py +22 -1
  204. holidays/groups/persian.py +1 -1
  205. holidays/groups/sinhala.py +1 -1
  206. holidays/groups/thai.py +1 -7
  207. holidays/helpers.py +1 -1
  208. holidays/holiday_base.py +393 -245
  209. holidays/ical.py +228 -0
  210. holidays/locale/ar/LC_MESSAGES/OM.mo +0 -0
  211. holidays/locale/ar_QA/LC_MESSAGES/QA.mo +0 -0
  212. holidays/locale/en_CI/LC_MESSAGES/CI.mo +0 -0
  213. holidays/locale/en_PK/LC_MESSAGES/PK.mo +0 -0
  214. holidays/locale/en_SL/LC_MESSAGES/SL.mo +0 -0
  215. holidays/locale/en_TL/LC_MESSAGES/TL.mo +0 -0
  216. holidays/locale/en_US/LC_MESSAGES/AR.mo +0 -0
  217. holidays/locale/en_US/LC_MESSAGES/CI.mo +0 -0
  218. holidays/locale/en_US/LC_MESSAGES/GN.mo +0 -0
  219. holidays/locale/en_US/LC_MESSAGES/OM.mo +0 -0
  220. holidays/locale/en_US/LC_MESSAGES/PK.mo +0 -0
  221. holidays/locale/en_US/LC_MESSAGES/QA.mo +0 -0
  222. holidays/locale/en_US/LC_MESSAGES/SL.mo +0 -0
  223. holidays/locale/en_US/LC_MESSAGES/SR.mo +0 -0
  224. holidays/locale/en_US/LC_MESSAGES/TF.mo +0 -0
  225. holidays/locale/en_US/LC_MESSAGES/TL.mo +0 -0
  226. holidays/locale/es/LC_MESSAGES/AR.mo +0 -0
  227. holidays/locale/fr/LC_MESSAGES/CI.mo +0 -0
  228. holidays/locale/fr/LC_MESSAGES/GN.mo +0 -0
  229. holidays/locale/fr/LC_MESSAGES/TF.mo +0 -0
  230. holidays/locale/hi/LC_MESSAGES/IN.mo +0 -0
  231. holidays/locale/nl/LC_MESSAGES/SR.mo +0 -0
  232. holidays/locale/pt_TL/LC_MESSAGES/TL.mo +0 -0
  233. holidays/locale/tet/LC_MESSAGES/TL.mo +0 -0
  234. holidays/locale/th/LC_MESSAGES/TL.mo +0 -0
  235. holidays/locale/uk/LC_MESSAGES/AR.mo +0 -0
  236. holidays/locale/uk/LC_MESSAGES/TF.mo +0 -0
  237. holidays/locale/ur_PK/LC_MESSAGES/PK.mo +0 -0
  238. holidays/mixins.py +2 -2
  239. holidays/observed_holiday_base.py +10 -3
  240. holidays/registry.py +10 -1
  241. holidays/utils.py +203 -151
  242. holidays/version.py +2 -2
  243. holidays-0.71.dist-info/METADATA +1432 -0
  244. {holidays-0.69.dist-info → holidays-0.71.dist-info}/RECORD +248 -217
  245. {holidays-0.69.dist-info → holidays-0.71.dist-info}/WHEEL +1 -1
  246. holidays-0.69.dist-info/AUTHORS → holidays-0.71.dist-info/licenses/AUTHORS.md +9 -2
  247. {holidays-0.69.dist-info → holidays-0.71.dist-info/licenses}/LICENSE +1 -1
  248. holidays-0.69.dist-info/METADATA +0 -1085
  249. {holidays-0.69.dist-info → holidays-0.71.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,66 @@ 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.
272
+
273
+ expand:
274
+ Whether the entire year is calculated when one date from that year
275
+ is requested.
276
+
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.
281
+
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).
285
+
286
+ prov:
287
+ *deprecated* use `subdiv` instead.
288
+
289
+ state:
290
+ *deprecated* use `subdiv` instead.
270
291
 
271
- :param expand:
272
- Whether the entire year is calculated when one date from that year
273
- is requested.
292
+ language:
293
+ Specifies the language in which holiday names are returned.
274
294
 
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.
295
+ Accepts either:
279
296
 
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).
297
+ * A two-letter ISO 639-1 language code (e.g., 'en' for English, 'fr' for French),
298
+ or
299
+ * A language and entity combination using an underscore (e.g., 'en_US' for U.S.
300
+ English, 'pt_BR' for Brazilian Portuguese).
283
301
 
284
- :param prov:
285
- *deprecated* use subdiv instead.
302
+ !!! warning
303
+ The provided language or locale code must be supported by the holiday
304
+ entity. Unsupported values will result in names being shown in the entity's
305
+ original language.
286
306
 
287
- :param state:
288
- *deprecated* use subdiv instead.
307
+ If not explicitly set (`language=None`), the system attempts to infer the
308
+ language from the environment's locale settings. The following environment
309
+ variables are checked, in order of precedence: LANGUAGE, LC_ALL, LC_MESSAGES, LANG.
289
310
 
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.
311
+ If none of these are set or they are empty, holiday names will default to the
312
+ original language of the entity's holiday implementation.
295
313
 
296
- :param categories:
297
- Requested holiday categories.
314
+ !!! warning
315
+ This fallback mechanism may yield inconsistent results across environments
316
+ (e.g., between a terminal session and a Jupyter notebook).
298
317
 
299
- :return:
300
- A :class:`HolidayBase` object matching the **country**.
318
+ To ensure consistent behavior, it is recommended to set the language parameter
319
+ explicitly. If the specified language is not supported, holiday names will remain
320
+ in the original language of the entity's holiday implementation.
321
+
322
+ This behavior will be updated and formalized in v1.
323
+
324
+ categories:
325
+ Requested holiday categories.
326
+
327
+ Returns:
328
+ A `HolidayBase` object matching the **country** or **market**.
301
329
  """
302
330
  super().__init__()
303
331
 
@@ -376,14 +404,14 @@ class HolidayBase(dict[date, str]):
376
404
 
377
405
  def __add__(self, other: Union[int, "HolidayBase", "HolidaySum"]) -> "HolidayBase":
378
406
  """Add another dictionary of public holidays creating a
379
- :class:`HolidaySum` object.
407
+ [HolidaySum][holidays.holiday_base.HolidaySum] object.
380
408
 
381
- :param other:
382
- The dictionary of public holiday to be added.
409
+ Args:
410
+ other:
411
+ The dictionary of public holiday to be added.
383
412
 
384
- :return:
385
- A :class:`HolidaySum` object unless the other object cannot be
386
- added, then :class:`self`.
413
+ Returns:
414
+ A `HolidayBase` object unless the other object cannot be added, then `self`.
387
415
  """
388
416
  if isinstance(other, int) and other == 0:
389
417
  # Required to sum() list of holidays
@@ -399,14 +427,21 @@ class HolidayBase(dict[date, str]):
399
427
  return len(self) > 0
400
428
 
401
429
  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.
430
+ """Check if a given date is a holiday.
431
+
432
+ The method supports the following input types:
433
+
434
+ * `datetime.date`,
435
+ * `datetime.datetime`,
436
+ * a `str` of any format recognized by `dateutil.parser.parse()`,
437
+ * or a `float` or `int` representing a POSIX timestamp.
438
+
439
+ Args:
440
+ key:
441
+ The date to check.
442
+
443
+ Returns:
444
+ `True` if the date is a holiday, `False` otherwise.
410
445
  """
411
446
 
412
447
  if not isinstance(key, (date, datetime, float, int, str)):
@@ -574,15 +609,21 @@ class HolidayBase(dict[date, str]):
574
609
  return state
575
610
 
576
611
  def __keytransform__(self, key: DateLike) -> date:
577
- """Transforms the date from one of the following types:
612
+ """Convert various date-like formats to `datetime.date`.
613
+
614
+ The method supports the following input types:
615
+ * `datetime.date`,
616
+ * `datetime.datetime`,
617
+ * a `str` of any format recognized by `dateutil.parser.parse()`,
618
+ * or a `float` or `int` representing a POSIX timestamp
578
619
 
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
620
+ Args:
621
+ key:
622
+ The date-like object to convert.
584
623
 
585
- to :class:`datetime.date`, which is how it's stored by the class."""
624
+ Returns:
625
+ The corresponding `datetime.date` representation.
626
+ """
586
627
 
587
628
  dt: Optional[date] = None
588
629
  # Try to catch `date` and `str` type keys first.
@@ -729,7 +770,11 @@ class HolidayBase(dict[date, str]):
729
770
 
730
771
  @classmethod
731
772
  def get_subdivision_aliases(cls) -> dict[str, list]:
732
- """Get subdivision aliases."""
773
+ """Get subdivision aliases.
774
+
775
+ Returns:
776
+ A dictionary mapping subdivision aliases to their official ISO 3166-2 codes.
777
+ """
733
778
  subdivision_aliases: dict[str, list[str]] = {s: [] for s in cls.subdivisions}
734
779
  for alias, subdivision in cls.subdivisions_aliases.items():
735
780
  subdivision_aliases[subdivision].append(alias)
@@ -856,13 +901,13 @@ class HolidayBase(dict[date, str]):
856
901
  directly from outside.
857
902
  To add holidays to an object, use the update() method.
858
903
 
859
- :param year:
860
- The year to populate with holidays.
904
+ Args:
905
+ year: The year to populate with holidays.
861
906
 
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))
907
+ >>> from holidays import country_holidays
908
+ >>> us_holidays = country_holidays('US', years=2020)
909
+ # to add new holidays to the object:
910
+ >>> us_holidays.update(country_holidays('US', years=2021))
866
911
  """
867
912
 
868
913
  if year < self.start_year or year > self.end_year:
@@ -903,7 +948,16 @@ class HolidayBase(dict[date, str]):
903
948
  )
904
949
 
905
950
  def append(self, *args: Union[dict[DateLike, str], list[DateLike], DateLike]) -> None:
906
- """Alias for :meth:`update` to mimic list type."""
951
+ """Alias for [update()][holidays.holiday_base.HolidayBase.update] to mimic list type.
952
+
953
+ Args:
954
+ args:
955
+ Holiday data to add. Can be:
956
+
957
+ * A dictionary mapping dates to holiday names.
958
+ * A list of dates (without names).
959
+ * A single date.
960
+ """
907
961
  return self.update(*args)
908
962
 
909
963
  def copy(self):
@@ -911,64 +965,73 @@ class HolidayBase(dict[date, str]):
911
965
  return copy.copy(self)
912
966
 
913
967
  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.
968
+ """Retrieve the holiday name(s) for a given date.
969
+
970
+ If the date is a holiday, returns the holiday name as a string.
971
+ If multiple holidays fall on the same date, their names are joined by a semicolon (`;`).
972
+ If the date is not a holiday, returns the provided `default` value (defaults to `None`).
973
+
974
+ Args:
975
+ key:
976
+ The date expressed in one of the following types:
977
+
978
+ * `datetime.date`,
979
+ * `datetime.datetime`,
980
+ * a `str` of any format recognized by `dateutil.parser.parse()`,
981
+ * or a `float` or `int` representing a POSIX timestamp.
982
+
983
+ default:
984
+ The default value to return if no value is found.
985
+
986
+ Returns:
987
+ The holiday name(s) as a string if the date is a holiday,
988
+ or the `default` value otherwise.
931
989
  """
932
990
  return dict.get(self, self.__keytransform__(key), default)
933
991
 
934
992
  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.
993
+ """Retrieve all holiday names for a given date.
994
+
995
+ Args:
996
+ key:
997
+ The date expressed in one of the following types:
998
+
999
+ * `datetime.date`,
1000
+ * `datetime.datetime`,
1001
+ * a `str` of any format recognized by `dateutil.parser.parse()`,
1002
+ * or a `float` or `int` representing a POSIX timestamp.
1003
+
1004
+ Returns:
1005
+ A list of holiday names if the date is a holiday, otherwise an empty list.
947
1006
  """
948
1007
  return [name for name in self.get(key, "").split(HOLIDAY_NAME_DELIMITER) if name]
949
1008
 
950
1009
  def get_named(
951
- self, holiday_name: str, lookup="icontains", split_multiple_names=True
1010
+ self, holiday_name: str, lookup: str = "icontains", split_multiple_names: bool = True
952
1011
  ) -> 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:
1012
+ """Find all holiday dates matching a given name.
1013
+
1014
+ The search by default is case-insensitive and includes partial matches.
1015
+
1016
+ Args:
1017
+ holiday_name:
1018
+ The holiday's name to try to match.
1019
+
1020
+ lookup:
1021
+ The holiday name lookup type:
1022
+
1023
+ * contains - case sensitive contains match;
1024
+ * exact - case sensitive exact match;
1025
+ * startswith - case sensitive starts with match;
1026
+ * icontains - case insensitive contains match;
1027
+ * iexact - case insensitive exact match;
1028
+ * istartswith - case insensitive starts with match;
1029
+
1030
+ split_multiple_names:
1031
+ Either use the exact name for each date or split it by holiday
1032
+ name delimiter.
1033
+
1034
+ Returns:
972
1035
  A list of all holiday dates matching the provided holiday name.
973
1036
  """
974
1037
  holiday_name_dates = (
@@ -1003,13 +1066,26 @@ class HolidayBase(dict[date, str]):
1003
1066
 
1004
1067
  def get_closest_holiday(
1005
1068
  self,
1006
- target_date: DateLike = None,
1069
+ target_date: Optional[DateLike] = None,
1007
1070
  direction: Literal["forward", "backward"] = "forward",
1008
1071
  ) -> 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."""
1072
+ """Find the closest holiday relative to a given date.
1012
1073
 
1074
+ If `direction` is "forward", returns the next holiday after `target_date`.
1075
+ If `direction` is "backward", returns the previous holiday before `target_date`.
1076
+ If `target_date` is not provided, the current date is used.
1077
+
1078
+ Args:
1079
+ target_date:
1080
+ The reference date. If None, defaults to today.
1081
+
1082
+ direction:
1083
+ Search direction, either "forward" (next holiday) or
1084
+ "backward" (previous holiday).
1085
+
1086
+ Returns:
1087
+ A tuple containing the holiday date and its name, or None if no holiday is found.
1088
+ """
1013
1089
  if direction not in {"backward", "forward"}:
1014
1090
  raise AttributeError(f"Unknown direction: {direction}")
1015
1091
 
@@ -1032,8 +1108,20 @@ class HolidayBase(dict[date, str]):
1032
1108
  return None
1033
1109
 
1034
1110
  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).
1111
+ """Find the n-th working day from a given date.
1112
+
1113
+ Moves forward if n is positive, or backward if n is negative.
1114
+
1115
+ Args:
1116
+ key:
1117
+ The starting date.
1118
+
1119
+ n:
1120
+ The number of working days to move. Positive values move forward,
1121
+ negative values move backward.
1122
+
1123
+ Returns:
1124
+ The calculated working day after shifting by n working days.
1037
1125
  """
1038
1126
  direction = +1 if n > 0 else -1
1039
1127
  dt = self.__keytransform__(key)
@@ -1044,16 +1132,20 @@ class HolidayBase(dict[date, str]):
1044
1132
  return dt
1045
1133
 
1046
1134
  def get_working_days_count(self, start: DateLike, end: DateLike) -> int:
1047
- """Return the number of working days between two dates.
1135
+ """Calculate the number of working days between two dates.
1048
1136
 
1049
1137
  The date range works in a closed interval fashion [start, end] so both
1050
1138
  endpoints are included.
1051
1139
 
1052
- :param start:
1053
- The range start date.
1140
+ Args:
1141
+ start:
1142
+ The range start date.
1054
1143
 
1055
- :param end:
1056
- The range end date.
1144
+ end:
1145
+ The range end date.
1146
+
1147
+ Returns:
1148
+ The total count of working days between the given dates.
1057
1149
  """
1058
1150
  dt1 = self.__keytransform__(start)
1059
1151
  dt2 = self.__keytransform__(end)
@@ -1063,55 +1155,83 @@ class HolidayBase(dict[date, str]):
1063
1155
  return sum(self.is_working_day(_timedelta(dt1, n)) for n in range(days))
1064
1156
 
1065
1157
  def is_working_day(self, key: DateLike) -> bool:
1066
- """Return True if date is a working day (not a holiday or a weekend)."""
1158
+ """Check if the given date is considered a working day.
1159
+
1160
+ Args:
1161
+ key:
1162
+ The date to check.
1163
+
1164
+ Returns:
1165
+ True if the date is a working day, False if it is a holiday or weekend.
1166
+ """
1067
1167
  dt = self.__keytransform__(key)
1068
1168
  return dt in self.weekend_workdays if self._is_weekend(dt) else dt not in self
1069
1169
 
1070
1170
  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.
1171
+ """Remove a holiday for a given date and return its name.
1073
1172
 
1074
- :param key:
1075
- The date expressed in one of the following types:
1173
+ If the specified date is a holiday, it will be removed, and its name will
1174
+ be returned. If the date is not a holiday, the provided `default` value
1175
+ will be returned instead.
1076
1176
 
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.
1177
+ Args:
1178
+ key:
1179
+ The date expressed in one of the following types:
1083
1180
 
1084
- :param default:
1085
- The default value to return if no match is found.
1181
+ * `datetime.date`,
1182
+ * `datetime.datetime`,
1183
+ * a `str` of any format recognized by `dateutil.parser.parse()`,
1184
+ * or a `float` or `int` representing a POSIX timestamp.
1086
1185
 
1087
- :return:
1088
- The date removed.
1186
+ default:
1187
+ The default value to return if no match is found.
1089
1188
 
1090
- :raise:
1091
- KeyError if date is not a holiday and default is not given.
1189
+ Returns:
1190
+ The name of the removed holiday if the date was a holiday, otherwise
1191
+ the provided `default` value.
1192
+
1193
+ Raises:
1194
+ KeyError: if date is not a holiday and default is not given.
1092
1195
  """
1093
1196
  if default is None:
1094
1197
  return dict.pop(self, self.__keytransform__(key))
1095
1198
 
1096
1199
  return dict.pop(self, self.__keytransform__(key), default)
1097
1200
 
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.
1201
+ def pop_named(self, holiday_name: str, lookup: str = "icontains") -> list[date]:
1202
+ """Remove all holidays matching the given name.
1203
+
1204
+ This method removes all dates associated with a holiday name, so they are
1205
+ no longer considered holidays. The search by default is case-insensitive and
1206
+ includes partial matches.
1207
+
1208
+ Args:
1209
+ holiday_name:
1210
+ The holiday's name to try to match.
1211
+
1212
+ lookup:
1213
+ The holiday name lookup type:
1102
1214
 
1103
- :param name:
1104
- The holiday's name to try to match.
1215
+ * contains - case sensitive contains match;
1216
+ * exact - case sensitive exact match;
1217
+ * startswith - case sensitive starts with match;
1218
+ * icontains - case insensitive contains match;
1219
+ * iexact - case insensitive exact match;
1220
+ * istartswith - case insensitive starts with match;
1105
1221
 
1106
- :return:
1222
+ Returns:
1107
1223
  A list of dates removed.
1108
1224
 
1109
- :raise:
1110
- KeyError if date is not a holiday and default is not given.
1225
+ Raises:
1226
+ KeyError: if date is not a holiday.
1111
1227
  """
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)
1228
+ use_exact_name = HOLIDAY_NAME_DELIMITER in holiday_name
1229
+ if not (
1230
+ dts := self.get_named(
1231
+ holiday_name, lookup=lookup, split_multiple_names=not use_exact_name
1232
+ )
1233
+ ):
1234
+ raise KeyError(holiday_name)
1115
1235
 
1116
1236
  popped = []
1117
1237
  for dt in dts:
@@ -1120,38 +1240,55 @@ class HolidayBase(dict[date, str]):
1120
1240
  popped.append(dt)
1121
1241
 
1122
1242
  # Keep the rest of holidays falling on the same date.
1123
- if not use_exact_name:
1124
- name_lower = name.lower()
1243
+ if use_exact_name:
1244
+ continue
1245
+ if lookup == "icontains":
1246
+ holiday_name_lower = holiday_name.lower()
1125
1247
  holiday_names = [
1126
- holiday_name
1127
- for holiday_name in holiday_names
1128
- if name_lower not in holiday_name.lower()
1248
+ name for name in holiday_names if holiday_name_lower not in name.lower()
1129
1249
  ]
1130
-
1131
- if holiday_names:
1132
- self[dt] = HOLIDAY_NAME_DELIMITER.join(holiday_names)
1250
+ elif lookup == "iexact":
1251
+ holiday_name_lower = holiday_name.lower()
1252
+ holiday_names = [
1253
+ name for name in holiday_names if holiday_name_lower != name.lower()
1254
+ ]
1255
+ elif lookup == "istartswith":
1256
+ holiday_name_lower = holiday_name.lower()
1257
+ holiday_names = [
1258
+ name
1259
+ for name in holiday_names
1260
+ if holiday_name_lower != name[: len(holiday_name)].lower()
1261
+ ]
1262
+ elif lookup == "contains":
1263
+ holiday_names = [name for name in holiday_names if holiday_name not in name]
1264
+ elif lookup == "exact":
1265
+ holiday_names = [name for name in holiday_names if holiday_name != name]
1266
+ else: # startswith
1267
+ holiday_names = [
1268
+ name for name in holiday_names if holiday_name != name[: len(holiday_name)]
1269
+ ]
1270
+ if holiday_names:
1271
+ self[dt] = HOLIDAY_NAME_DELIMITER.join(holiday_names)
1133
1272
 
1134
1273
  return popped
1135
1274
 
1136
1275
  def update( # type: ignore[override]
1137
1276
  self, *args: Union[dict[DateLike, str], list[DateLike], DateLike]
1138
1277
  ) -> None:
1139
- # TODO: fix arguments; should not be *args (cannot properly Type hint)
1140
1278
  """Update the object, overwriting existing dates.
1141
1279
 
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".
1280
+ Args:
1281
+ args:
1282
+ Either another dictionary object where keys are dates and values
1283
+ are holiday names, or a single date (or a list of dates) for which
1284
+ the value will be set to "Holiday".
1146
1285
 
1147
- Dates can be expressed in one or more of the following types:
1286
+ Dates can be expressed in one or more of the following types:
1148
1287
 
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.
1288
+ * `datetime.date`,
1289
+ * `datetime.datetime`,
1290
+ * a `str` of any format recognized by `dateutil.parser.parse()`,
1291
+ * or a `float` or `int` representing a POSIX timestamp.
1155
1292
  """
1156
1293
  for arg in args:
1157
1294
  if isinstance(arg, dict):
@@ -1166,11 +1303,11 @@ class HolidayBase(dict[date, str]):
1166
1303
 
1167
1304
  class HolidaySum(HolidayBase):
1168
1305
  """
1169
- Returns a :class:`dict`-like object resulting from the addition of two or
1306
+ Returns a `dict`-like object resulting from the addition of two or
1170
1307
  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,
1308
+ are available as a `list` in the attribute `holidays,` and
1309
+ `country` and `subdiv` attributes are added
1310
+ together and could become `list` s. Holiday names, when different,
1174
1311
  are merged. All years are calculated (expanded) for all operands.
1175
1312
  """
1176
1313
 
@@ -1189,30 +1326,31 @@ class HolidaySum(HolidayBase):
1189
1326
  self, h1: Union[HolidayBase, "HolidaySum"], h2: Union[HolidayBase, "HolidaySum"]
1190
1327
  ) -> None:
1191
1328
  """
1192
- :param h1:
1193
- The first HolidayBase object to add.
1329
+ Args:
1330
+ h1:
1331
+ The first HolidayBase object to add.
1194
1332
 
1195
- :param h2:
1196
- The other HolidayBase object to add.
1333
+ h2:
1334
+ The other HolidayBase object to add.
1197
1335
 
1198
1336
  Example:
1199
1337
 
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')]
1338
+ >>> from holidays import country_holidays
1339
+ >>> nafta_holidays = country_holidays('US', years=2020) + \
1340
+ country_holidays('CA') + country_holidays('MX')
1341
+ >>> dates = sorted(nafta_holidays.items(), key=lambda x: x[0])
1342
+ >>> from pprint import pprint
1343
+ >>> pprint(dates[:10], width=72)
1344
+ [(datetime.date(2020, 1, 1), "Año Nuevo; New Year's Day"),
1345
+ (datetime.date(2020, 1, 20), 'Martin Luther King Jr. Day'),
1346
+ (datetime.date(2020, 2, 3), 'Día de la Constitución'),
1347
+ (datetime.date(2020, 2, 17), "Washington's Birthday"),
1348
+ (datetime.date(2020, 3, 16), 'Natalicio de Benito Juárez'),
1349
+ (datetime.date(2020, 4, 10), 'Good Friday'),
1350
+ (datetime.date(2020, 5, 1), 'Día del Trabajo'),
1351
+ (datetime.date(2020, 5, 25), 'Memorial Day'),
1352
+ (datetime.date(2020, 7, 1), 'Canada Day'),
1353
+ (datetime.date(2020, 7, 3), 'Independence Day (observed)')]
1216
1354
  """
1217
1355
  # Store originals in the holidays attribute.
1218
1356
  self.holidays = []
@@ -1260,8 +1398,18 @@ country_holidays('CA') + country_holidays('MX')
1260
1398
  else:
1261
1399
  setattr(self, attr, value)
1262
1400
 
1401
+ # Retain language if they match and are strings.
1402
+ # If language wasn't assigned, default_language acts as fallback.
1403
+ h1_language = h1.language or h1.default_language
1404
+ h2_language = h2.language or h2.default_language
1405
+ if isinstance(h1_language, str) and h1_language == h2_language:
1406
+ kwargs["language"] = h1_language
1407
+
1263
1408
  HolidayBase.__init__(self, **kwargs)
1264
1409
 
1410
+ # supported_languages is used for iCalExporter language check as well.
1411
+ self.supported_languages = (h1_language,) if h1_language else ()
1412
+
1265
1413
  def _populate(self, year):
1266
1414
  for operand in self.holidays:
1267
1415
  operand._populate(year)