pandas-market-calendars 4.4.0__py3-none-any.whl → 4.6.0__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.
@@ -31,6 +31,7 @@ from pandas_market_calendars.holidays.us import (
31
31
  ChristmasEveBefore1993,
32
32
  ChristmasEveInOrAfter1993,
33
33
  USBlackFridayInOrAfter1993,
34
+ USJuneteenthAfter2022,
34
35
  USIndependenceDay,
35
36
  USMartinLutherKingJrAfter1998,
36
37
  USMemorialDay,
@@ -98,6 +99,7 @@ class CMEEquityExchangeCalendar(MarketCalendar):
98
99
  USPresidentsDay,
99
100
  USMemorialDay,
100
101
  USLaborDay,
102
+ USJuneteenthAfter2022,
101
103
  USIndependenceDay,
102
104
  USThanksgivingDay,
103
105
  USBlackFridayInOrAfter1993,
@@ -158,6 +160,7 @@ class CMEAgricultureExchangeCalendar(MarketCalendar):
158
160
  USPresidentsDay,
159
161
  GoodFriday,
160
162
  USMemorialDay,
163
+ USJuneteenthAfter2022,
161
164
  USIndependenceDay,
162
165
  USLaborDay,
163
166
  USThanksgivingDay,
@@ -124,3 +124,49 @@ class CMEGlobexLivestockExchangeCalendar(CMEGlobexAgricultureExchangeCalendar):
124
124
  ),
125
125
  )
126
126
  ]
127
+
128
+
129
+ class CMEGlobexGrainsAndOilseedsExchangeCalendar(CMEGlobexAgricultureExchangeCalendar):
130
+ """
131
+ Exchange calendar for CME for Grains & Oilseeds
132
+
133
+ https://www.cmegroup.com/trading/agricultural/grain-and-oilseed.html
134
+
135
+ GLOBEX Trading Times
136
+ https://www.cmegroup.com/markets/agriculture/oilseeds/soybean.contractSpecs.html
137
+ https://www.cmegroup.com/markets/agriculture/grains/corn.contractSpecs.html
138
+ https://www.cmegroup.com/markets/agriculture/grains/wheat.contractSpecs.html
139
+ Sunday - Friday: 7:00 p.m. - 7:45 a.m. CT and Monday - Friday: 8:30 a.m. - 1:20 p.m. CT
140
+ """
141
+
142
+ aliases = [
143
+ "CMEGlobex_Grains",
144
+ "CMEGlobex_Oilseeds",
145
+ ]
146
+
147
+ regular_market_times = {
148
+ "market_open": ((None, time(19), -1),), # offset by -1 day
149
+ "market_close": ((None, time(13, 20)),),
150
+ "break_start": ((None, time(7, 45)),),
151
+ "break_end": ((None, time(8, 30)),),
152
+ }
153
+
154
+ @property
155
+ def name(self):
156
+ return "CMEGlobex_GrainsAndOilseeds"
157
+
158
+ @property
159
+ def regular_holidays(self):
160
+ return AbstractHolidayCalendar(
161
+ rules=[
162
+ USNewYearsDay,
163
+ USMartinLutherKingJrAfter1998,
164
+ USPresidentsDay,
165
+ GoodFriday,
166
+ USMemorialDay,
167
+ USIndependenceDay,
168
+ USLaborDay,
169
+ USThanksgivingDay,
170
+ Christmas,
171
+ ]
172
+ )
@@ -43,13 +43,6 @@ MayBank = Holiday(
43
43
  day=1,
44
44
  days_of_week=(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY),
45
45
  )
46
- # German National Holiday (Tag der Deutschen Einheit)
47
- GermanNationalDay = Holiday(
48
- "Tag der Deutschen Einheit",
49
- month=10,
50
- day=3,
51
- days_of_week=(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY),
52
- )
53
46
  # Christmas Eve
54
47
  ChristmasEve = Holiday(
55
48
  "Christmas Eve",
@@ -116,7 +109,6 @@ class EUREXExchangeCalendar(MarketCalendar):
116
109
  GoodFriday,
117
110
  EasterMonday,
118
111
  MayBank,
119
- GermanNationalDay,
120
112
  Christmas,
121
113
  WeekendChristmas,
122
114
  BoxingDay,
@@ -354,6 +354,9 @@ HKClosedDay = [
354
354
  Timestamp("2016-10-21", tz="UTC"), # 台风海马1622
355
355
  # Timestamp(2017-06-12', tz='UTC'), # 台风苗柏1702,期货夜盘17:35休市
356
356
  Timestamp("2017-08-23", tz="UTC"), # 台风天鸽1713
357
+ Timestamp("2023-07-17", tz="UTC"), # Typhoon closure
358
+ Timestamp("2023-09-01", tz="UTC"), # Typhoon closure
359
+ Timestamp("2023-09-08", tz="UTC"), # Typhoon closure
357
360
  ]
358
361
 
359
362
 
@@ -1,9 +1,13 @@
1
1
  from datetime import time
2
2
  from itertools import chain
3
3
 
4
+ from pandas import Timestamp, DatetimeIndex, Timedelta
4
5
  from pandas.tseries.holiday import AbstractHolidayCalendar
5
6
  from pytz import timezone
6
7
 
8
+ from typing import Literal, Union
9
+ from pandas_market_calendars import calendar_utils as u
10
+
7
11
  from pandas_market_calendars.holidays.nyse import (
8
12
  USPresidentsDay,
9
13
  GoodFriday,
@@ -106,7 +110,42 @@ class IEXExchangeCalendar(NYSEExchangeCalendar):
106
110
  return []
107
111
 
108
112
  def valid_days(self, start_date, end_date, tz="UTC"):
109
- trading_days = super().valid_days(
110
- start_date, end_date, tz=tz
111
- ) # all NYSE valid days
112
- return trading_days[~(trading_days <= "2013-08-25")]
113
+ start_date = Timestamp(start_date)
114
+ if start_date.tz is not None:
115
+ # Ensure valid Comparison to "2013-08-25" is possible
116
+ start_date.tz_convert(self.tz).tz_localize(None)
117
+
118
+ # Limit Start_date to the Exchange's Open
119
+ start_date = max(start_date, Timestamp("2013-08-25"))
120
+ return super().valid_days(start_date, end_date, tz=tz)
121
+
122
+ def date_range_htf(
123
+ self,
124
+ frequency: Union[str, Timedelta, int, float],
125
+ start: Union[str, Timestamp, int, float, None] = None,
126
+ end: Union[str, Timestamp, int, float, None] = None,
127
+ periods: Union[int, None] = None,
128
+ closed: Union[Literal["left", "right"], None] = "right",
129
+ *,
130
+ day_anchor: u.Day_Anchor = "SUN",
131
+ month_anchor: u.Month_Anchor = "JAN",
132
+ ) -> DatetimeIndex:
133
+
134
+ start, end, periods = u._error_check_htf_range(start, end, periods)
135
+
136
+ # Cap Beginning and end dates to the opening date of IEX
137
+ if start is not None:
138
+ start = max(start, Timestamp("2013-08-25"))
139
+ if end is not None:
140
+ end = max(end, Timestamp("2013-08-25"))
141
+
142
+ return u.date_range_htf(
143
+ self.holidays(),
144
+ frequency,
145
+ start,
146
+ end,
147
+ periods,
148
+ closed,
149
+ day_anchor=day_anchor,
150
+ month_anchor=month_anchor,
151
+ )
@@ -21,13 +21,17 @@ class JPXExchangeCalendar(MarketCalendar):
21
21
 
22
22
  Open Time: 9:31 AM, Asia/Tokyo
23
23
  LUNCH BREAK :facepalm: : 11:30 AM - 12:30 PM Asia/Tokyo
24
- Close Time: 4:00 PM, Asia/Tokyo
24
+ Close Time: 3:30 PM, Asia/Tokyo
25
+
26
+ Market close of Japan changed from 3:00 PM to 3:30 PM on November 5, 2024
27
+ Reference:
28
+ https://www.jpx.co.jp/english/equities/trading/domestic/tvdivq0000006blj-att/tradinghours_eg.pdf
25
29
  """
26
30
 
27
31
  aliases = ["JPX", "XJPX"]
28
32
  regular_market_times = {
29
33
  "market_open": ((None, time(9)),),
30
- "market_close": ((None, time(15)),),
34
+ "market_close": ((None, time(15)), ("2024-11-05", time(15, 30))),
31
35
  "break_start": ((None, time(11, 30)),),
32
36
  "break_end": ((None, time(12, 30)),),
33
37
  }
@@ -8,6 +8,8 @@ import exchange_calendars
8
8
 
9
9
  from pandas_market_calendars.market_calendar import MarketCalendar
10
10
 
11
+ DAYMASKS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
12
+
11
13
 
12
14
  class TradingCalendar(MarketCalendar):
13
15
  """
@@ -97,6 +99,23 @@ class TradingCalendar(MarketCalendar):
97
99
  def special_closes_adhoc(self):
98
100
  return self._ec.special_closes_adhoc
99
101
 
102
+ @property
103
+ def weekmask(self):
104
+ if hasattr(self._ec, "weekmask"):
105
+ if "1" in self._ec.weekmask or "0" in self._ec.weekmask:
106
+ # Convert 1s & 0s to Day Abbreviations
107
+ return " ".join(
108
+ [
109
+ DAYMASKS[i]
110
+ for i, val in enumerate(self._ec.weekmask)
111
+ if val == "1"
112
+ ]
113
+ )
114
+ else:
115
+ return self._ec.weekmask
116
+ else:
117
+ return "Mon Tue Wed Thu Fri"
118
+
100
119
 
101
120
  calendars = exchange_calendars.calendar_utils._default_calendar_factories # noqa
102
121
 
@@ -18,8 +18,12 @@ from itertools import chain
18
18
 
19
19
  import pandas as pd
20
20
  from pandas.tseries.holiday import AbstractHolidayCalendar
21
+ from pandas.tseries.offsets import CustomBusinessDay
21
22
  from pytz import timezone
22
23
 
24
+ from typing import Literal, Union
25
+ from pandas_market_calendars import calendar_utils as u
26
+
23
27
  from pandas_market_calendars.holidays.nyse import (
24
28
  # Always Celebrated Holidays
25
29
  USNewYearsDayNYSEpost1952,
@@ -297,6 +301,8 @@ from pandas_market_calendars.holidays.nyse import (
297
301
  HurricaneSandyClosings2012,
298
302
  # 2018
299
303
  GeorgeHWBushDeath2018,
304
+ # 2025
305
+ JimmyCarterDeath2025,
300
306
  )
301
307
  from pandas_market_calendars.market_calendar import MarketCalendar
302
308
 
@@ -828,7 +834,28 @@ class NYSEExchangeCalendar(MarketCalendar):
828
834
 
829
835
  @property
830
836
  def weekmask(self):
831
- return "Mon Tue Wed Thu Fri Sat" # Market open on Saturdays thru 5/24/1952
837
+ return "Mon Tue Wed Thu Fri"
838
+
839
+ @property
840
+ def weekmask_pre_1952(self):
841
+ return "Mon Tue Wed Thu Fri Sat"
842
+
843
+ def holidays_pre_1952(self):
844
+ """
845
+ NYSE Market open on Saturdays pre 5/24/1952.
846
+ CustomBusinessDay object that can be used inplace of holidays() for dates prior to crossover
847
+
848
+ :return: CustomBusinessDay object of holidays
849
+ """
850
+ if hasattr(self, "_holidays_hist"):
851
+ return self._holidays_hist
852
+
853
+ self._holidays_hist = CustomBusinessDay(
854
+ holidays=self.adhoc_holidays,
855
+ calendar=self.regular_holidays,
856
+ weekmask=self.weekmask_pre_1952,
857
+ )
858
+ return self._holidays_hist
832
859
 
833
860
  @property
834
861
  def regular_holidays(self):
@@ -961,10 +988,10 @@ class NYSEExchangeCalendar(MarketCalendar):
961
988
  September11Closings2001,
962
989
  HurricaneSandyClosings2012,
963
990
  GeorgeHWBushDeath2018,
991
+ JimmyCarterDeath2025,
964
992
  )
965
993
  )
966
994
 
967
- #
968
995
  @property
969
996
  def special_closes(self):
970
997
  return [
@@ -1085,7 +1112,6 @@ class NYSEExchangeCalendar(MarketCalendar):
1085
1112
  ),
1086
1113
  ]
1087
1114
 
1088
- #
1089
1115
  @property
1090
1116
  def special_closes_adhoc(self):
1091
1117
  def _union_many(indexes):
@@ -1140,7 +1166,6 @@ class NYSEExchangeCalendar(MarketCalendar):
1140
1166
  ),
1141
1167
  ]
1142
1168
 
1143
- #
1144
1169
  @property
1145
1170
  def special_opens(self):
1146
1171
  return [
@@ -1254,7 +1279,6 @@ class NYSEExchangeCalendar(MarketCalendar):
1254
1279
  ),
1255
1280
  ]
1256
1281
 
1257
- #
1258
1282
  @property
1259
1283
  def special_opens_adhoc(self):
1260
1284
  return [
@@ -1272,7 +1296,7 @@ class NYSEExchangeCalendar(MarketCalendar):
1272
1296
  ),
1273
1297
  ]
1274
1298
 
1275
- # Override market_calendar.py
1299
+ # Override market_calendar.py to split calc between pre & post 1952 Saturday Close
1276
1300
  def valid_days(self, start_date, end_date, tz="UTC"):
1277
1301
  """
1278
1302
  Get a DatetimeIndex of valid open business days.
@@ -1282,7 +1306,8 @@ class NYSEExchangeCalendar(MarketCalendar):
1282
1306
  :param tz: time zone in either string or pytz.timezone
1283
1307
  :return: DatetimeIndex of valid business days
1284
1308
  """
1285
- trading_days = super().valid_days(start_date, end_date, tz=tz)
1309
+ start_date = pd.Timestamp(start_date, tz=tz)
1310
+ end_date = pd.Timestamp(end_date, tz=tz)
1286
1311
 
1287
1312
  # Starting Monday Sept. 29, 1952, no more saturday trading days
1288
1313
  if tz is None:
@@ -1290,12 +1315,32 @@ class NYSEExchangeCalendar(MarketCalendar):
1290
1315
  else:
1291
1316
  saturday_end = self._saturday_end
1292
1317
 
1293
- above_cut_off = trading_days >= saturday_end
1294
- if above_cut_off.any():
1295
- above_and_saturday = (trading_days.weekday == 5) & above_cut_off
1296
- trading_days = trading_days[~above_and_saturday]
1318
+ # Don't care about Saturdays. Call super.
1319
+ if start_date > saturday_end:
1320
+ return super().valid_days(start_date, end_date, tz=tz)
1297
1321
 
1298
- return trading_days
1322
+ # Full Date Range is pre 1952. Augment the Super call
1323
+ if end_date <= saturday_end:
1324
+ return pd.date_range(
1325
+ start_date,
1326
+ end_date,
1327
+ freq=self.holidays_pre_1952(),
1328
+ normalize=True,
1329
+ tz=tz,
1330
+ )
1331
+
1332
+ # Range is split across 1952. Concatenate Two different Date_Range calls
1333
+ days_pre = pd.date_range(
1334
+ start_date,
1335
+ saturday_end,
1336
+ freq=self.holidays_pre_1952(),
1337
+ normalize=True,
1338
+ tz=tz,
1339
+ )
1340
+ days_post = pd.date_range(
1341
+ saturday_end, end_date, freq=self.holidays(), normalize=True, tz=tz
1342
+ )
1343
+ return days_pre.union(days_post)
1299
1344
 
1300
1345
  def days_at_time(self, days, market_time, day_offset=0):
1301
1346
  days = super().days_at_time(days, market_time, day_offset=day_offset)
@@ -1309,6 +1354,103 @@ class NYSEExchangeCalendar(MarketCalendar):
1309
1354
  days = days.dt.tz_convert("UTC")
1310
1355
  return days
1311
1356
 
1357
+ def date_range_htf(
1358
+ self,
1359
+ frequency: Union[str, pd.Timedelta, int, float],
1360
+ start: Union[str, pd.Timestamp, int, float, None] = None,
1361
+ end: Union[str, pd.Timestamp, int, float, None] = None,
1362
+ periods: Union[int, None] = None,
1363
+ closed: Union[Literal["left", "right"], None] = "right",
1364
+ *,
1365
+ day_anchor: u.Day_Anchor = "SUN",
1366
+ month_anchor: u.Month_Anchor = "JAN",
1367
+ ) -> pd.DatetimeIndex:
1368
+ # __doc__ = MarketCalendar.date_range_htf.__doc__
1369
+
1370
+ start, end, periods = u._error_check_htf_range(start, end, periods)
1371
+
1372
+ args = {
1373
+ "frequency": frequency,
1374
+ "start": start,
1375
+ "end": end,
1376
+ "periods": periods,
1377
+ "closed": closed,
1378
+ "day_anchor": day_anchor,
1379
+ "month_anchor": month_anchor,
1380
+ }
1381
+
1382
+ saturday_end = self._saturday_end.tz_localize(None)
1383
+
1384
+ # All Dates post 1952 This is the most common use case so return it first
1385
+ if start is not None and start > saturday_end:
1386
+ return u.date_range_htf(self.holidays(), **args)
1387
+
1388
+ # ---- Start-Date to End-Date w/ pre-1952 ----
1389
+ if start is not None and end is not None:
1390
+ if end <= saturday_end:
1391
+ # All pre 1952 Dates
1392
+ return u.date_range_htf(self.holidays_pre_1952(), **args)
1393
+ else:
1394
+ # Split Range Across 1952
1395
+ pre = u.date_range_htf( # Only Generate to the last saturday
1396
+ self.holidays_pre_1952(), **(args | {"end": saturday_end})
1397
+ )
1398
+ post = u.date_range_htf( # start generating from the last date of 'pre'
1399
+ self.holidays(), **(args | {"start": pre[-1]})
1400
+ )
1401
+ return pd.DatetimeIndex(pre.union(post), dtype="datetime64[ns]")
1402
+
1403
+ # ---- Periods from Start-Date w/ pre-1952 ----
1404
+ elif start is not None and periods is not None:
1405
+ # Start prior to 1952 & Number of periods given
1406
+ rtn_dt = u.date_range_htf(self.holidays_pre_1952(), **args)
1407
+ if rtn_dt[-1] <= saturday_end:
1408
+ return rtn_dt # never passed 1952, good to return
1409
+
1410
+ # Date Range Split.
1411
+ pre = rtn_dt[rtn_dt <= saturday_end]
1412
+ post = u.date_range_htf(
1413
+ self.holidays(),
1414
+ **(args | {"start": pre[-1], "periods": periods - len(pre) + 1}),
1415
+ )
1416
+ return pd.DatetimeIndex(pre.union(post)[:periods], dtype="datetime64[ns]")
1417
+
1418
+ # ---- Periods from End-Date ----
1419
+ elif end is not None and periods is not None:
1420
+ if end <= saturday_end:
1421
+ # All Dates pre-1952, Good to return the normal call
1422
+ return u.date_range_htf(self.holidays_pre_1952(), **args)
1423
+ else:
1424
+ rtn_dt = u.date_range_htf(self.holidays(), **args)
1425
+
1426
+ if rtn_dt[0] > saturday_end:
1427
+ return rtn_dt # never passed 1952, good to return
1428
+
1429
+ # Date Range Split
1430
+ post = rtn_dt[rtn_dt > saturday_end]
1431
+ _, period_code = u._standardize_htf_freq(frequency)
1432
+ altered_args = {
1433
+ # This nonsense is to realign the schedules as best as possible. This
1434
+ # essentially creates the 'pre-1952' equivalent date to the last generated 'post-1952'
1435
+ # date. Start the Range from there, then pre[0:-1] trims off that extra date where we
1436
+ # started from
1437
+ "end": post[0].to_period(period_code).end_time.normalize(),
1438
+ "periods": periods - len(post) + 2,
1439
+ }
1440
+ pre = u.date_range_htf(
1441
+ self.holidays_pre_1952(),
1442
+ **(args | altered_args),
1443
+ )
1444
+
1445
+ return pd.DatetimeIndex(
1446
+ pre[:-1].union(post)[-periods:], dtype="datetime64[ns]"
1447
+ )
1448
+ else:
1449
+ _, _ = u._standardize_htf_freq(frequency)
1450
+ raise ValueError(
1451
+ "This should never be raised, the above call should error first"
1452
+ )
1453
+
1312
1454
  def early_closes(self, schedule):
1313
1455
  """
1314
1456
  Get a DataFrame of the dates that are an early close.
@@ -42,7 +42,7 @@ class SSEExchangeCalendar(MarketCalendar):
42
42
  # Since all past holidays are adhoc, start_year should always be a year in the future.
43
43
  # For example: Holiday arrangements for 2022 are now included,
44
44
  # then our guesswork starts from the next year so start_year = 2023
45
- start_year = 2024
45
+ start_year = 2026
46
46
 
47
47
  return AbstractHolidayCalendar(
48
48
  rules=[
@@ -1,9 +1,11 @@
1
1
  from datetime import time
2
2
 
3
- from pandas import Timestamp
3
+ from typing import Literal, Union
4
+ from pandas import Timestamp, Timedelta, DatetimeIndex
4
5
  from pytz import timezone
5
6
 
6
7
  from pandas_market_calendars.market_calendar import MarketCalendar
8
+ from pandas_market_calendars.calendar_utils import Day_Anchor, Month_Anchor
7
9
 
8
10
  TASEClosedDay = [
9
11
  # 2019
@@ -195,3 +197,24 @@ class TASEExchangeCalendar(MarketCalendar):
195
197
  @property
196
198
  def weekmask(self):
197
199
  return "Sun Mon Tue Wed Thu"
200
+
201
+ def date_range_htf(
202
+ self,
203
+ frequency: Union[str, Timedelta, int, float],
204
+ start: Union[str, Timestamp, int, float, None] = None,
205
+ end: Union[str, Timestamp, int, float, None] = None,
206
+ periods: Union[int, None] = None,
207
+ closed: Union[Literal["left", "right"], None] = "right",
208
+ *,
209
+ day_anchor: Day_Anchor = "SAT", # Change the default day anchor
210
+ month_anchor: Month_Anchor = "JAN",
211
+ ) -> DatetimeIndex:
212
+ return super().date_range_htf(
213
+ frequency,
214
+ start,
215
+ end,
216
+ periods,
217
+ closed,
218
+ day_anchor=day_anchor,
219
+ month_anchor=month_anchor,
220
+ )
@@ -565,6 +565,7 @@ all_holidays = [
565
565
  Timestamp("2023-10-05"),
566
566
  Timestamp("2023-10-06"),
567
567
  Timestamp("2024-01-01"),
568
+ Timestamp("2024-02-09"),
568
569
  Timestamp("2024-02-12"),
569
570
  Timestamp("2024-02-13"),
570
571
  Timestamp("2024-02-14"),
@@ -583,6 +584,26 @@ all_holidays = [
583
584
  Timestamp("2024-10-03"),
584
585
  Timestamp("2024-10-04"),
585
586
  Timestamp("2024-10-07"),
587
+ # 2025 holidays
588
+ Timestamp("2025-01-01"), # New Year
589
+ Timestamp("2025-01-28"), # Spring Festival
590
+ Timestamp("2025-01-29"),
591
+ Timestamp("2025-01-30"),
592
+ Timestamp("2025-01-31"),
593
+ Timestamp("2025-02-03"),
594
+ Timestamp("2025-02-04"),
595
+ Timestamp("2025-04-04"), # Tomb-sweeping Day
596
+ Timestamp("2025-04-05"),
597
+ Timestamp("2025-05-01"), # Labor Day
598
+ Timestamp("2025-05-02"),
599
+ Timestamp("2025-05-05"),
600
+ Timestamp("2025-06-02"), # Dragon Boat Festival
601
+ Timestamp("2025-10-01"), # National Day & Mid-autumn Festival
602
+ Timestamp("2025-10-02"),
603
+ Timestamp("2025-10-03"),
604
+ Timestamp("2025-10-06"),
605
+ Timestamp("2025-10-07"),
606
+ Timestamp("2025-10-08"),
586
607
  ]
587
608
 
588
609
  # The following holidays are based on Solar terms or Chinese lunisolar calendar,
@@ -11,6 +11,7 @@ from the Tokyo exchange inauguration through 2099,
11
11
  using pyephem (http://rhodesmill.org/pyephem/quick.html#equinoxes-solstices).
12
12
  For a double check, see: https://aa.usno.navy.mil/data/docs/EarthSeasons.php
13
13
  """
14
+
14
15
  import pandas as pd
15
16
  from pandas.tseries.holiday import sunday_to_monday
16
17
 
@@ -1529,3 +1529,8 @@ HurricaneSandyClosings2012 = [
1529
1529
  GeorgeHWBushDeath2018 = [
1530
1530
  Timestamp("2018-12-05", tz="UTC"),
1531
1531
  ]
1532
+
1533
+ # 2025
1534
+ JimmyCarterDeath2025 = [
1535
+ Timestamp("2025-01-09", tz="UTC"),
1536
+ ]