From 4ca2677c3c789f9b8eed50dc7c840f5384d191d6 Mon Sep 17 00:00:00 2001 From: Marcus Read Date: Thu, 7 Sep 2023 08:56:08 +0100 Subject: [PATCH] Migrate from `pytz` to `zoneinfo` Migrates code base and tests from `pytz` to `zoneinfo`. --- etc/bench.py | 2 +- etc/check_holidays.py | 4 +- etc/factory_bounds.py | 18 ++++--- etc/lunisolar | 4 +- exchange_calendars/always_open.py | 3 +- exchange_calendars/calendar_helpers.py | 27 +++++----- exchange_calendars/exchange_calendar.py | 15 +++--- exchange_calendars/exchange_calendar_aixk.py | 4 +- exchange_calendars/exchange_calendar_asex.py | 4 +- exchange_calendars/exchange_calendar_bvmf.py | 4 +- exchange_calendars/exchange_calendar_cmes.py | 4 +- exchange_calendars/exchange_calendar_iepa.py | 4 +- exchange_calendars/exchange_calendar_xams.py | 4 +- exchange_calendars/exchange_calendar_xasx.py | 4 +- exchange_calendars/exchange_calendar_xbkk.py | 5 +- exchange_calendars/exchange_calendar_xbog.py | 4 +- exchange_calendars/exchange_calendar_xbom.py | 4 +- exchange_calendars/exchange_calendar_xbru.py | 4 +- exchange_calendars/exchange_calendar_xbse.py | 4 +- exchange_calendars/exchange_calendar_xbud.py | 4 +- exchange_calendars/exchange_calendar_xbue.py | 4 +- exchange_calendars/exchange_calendar_xcbf.py | 6 +-- exchange_calendars/exchange_calendar_xcse.py | 4 +- exchange_calendars/exchange_calendar_xdub.py | 4 +- exchange_calendars/exchange_calendar_xetr.py | 10 ++-- exchange_calendars/exchange_calendar_xfra.py | 10 ++-- exchange_calendars/exchange_calendar_xhel.py | 4 +- exchange_calendars/exchange_calendar_xhkg.py | 8 ++- exchange_calendars/exchange_calendar_xice.py | 4 +- exchange_calendars/exchange_calendar_xidx.py | 4 +- exchange_calendars/exchange_calendar_xist.py | 4 +- exchange_calendars/exchange_calendar_xjse.py | 4 +- exchange_calendars/exchange_calendar_xkar.py | 4 +- exchange_calendars/exchange_calendar_xkls.py | 5 +- exchange_calendars/exchange_calendar_xkrx.py | 6 +-- exchange_calendars/exchange_calendar_xlim.py | 4 +- exchange_calendars/exchange_calendar_xlis.py | 4 +- exchange_calendars/exchange_calendar_xlon.py | 4 +- exchange_calendars/exchange_calendar_xmad.py | 6 +-- exchange_calendars/exchange_calendar_xmex.py | 4 +- exchange_calendars/exchange_calendar_xmil.py | 4 +- exchange_calendars/exchange_calendar_xmos.py | 4 +- exchange_calendars/exchange_calendar_xnys.py | 4 +- exchange_calendars/exchange_calendar_xnze.py | 6 +-- exchange_calendars/exchange_calendar_xosl.py | 4 +- exchange_calendars/exchange_calendar_xpar.py | 4 +- exchange_calendars/exchange_calendar_xphs.py | 4 +- exchange_calendars/exchange_calendar_xpra.py | 4 +- exchange_calendars/exchange_calendar_xsau.py | 4 +- exchange_calendars/exchange_calendar_xses.py | 4 +- exchange_calendars/exchange_calendar_xsgo.py | 4 +- exchange_calendars/exchange_calendar_xshg.py | 4 +- exchange_calendars/exchange_calendar_xsto.py | 4 +- exchange_calendars/exchange_calendar_xswx.py | 4 +- exchange_calendars/exchange_calendar_xtae.py | 4 +- exchange_calendars/exchange_calendar_xtai.py | 4 +- exchange_calendars/exchange_calendar_xtks.py | 4 +- exchange_calendars/exchange_calendar_xtse.py | 4 +- exchange_calendars/exchange_calendar_xwar.py | 4 +- exchange_calendars/exchange_calendar_xwbo.py | 4 +- .../pandas_extensions/korean_holiday.py | 18 ++++--- exchange_calendars/us_futures_calendar.py | 6 ++- exchange_calendars/utils/pandas_utils.py | 7 +-- exchange_calendars/weekday_calendar.py | 3 +- tests/test_always_open.py | 2 +- tests/test_asex_calendar.py | 11 ++-- tests/test_calendar_helpers.py | 53 +++++++++++-------- tests/test_exchange_calendar.py | 31 +++++------ tests/test_weekday_calendar.py | 2 +- 69 files changed, 231 insertions(+), 213 deletions(-) diff --git a/etc/bench.py b/etc/bench.py index b38924f3..0f4c780d 100644 --- a/etc/bench.py +++ b/etc/bench.py @@ -1,9 +1,9 @@ import itertools import pandas as pd -from pytz import UTC from exchange_calendars import get_calendar +from exchange_calendars.calendar_helpers import UTC from exchange_calendars.calendar_utils import ( ExchangeCalendarDispatcher, _default_calendar_aliases, diff --git a/etc/check_holidays.py b/etc/check_holidays.py index d0f4a48e..7aba50ca 100644 --- a/etc/check_holidays.py +++ b/etc/check_holidays.py @@ -4,6 +4,7 @@ import pandas as pd from exchange_calendars import get_calendar +from exchange_calendars.calendar_helpers import UTC from exchange_calendars.calendar_utils import default_calendar_names @@ -136,7 +137,7 @@ def _check_range(start, end, holidays, cal, calendar_name): @click.option( "--min-date", default=pd.Timestamp("2002-01-01"), - type=TimestampType(tz="UTC"), + type=TimestampType(tz=UTC), help="Start the holiday comparison at this date.", show_default=True, ) @@ -190,7 +191,6 @@ def main( strip_x_from_cal_name, answer_key_calendar_name, ): - check_holidays( holiday_key_path, calendar_column, diff --git a/etc/factory_bounds.py b/etc/factory_bounds.py index 79bc8e49..141dabe4 100644 --- a/etc/factory_bounds.py +++ b/etc/factory_bounds.py @@ -10,8 +10,9 @@ """ from __future__ import annotations -import dataclasses + import abc +import dataclasses import pathlib import pickle from typing import Literal, Type @@ -19,6 +20,7 @@ import pandas as pd import exchange_calendars as xcals +from exchange_calendars.calendar_helpers import UTC @dataclasses.dataclass @@ -72,7 +74,7 @@ def calendar_name(self) -> str: @property def today(self) -> pd.Timestamp: - return pd.Timestamp.now(tz="UTC").floor("D") + return pd.Timestamp.now(tz=UTC).floor("D") def _get_calendar( self, @@ -173,13 +175,13 @@ def _try_short_cut( """ if bound == "start": likely_bounds = [ - pd.Timestamp("1678-01-01", tz="UTC"), - pd.Timestamp("1679-01-01", tz="UTC"), + pd.Timestamp("1678-01-01", tz=UTC), + pd.Timestamp("1679-01-01", tz=UTC), ] else: likely_bounds = [ - pd.Timestamp("2260-12-31", tz="UTC"), - pd.Timestamp("2262-04-10", tz="UTC"), + pd.Timestamp("2260-12-31", tz=UTC), + pd.Timestamp("2262-04-10", tz=UTC), ] for likely_bound in likely_bounds: @@ -191,9 +193,9 @@ def _try_short_cut( @staticmethod def _initial_value(bound: Literal["start", "end"]) -> pd.Timestamp: if bound == "start": - return pd.Timestamp.min.ceil("D").tz_localize("UTC") + return pd.Timestamp.min.ceil("D").tz_localize(UTC) else: - return pd.Timestamp.max.floor("D").tz_localize("UTC") + return pd.Timestamp.max.floor("D").tz_localize(UTC) def _get_bound( self, bound: Literal["start", "end"] diff --git a/etc/lunisolar b/etc/lunisolar index 78a4de31..05447eaa 100755 --- a/etc/lunisolar +++ b/etc/lunisolar @@ -30,6 +30,8 @@ import pandas as pd import toolz from novas.compat import eph_manager +from exchange_calendars.calendar_helpers import UTC + @contextlib.contextmanager def ephemeris(): @@ -1089,7 +1091,7 @@ def utc_to_chinese_date(arr): An array of datetime64[ns] at midnight corresponding the date in China of the input. """ - ts = pd.to_datetime(arr).tz_localize("UTC").tz_convert("Asia/Shanghai") + ts = pd.to_datetime(arr).tz_localize(UTC).tz_convert("Asia/Shanghai") out = ts.normalize().tz_localize(None) if isinstance(out, pd.Timestamp): return out.asm8 diff --git a/exchange_calendars/always_open.py b/exchange_calendars/always_open.py index 36ee0b2c..2e76718a 100644 --- a/exchange_calendars/always_open.py +++ b/exchange_calendars/always_open.py @@ -1,8 +1,7 @@ from datetime import time -from pytz import UTC - from .exchange_calendar import ExchangeCalendar +from exchange_calendars.calendar_helpers import UTC class AlwaysOpenCalendar(ExchangeCalendar): diff --git a/exchange_calendars/calendar_helpers.py b/exchange_calendars/calendar_helpers.py index 8df5a6bd..64c8aefe 100644 --- a/exchange_calendars/calendar_helpers.py +++ b/exchange_calendars/calendar_helpers.py @@ -4,16 +4,18 @@ import datetime import typing from typing import Literal +from zoneinfo import ZoneInfo import numpy as np import pandas as pd -import pytz from exchange_calendars import errors if typing.TYPE_CHECKING: from exchange_calendars import ExchangeCalendar +UTC = ZoneInfo("UTC") + NANOSECONDS_PER_MINUTE = int(6e10) NP_NAT = pd.NaT.value @@ -36,7 +38,6 @@ def next_divider_idx(dividers: np.ndarray, minute_val: int) -> int: - divider_idx = np.searchsorted(dividers, minute_val, side="right") target = dividers[divider_idx] @@ -48,7 +49,6 @@ def next_divider_idx(dividers: np.ndarray, minute_val: int) -> int: def previous_divider_idx(dividers: np.ndarray, minute_val: int) -> int: - divider_idx = np.searchsorted(dividers, minute_val) if divider_idx == 0: @@ -146,9 +146,9 @@ def to_utc(ts: pd.Timestamp) -> pd.Timestamp: Timestamp to return a copy of with timezone set to UTC. """ try: - return ts.tz_convert(pytz.UTC) + return ts.tz_convert(UTC) except TypeError: - return ts.tz_localize(pytz.UTC) + return ts.tz_localize(UTC) def parse_timestamp( @@ -189,9 +189,9 @@ def parse_timestamp( to minute resolution. utc : default: True - True - convert / set timezone to "UTC". + True - convert / set timezone to UTC. False - leave any timezone unchanged. Note, if timezone of - `timestamp` is "UTC" then will remain as "UTC". + `timestamp` is UTC then will remain as UTC. Raises ------ @@ -224,8 +224,8 @@ def parse_timestamp( else: raise ValueError(msg) from e - if utc and ts.tz is not pytz.UTC: - ts = ts.tz_localize("UTC") if ts.tz is None else ts.tz_convert("UTC") + if utc and ts.tz is not UTC: + ts = ts.tz_localize(UTC) if ts.tz is None else ts.tz_convert(UTC) if ts.second or ts.microsecond or ts.nanosecond: if side is None and calendar is None: @@ -376,7 +376,7 @@ def parse_date( if ts.tz is not None: raise ValueError( - f"Parameter `{param_name}` received with timezone defined as '{ts.tz.zone}'" + f"Parameter `{param_name}` received with timezone defined as '{ts.tz.key}'" f" although a Date must be timezone naive." ) @@ -630,7 +630,6 @@ def _trading_index(self) -> np.ndarray: becoming unsynced with the corresponding left indices. """ if self.has_break: - # sessions with breaks index_am = self._create_index_for_sessions( self.opens[self.mask], @@ -680,7 +679,7 @@ def trading_index(self) -> pd.DatetimeIndex: index = self._trading_index() if self.has_break: index.sort() - index = pd.DatetimeIndex(index, tz=pytz.UTC) + index = pd.DatetimeIndex(index, tz=UTC) return self.curtail_for_times(index) @contextlib.contextmanager @@ -718,7 +717,7 @@ def trading_index_intervals(self) -> pd.IntervalIndex: else: raise errors.IntervalsOverlapError() - left = pd.DatetimeIndex(left, tz=pytz.UTC) - right = pd.DatetimeIndex(right, tz=pytz.UTC) + left = pd.DatetimeIndex(left, tz=UTC) + right = pd.DatetimeIndex(right, tz=UTC) index = pd.IntervalIndex.from_arrays(left, right, self.closed) return self.curtail_for_times(index) diff --git a/exchange_calendars/exchange_calendar.py b/exchange_calendars/exchange_calendar.py index a5dd4b95..de36366a 100644 --- a/exchange_calendars/exchange_calendar.py +++ b/exchange_calendars/exchange_calendar.py @@ -22,17 +22,17 @@ import operator from typing import TYPE_CHECKING, Literal, Any import warnings +from zoneinfo import ZoneInfo import numpy as np import pandas as pd import toolz from pandas.tseries.holiday import AbstractHolidayCalendar from pandas.tseries.offsets import CustomBusinessDay -import pytz -from pytz import UTC from exchange_calendars import errors from .calendar_helpers import ( + UTC, NANOSECONDS_PER_MINUTE, NP_NAT, Date, @@ -55,6 +55,7 @@ if TYPE_CHECKING: from pandas._libs.tslibs.nattype import NaTType + GLOBAL_DEFAULT_START = pd.Timestamp.now().floor("D") - pd.DateOffset(years=20) # Give an aggressive buffer for logic that needs to use the next trading # day or minute. @@ -84,7 +85,7 @@ def selection( def _group_times( sessions: pd.DatetimeIndex, times: None | Sequence[tuple[pd.Timestamp | None, datetime.time]], - tz: pytz.tzinfo.BaseTzInfo, + tz: ZoneInfo, offset: int = 0, ) -> pd.DatetimeIndex | None: """Evaluate standard times for a specific session bound. @@ -424,7 +425,7 @@ def _bound_max_error_msg(self, end: pd.Timestamp) -> str: @property @abstractmethod - def tz(self) -> pytz.tzinfo.BaseTzInfo: + def tz(self) -> ZoneInfo: """Calendar timezone.""" raise NotImplementedError() @@ -1475,8 +1476,8 @@ def is_open_at_time( f" got type {type(ts)}." ) - if ts.tz is not pytz.UTC: - ts = ts.tz_localize("UTC") if ts.tz is None else ts.tz_convert("UTC") + if ts.tz is not UTC: + ts = ts.tz_localize(UTC) if ts.tz is None else ts.tz_convert(UTC) if self._minute_oob(ts): raise errors.MinuteOutOfBounds(self, ts, "timestamp") @@ -2820,7 +2821,7 @@ def scheduled_special_times( start: pd.Timestamp, end: pd.Timestamp, time: datetime.time, - tz: pytz.tzinfo.BaseTzInfo, + tz: ZoneInfo, ) -> pd.Series: """Return map of dates to special times. diff --git a/exchange_calendars/exchange_calendar_aixk.py b/exchange_calendars/exchange_calendar_aixk.py index b4a32b1b..f0c8cbfa 100644 --- a/exchange_calendars/exchange_calendar_aixk.py +++ b/exchange_calendars/exchange_calendar_aixk.py @@ -1,5 +1,6 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import ( @@ -8,7 +9,6 @@ nearest_workday, next_workday, ) -import pytz from .common_holidays import new_years_day, eid_al_adha_first_day from .exchange_calendar import ( @@ -172,7 +172,7 @@ class AIXKExchangeCalendar(ExchangeCalendar): name = "AIXK" - tz = pytz.timezone("Asia/Almaty") + tz = ZoneInfo("Asia/Almaty") open_times = ((None, time(11)),) diff --git a/exchange_calendars/exchange_calendar_asex.py b/exchange_calendars/exchange_calendar_asex.py index 92bebd4e..7557eb86 100644 --- a/exchange_calendars/exchange_calendar_asex.py +++ b/exchange_calendars/exchange_calendar_asex.py @@ -15,10 +15,10 @@ from datetime import time, timedelta from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( assumption_day, @@ -102,7 +102,7 @@ class ASEXExchangeCalendar(ExchangeCalendar): name = "ASEX" - tz = timezone("Europe/Athens") + tz = ZoneInfo("Europe/Athens") open_times = ((None, time(10)),) diff --git a/exchange_calendars/exchange_calendar_bvmf.py b/exchange_calendars/exchange_calendar_bvmf.py index d1881256..cc985694 100644 --- a/exchange_calendars/exchange_calendar_bvmf.py +++ b/exchange_calendars/exchange_calendar_bvmf.py @@ -14,6 +14,7 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import ( @@ -23,7 +24,6 @@ Holiday, previous_friday, ) -from pytz import timezone from .common_holidays import corpus_christi from .exchange_calendar import HolidayCalendar, ExchangeCalendar @@ -174,7 +174,7 @@ class BVMFExchangeCalendar(ExchangeCalendar): name = "BVMF" - tz = timezone("America/Sao_Paulo") + tz = ZoneInfo("America/Sao_Paulo") regular_late_open = time(13) diff --git a/exchange_calendars/exchange_calendar_cmes.py b/exchange_calendars/exchange_calendar_cmes.py index faee8e31..86661c63 100644 --- a/exchange_calendars/exchange_calendar_cmes.py +++ b/exchange_calendars/exchange_calendar_cmes.py @@ -14,6 +14,7 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import ( GoodFriday, @@ -21,7 +22,6 @@ USPresidentsDay, USThanksgivingDay, ) -from pytz import timezone from .exchange_calendar import HolidayCalendar, ExchangeCalendar from .us_holidays import ( @@ -55,7 +55,7 @@ class CMESExchangeCalendar(ExchangeCalendar): name = "CMES" - tz = timezone("America/Chicago") + tz = ZoneInfo("America/Chicago") open_times = ((None, time(17)),) diff --git a/exchange_calendars/exchange_calendar_iepa.py b/exchange_calendars/exchange_calendar_iepa.py index 721397a4..2be6bdcc 100644 --- a/exchange_calendars/exchange_calendar_iepa.py +++ b/exchange_calendars/exchange_calendar_iepa.py @@ -1,5 +1,6 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo from pandas import Timestamp from pandas.tseries.holiday import ( @@ -8,7 +9,6 @@ USPresidentsDay, USThanksgivingDay, ) -from pytz import timezone from .exchange_calendar import ExchangeCalendar from exchange_calendars.exchange_calendar import HolidayCalendar @@ -34,7 +34,7 @@ class IEPAExchangeCalendar(ExchangeCalendar): name = "IEPA" - tz = timezone("America/New_York") + tz = ZoneInfo("America/New_York") open_times = ((None, time(20)),) diff --git a/exchange_calendars/exchange_calendar_xams.py b/exchange_calendars/exchange_calendar_xams.py index 5336a938..cee28217 100644 --- a/exchange_calendars/exchange_calendar_xams.py +++ b/exchange_calendars/exchange_calendar_xams.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( ascension_day, @@ -85,7 +85,7 @@ class XAMSExchangeCalendar(ExchangeCalendar): regular_early_close = time(14, 5) name = "XAMS" # Euronext Amsterdam - tz = timezone("Europe/Amsterdam") + tz = ZoneInfo("Europe/Amsterdam") open_times = ((None, time(9)),) close_times = ((None, time(17, 30)),) diff --git a/exchange_calendars/exchange_calendar_xasx.py b/exchange_calendars/exchange_calendar_xasx.py index 9954077e..cae7e298 100644 --- a/exchange_calendars/exchange_calendar_xasx.py +++ b/exchange_calendars/exchange_calendar_xasx.py @@ -14,6 +14,7 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from dateutil.relativedelta import MO from pandas import DateOffset, Timestamp @@ -25,7 +26,6 @@ sunday_to_monday, weekend_to_monday, ) -from pytz import timezone from .common_holidays import ( anzac_day, @@ -163,7 +163,7 @@ class XASXExchangeCalendar(ExchangeCalendar): name = "XASX" - tz = timezone("Australia/Sydney") + tz = ZoneInfo("Australia/Sydney") open_times = ((None, time(10)),) # Zipline compatability (10,1); else (10,0) diff --git a/exchange_calendars/exchange_calendar_xbkk.py b/exchange_calendars/exchange_calendar_xbkk.py index d7b12502..47d132c2 100644 --- a/exchange_calendars/exchange_calendar_xbkk.py +++ b/exchange_calendars/exchange_calendar_xbkk.py @@ -15,8 +15,7 @@ from datetime import time from itertools import chain - -from pytz import timezone +from zoneinfo import ZoneInfo from .exchange_calendar import HolidayCalendar, ExchangeCalendar from .xbkk_holidays import ( @@ -80,7 +79,7 @@ class XBKKExchangeCalendar(ExchangeCalendar): name = "XBKK" - tz = timezone("Asia/Bangkok") + tz = ZoneInfo("Asia/Bangkok") open_times = ((None, time(10)),) diff --git a/exchange_calendars/exchange_calendar_xbog.py b/exchange_calendars/exchange_calendar_xbog.py index 41ed5144..7b70d386 100644 --- a/exchange_calendars/exchange_calendar_xbog.py +++ b/exchange_calendars/exchange_calendar_xbog.py @@ -14,6 +14,7 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import ( MO, @@ -24,7 +25,6 @@ previous_friday, ) from pandas.tseries.offsets import Day -from pytz import timezone from .common_holidays import ( christmas, @@ -162,7 +162,7 @@ class XBOGExchangeCalendar(ExchangeCalendar): # Though Bogota uses Colombia Standard Time, XBOG uses # US Eastern for trading times - tz = timezone("America/New_York") + tz = ZoneInfo("America/New_York") open_times = ((None, time(9, 30)),) diff --git a/exchange_calendars/exchange_calendar_xbom.py b/exchange_calendars/exchange_calendar_xbom.py index 5f4206e0..0cca9ee6 100644 --- a/exchange_calendars/exchange_calendar_xbom.py +++ b/exchange_calendars/exchange_calendar_xbom.py @@ -1,7 +1,7 @@ from datetime import time +from zoneinfo import ZoneInfo import pandas as pd -from pytz import timezone from .precomputed_exchange_calendar import PrecomputedExchangeCalendar @@ -435,7 +435,7 @@ class XBOMExchangeCalendar(PrecomputedExchangeCalendar): """ name = "XBOM" - tz = timezone("Asia/Calcutta") + tz = ZoneInfo("Asia/Calcutta") open_times = ((None, time(9, 15)),) close_times = ((None, time(15, 30)),) diff --git a/exchange_calendars/exchange_calendar_xbru.py b/exchange_calendars/exchange_calendar_xbru.py index d06cfada..f8292811 100644 --- a/exchange_calendars/exchange_calendar_xbru.py +++ b/exchange_calendars/exchange_calendar_xbru.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( ascension_day, @@ -85,7 +85,7 @@ class XBRUExchangeCalendar(ExchangeCalendar): regular_early_close = time(14, 5) name = "XBRU" # Euronext Brussels - tz = timezone("Europe/Brussels") + tz = ZoneInfo("Europe/Brussels") open_times = ((None, time(9)),) close_times = ((None, time(17, 30)),) diff --git a/exchange_calendars/exchange_calendar_xbse.py b/exchange_calendars/exchange_calendar_xbse.py index 081c476b..bc269c2f 100644 --- a/exchange_calendars/exchange_calendar_xbse.py +++ b/exchange_calendars/exchange_calendar_xbse.py @@ -1,8 +1,8 @@ from datetime import time, timedelta from itertools import chain +from zoneinfo import ZoneInfo from pandas.tseries.holiday import Holiday -from pytz import timezone from .common_holidays import ( christmas, @@ -91,7 +91,7 @@ class XBSEExchangeCalendar(ExchangeCalendar): name = "XBSE" - tz = timezone("Europe/Bucharest") + tz = ZoneInfo("Europe/Bucharest") open_times = ((None, time(10)),) diff --git a/exchange_calendars/exchange_calendar_xbud.py b/exchange_calendars/exchange_calendar_xbud.py index 4302abe5..0c89ede1 100644 --- a/exchange_calendars/exchange_calendar_xbud.py +++ b/exchange_calendars/exchange_calendar_xbud.py @@ -16,10 +16,10 @@ from __future__ import annotations import datetime +from zoneinfo import ZoneInfo from pandas.tseries.holiday import Easter, EasterMonday, Holiday from pandas.tseries.offsets import Day -from pytz import timezone from .common_holidays import ( all_saints_day, @@ -150,7 +150,7 @@ class XBUDExchangeCalendar(ExchangeCalendar): name = "XBUD" - tz = timezone("Europe/Budapest") + tz = ZoneInfo("Europe/Budapest") open_times = ((None, datetime.time(9)),) diff --git a/exchange_calendars/exchange_calendar_xbue.py b/exchange_calendars/exchange_calendar_xbue.py index 8031ddb6..072af9e1 100644 --- a/exchange_calendars/exchange_calendar_xbue.py +++ b/exchange_calendars/exchange_calendar_xbue.py @@ -17,11 +17,11 @@ import datetime from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import MO, Easter, GoodFriday, Holiday from pandas.tseries.offsets import Day -from pytz import timezone from .common_holidays import ( christmas, @@ -252,7 +252,7 @@ class XBUEExchangeCalendar(ExchangeCalendar): name = "XBUE" - tz = timezone("America/Argentina/Buenos_Aires") + tz = ZoneInfo("America/Argentina/Buenos_Aires") open_times = ((None, datetime.time(11)),) diff --git a/exchange_calendars/exchange_calendar_xcbf.py b/exchange_calendars/exchange_calendar_xcbf.py index 88554df3..90651909 100644 --- a/exchange_calendars/exchange_calendar_xcbf.py +++ b/exchange_calendars/exchange_calendar_xcbf.py @@ -1,5 +1,6 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo from pandas.tseries.holiday import ( GoodFriday, @@ -7,7 +8,6 @@ USPresidentsDay, USThanksgivingDay, ) -from pytz import timezone from .exchange_calendar import ExchangeCalendar from exchange_calendars.exchange_calendar import HolidayCalendar @@ -20,7 +20,7 @@ USMemorialDay, USNationalDaysofMourning, USNewYearsDay, - USJuneteenth + USJuneteenth, ) @@ -38,7 +38,7 @@ class XCBFExchangeCalendar(ExchangeCalendar): name = "XCBF" - tz = timezone("America/Chicago") + tz = ZoneInfo("America/Chicago") open_times = ((None, time(8, 30)),) diff --git a/exchange_calendars/exchange_calendar_xcse.py b/exchange_calendars/exchange_calendar_xcse.py index 7852d84f..ff0f55ea 100644 --- a/exchange_calendars/exchange_calendar_xcse.py +++ b/exchange_calendars/exchange_calendar_xcse.py @@ -14,10 +14,10 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import Easter, EasterMonday, GoodFriday, Holiday from pandas.tseries.offsets import Day -from pytz import timezone from .common_holidays import ( ascension_day, @@ -86,7 +86,7 @@ class XCSEExchangeCalendar(ExchangeCalendar): """ name = "XCSE" - tz = timezone("Europe/Copenhagen") + tz = ZoneInfo("Europe/Copenhagen") open_times = ((None, time(9)),) close_times = ((None, time(17)),) diff --git a/exchange_calendars/exchange_calendar_xdub.py b/exchange_calendars/exchange_calendar_xdub.py index 9b6c7684..a634a6f5 100644 --- a/exchange_calendars/exchange_calendar_xdub.py +++ b/exchange_calendars/exchange_calendar_xdub.py @@ -14,6 +14,7 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import ( @@ -25,7 +26,6 @@ previous_friday, weekend_to_monday, ) -import pytz from .common_holidays import ( boxing_day, @@ -128,7 +128,7 @@ class XDUBExchangeCalendar(ExchangeCalendar): """ name = "XDUB" - tz = pytz.timezone("Europe/Dublin") + tz = ZoneInfo("Europe/Dublin") open_times = ((None, time(8)),) close_times = ((None, time(16, 28)),) regular_early_close = time(12, 28) diff --git a/exchange_calendars/exchange_calendar_xetr.py b/exchange_calendars/exchange_calendar_xetr.py index c03490f8..84e0be2f 100644 --- a/exchange_calendars/exchange_calendar_xetr.py +++ b/exchange_calendars/exchange_calendar_xetr.py @@ -14,10 +14,10 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas import Timestamp from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday, previous_workday -from pytz import timezone from .common_holidays import ( boxing_day, @@ -45,7 +45,11 @@ WhitMondayUntil2022 = whit_monday(start_date="2015-01-01", end_date="2022-01-01") DayOfGermanUnityUntil2022 = Holiday( - "Day of German Unity", month=10, day=3, start_date="2014-01-01", end_date="2022-01-01" + "Day of German Unity", + month=10, + day=3, + start_date="2014-01-01", + end_date="2022-01-01", ) # Reformation Day was a German national holiday in 2017. @@ -99,7 +103,7 @@ class XETRExchangeCalendar(ExchangeCalendar): name = "XETR" - tz = timezone("CET") + tz = ZoneInfo("CET") open_times = ((None, time(9)),) diff --git a/exchange_calendars/exchange_calendar_xfra.py b/exchange_calendars/exchange_calendar_xfra.py index 8c1dc5ca..c5e84a9e 100644 --- a/exchange_calendars/exchange_calendar_xfra.py +++ b/exchange_calendars/exchange_calendar_xfra.py @@ -14,10 +14,10 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas import Timestamp from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday, previous_workday -from pytz import timezone from .common_holidays import ( boxing_day, @@ -45,7 +45,11 @@ WhitMondayUntil2022 = whit_monday(start_date="2015-01-01", end_date="2022-01-01") DayOfGermanUnityUntil2022 = Holiday( - "Day of German Unity", month=10, day=3, start_date="2014-01-01", end_date="2022-01-01" + "Day of German Unity", + month=10, + day=3, + start_date="2014-01-01", + end_date="2022-01-01", ) # Reformation Day was a German national holiday in 2017. @@ -98,7 +102,7 @@ class XFRAExchangeCalendar(ExchangeCalendar): name = "XFRA" - tz = timezone("CET") + tz = ZoneInfo("CET") open_times = ((None, time(9)),) diff --git a/exchange_calendars/exchange_calendar_xhel.py b/exchange_calendars/exchange_calendar_xhel.py index 498b6278..9fbd975c 100644 --- a/exchange_calendars/exchange_calendar_xhel.py +++ b/exchange_calendars/exchange_calendar_xhel.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( ascension_day, @@ -76,7 +76,7 @@ class XHELExchangeCalendar(ExchangeCalendar): """ name = "XHEL" - tz = timezone("Europe/Helsinki") + tz = ZoneInfo("Europe/Helsinki") open_times = ((None, time(10)),) close_times = ((None, time(18, 30)),) diff --git a/exchange_calendars/exchange_calendar_xhkg.py b/exchange_calendars/exchange_calendar_xhkg.py index 872f52d4..5b88e24c 100644 --- a/exchange_calendars/exchange_calendar_xhkg.py +++ b/exchange_calendars/exchange_calendar_xhkg.py @@ -16,13 +16,13 @@ from datetime import time, timedelta from itertools import chain +from zoneinfo import ZoneInfo import numpy as np import pandas as pd import toolz from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday, sunday_to_monday from pandas.tseries.offsets import LastWeekOfMonth, WeekOfMonth -import pytz from .common_holidays import ( boxing_day, @@ -231,9 +231,7 @@ def process_queen_birthday(dt): # which means the day after is a Sunday. In 2022, HKSE had a holiday # on the Monday (2022-09-12). In the past they don't seem to have followed # this pattern. We'll have to wait and see before we generalise this into a rule. - pd.Timestamp( - "2022-09-12" - ) + pd.Timestamp("2022-09-12"), ] @@ -279,7 +277,7 @@ class XHKGExchangeCalendar(PrecomputedExchangeCalendar): """ name = "XHKG" - tz = pytz.timezone("Asia/Hong_Kong") + tz = ZoneInfo("Asia/Hong_Kong") open_times = ( (None, time(10)), diff --git a/exchange_calendars/exchange_calendar_xice.py b/exchange_calendars/exchange_calendar_xice.py index d54b1d30..e1a3c565 100644 --- a/exchange_calendars/exchange_calendar_xice.py +++ b/exchange_calendars/exchange_calendar_xice.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import MO, TH, DateOffset, EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( ascension_day, @@ -92,7 +92,7 @@ class XICEExchangeCalendar(ExchangeCalendar): """ name = "XICE" - tz = timezone("Atlantic/Reykjavik") + tz = ZoneInfo("Atlantic/Reykjavik") open_times = ((None, time(9, 30)),) close_times = ((None, time(15, 30)),) diff --git a/exchange_calendars/exchange_calendar_xidx.py b/exchange_calendars/exchange_calendar_xidx.py index 4b835dbc..f9667a60 100644 --- a/exchange_calendars/exchange_calendar_xidx.py +++ b/exchange_calendars/exchange_calendar_xidx.py @@ -15,10 +15,10 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import GoodFriday, Holiday -from pytz import timezone from .common_holidays import ascension_day, christmas, new_years_day, new_years_eve from .lunisolar_holidays import chinese_lunar_new_year_dates @@ -56,7 +56,7 @@ class XIDXExchangeCalendar(ExchangeCalendar): name = "XIDX" - tz = timezone("Asia/Jakarta") + tz = ZoneInfo("Asia/Jakarta") open_times = ((None, time(9)),) diff --git a/exchange_calendars/exchange_calendar_xist.py b/exchange_calendars/exchange_calendar_xist.py index 0014ab73..b84d5c37 100644 --- a/exchange_calendars/exchange_calendar_xist.py +++ b/exchange_calendars/exchange_calendar_xist.py @@ -15,10 +15,10 @@ from datetime import time, timedelta from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import Holiday -import pytz from .common_holidays import ( eid_al_adha_first_day, @@ -117,7 +117,7 @@ class XISTExchangeCalendar(ExchangeCalendar): name = "XIST" - tz = pytz.timezone("Europe/Istanbul") + tz = ZoneInfo("Europe/Istanbul") open_times = ((None, time(10)),) diff --git a/exchange_calendars/exchange_calendar_xjse.py b/exchange_calendars/exchange_calendar_xjse.py index eaa69140..139c116c 100644 --- a/exchange_calendars/exchange_calendar_xjse.py +++ b/exchange_calendars/exchange_calendar_xjse.py @@ -14,11 +14,11 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas import Timestamp from pandas.tseries.holiday import Easter, GoodFriday, Holiday, sunday_to_monday from pandas.tseries.offsets import Day -from pytz import timezone from .common_holidays import new_years_day from .exchange_calendar import HolidayCalendar, ExchangeCalendar @@ -55,7 +55,7 @@ class XJSEExchangeCalendar(ExchangeCalendar): name = "XJSE" - tz = timezone("Africa/Johannesburg") + tz = ZoneInfo("Africa/Johannesburg") open_times = ((None, time(9)),) diff --git a/exchange_calendars/exchange_calendar_xkar.py b/exchange_calendars/exchange_calendar_xkar.py index ec568f98..6ea9ef7f 100644 --- a/exchange_calendars/exchange_calendar_xkar.py +++ b/exchange_calendars/exchange_calendar_xkar.py @@ -15,10 +15,10 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import Holiday -from pytz import timezone from .common_holidays import european_labour_day from .exchange_calendar import HolidayCalendar, ExchangeCalendar @@ -54,7 +54,7 @@ class XKARExchangeCalendar(ExchangeCalendar): name = "XKAR" - tz = timezone("Asia/Karachi") + tz = ZoneInfo("Asia/Karachi") # NOTE: The Pakistan Stock Exchange is open from 09:32-15:30 # Monday-Thursday, and from 09:17-12:00 AND 14:32-16:30 on Friday diff --git a/exchange_calendars/exchange_calendar_xkls.py b/exchange_calendars/exchange_calendar_xkls.py index 0b65a381..609a9cdf 100644 --- a/exchange_calendars/exchange_calendar_xkls.py +++ b/exchange_calendars/exchange_calendar_xkls.py @@ -15,9 +15,9 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd -import pytz from .exchange_calendar import HolidayCalendar, ExchangeCalendar from .xkls_holidays import ( @@ -78,7 +78,7 @@ class XKLSExchangeCalendar(ExchangeCalendar): name = "XKLS" - tz = pytz.timezone("Asia/Kuala_Lumpur") + tz = ZoneInfo("Asia/Kuala_Lumpur") open_times = ((None, time(9)),) @@ -101,7 +101,6 @@ def regular_holidays(self): @property def adhoc_holidays(self): - return list( chain( misc_adhoc, diff --git a/exchange_calendars/exchange_calendar_xkrx.py b/exchange_calendars/exchange_calendar_xkrx.py index 641d5f65..846e79b2 100644 --- a/exchange_calendars/exchange_calendar_xkrx.py +++ b/exchange_calendars/exchange_calendar_xkrx.py @@ -16,11 +16,11 @@ from datetime import time import functools +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import Holiday from pandas.tseries.offsets import CustomBusinessDay -import pytz from .exchange_calendar import HolidayCalendar from .precomputed_exchange_calendar import PrecomputedExchangeCalendar @@ -65,7 +65,7 @@ class XKRXExchangeCalendar(PrecomputedExchangeCalendar): name = "XKRX" - tz = pytz.timezone("Asia/Seoul") + tz = ZoneInfo("Asia/Seoul") # KRX schedule change history # https://blog.naver.com/daishin_blog/220724111002 @@ -396,7 +396,7 @@ class PrecomputedXKRXExchangeCalendar(PrecomputedExchangeCalendar): name = "XKRX" - tz = pytz.timezone("Asia/Seoul") + tz = ZoneInfo("Asia/Seoul") open_times = ((None, time(9)),) close_times = ((None, time(15, 30)),) diff --git a/exchange_calendars/exchange_calendar_xlim.py b/exchange_calendars/exchange_calendar_xlim.py index 47aba851..767558eb 100644 --- a/exchange_calendars/exchange_calendar_xlim.py +++ b/exchange_calendars/exchange_calendar_xlim.py @@ -15,10 +15,10 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( all_saints_day, @@ -114,7 +114,7 @@ class XLIMExchangeCalendar(ExchangeCalendar): """ name = "XLIM" - tz = timezone("America/Lima") + tz = ZoneInfo("America/Lima") open_times = ((None, time(9)),) close_times = ((None, time(16)),) diff --git a/exchange_calendars/exchange_calendar_xlis.py b/exchange_calendars/exchange_calendar_xlis.py index 53b1b7c8..c9498895 100644 --- a/exchange_calendars/exchange_calendar_xlis.py +++ b/exchange_calendars/exchange_calendar_xlis.py @@ -14,10 +14,10 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import Easter, EasterMonday, GoodFriday, Holiday from pandas.tseries.offsets import Day -from pytz import timezone from .common_holidays import ( all_saints_day, @@ -126,7 +126,7 @@ class XLISExchangeCalendar(ExchangeCalendar): regular_early_close = time(13, 5) name = "XLIS" # Euronext Lisbon - tz = timezone("Europe/Lisbon") + tz = ZoneInfo("Europe/Lisbon") open_times = ((None, time(8)),) close_times = ((None, time(16, 30)),) diff --git a/exchange_calendars/exchange_calendar_xlon.py b/exchange_calendars/exchange_calendar_xlon.py index 14dd4c2e..4e613b49 100644 --- a/exchange_calendars/exchange_calendar_xlon.py +++ b/exchange_calendars/exchange_calendar_xlon.py @@ -14,6 +14,7 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import ( @@ -25,7 +26,6 @@ previous_friday, weekend_to_monday, ) -from pytz import timezone from .common_holidays import ( boxing_day, @@ -188,7 +188,7 @@ class XLONExchangeCalendar(ExchangeCalendar): name = "XLON" - tz = timezone("Europe/London") + tz = ZoneInfo("Europe/London") open_times = ((None, time(8)),) diff --git a/exchange_calendars/exchange_calendar_xmad.py b/exchange_calendars/exchange_calendar_xmad.py index 52812825..b833dec9 100644 --- a/exchange_calendars/exchange_calendar_xmad.py +++ b/exchange_calendars/exchange_calendar_xmad.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday, weekend_to_monday -from pytz import timezone from .common_holidays import ( all_saints_day, @@ -111,7 +111,7 @@ class XMADExchangeCalendar(ExchangeCalendar): name = "XMAD" - tz = timezone("Europe/Madrid") + tz = ZoneInfo("Europe/Madrid") open_times = ((None, time(9)),) @@ -136,7 +136,7 @@ def regular_holidays(self): Christmas, BoxingDay, NewYearsEveThrough2010, - NewYearsEveFrom2021 + NewYearsEveFrom2021, ] ) diff --git a/exchange_calendars/exchange_calendar_xmex.py b/exchange_calendars/exchange_calendar_xmex.py index 6b7a3501..619e19ca 100644 --- a/exchange_calendars/exchange_calendar_xmex.py +++ b/exchange_calendars/exchange_calendar_xmex.py @@ -14,11 +14,11 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import MO, GoodFriday, Holiday from pandas.tseries.offsets import DateOffset -from pytz import timezone from .common_holidays import ( christmas, @@ -102,7 +102,7 @@ class XMEXExchangeCalendar(ExchangeCalendar): """ name = "XMEX" - tz = timezone("America/Mexico_City") + tz = ZoneInfo("America/Mexico_City") open_times = ((None, time(8, 30)),) close_times = ((None, time(15)),) diff --git a/exchange_calendars/exchange_calendar_xmil.py b/exchange_calendars/exchange_calendar_xmil.py index d49689ec..96521e33 100644 --- a/exchange_calendars/exchange_calendar_xmil.py +++ b/exchange_calendars/exchange_calendar_xmil.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( boxing_day, @@ -66,7 +66,7 @@ class XMILExchangeCalendar(ExchangeCalendar): name = "XMIL" # Rome is the same timezone as Milan. - tz = timezone("Europe/Rome") + tz = ZoneInfo("Europe/Rome") open_times = ((None, time(9)),) diff --git a/exchange_calendars/exchange_calendar_xmos.py b/exchange_calendars/exchange_calendar_xmos.py index 93b1e532..4a237acc 100644 --- a/exchange_calendars/exchange_calendar_xmos.py +++ b/exchange_calendars/exchange_calendar_xmos.py @@ -17,9 +17,9 @@ import datetime from itertools import chain +from zoneinfo import ZoneInfo from pandas.tseries.holiday import Holiday, weekend_to_monday -from pytz import timezone from .common_holidays import european_labour_day, new_years_day, new_years_eve from .exchange_calendar import WEEKDAYS, HolidayCalendar, ExchangeCalendar @@ -249,7 +249,7 @@ class XMOSExchangeCalendar(ExchangeCalendar): name = "XMOS" - tz = timezone("Europe/Moscow") + tz = ZoneInfo("Europe/Moscow") open_times = ((None, datetime.time(10)),) diff --git a/exchange_calendars/exchange_calendar_xnys.py b/exchange_calendars/exchange_calendar_xnys.py index 4ccd2f39..f8b61028 100644 --- a/exchange_calendars/exchange_calendar_xnys.py +++ b/exchange_calendars/exchange_calendar_xnys.py @@ -15,10 +15,10 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo from pandas import DatetimeIndex from pandas.tseries.holiday import GoodFriday, USLaborDay -import pytz from .exchange_calendar import HolidayCalendar, ExchangeCalendar from .us_holidays import ( @@ -157,7 +157,7 @@ class XNYSExchangeCalendar(ExchangeCalendar): name = "XNYS" - tz = pytz.timezone("America/New_York") + tz = ZoneInfo("America/New_York") open_times = ((None, time(9, 30)),) diff --git a/exchange_calendars/exchange_calendar_xnze.py b/exchange_calendars/exchange_calendar_xnze.py index ecbc426e..100100b2 100644 --- a/exchange_calendars/exchange_calendar_xnze.py +++ b/exchange_calendars/exchange_calendar_xnze.py @@ -18,6 +18,7 @@ # http://www.TeAra.govt.nz/en/public-holidays/print (accessed 22 December 2019) from datetime import time +from zoneinfo import ZoneInfo from pandas import Timestamp from pandas.tseries.holiday import ( @@ -31,7 +32,6 @@ previous_workday, weekend_to_monday, ) -from pytz import timezone from .common_holidays import anzac_day, boxing_day, christmas, new_years_day from .exchange_calendar import HolidayCalendar, ExchangeCalendar @@ -185,7 +185,7 @@ class XNZEExchangeCalendar(ExchangeCalendar): name = "XNZE" - tz = timezone("NZ") + tz = ZoneInfo("NZ") open_times = ((None, time(10)),) @@ -225,7 +225,7 @@ def adhoc_holidays(self): XMAS27DEC91, NYDX03JAN92, XMAS31DEC99, - QueenMourning2022 + QueenMourning2022, ] dates += MatarikiDayDates.values() return dates diff --git a/exchange_calendars/exchange_calendar_xosl.py b/exchange_calendars/exchange_calendar_xosl.py index b17af942..1ff2978d 100644 --- a/exchange_calendars/exchange_calendar_xosl.py +++ b/exchange_calendars/exchange_calendar_xosl.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( ascension_day, @@ -76,7 +76,7 @@ class XOSLExchangeCalendar(ExchangeCalendar): """ name = "XOSL" - tz = timezone("Europe/Oslo") + tz = ZoneInfo("Europe/Oslo") open_times = ((None, time(9)),) close_times = ((None, time(16, 20)),) regular_early_close = time(13) diff --git a/exchange_calendars/exchange_calendar_xpar.py b/exchange_calendars/exchange_calendar_xpar.py index b2fcb634..8325061f 100644 --- a/exchange_calendars/exchange_calendar_xpar.py +++ b/exchange_calendars/exchange_calendar_xpar.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( boxing_day, @@ -83,7 +83,7 @@ class XPARExchangeCalendar(ExchangeCalendar): regular_early_close = time(14, 5) name = "XPAR" # Euronext Paris - tz = timezone("Europe/Paris") + tz = ZoneInfo("Europe/Paris") open_times = ((None, time(9)),) close_times = ((None, time(17, 30)),) diff --git a/exchange_calendars/exchange_calendar_xphs.py b/exchange_calendars/exchange_calendar_xphs.py index 5bdbafb1..7c4c9a34 100644 --- a/exchange_calendars/exchange_calendar_xphs.py +++ b/exchange_calendars/exchange_calendar_xphs.py @@ -17,10 +17,10 @@ import datetime from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import MO, DateOffset, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( all_saints_day, @@ -193,7 +193,7 @@ class XPHSExchangeCalendar(ExchangeCalendar): name = "XPHS" - tz = timezone("Asia/Manila") + tz = ZoneInfo("Asia/Manila") open_times = ((None, datetime.time(9, 30)),) diff --git a/exchange_calendars/exchange_calendar_xpra.py b/exchange_calendars/exchange_calendar_xpra.py index 15647846..27027e56 100644 --- a/exchange_calendars/exchange_calendar_xpra.py +++ b/exchange_calendars/exchange_calendar_xpra.py @@ -14,11 +14,11 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import Easter, EasterMonday, Holiday from pandas.tseries.offsets import Day -from pytz import timezone from .common_holidays import ( christmas, @@ -116,7 +116,7 @@ class XPRAExchangeCalendar(ExchangeCalendar): name = "XPRA" - tz = timezone("Europe/Prague") + tz = ZoneInfo("Europe/Prague") open_times = ((None, time(9)),) diff --git a/exchange_calendars/exchange_calendar_xsau.py b/exchange_calendars/exchange_calendar_xsau.py index ab49bdff..9df30eab 100644 --- a/exchange_calendars/exchange_calendar_xsau.py +++ b/exchange_calendars/exchange_calendar_xsau.py @@ -1,8 +1,8 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd -import pytz from pandas.tseries.holiday import Holiday from exchange_calendars.exchange_calendar import ExchangeCalendar, HolidayCalendar @@ -73,7 +73,7 @@ class XSAUExchangeCalendar(ExchangeCalendar): name = "XSAU" - tz = pytz.timezone("Asia/Riyadh") + tz = ZoneInfo("Asia/Riyadh") open_times = ((None, time(10)),) diff --git a/exchange_calendars/exchange_calendar_xses.py b/exchange_calendars/exchange_calendar_xses.py index 27236bdd..2c9c5c47 100644 --- a/exchange_calendars/exchange_calendar_xses.py +++ b/exchange_calendars/exchange_calendar_xses.py @@ -1,7 +1,7 @@ from datetime import time +from zoneinfo import ZoneInfo import pandas as pd -from pytz import timezone from .precomputed_exchange_calendar import PrecomputedExchangeCalendar @@ -412,7 +412,7 @@ class XSESExchangeCalendar(PrecomputedExchangeCalendar): """ name = "XSES" - tz = timezone("Asia/Singapore") + tz = ZoneInfo("Asia/Singapore") open_times = ((None, time(9)),) close_times = ((None, time(17, 0)),) diff --git a/exchange_calendars/exchange_calendar_xsgo.py b/exchange_calendars/exchange_calendar_xsgo.py index adde7e9c..a6e236ec 100644 --- a/exchange_calendars/exchange_calendar_xsgo.py +++ b/exchange_calendars/exchange_calendar_xsgo.py @@ -16,11 +16,11 @@ from __future__ import annotations import datetime +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import Easter, GoodFriday, Holiday from pandas.tseries.offsets import Day -from pytz import timezone from .common_holidays import ( all_saints_day, @@ -205,7 +205,7 @@ class XSGOExchangeCalendar(ExchangeCalendar): """ name = "XSGO" - tz = timezone("America/Santiago") + tz = ZoneInfo("America/Santiago") open_times = ((None, datetime.time(9, 30)),) early_close_1230 = datetime.time(12, 30) diff --git a/exchange_calendars/exchange_calendar_xshg.py b/exchange_calendars/exchange_calendar_xshg.py index 8ffad79f..c8e26fe0 100644 --- a/exchange_calendars/exchange_calendar_xshg.py +++ b/exchange_calendars/exchange_calendar_xshg.py @@ -1,7 +1,7 @@ from datetime import time +from zoneinfo import ZoneInfo import pandas as pd -import pytz from .precomputed_exchange_calendar import PrecomputedExchangeCalendar @@ -596,7 +596,7 @@ class XSHGExchangeCalendar(PrecomputedExchangeCalendar): """ name = "XSHG" - tz = pytz.timezone("Asia/Shanghai") + tz = ZoneInfo("Asia/Shanghai") open_times = ((None, time(9, 30)),) break_start_times = ((None, time(11, 30)),) break_end_times = ((None, time(13, 0)),) diff --git a/exchange_calendars/exchange_calendar_xsto.py b/exchange_calendars/exchange_calendar_xsto.py index 3d18a018..1fc85ca6 100644 --- a/exchange_calendars/exchange_calendar_xsto.py +++ b/exchange_calendars/exchange_calendar_xsto.py @@ -14,6 +14,7 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import ( FR, @@ -24,7 +25,6 @@ Holiday, ) from pandas.tseries.offsets import Day -from pytz import timezone from .common_holidays import ( ascension_day, @@ -121,7 +121,7 @@ class XSTOExchangeCalendar(ExchangeCalendar): """ name = "XSTO" - tz = timezone("Europe/Stockholm") + tz = ZoneInfo("Europe/Stockholm") open_times = ((None, time(9, 0)),) close_times = ((None, time(17, 30)),) regular_early_close = time(13) diff --git a/exchange_calendars/exchange_calendar_xswx.py b/exchange_calendars/exchange_calendar_xswx.py index ce27568a..d9949170 100644 --- a/exchange_calendars/exchange_calendar_xswx.py +++ b/exchange_calendars/exchange_calendar_xswx.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( ascension_day, @@ -81,7 +81,7 @@ class XSWXExchangeCalendar(ExchangeCalendar): name = "XSWX" - tz = timezone("Europe/Zurich") + tz = ZoneInfo("Europe/Zurich") open_times = ((None, time(9, 0)),) diff --git a/exchange_calendars/exchange_calendar_xtae.py b/exchange_calendars/exchange_calendar_xtae.py index 51ee2405..9e8c25e0 100644 --- a/exchange_calendars/exchange_calendar_xtae.py +++ b/exchange_calendars/exchange_calendar_xtae.py @@ -14,9 +14,9 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo import pandas as pd -import pytz from .tase_holidays import ( FastDay, @@ -101,7 +101,7 @@ class XTAEExchangeCalendar(ExchangeCalendar): name = "XTAE" - tz = pytz.timezone("Asia/Tel_Aviv") + tz = ZoneInfo("Asia/Tel_Aviv") open_times = ((None, time(9, 59)),) diff --git a/exchange_calendars/exchange_calendar_xtai.py b/exchange_calendars/exchange_calendar_xtai.py index bb866049..e39675c8 100644 --- a/exchange_calendars/exchange_calendar_xtai.py +++ b/exchange_calendars/exchange_calendar_xtai.py @@ -17,6 +17,7 @@ import datetime from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import ( @@ -25,7 +26,6 @@ next_monday, previous_friday, ) -from pytz import timezone from .common_holidays import european_labour_day, new_years_day from .lunisolar_holidays import ( @@ -340,7 +340,7 @@ class XTAIExchangeCalendar(ExchangeCalendar): name = "XTAI" - tz = timezone("Asia/Taipei") + tz = ZoneInfo("Asia/Taipei") open_times = ((None, datetime.time(9)),) diff --git a/exchange_calendars/exchange_calendar_xtks.py b/exchange_calendars/exchange_calendar_xtks.py index 9df025a0..d04802d2 100644 --- a/exchange_calendars/exchange_calendar_xtks.py +++ b/exchange_calendars/exchange_calendar_xtks.py @@ -1,8 +1,8 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd -import pytz from .exchange_calendar import HolidayCalendar, ExchangeCalendar from .xtks_holidays import ( @@ -80,7 +80,7 @@ class XTKSExchangeCalendar(ExchangeCalendar): name = "XTKS" - tz = pytz.timezone("Asia/Tokyo") + tz = ZoneInfo("Asia/Tokyo") open_times = ((None, time(9)),) break_start_times = ((None, time(11, 30)),) diff --git a/exchange_calendars/exchange_calendar_xtse.py b/exchange_calendars/exchange_calendar_xtse.py index 3bc5c4fb..b1c24edf 100644 --- a/exchange_calendars/exchange_calendar_xtse.py +++ b/exchange_calendars/exchange_calendar_xtse.py @@ -1,5 +1,6 @@ from datetime import time from itertools import chain +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import ( @@ -9,7 +10,6 @@ Holiday, weekend_to_monday, ) -from pytz import timezone from .common_holidays import ( boxing_day, @@ -127,7 +127,7 @@ class XTSEExchangeCalendar(ExchangeCalendar): name = "XTSE" - tz = timezone("America/Toronto") + tz = ZoneInfo("America/Toronto") open_times = ((None, time(9, 30)),) diff --git a/exchange_calendars/exchange_calendar_xwar.py b/exchange_calendars/exchange_calendar_xwar.py index 21e87281..3b79527f 100644 --- a/exchange_calendars/exchange_calendar_xwar.py +++ b/exchange_calendars/exchange_calendar_xwar.py @@ -16,10 +16,10 @@ from __future__ import annotations import datetime +from zoneinfo import ZoneInfo import pandas as pd from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday -from pytz import timezone from .common_holidays import ( all_saints_day, @@ -110,7 +110,7 @@ class XWARExchangeCalendar(ExchangeCalendar): name = "XWAR" - tz = timezone("Europe/Warsaw") + tz = ZoneInfo("Europe/Warsaw") open_times = ((None, datetime.time(9)),) close_times = ((None, datetime.time(17)),) diff --git a/exchange_calendars/exchange_calendar_xwbo.py b/exchange_calendars/exchange_calendar_xwbo.py index e46d8b7a..1c34671f 100644 --- a/exchange_calendars/exchange_calendar_xwbo.py +++ b/exchange_calendars/exchange_calendar_xwbo.py @@ -14,6 +14,7 @@ # limitations under the License. from datetime import time +from zoneinfo import ZoneInfo from pandas.tseries.holiday import ( EasterMonday, @@ -22,7 +23,6 @@ previous_friday, previous_workday, ) -from pytz import timezone from .common_holidays import ( all_saints_day, @@ -122,7 +122,7 @@ class XWBOExchangeCalendar(ExchangeCalendar): name = "XWBO" - tz = timezone("Europe/Vienna") + tz = ZoneInfo("Europe/Vienna") open_times = ((None, time(9)),) diff --git a/exchange_calendars/pandas_extensions/korean_holiday.py b/exchange_calendars/pandas_extensions/korean_holiday.py index dfb97091..cad1b9ac 100644 --- a/exchange_calendars/pandas_extensions/korean_holiday.py +++ b/exchange_calendars/pandas_extensions/korean_holiday.py @@ -1,9 +1,9 @@ import datetime import pandas as pd +from zoneinfo import ZoneInfo from pandas.tseries.offsets import Day from korean_lunar_calendar import KoreanLunarCalendar -from pytz import timezone from .holiday import Holiday from .offsets import _is_normalized @@ -14,8 +14,7 @@ def is_naive(dt): class KoreanHoliday(Holiday): - - _timezone = timezone("Asia/Seoul") + _timezone = ZoneInfo("Asia/Seoul") _local_timezone = datetime.datetime.now().astimezone().tzinfo _computed_holidays = pd.Series([], index=pd.DatetimeIndex([]), dtype=object) @@ -147,7 +146,6 @@ def last_business_day(dt): class KoreanSolarHoliday(KoreanHoliday): - pass @@ -187,7 +185,8 @@ def korean_solar_to_lunar_datetime(dt, round_down: bool): For example, 2022-03-31 (Gregorian) corresponds to 2022-02-29 (Korean lunar). The latter is not a valid Gregorian date. So, we introduce a rounding flag. If round_down is True, then this method will decrement the solar date until the lunar date happens to be a valid - Gregorian one. If round_down is False, then the solar date will be incremented analogously.""" + Gregorian one. If round_down is False, then the solar date will be incremented analogously. + """ while True: year, month, day = korean_solar_to_lunar(dt.year, dt.month, dt.day) try: @@ -198,7 +197,6 @@ def korean_solar_to_lunar_datetime(dt, round_down: bool): class KoreanLunarHoliday(KoreanHoliday): - _max_solar_end_date = pd.to_datetime( str(KoreanLunarCalendar.KOREAN_SOLAR_MAX_VALUE), format="%Y%m%d" ) @@ -221,8 +219,12 @@ def _reference_dates(self, start_date, end_date, strict=False): ) # Get lunar reference dates - lunar_start_date = korean_solar_to_lunar_datetime(solar_start_date, round_down=True) - lunar_end_date = korean_solar_to_lunar_datetime(solar_end_date, round_down=False) + lunar_start_date = korean_solar_to_lunar_datetime( + solar_start_date, round_down=True + ) + lunar_end_date = korean_solar_to_lunar_datetime( + solar_end_date, round_down=False + ) dates = super()._reference_dates(lunar_start_date, lunar_end_date) # Still restrict date range to fall into supported range of korean_lunar_calendar library diff --git a/exchange_calendars/us_futures_calendar.py b/exchange_calendars/us_futures_calendar.py index 3cd460e5..ca74803b 100644 --- a/exchange_calendars/us_futures_calendar.py +++ b/exchange_calendars/us_futures_calendar.py @@ -1,13 +1,15 @@ from datetime import time +from zoneinfo import ZoneInfo import numpy as np import pandas as pd from pandas.tseries.holiday import GoodFriday -from pytz import UTC, timezone +from exchange_calendars.calendar_helpers import UTC from exchange_calendars.exchange_calendar import ExchangeCalendar, HolidayCalendar from exchange_calendars.us_holidays import Christmas, USNewYearsDay + # Number of hours of offset between the open and close times dictated by this # calendar versus the 6:31am to 5:00pm times over which we want to simulate # futures algos. @@ -37,7 +39,7 @@ class QuantopianUSFuturesCalendar(ExchangeCalendar): """ name = "us_futures" - tz = timezone("America/New_York") + tz = ZoneInfo("America/New_York") open_times = ((None, time(18)),) close_times = ((None, time(18)),) open_offset = -1 diff --git a/exchange_calendars/utils/pandas_utils.py b/exchange_calendars/utils/pandas_utils.py index 80b4206b..2f7e6a88 100644 --- a/exchange_calendars/utils/pandas_utils.py +++ b/exchange_calendars/utils/pandas_utils.py @@ -1,17 +1,18 @@ from __future__ import annotations import datetime +from zoneinfo import ZoneInfo import numpy as np import pandas as pd -import pytz -from pytz import UTC + +from exchange_calendars.calendar_helpers import UTC def days_at_time( dates: pd.DatetimeIndex, time: datetime.time | None, - tz: pytz.tzinfo.BaseTzInfo, + tz: ZoneInfo, day_offset: int, ) -> pd.DatetimeIndex: """Return UTC DatetimeIndex of given dates at a given time. diff --git a/exchange_calendars/weekday_calendar.py b/exchange_calendars/weekday_calendar.py index 39ac3af9..9878f312 100644 --- a/exchange_calendars/weekday_calendar.py +++ b/exchange_calendars/weekday_calendar.py @@ -1,7 +1,6 @@ from datetime import time -from pytz import UTC - +from exchange_calendars.calendar_helpers import UTC from .exchange_calendar import ExchangeCalendar diff --git a/tests/test_always_open.py b/tests/test_always_open.py index a56ece80..8a672804 100644 --- a/tests/test_always_open.py +++ b/tests/test_always_open.py @@ -1,9 +1,9 @@ import pytest import pandas as pd import pandas.testing as tm -from pytz import UTC from exchange_calendars.always_open import AlwaysOpenCalendar +from exchange_calendars.calendar_helpers import UTC from .test_exchange_calendar import ExchangeCalendarTestBase diff --git a/tests/test_asex_calendar.py b/tests/test_asex_calendar.py index 03f22d78..1642eade 100644 --- a/tests/test_asex_calendar.py +++ b/tests/test_asex_calendar.py @@ -1,3 +1,5 @@ +from zoneinfo import ZoneInfo + import pandas as pd import pytest @@ -129,13 +131,14 @@ def test_close_time_change(self, default_calendar): """ cal = default_calendar close_time = cal.closes["2006-09-29"] - assert close_time == pd.Timestamp("2006-09-29 17:00", tz="Europe/Athens") + tz = ZoneInfo("Europe/Athens") + assert close_time == pd.Timestamp("2006-09-29 17:00", tz=tz) close_time = cal.closes["2008-09-26"] - assert close_time == pd.Timestamp("2008-09-26 17:00", tz="Europe/Athens") + assert close_time == pd.Timestamp("2008-09-26 17:00", tz=tz) close_time = cal.closes["2008-09-29"] - assert close_time == pd.Timestamp("2008-09-29 17:20", tz="Europe/Athens") + assert close_time == pd.Timestamp("2008-09-29 17:20", tz=tz) close_time = cal.closes["2008-09-30"] - assert close_time == pd.Timestamp("2008-09-30 17:20", tz="Europe/Athens") + assert close_time == pd.Timestamp("2008-09-30 17:20", tz=tz) diff --git a/tests/test_calendar_helpers.py b/tests/test_calendar_helpers.py index 3ba435b2..82426be2 100644 --- a/tests/test_calendar_helpers.py +++ b/tests/test_calendar_helpers.py @@ -2,17 +2,17 @@ from __future__ import annotations +from collections import abc import datetime from datetime import time import itertools import operator import re -from collections import abc +from zoneinfo import ZoneInfo import numpy as np import pandas as pd import pytest -import pytz from hypothesis import assume, given, settings, HealthCheck from hypothesis import strategies as st from pandas.testing import assert_index_equal @@ -20,6 +20,7 @@ from exchange_calendars import ExchangeCalendar from exchange_calendars import calendar_helpers as m from exchange_calendars import calendar_utils, errors +from exchange_calendars.calendar_helpers import UTC from exchange_calendars.calendar_utils import XTAEExchangeCalendar from .test_exchange_calendar import Answers @@ -27,6 +28,13 @@ # TODO tests for next_divider_idx, previous_divider_idx, compute_minutes (#15) +def test_constants(): + # Just to make sure they aren't inadvertently changed + assert m.UTC is ZoneInfo("UTC") + assert m.NANOSECONDS_PER_MINUTE == int(6e10) + assert m.NP_NAT == pd.NaT.value + + @pytest.fixture(scope="class") def one_min() -> abc.Iterator[pd.Timedelta]: yield pd.Timedelta(1, "T") @@ -43,10 +51,11 @@ def test_is_date(one_min): assert not f(T("2021-11-01 23:59:00.999999")) assert not f(T("2021-11-02 12:00")) + tz = ZoneInfo("US/Eastern") minutes = [ - T("2021-11-02", tz=pytz.UTC), - T("2021-11-02", tz="US/Eastern"), - T("2021-11-02", tz=pytz.UTC).tz_convert("US/Eastern"), + T("2021-11-02", tz=UTC), + T("2021-11-02", tz=tz), + T("2021-11-02", tz=UTC).tz_convert(tz), ] for minute in minutes: assert not f(minute) @@ -57,13 +66,13 @@ def test_is_utc(): f = m.to_utc T = pd.Timestamp - expected = T("2021-11-02", tz="UTC") - assert f(T("2021-11-02", tz="UTC")) == expected + expected = T("2021-11-02", tz=UTC) + assert f(T("2021-11-02", tz=UTC)) == expected assert f(T("2021-11-02")) == expected - expected = T("2021-11-02 13:33", tz="UTC") + expected = T("2021-11-02 13:33", tz=UTC) assert f(T("2021-11-02 13:33")) == expected - assert f(T("2021-11-02 09:33", tz="US/Eastern")) == expected + assert f(T("2021-11-02 09:33", tz=ZoneInfo("US/Eastern"))) == expected @pytest.fixture @@ -101,7 +110,7 @@ def minute() -> abc.Iterator[str]: params=[ "2021-06-02 23:00", pd.Timestamp("2021-06-02 23:00"), - pd.Timestamp("2021-06-02 23:00", tz="UTC"), + pd.Timestamp("2021-06-02 23:00", tz=UTC), ] ) def minute_mult(request) -> abc.Iterator[str | pd.Timestamp]: @@ -172,7 +181,7 @@ def test_parse_timestamp_with_date(date_mult, param_name, calendar, utc): if not utc and not date_is_utc_ts: assert dt == pd.Timestamp("2021-06-05") else: - assert dt == pd.Timestamp("2021-06-05", tz="UTC") + assert dt == pd.Timestamp("2021-06-05", tz=UTC) assert dt == dt.floor("T") @@ -183,7 +192,7 @@ def test_parse_timestamp_with_minute(minute_mult, param_name, calendar, utc): if not utc and not minute_is_utc_ts: assert dt == pd.Timestamp("2021-06-02 23:00") else: - assert dt == pd.Timestamp("2021-06-02 23:00", tz="UTC") + assert dt == pd.Timestamp("2021-06-02 23:00", tz=UTC) assert dt == dt.floor("T") @@ -199,9 +208,9 @@ def test_parse_timestamp_with_second(second, sides, param_name): else: parsed = m.parse_timestamp(second, param_name, raise_oob=False, side=side) if side == "left": - assert parsed == pd.Timestamp("2021-06-02 23:01", tz="UTC") + assert parsed == pd.Timestamp("2021-06-02 23:01", tz=UTC) else: - assert parsed == pd.Timestamp("2021-06-02 23:02", tz="UTC") + assert parsed == pd.Timestamp("2021-06-02 23:02", tz=UTC) def test_parse_timestamp_error_malformed(malformed, param_name, calendar): @@ -251,9 +260,9 @@ def test_parse_date_or_minute_for_minute( def f(ts: pd.Timestamp) -> tuple[pd.Timestamp, bool]: return m.parse_date_or_minute(ts, param_name, calendar) - assert f(minute_mult) == (pd.Timestamp(minute, tz=pytz.UTC), True) + assert f(minute_mult) == (pd.Timestamp(minute, tz=UTC), True) # verify that midnight with tz as UTC intepreted as minute, not date. - assert f(pd.Timestamp(date, tz=pytz.UTC)) == (pd.Timestamp(date, tz=pytz.UTC), True) + assert f(pd.Timestamp(date, tz=UTC)) == (pd.Timestamp(date, tz=UTC), True) def test_parse_date_or_minute_for_date(calendar, param_name, date, date_mult): @@ -309,7 +318,7 @@ def test_parse_date(date_mult, param_name): def test_parse_date_errors(calendar, param_name, date_too_early, date_too_late): - dt = pd.Timestamp("2021-06-02", tz="US/Central") + dt = pd.Timestamp("2021-06-02", tz=ZoneInfo("US/Central")) with pytest.raises(ValueError, match="a Date must be timezone naive"): m.parse_date(dt, param_name, raise_oob=False) @@ -364,7 +373,7 @@ def test_parse_trading_minute( calendar, trading_minute, minute, minute_too_early, minute_too_late, param_name ): ts = m.parse_trading_minute(calendar, trading_minute, param_name) - assert ts == pd.Timestamp(trading_minute, tz="UTC") + assert ts == pd.Timestamp(trading_minute, tz=UTC) with pytest.raises( errors.NotTradingMinuteError, match="not a trading minute of calendar" @@ -1271,7 +1280,7 @@ def test_align( closed_left = closed in ["left", "both"] closed_right = closed in ["right", "both"] - tz = pytz.UTC + tz = UTC def create_expected( starts: list[pd.Timestamp], @@ -1313,7 +1322,7 @@ def create_expected_intervals( combine = datetime.datetime.combine def get_start(date: pd.Timestamp, tm: time): - return pd.Timestamp(combine(date.date(), tm), tz=pytz.UTC) + return pd.Timestamp(combine(date.date(), tm), tz=UTC) aligned_time_am, _ = aligned_start_times[align] starts = [get_start(from_, aligned_time_am)] @@ -1380,7 +1389,7 @@ def test_align_overlap(self, cal_with_ans_align, dates_align, one_min): *dates_align, period, intervals=intervals, align_pm=align_pm, **kwargs ) limit = pd.Timestamp( - datetime.datetime.combine(dates_align[0], time(15)), tz=pytz.UTC + datetime.datetime.combine(dates_align[0], time(15)), tz=UTC ) assert limit in rtrn.right @@ -1747,7 +1756,7 @@ def test_parsing_errors(self, cal_start_end): ) # Verify raises error if period "1D" and start or end not passed as a date. - start = pd.Timestamp("2018-05-01", tz=pytz.UTC) + start = pd.Timestamp("2018-05-01", tz=UTC) end = pd.Timestamp("2018-05-31") with pytest.raises(ValueError, match="a Date must be timezone naive"): cal.trading_index(start, end, "1D") diff --git a/tests/test_exchange_calendar.py b/tests/test_exchange_calendar.py index d4847cd9..9b397e28 100644 --- a/tests/test_exchange_calendar.py +++ b/tests/test_exchange_calendar.py @@ -11,24 +11,24 @@ # limitations under the License. from __future__ import annotations +from collections import abc import datetime +from datetime import time import functools import itertools import pathlib import re import typing from typing import Literal -from collections import abc -from datetime import time +from zoneinfo import ZoneInfo import numpy as np import pandas as pd import pandas.testing as tm import pytest -import pytz -from pytz import UTC from exchange_calendars import errors +from exchange_calendars.calendar_helpers import UTC from exchange_calendars.calendar_utils import ( ExchangeCalendarDispatcher, _default_calendar_aliases, @@ -137,7 +137,7 @@ def test_default_calendars(): "2016-07-19", 0, time(9, 31), - pytz.timezone("America/New_York"), + ZoneInfo("America/New_York"), "2016-07-19 9:31", ), # CME standard day @@ -145,7 +145,7 @@ def test_default_calendars(): "2016-07-19", -1, time(17, 1), - pytz.timezone("America/Chicago"), + ZoneInfo("America/Chicago"), "2016-07-18 17:01", ), # CME day after DST start @@ -153,7 +153,7 @@ def test_default_calendars(): "2004-04-05", -1, time(17, 1), - pytz.timezone("America/Chicago"), + ZoneInfo("America/Chicago"), "2004-04-04 17:01", ), # ICE day after DST start @@ -161,7 +161,7 @@ def test_default_calendars(): "1990-04-02", -1, time(19, 1), - pytz.timezone("America/Chicago"), + ZoneInfo("America/Chicago"), "1990-04-01 19:01", ), ], @@ -2133,15 +2133,12 @@ def daylight_savings_dates( cal = default_calendar year = cal.last_session.year - 1 days = pd.date_range(str(year), str(year + 1), freq="D") - tzinfo = pytz.timezone(cal.tz.zone) + tz = cal.tz - prev_offset = tzinfo.utcoffset(days[0]) + prev_offset = tz.utcoffset(days[0]) dates = [] for day in days[1:]: - try: - offset = tzinfo.utcoffset(day) - except pytz.NonExistentTimeError: - offset = tzinfo.utcoffset(day + pd.Timedelta(1, "H")) + offset = tz.utcoffset(day) if offset != prev_offset: dates.append(day) if len(dates) == 2: @@ -3863,9 +3860,7 @@ def unite(dtis: list[pd.DatetimeIndex]) -> pd.DatetimeIndex: else: ends = ans.closes # index for a 'left' calendar, add end so evaluated as if 'both' - index = index.append( - pd.DatetimeIndex([ends[session]], tz=pytz.UTC) - ) + index = index.append(pd.DatetimeIndex([ends[session]], tz=UTC)) index = index[::mins] # only want every period if not index[-1] == ends[session]: @@ -3873,7 +3868,7 @@ def unite(dtis: list[pd.DatetimeIndex]) -> pd.DatetimeIndex: # last interval which lies beyond end. last_indice = index[-1] + period index = index.append( - pd.DatetimeIndex([last_indice], tz=pytz.UTC) + pd.DatetimeIndex([last_indice], tz=UTC) ) dtis.append(index) diff --git a/tests/test_weekday_calendar.py b/tests/test_weekday_calendar.py index 7e8c6a30..e54ad7d3 100644 --- a/tests/test_weekday_calendar.py +++ b/tests/test_weekday_calendar.py @@ -1,8 +1,8 @@ import pytest import pandas as pd import pandas.testing as tm -from pytz import UTC +from exchange_calendars.calendar_helpers import UTC from exchange_calendars.weekday_calendar import WeekdayCalendar from .test_exchange_calendar import ExchangeCalendarTestBase