Skip to content

Commit 0bf4c9d

Browse files
mroeschkenoatamir
authored andcommitted
BUG: DTI.intersection with DST transition (pandas-dev#48167)
* BUG: DTI.intersection with DST transition * Add whatsnew note * Add fixed offset as well
1 parent b0e3bbf commit 0bf4c9d

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
@@ -18,6 +18,6 @@ cpdef object get_timezone(tzinfo tz)
1818
cpdef tzinfo maybe_get_tz(object tz)
1919

2020
cdef timedelta get_utcoffset(tzinfo tz, datetime obj)
21-
cdef bint is_fixed_offset(tzinfo tz)
21+
cpdef bint is_fixed_offset(tzinfo tz)
2222

2323
cdef object get_dst_info(tzinfo tz)

pandas/_libs/tslibs/timezones.pyi

+1
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ def infer_tzinfo(
1818
def maybe_get_tz(tz: str | int | np.int64 | tzinfo | None) -> tzinfo | None: ...
1919
def get_timezone(tz: tzinfo) -> tzinfo | str: ...
2020
def is_utc(tz: tzinfo | None) -> bool: ...
21+
def is_fixed_offset(tz: tzinfo) -> bool: ...

pandas/_libs/tslibs/timezones.pyx

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

238238

239-
cdef inline bint is_fixed_offset(tzinfo tz):
239+
cpdef inline bint is_fixed_offset(tzinfo tz):
240240
if treat_tz_as_dateutil(tz):
241241
if len(tz._trans_idx) == 0 and len(tz._trans_list) == 0:
242242
return 1

pandas/core/indexes/datetimes.py

+17
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,23 @@ def _formatter_func(self):
416416
# --------------------------------------------------------------------
417417
# Set Operation Methods
418418

419+
def _can_range_setop(self, other) -> bool:
420+
# GH 46702: If self or other have non-UTC tzs, DST transitions prevent
421+
# range representation due to no singular step
422+
if (
423+
self.tz is not None
424+
and not timezones.is_utc(self.tz)
425+
and not timezones.is_fixed_offset(self.tz)
426+
):
427+
return False
428+
if (
429+
other.tz is not None
430+
and not timezones.is_utc(other.tz)
431+
and not timezones.is_fixed_offset(other.tz)
432+
):
433+
return False
434+
return super()._can_range_setop(other)
435+
419436
def union_many(self, others):
420437
"""
421438
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

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

0 commit comments

Comments
 (0)