diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 09e1853429d9f..d8c4f633d2d0d 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -287,6 +287,7 @@ Datetimelike - Bug in :meth:`Timestamp.round`, :meth:`Timestamp.floor`, :meth:`Timestamp.ceil` for values near the implementation bounds of :class:`Timestamp` (:issue:`39244`) - Bug in :meth:`Timedelta.round`, :meth:`Timedelta.floor`, :meth:`Timedelta.ceil` for values near the implementation bounds of :class:`Timedelta` (:issue:`38964`) - Bug in :func:`date_range` incorrectly creating :class:`DatetimeIndex` containing ``NaT`` instead of raising ``OutOfBoundsDatetime`` in corner cases (:issue:`24124`) +- Bug in :func:`infer_freq` incorrectly fails to infer 'H' frequency of :class:`DatetimeIndex` if the latter has a timezone and crosses DST boundaries (:issue:`39556`) Timedelta ^^^^^^^^^ diff --git a/pandas/tests/tseries/frequencies/test_inference.py b/pandas/tests/tseries/frequencies/test_inference.py index 95edd038dab9b..892be119093e5 100644 --- a/pandas/tests/tseries/frequencies/test_inference.py +++ b/pandas/tests/tseries/frequencies/test_inference.py @@ -267,7 +267,7 @@ def test_infer_freq_tz(tz_naive_fixture, expected, dates): ], ) @pytest.mark.parametrize( - "freq", ["3H", "10T", "3601S", "3600001L", "3600000001U", "3600000000001N"] + "freq", ["H", "3H", "10T", "3601S", "3600001L", "3600000001U", "3600000000001N"] ) def test_infer_freq_tz_transition(tz_naive_fixture, date_pair, freq): # see gh-8772 diff --git a/pandas/tseries/frequencies.py b/pandas/tseries/frequencies.py index 0d5598fcaf890..2257ce47d8936 100644 --- a/pandas/tseries/frequencies.py +++ b/pandas/tseries/frequencies.py @@ -240,16 +240,17 @@ def get_freq(self) -> Optional[str]: return None delta = self.deltas[0] - if _is_multiple(delta, _ONE_DAY): + if delta and _is_multiple(delta, _ONE_DAY): return self._infer_daily_rule() # Business hourly, maybe. 17: one day / 65: one weekend if self.hour_deltas in ([1, 17], [1, 65], [1, 17, 65]): return "BH" + # Possibly intraday frequency. Here we use the # original .asi8 values as the modified values # will not work around DST transitions. See #8772 - elif not self.is_unique_asi8: + if not self.is_unique_asi8: return None delta = self.deltas_asi8[0]