holidays 0.80__py3-none-any.whl → 0.82__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 (142) hide show
  1. holidays/calendars/__init__.py +1 -0
  2. holidays/calendars/burmese.py +319 -0
  3. holidays/calendars/chinese.py +39 -1
  4. holidays/calendars/hebrew.py +2 -2
  5. holidays/calendars/thai.py +49 -2
  6. holidays/countries/__init__.py +16 -0
  7. holidays/countries/afghanistan.py +7 -5
  8. holidays/countries/algeria.py +89 -24
  9. holidays/countries/antarctica.py +58 -0
  10. holidays/countries/bouvet_island.py +31 -0
  11. holidays/countries/brazil.py +1 -1
  12. holidays/countries/british_indian_ocean_territory.py +31 -0
  13. holidays/countries/bulgaria.py +6 -1
  14. holidays/countries/chile.py +9 -8
  15. holidays/countries/china.py +4 -0
  16. holidays/countries/cuba.py +3 -4
  17. holidays/countries/djibouti.py +1 -1
  18. holidays/countries/heard_island_and_mcdonald_islands.py +31 -0
  19. holidays/countries/hongkong.py +5 -1
  20. holidays/countries/hungary.py +4 -5
  21. holidays/countries/india.py +6 -0
  22. holidays/countries/japan.py +22 -18
  23. holidays/countries/jordan.py +6 -3
  24. holidays/countries/kuwait.py +6 -3
  25. holidays/countries/macau.py +9 -0
  26. holidays/countries/malaysia.py +14 -3
  27. holidays/countries/mongolia.py +2 -0
  28. holidays/countries/myanmar.py +195 -0
  29. holidays/countries/north_korea.py +161 -0
  30. holidays/countries/norway.py +23 -8
  31. holidays/countries/oman.py +6 -2
  32. holidays/countries/paraguay.py +70 -23
  33. holidays/countries/philippines.py +11 -2
  34. holidays/countries/portugal.py +5 -6
  35. holidays/countries/qatar.py +5 -2
  36. holidays/countries/rwanda.py +6 -1
  37. holidays/countries/saint_helena_ascension_and_tristan_da_cunha.py +197 -0
  38. holidays/countries/saudi_arabia.py +6 -5
  39. holidays/countries/serbia.py +5 -0
  40. holidays/countries/south_africa.py +96 -53
  41. holidays/countries/south_korea.py +10 -1
  42. holidays/countries/spain.py +26 -4
  43. holidays/countries/sudan.py +118 -0
  44. holidays/countries/switzerland.py +169 -3
  45. holidays/countries/taiwan.py +27 -3
  46. holidays/countries/tajikistan.py +1 -1
  47. holidays/countries/tanzania.py +6 -1
  48. holidays/countries/thailand.py +21 -0
  49. holidays/countries/tonga.py +6 -1
  50. holidays/countries/trinidad_and_tobago.py +6 -1
  51. holidays/countries/united_arab_emirates.py +9 -2
  52. holidays/countries/united_states.py +16 -0
  53. holidays/countries/uruguay.py +6 -1
  54. holidays/countries/vietnam.py +10 -1
  55. holidays/countries/yemen.py +6 -3
  56. holidays/groups/__init__.py +1 -0
  57. holidays/groups/balinese_saka.py +1 -1
  58. holidays/groups/buddhist.py +1 -1
  59. holidays/groups/burmese.py +273 -0
  60. holidays/groups/chinese.py +27 -14
  61. holidays/groups/custom.py +8 -2
  62. holidays/groups/eastern.py +25 -3
  63. holidays/groups/hebrew.py +16 -14
  64. holidays/groups/hindu.py +15 -13
  65. holidays/groups/islamic.py +52 -47
  66. holidays/groups/mongolian.py +1 -1
  67. holidays/groups/sinhala.py +4 -9
  68. holidays/groups/tibetan.py +3 -4
  69. holidays/holiday_base.py +5 -4
  70. holidays/ical.py +6 -4
  71. holidays/locale/ar/LC_MESSAGES/DZ.mo +0 -0
  72. holidays/locale/ar_SD/LC_MESSAGES/SD.mo +0 -0
  73. holidays/locale/ca/LC_MESSAGES/ES.mo +0 -0
  74. holidays/locale/en_GB/LC_MESSAGES/SH.mo +0 -0
  75. holidays/locale/en_HK/LC_MESSAGES/HK.mo +0 -0
  76. holidays/locale/en_IN/LC_MESSAGES/IN.mo +0 -0
  77. holidays/locale/en_MO/LC_MESSAGES/MO.mo +0 -0
  78. holidays/locale/en_PH/LC_MESSAGES/PH.mo +0 -0
  79. holidays/locale/en_US/LC_MESSAGES/BR.mo +0 -0
  80. holidays/locale/en_US/LC_MESSAGES/CN.mo +0 -0
  81. holidays/locale/en_US/LC_MESSAGES/DZ.mo +0 -0
  82. holidays/locale/en_US/LC_MESSAGES/ES.mo +0 -0
  83. holidays/locale/en_US/LC_MESSAGES/HK.mo +0 -0
  84. holidays/locale/en_US/LC_MESSAGES/IN.mo +0 -0
  85. holidays/locale/en_US/LC_MESSAGES/JP.mo +0 -0
  86. holidays/locale/en_US/LC_MESSAGES/KP.mo +0 -0
  87. holidays/locale/en_US/LC_MESSAGES/KR.mo +0 -0
  88. holidays/locale/en_US/LC_MESSAGES/MM.mo +0 -0
  89. holidays/locale/en_US/LC_MESSAGES/MN.mo +0 -0
  90. holidays/locale/en_US/LC_MESSAGES/MO.mo +0 -0
  91. holidays/locale/en_US/LC_MESSAGES/PH.mo +0 -0
  92. holidays/locale/en_US/LC_MESSAGES/PY.mo +0 -0
  93. holidays/locale/en_US/LC_MESSAGES/SD.mo +0 -0
  94. holidays/locale/en_US/LC_MESSAGES/SH.mo +0 -0
  95. holidays/locale/en_US/LC_MESSAGES/TW.mo +0 -0
  96. holidays/locale/en_US/LC_MESSAGES/US.mo +0 -0
  97. holidays/locale/en_US/LC_MESSAGES/VN.mo +0 -0
  98. holidays/locale/es/LC_MESSAGES/ES.mo +0 -0
  99. holidays/locale/es/LC_MESSAGES/PY.mo +0 -0
  100. holidays/locale/fil/LC_MESSAGES/PH.mo +0 -0
  101. holidays/locale/fr/LC_MESSAGES/DZ.mo +0 -0
  102. holidays/locale/hi/LC_MESSAGES/IN.mo +0 -0
  103. holidays/locale/ja/LC_MESSAGES/JP.mo +0 -0
  104. holidays/locale/ko/LC_MESSAGES/KR.mo +0 -0
  105. holidays/locale/ko_KP/LC_MESSAGES/KP.mo +0 -0
  106. holidays/locale/mn/LC_MESSAGES/MN.mo +0 -0
  107. holidays/locale/my/LC_MESSAGES/MM.mo +0 -0
  108. holidays/locale/pt_BR/LC_MESSAGES/BR.mo +0 -0
  109. holidays/locale/pt_MO/LC_MESSAGES/MO.mo +0 -0
  110. holidays/locale/th/LC_MESSAGES/CN.mo +0 -0
  111. holidays/locale/th/LC_MESSAGES/HK.mo +0 -0
  112. holidays/locale/th/LC_MESSAGES/JP.mo +0 -0
  113. holidays/locale/th/LC_MESSAGES/KR.mo +0 -0
  114. holidays/locale/th/LC_MESSAGES/MM.mo +0 -0
  115. holidays/locale/th/LC_MESSAGES/MO.mo +0 -0
  116. holidays/locale/th/LC_MESSAGES/PH.mo +0 -0
  117. holidays/locale/th/LC_MESSAGES/TW.mo +0 -0
  118. holidays/locale/th/LC_MESSAGES/US.mo +0 -0
  119. holidays/locale/th/LC_MESSAGES/VN.mo +0 -0
  120. holidays/locale/uk/LC_MESSAGES/BR.mo +0 -0
  121. holidays/locale/uk/LC_MESSAGES/ES.mo +0 -0
  122. holidays/locale/uk/LC_MESSAGES/PY.mo +0 -0
  123. holidays/locale/vi/LC_MESSAGES/VN.mo +0 -0
  124. holidays/locale/zh_CN/LC_MESSAGES/CN.mo +0 -0
  125. holidays/locale/zh_CN/LC_MESSAGES/HK.mo +0 -0
  126. holidays/locale/zh_CN/LC_MESSAGES/MO.mo +0 -0
  127. holidays/locale/zh_CN/LC_MESSAGES/TW.mo +0 -0
  128. holidays/locale/zh_HK/LC_MESSAGES/HK.mo +0 -0
  129. holidays/locale/zh_MO/LC_MESSAGES/MO.mo +0 -0
  130. holidays/locale/zh_TW/LC_MESSAGES/CN.mo +0 -0
  131. holidays/locale/zh_TW/LC_MESSAGES/TW.mo +0 -0
  132. holidays/no_holiday_base.py +21 -0
  133. holidays/observed_holiday_base.py +1 -1
  134. holidays/registry.py +12 -0
  135. holidays/utils.py +5 -5
  136. holidays/version.py +1 -1
  137. {holidays-0.80.dist-info → holidays-0.82.dist-info}/METADATA +61 -5
  138. {holidays-0.80.dist-info → holidays-0.82.dist-info}/RECORD +142 -121
  139. {holidays-0.80.dist-info → holidays-0.82.dist-info}/licenses/CONTRIBUTORS +2 -0
  140. {holidays-0.80.dist-info → holidays-0.82.dist-info}/WHEEL +0 -0
  141. {holidays-0.80.dist-info → holidays-0.82.dist-info}/licenses/LICENSE +0 -0
  142. {holidays-0.80.dist-info → holidays-0.82.dist-info}/top_level.txt +0 -0
@@ -14,6 +14,7 @@
14
14
 
15
15
  from holidays.calendars.balinese_saka import _BalineseSakaLunar
16
16
  from holidays.calendars.buddhist import _BuddhistLunisolar, _CustomBuddhistHolidays
17
+ from holidays.calendars.burmese import _BurmeseLunisolar
17
18
  from holidays.calendars.chinese import _ChineseLunisolar, _CustomChineseHolidays
18
19
  from holidays.calendars.custom import _CustomCalendar
19
20
  from holidays.calendars.gregorian import GREGORIAN_CALENDAR
@@ -0,0 +1,319 @@
1
+ # holidays
2
+ # --------
3
+ # A fast, efficient Python library for generating country, province and state
4
+ # specific sets of holidays on the fly. It aims to make determining whether a
5
+ # specific date is a holiday as fast and flexible as possible.
6
+ #
7
+ # Authors: Vacanza Team and individual contributors (see CONTRIBUTORS file)
8
+ # dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
9
+ # ryanss <ryanssdev@icloud.com> (c) 2014-2017
10
+ # Website: https://github.com/vacanza/holidays
11
+ # License: MIT (see LICENSE file)
12
+
13
+ from datetime import date
14
+ from functools import cache
15
+ from typing import Optional
16
+
17
+ from holidays.calendars.gregorian import _timedelta
18
+
19
+ MO = 1954168.050623 # Beginning of 0 ME for MMT.
20
+ SY = 1577917828.0 / 4320000.0 # Solar year (365.2587565 days).
21
+
22
+
23
+ class _BurmeseLunisolar:
24
+ """Burmese Lunisolar calendar.
25
+
26
+ References:
27
+ * [Algorithm, Program and Calculation of Myanmar Calendar](https://web.archive.org/web/20250510011425/http://cool-emerald.blogspot.com/2013/06/algorithm-program-and-calculation-of.html)
28
+ """
29
+
30
+ START_DATE = date(1939, 3, 20) # 1 Late Tagu 1301 Burmese Era.
31
+ START_YEAR = 1939 # 1301 Burmese Era.
32
+ END_YEAR = 2100 # 1463 Burmese Era.
33
+
34
+ LITTLE_WATAT_YEARS_GREGORIAN = {
35
+ 1939,
36
+ 1948,
37
+ 1955,
38
+ 1958,
39
+ 1966,
40
+ 1972,
41
+ 1974,
42
+ 1982,
43
+ 1988,
44
+ 1993,
45
+ 1999,
46
+ 2004,
47
+ 2012,
48
+ 2018,
49
+ 2020,
50
+ 2029,
51
+ 2034,
52
+ 2039,
53
+ 2045,
54
+ 2050,
55
+ 2056,
56
+ 2061,
57
+ 2069,
58
+ 2075,
59
+ 2077,
60
+ 2086,
61
+ 2091,
62
+ 2096,
63
+ }
64
+
65
+ BIG_WATAT_YEARS_GREGORIAN = {
66
+ 1942,
67
+ 1945,
68
+ 1950,
69
+ 1953,
70
+ 1961,
71
+ 1964,
72
+ 1969,
73
+ 1977,
74
+ 1980,
75
+ 1985,
76
+ 1991,
77
+ 1996,
78
+ 2001,
79
+ 2007,
80
+ 2010,
81
+ 2015,
82
+ 2023,
83
+ 2026,
84
+ 2031,
85
+ 2037,
86
+ 2042,
87
+ 2048,
88
+ 2053,
89
+ 2058,
90
+ 2064,
91
+ 2067,
92
+ 2072,
93
+ 2080,
94
+ 2083,
95
+ 2088,
96
+ 2094,
97
+ 2099,
98
+ }
99
+
100
+ @staticmethod
101
+ def jdn_to_gregorian(jdn: int) -> date:
102
+ """Convert Julian Day Number to Gregorian date.
103
+
104
+ Args:
105
+ jdn: Julian Day Number.
106
+
107
+ Returns:
108
+ Gregorian date.
109
+ """
110
+ j = jdn - 1721119
111
+ y, j = divmod(4 * j - 1, 146097)
112
+ d = j // 4
113
+ j, d = divmod(4 * d + 3, 1461)
114
+ d = (d + 4) // 4
115
+ m, d = divmod(5 * d - 3, 153)
116
+ d = (d + 5) // 5
117
+ y = 100 * y + j
118
+ if m < 10:
119
+ m += 3
120
+ else:
121
+ m -= 9
122
+ y += 1
123
+
124
+ return date(y, m, d)
125
+
126
+ @cache
127
+ def _get_start_date(self, year: int) -> Optional[date]:
128
+ if year < self.START_YEAR or year > self.END_YEAR:
129
+ return None
130
+
131
+ delta_days = 354 * (year - self.START_YEAR)
132
+ for iter_year in range(self.START_YEAR, year):
133
+ if iter_year in self.LITTLE_WATAT_YEARS_GREGORIAN:
134
+ delta_days += 30
135
+ elif iter_year in self.BIG_WATAT_YEARS_GREGORIAN:
136
+ delta_days += 31
137
+
138
+ return _timedelta(self.START_DATE, delta_days)
139
+
140
+ def thingyan_dates(self, year: int) -> tuple[Optional[date], Optional[date]]:
141
+ """Calculate key dates of Thingyan (Myanmar New Year festival) - Akya day
142
+ and Atat day.
143
+
144
+ Args:
145
+ year:
146
+ Gregorian year.
147
+
148
+ Returns:
149
+ Akya day date, Atat day date.
150
+
151
+ """
152
+ if year < self.START_YEAR or year > self.END_YEAR:
153
+ return None, None
154
+
155
+ ja = SY * (year - 638) + MO
156
+ jk = (ja - 2.169918982) if year >= 1950 else (ja - 2.1675)
157
+
158
+ return self.jdn_to_gregorian(round(jk)), self.jdn_to_gregorian(round(ja))
159
+
160
+ def kason_full_moon_date(self, year: int) -> Optional[date]:
161
+ """Calculate the Gregorian date of Full Moon Day of Kason.
162
+
163
+ 15th day of 2nd month (Kason).
164
+
165
+ To calculate, we use the following time delta:
166
+
167
+ * All years:
168
+ 29 [1] + 15 - 1 = 43.
169
+
170
+ Args:
171
+ year:
172
+ Gregorian year.
173
+
174
+ Returns:
175
+ Gregorian date of Full Moon Day of Kason.
176
+ `None` if the Gregorian year is out of supported range.
177
+ """
178
+ if not (start_date := self._get_start_date(year)):
179
+ return None
180
+
181
+ return _timedelta(start_date, +43)
182
+
183
+ def waso_full_moon_date(self, year: int) -> Optional[date]:
184
+ """Calculate the Gregorian date of Full Moon Day of Waso.
185
+
186
+ 15th day of 4th month (Waso).
187
+
188
+ To calculate, we use the following time delta:
189
+
190
+ * All years:
191
+ Year_length - 266 [4-12] + 15 - 1 = Year_length - 252.
192
+
193
+ Args:
194
+ year:
195
+ Gregorian year.
196
+
197
+ Returns:
198
+ Gregorian date of Full Moon Day of Waso.
199
+ `None` if the Gregorian year is out of supported range.
200
+ """
201
+ if not (next_year_start_date := self._get_start_date(year + 1)):
202
+ return None
203
+
204
+ return _timedelta(next_year_start_date, -252)
205
+
206
+ def thadingyut_full_moon_date(self, year: int) -> Optional[date]:
207
+ """Calculate the Gregorian date of Full Moon Day of Thadingyut.
208
+
209
+ 15th day of 7th month (Thadingyut).
210
+
211
+ To calculate, we use the following time delta:
212
+
213
+ * All years:
214
+ Year_length - 177 [7-12] + 15 - 1 = Year_length - 163.
215
+
216
+ Args:
217
+ year:
218
+ Gregorian year.
219
+
220
+ Returns:
221
+ Gregorian date of Full Moon Day of Thadingyut.
222
+ `None` if the Gregorian year is out of supported range.
223
+ """
224
+ if not (next_year_start_date := self._get_start_date(year + 1)):
225
+ return None
226
+
227
+ return _timedelta(next_year_start_date, -163)
228
+
229
+ def tazaungmon_waxing_moon_date(self, year: int) -> Optional[date]:
230
+ """Calculate the Gregorian date of 1st Waxing Day of Tazaungmon.
231
+
232
+ 1st day of 8th month (Tazaungmon).
233
+
234
+ To calculate, we use the following time delta:
235
+
236
+ * All years:
237
+ Year_length - 148 [8-12] + 1 - 1 = Year_length - 148.
238
+
239
+ Args:
240
+ year:
241
+ Gregorian year.
242
+
243
+ Returns:
244
+ Gregorian date of 1st Waxing Day of Tazaungmon.
245
+ `None` if the Gregorian year is out of supported range.
246
+ """
247
+ if not (next_year_start_date := self._get_start_date(year + 1)):
248
+ return None
249
+
250
+ return _timedelta(next_year_start_date, -148)
251
+
252
+ def tazaungmon_full_moon_date(self, year: int) -> Optional[date]:
253
+ """Calculate the Gregorian date of Full Moon Day of Tazaungmon.
254
+
255
+ 15th day of 8th month (Tazaungmon).
256
+
257
+ To calculate, we use the following time delta:
258
+
259
+ * All years:
260
+ Year_length - 148 [8-12] + 15 - 1 = Year_length - 134.
261
+
262
+ Args:
263
+ year:
264
+ Gregorian year.
265
+
266
+ Returns:
267
+ Gregorian date of Full Moon Day of Tazaungmon.
268
+ `None` if the Gregorian year is out of supported range.
269
+ """
270
+ if not (next_year_start_date := self._get_start_date(year + 1)):
271
+ return None
272
+
273
+ return _timedelta(next_year_start_date, -134)
274
+
275
+ def pyatho_waxing_moon_date(self, year: int) -> Optional[date]:
276
+ """Calculate the Gregorian date of 1st Waxing Day of Pyatho.
277
+
278
+ 1st day of 10th month (Pyatho).
279
+
280
+ To calculate, we use the following time delta:
281
+
282
+ * All years:
283
+ Year_length - 89 [10-12] + 1 - 1 = Year_length - 89.
284
+
285
+ Args:
286
+ year:
287
+ Gregorian year.
288
+
289
+ Returns:
290
+ Gregorian date of 1st Waxing Day of Pyatho.
291
+ `None` if the Gregorian year is out of supported range.
292
+ """
293
+ if not (next_year_start_date := self._get_start_date(year + 1)):
294
+ return None
295
+
296
+ return _timedelta(next_year_start_date, -89)
297
+
298
+ def tabaung_full_moon_date(self, year: int) -> Optional[date]:
299
+ """Calculate the Gregorian date of Full Moon Day of Tabaung.
300
+
301
+ 15th day of 12th month (Tabaung).
302
+
303
+ To calculate, we use the following time delta:
304
+
305
+ * All years:
306
+ Year_length - 30 [12] + 15 - 1 = Year_length - 16.
307
+
308
+ Args:
309
+ year:
310
+ Gregorian year.
311
+
312
+ Returns:
313
+ Gregorian date of Full Moon Day of Tabaung.
314
+ `None` if the Gregorian year is out of supported range.
315
+ """
316
+ if not (next_year_start_date := self._get_start_date(year + 1)):
317
+ return None
318
+
319
+ return _timedelta(next_year_start_date, -16)
@@ -14,7 +14,7 @@ from datetime import date
14
14
  from typing import Optional
15
15
 
16
16
  from holidays.calendars.custom import _CustomCalendar
17
- from holidays.calendars.gregorian import JAN, FEB, MAR, APR, MAY, JUN, SEP, OCT, NOV
17
+ from holidays.calendars.gregorian import JAN, FEB, MAR, APR, MAY, JUN, SEP, OCT, NOV, DEC
18
18
 
19
19
  CHINESE_CALENDAR = "CHINESE_CALENDAR"
20
20
  KOREAN_CALENDAR = "KOREAN_CALENDAR"
@@ -1307,6 +1307,24 @@ class _ChineseLunisolar:
1307
1307
  2053: (FEB, 18),
1308
1308
  }
1309
1309
 
1310
+ WINTER_SOLSTICE_THRESHOLDS: dict[str, dict[str, dict[int, int]]] = {
1311
+ # UTC+7.
1312
+ VIETNAMESE_CALENDAR: {
1313
+ "dec_21": {0: 1980, 1: 2017, 2: 2050, 3: 2083},
1314
+ "dec_23": {3: 1943},
1315
+ },
1316
+ # UTC+8.
1317
+ CHINESE_CALENDAR: {
1318
+ "dec_21": {0: 1988, 1: 2021, 2: 2058, 3: 2091},
1319
+ "dec_23": {3: 1947},
1320
+ },
1321
+ # UTC+9.
1322
+ KOREAN_CALENDAR: {
1323
+ "dec_21": {0: 1992, 1: 2029, 2: 2062, 3: 2099},
1324
+ "dec_23": {3: 1955},
1325
+ },
1326
+ }
1327
+
1310
1328
  def __init__(self, calendar: str = CHINESE_CALENDAR) -> None:
1311
1329
  self.__verify_calendar(calendar)
1312
1330
  self.__calendar = calendar
@@ -1359,6 +1377,26 @@ class _ChineseLunisolar:
1359
1377
  def mid_autumn_date(self, year: int, calendar=None) -> tuple[Optional[date], bool]:
1360
1378
  return self._get_holiday(MID_AUTUMN, year, calendar)
1361
1379
 
1380
+ def winter_solstice_date(self, year: int, calendar=None) -> tuple[Optional[date], bool]:
1381
+ """Return Winter Solstice (22nd solar term in Chinese Lunisolar calendar) date.
1382
+
1383
+ !!! note "Note"
1384
+ This approximation is reliable for 1941-2099 years.
1385
+ """
1386
+ calendar = calendar or self.__calendar
1387
+ self.__verify_calendar(calendar)
1388
+
1389
+ thresholds = self.WINTER_SOLSTICE_THRESHOLDS[calendar]
1390
+ year_mod = year % 4
1391
+ if year >= thresholds["dec_21"][year_mod]:
1392
+ day = 21
1393
+ elif year <= thresholds["dec_23"].get(year_mod, 0):
1394
+ day = 23
1395
+ else:
1396
+ day = 22
1397
+
1398
+ return date(year, DEC, day), not (1941 <= year <= 2099)
1399
+
1362
1400
 
1363
1401
  class _CustomChineseHolidays(_CustomCalendar, _ChineseLunisolar):
1364
1402
  pass
@@ -1602,8 +1602,8 @@ class _HebrewLunisolar:
1602
1602
  dt = getattr(self, f"{holiday}_DATES", {}).get(year, ())
1603
1603
  return date(year, *dt) if dt else None
1604
1604
 
1605
- def hanukkah_date(self, year: int) -> set[Optional[date]]:
1606
- return {self._get_holiday(HANUKKAH, y) for y in (year - 1, year)}
1605
+ def hanukkah_date(self, year: int) -> set[date]:
1606
+ return {dt for y in (year - 1, year) if (dt := self._get_holiday(HANUKKAH, y)) is not None}
1607
1607
 
1608
1608
  def israel_independence_date(self, year: int) -> Optional[date]:
1609
1609
  return self._get_holiday(INDEPENDENCE_DAY, year)
@@ -11,7 +11,7 @@
11
11
  # License: MIT (see LICENSE file)
12
12
 
13
13
  from datetime import date
14
- from functools import lru_cache
14
+ from functools import cache
15
15
  from typing import Optional
16
16
 
17
17
  from holidays.calendars.gregorian import _timedelta
@@ -100,6 +100,8 @@ class _ThaiLunisolar:
100
100
  References:
101
101
  * <https://web.archive.org/web/20241016080156/https://www.ninenik.com/แนวทางฟังก์ชั่น_php_อย่างง่ายกับการหาวันข้างขึ้นข้างแรม-1021.html>
102
102
  * <https://web.archive.org/web/20250119171416/https://www.myhora.com/ปฏิทิน/ปฏิทิน-พ.ศ.2560.aspx>
103
+ * <https://web.archive.org/web/20250302100842/https://calendar.kunthet.com/#/>
104
+ * [2025 Khmer Lunar Calendar](https://web.archive.org/web/20250921045847/https://static1.squarespace.com/static/67722f65f2908e531b5f326d/t/678a87776503cc3f8bc538ac/1737131904673/2025Calendar-compressed.pdf)
103
105
 
104
106
  Example:
105
107
 
@@ -293,7 +295,7 @@ class _ThaiLunisolar:
293
295
  f"Unknown calendar name: {calendar}. Use `KHMER_CALENDAR` or `THAI_CALENDAR`."
294
296
  )
295
297
 
296
- @lru_cache
298
+ @cache
297
299
  def _get_start_date(self, year: int) -> Optional[date]:
298
300
  """Calculate the start date of that particular Thai Lunar Calendar Year.
299
301
 
@@ -320,6 +322,51 @@ class _ThaiLunisolar:
320
322
 
321
323
  return _timedelta(_ThaiLunisolar.START_DATE, delta_days)
322
324
 
325
+ @cache
326
+ def buddhist_sabbath_dates(self, year: int) -> set[date]:
327
+ """Return all Buddhist Sabbath (Uposatha) days in a given Gregorian year.
328
+
329
+ This function works independently of the calendar system in use,
330
+ whether `THAI_CALENDAR` or `KHMER_CALENDAR`.
331
+
332
+ Args:
333
+ year:
334
+ The Gregorian year.
335
+
336
+ Returns:
337
+ A set of `date` objects representing all Buddhist Sabbath days in the specified
338
+ Gregorian year. Returns an empty set if the year is outside the supported range.
339
+ """
340
+ start_date = self._get_start_date(year)
341
+ if not start_date:
342
+ return set()
343
+
344
+ # Initializes Thai lunar month lengths.
345
+ months = [29, 30] * 6
346
+ if year in _ThaiLunisolar.ATHIKAMAT_YEARS_GREGORIAN:
347
+ months.insert(7, 30)
348
+ elif year in _ThaiLunisolar.ATHIKAWAN_YEARS_GREGORIAN:
349
+ months[6] += 1
350
+ # Includes first two months of the next Thai lunar year to ensure all Buddhist Sabbaths
351
+ # in the Gregorian year are captured.
352
+ months.extend([29, 30])
353
+
354
+ buddhist_sabbaths: set[date] = set()
355
+ day_cursor = start_date
356
+ for month_days in months:
357
+ if day_cursor.year > year:
358
+ break
359
+ # Buddhist Sabbaths: 8 Waxing, 15 Waxing, 8 Waning, 14/15 Waning.
360
+ for offset in (7, 14, 22, month_days - 1):
361
+ buddhist_sabbath = _timedelta(day_cursor, offset)
362
+ if buddhist_sabbath.year == year:
363
+ buddhist_sabbaths.add(buddhist_sabbath)
364
+ elif buddhist_sabbath.year > year:
365
+ break
366
+ day_cursor = _timedelta(day_cursor, month_days)
367
+
368
+ return buddhist_sabbaths
369
+
323
370
  def makha_bucha_date(self, year: int, calendar=None) -> Optional[date]:
324
371
  """Calculate the estimated Gregorian date of Makha Bucha.
325
372
 
@@ -20,6 +20,7 @@ from holidays.countries.american_samoa import AmericanSamoa, AS, ASM, HolidaysAS
20
20
  from holidays.countries.andorra import Andorra, AD, AND
21
21
  from holidays.countries.angola import Angola, AO, AGO
22
22
  from holidays.countries.anguilla import Anguilla, AI, AIA
23
+ from holidays.countries.antarctica import Antarctica, AQ, ATA
23
24
  from holidays.countries.antigua_and_barbuda import AntiguaAndBarbuda, AG, ATG
24
25
  from holidays.countries.argentina import Argentina, AR, ARG
25
26
  from holidays.countries.armenia import Armenia, AM, ARM
@@ -41,7 +42,9 @@ from holidays.countries.bolivia import Bolivia, BO, BOL
41
42
  from holidays.countries.bonaire_sint_eustatius_and_saba import BonaireSintEustatiusAndSaba, BQ, BES
42
43
  from holidays.countries.bosnia_and_herzegovina import BosniaAndHerzegovina, BA, BIH
43
44
  from holidays.countries.botswana import Botswana, BW, BWA
45
+ from holidays.countries.bouvet_island import BouvetIsland, BV, BVT
44
46
  from holidays.countries.brazil import Brazil, BR, BRA
47
+ from holidays.countries.british_indian_ocean_territory import BritishIndianOceanTerritory, IO, IOT
45
48
  from holidays.countries.british_virgin_islands import BritishVirginIslands, VG, VGB
46
49
  from holidays.countries.brunei import Brunei, BN, BRN
47
50
  from holidays.countries.bulgaria import Bulgaria, BG, BLG
@@ -111,6 +114,11 @@ from holidays.countries.guinea import Guinea, GN, GIN
111
114
  from holidays.countries.guinea_bissau import GuineaBissau, GW, GNB
112
115
  from holidays.countries.guyana import Guyana, GY, GUY
113
116
  from holidays.countries.haiti import Haiti, HT, HTI
117
+ from holidays.countries.heard_island_and_mcdonald_islands import (
118
+ HeardIslandAndMcDonaldIslands,
119
+ HM,
120
+ HMD,
121
+ )
114
122
  from holidays.countries.honduras import Honduras, HN, HND
115
123
  from holidays.countries.hongkong import HongKong, HK, HKG
116
124
  from holidays.countries.hungary import Hungary, HU, HUN
@@ -163,6 +171,7 @@ from holidays.countries.montenegro import Montenegro, ME, MNE
163
171
  from holidays.countries.montserrat import Montserrat, MS, MSR
164
172
  from holidays.countries.morocco import Morocco, MA, MOR
165
173
  from holidays.countries.mozambique import Mozambique, MZ, MOZ
174
+ from holidays.countries.myanmar import Myanmar, MM, MMR
166
175
  from holidays.countries.namibia import Namibia, NA, NAM
167
176
  from holidays.countries.nauru import Nauru, NR, NRU
168
177
  from holidays.countries.nepal import Nepal, NP, NPL
@@ -174,6 +183,7 @@ from holidays.countries.niger import Niger, NE, NER
174
183
  from holidays.countries.nigeria import Nigeria, NG, NGA
175
184
  from holidays.countries.niue import Niue, NU, NIU
176
185
  from holidays.countries.norfolk_island import NorfolkIsland, NF, NFK
186
+ from holidays.countries.north_korea import NorthKorea, KP, PRK
177
187
  from holidays.countries.north_macedonia import NorthMacedonia, MK, MKD
178
188
  from holidays.countries.northern_mariana_islands import NorthernMarianaIslands, MP, MNP, HolidaysMP
179
189
  from holidays.countries.norway import Norway, NO, NOR
@@ -196,6 +206,11 @@ from holidays.countries.romania import Romania, RO, ROU
196
206
  from holidays.countries.russia import Russia, RU, RUS
197
207
  from holidays.countries.rwanda import Rwanda, RW, RWA
198
208
  from holidays.countries.saint_barthelemy import SaintBarthelemy, BL, BLM, HolidaysBL
209
+ from holidays.countries.saint_helena_ascension_and_tristan_da_cunha import (
210
+ SaintHelenaAscensionAndTristanDaCunha,
211
+ SH,
212
+ SHN,
213
+ )
199
214
  from holidays.countries.saint_kitts_and_nevis import SaintKittsAndNevis, KN, KNA
200
215
  from holidays.countries.saint_lucia import SaintLucia, LC, LCA
201
216
  from holidays.countries.saint_martin import SaintMartin, MF, MAF, HolidaysMF
@@ -234,6 +249,7 @@ from holidays.countries.south_korea import SouthKorea, KR, KOR, Korea
234
249
  from holidays.countries.south_sudan import SouthSudan, SS, SSD
235
250
  from holidays.countries.spain import Spain, ES, ESP
236
251
  from holidays.countries.sri_lanka import SriLanka, LK, LKA
252
+ from holidays.countries.sudan import Sudan, SD, SDN
237
253
  from holidays.countries.suriname import Suriname, SR, SUR
238
254
  from holidays.countries.svalbard_and_jan_mayen import SvalbardAndJanMayen, SJ, SJM, HolidaysSJ
239
255
  from holidays.countries.sweden import Sweden, SE, SWE
@@ -23,7 +23,7 @@ class Afghanistan(HolidayBase, InternationalHolidays, IslamicHolidays, PersianCa
23
23
 
24
24
  References:
25
25
  * <https://en.wikipedia.org/wiki/Public_holidays_in_Afghanistan>
26
- * <https://web.archive.org/web/20250408032244/https://www.timeanddate.com/holidays/afghanistan>
26
+ * <https://web.archive.org/web/20250903162748/https://www.timeanddate.com/holidays/afghanistan>
27
27
  * <https://en.wikipedia.org/wiki/Workweek_and_weekend>
28
28
  """
29
29
 
@@ -131,16 +131,17 @@ class AfghanistanIslamicHolidays(_CustomIslamicHolidays):
131
131
  2021: (AUG, 19),
132
132
  }
133
133
 
134
- EID_AL_ADHA_DATES_CONFIRMED_YEARS = (2014, 2024)
134
+ EID_AL_ADHA_DATES_CONFIRMED_YEARS = (2014, 2025)
135
135
  EID_AL_ADHA_DATES = {
136
136
  2014: (OCT, 5),
137
137
  2016: (SEP, 13),
138
138
  2017: (SEP, 2),
139
139
  2018: (AUG, 22),
140
140
  2024: (JUN, 17),
141
+ 2025: (JUN, 7),
141
142
  }
142
143
 
143
- EID_AL_FITR_DATES_CONFIRMED_YEARS = (2014, 2024)
144
+ EID_AL_FITR_DATES_CONFIRMED_YEARS = (2014, 2025)
144
145
  EID_AL_FITR_DATES = {
145
146
  2014: (JUL, 29),
146
147
  2015: (JUL, 18),
@@ -150,7 +151,7 @@ class AfghanistanIslamicHolidays(_CustomIslamicHolidays):
150
151
  2023: (APR, 22),
151
152
  }
152
153
 
153
- MAWLID_DATES_CONFIRMED_YEARS = (2014, 2024)
154
+ MAWLID_DATES_CONFIRMED_YEARS = (2014, 2025)
154
155
  MAWLID_DATES = {
155
156
  2014: (JAN, 14),
156
157
  2015: ((JAN, 3), (DEC, 24)),
@@ -160,9 +161,10 @@ class AfghanistanIslamicHolidays(_CustomIslamicHolidays):
160
161
  2019: (NOV, 10),
161
162
  2021: (OCT, 19),
162
163
  2024: (SEP, 16),
164
+ 2025: (SEP, 5),
163
165
  }
164
166
 
165
- RAMADAN_BEGINNING_DATES_CONFIRMED_YEARS = (2014, 2024)
167
+ RAMADAN_BEGINNING_DATES_CONFIRMED_YEARS = (2014, 2025)
166
168
  RAMADAN_BEGINNING_DATES = {
167
169
  2014: (JUN, 29),
168
170
  2016: (JUN, 7),