Skip to content

Commit 7a1ec99

Browse files
Backport PR #48167 on branch 1.4.x (BUG: DTI.intersection with DST transition) (#48189)
Backport PR #48167: BUG: DTI.intersection with DST transition Co-authored-by: Matthew Roeschke <[email protected]>
1 parent d214b52 commit 7a1ec99

File tree

6 files changed

+33
-2
lines changed

6 files changed

+33
-2
lines changed

doc/source/whatsnew/v1.4.4.rst

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Fixed regressions
2222
- Fixed regression in :meth:`DataFrame.loc` not aligning index in some cases when setting a :class:`DataFrame` (:issue:`47578`)
2323
- Fixed regression in :meth:`DataFrame.loc` setting a length-1 array like value to a single value in the DataFrame (:issue:`46268`)
2424
- Fixed regression in setting ``None`` or non-string value into a ``string``-dtype Series using a mask (:issue:`47628`)
25+
- Fixed regression in :meth:`DatetimeIndex.intersection` when the :class:`DatetimeIndex` has dates crossing daylight savings time (:issue:`46702`)
2526
- Fixed regression in :func:`merge` throwing an error when passing a :class:`Series` with a multi-level name (:issue:`47946`)
2627
- Fixed regression in :meth:`DataFrame.eval` creating a copy when updating inplace (:issue:`47449`)
2728
-

pandas/_libs/tslibs/timezones.pxd

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ cpdef object get_timezone(tzinfo tz)
1717
cpdef tzinfo maybe_get_tz(object tz)
1818

1919
cdef timedelta get_utcoffset(tzinfo tz, datetime obj)
20-
cdef bint is_fixed_offset(tzinfo tz)
20+
cpdef bint is_fixed_offset(tzinfo tz)
2121

2222
cdef object get_dst_info(tzinfo tz)

pandas/_libs/tslibs/timezones.pyi

+1
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ def get_dst_info(
2323
def maybe_get_tz(tz: str | int | np.int64 | tzinfo | None) -> tzinfo | None: ...
2424
def get_timezone(tz: tzinfo) -> tzinfo | str: ...
2525
def is_utc(tz: tzinfo | None) -> bool: ...
26+
def is_fixed_offset(tz: tzinfo) -> bool: ...

pandas/_libs/tslibs/timezones.pyx

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ cdef timedelta get_utcoffset(tzinfo tz, datetime obj):
198198
return tz.utcoffset(obj)
199199

200200

201-
cdef inline bint is_fixed_offset(tzinfo tz):
201+
cpdef inline bint is_fixed_offset(tzinfo tz):
202202
if treat_tz_as_dateutil(tz):
203203
if len(tz._trans_idx) == 0 and len(tz._trans_list) == 0:
204204
return 1

pandas/core/indexes/datetimes.py

+17
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,23 @@ def _formatter_func(self):
383383
# --------------------------------------------------------------------
384384
# Set Operation Methods
385385

386+
def _can_range_setop(self, other) -> bool:
387+
# GH 46702: If self or other have non-UTC tzs, DST transitions prevent
388+
# range representation due to no singular step
389+
if (
390+
self.tz is not None
391+
and not timezones.is_utc(self.tz)
392+
and not timezones.is_fixed_offset(self.tz)
393+
):
394+
return False
395+
if (
396+
other.tz is not None
397+
and not timezones.is_utc(other.tz)
398+
and not timezones.is_fixed_offset(other.tz)
399+
):
400+
return False
401+
return super()._can_range_setop(other)
402+
386403
def union_many(self, others):
387404
"""
388405
A bit of a hack to accelerate unioning a collection of indexes.

pandas/tests/indexes/datetimes/test_setops.py

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import numpy as np
44
import pytest
5+
import pytz
56

67
import pandas.util._test_decorators as td
78

@@ -597,3 +598,14 @@ def test_intersection_bug(self):
597598
result = a.intersection(b)
598599
tm.assert_index_equal(result, b)
599600
assert result.freq == b.freq
601+
602+
@pytest.mark.parametrize(
603+
"tz", [None, "UTC", "Europe/Berlin", pytz.FixedOffset(-60)]
604+
)
605+
def test_intersection_dst_transition(self, tz):
606+
# GH 46702: Europe/Berlin has DST transition
607+
idx1 = date_range("2020-03-27", periods=5, freq="D", tz=tz)
608+
idx2 = date_range("2020-03-30", periods=5, freq="D", tz=tz)
609+
result = idx1.intersection(idx2)
610+
expected = date_range("2020-03-30", periods=2, freq="D", tz=tz)
611+
tm.assert_index_equal(result, expected)

0 commit comments

Comments
 (0)