Skip to content

Commit 490b189

Browse files
authored
BUG: Add fix for hashing timestamps with folds (#44282)
1 parent 8ae1b4c commit 490b189

File tree

4 files changed

+67
-0
lines changed

4 files changed

+67
-0
lines changed

doc/source/whatsnew/v1.4.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ Datetimelike
724724
- Bug in :class:`DateOffset`` addition with :class:`Timestamp` where ``offset.nanoseconds`` would not be included in the result (:issue:`43968`, :issue:`36589`)
725725
- Bug in :meth:`Timestamp.fromtimestamp` not supporting the ``tz`` argument (:issue:`45083`)
726726
- Bug in :class:`DataFrame` construction from dict of :class:`Series` with mismatched index dtypes sometimes raising depending on the ordering of the passed dict (:issue:`44091`)
727+
- Bug in :class:`Timestamp` hashing during some DST transitions caused a segmentation fault (:issue:`33931` and :issue:`40817`)
727728
-
728729

729730
Timedelta

pandas/_libs/tslibs/timestamps.pyx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ cdef class _Timestamp(ABCTimestamp):
180180
def __hash__(_Timestamp self):
181181
if self.nanosecond:
182182
return hash(self.value)
183+
if self.fold:
184+
return datetime.__hash__(self.replace(fold=0))
183185
return datetime.__hash__(self)
184186

185187
def __richcmp__(_Timestamp self, object other, int op):

pandas/tests/frame/methods/test_reindex.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import numpy as np
99
import pytest
1010

11+
from pandas._libs.tslibs.timezones import dateutil_gettz as gettz
12+
1113
import pandas as pd
1214
from pandas import (
1315
Categorical,
@@ -78,6 +80,41 @@ def test_setitem_reset_index_dtypes(self):
7880
result = df2.reset_index()
7981
tm.assert_frame_equal(result, expected)
8082

83+
@pytest.mark.parametrize(
84+
"timezone, year, month, day, hour",
85+
[["America/Chicago", 2013, 11, 3, 1], ["America/Santiago", 2021, 4, 3, 23]],
86+
)
87+
def test_reindex_timestamp_with_fold(self, timezone, year, month, day, hour):
88+
# see gh-40817
89+
test_timezone = gettz(timezone)
90+
transition_1 = pd.Timestamp(
91+
year=year,
92+
month=month,
93+
day=day,
94+
hour=hour,
95+
minute=0,
96+
fold=0,
97+
tzinfo=test_timezone,
98+
)
99+
transition_2 = pd.Timestamp(
100+
year=year,
101+
month=month,
102+
day=day,
103+
hour=hour,
104+
minute=0,
105+
fold=1,
106+
tzinfo=test_timezone,
107+
)
108+
df = (
109+
DataFrame({"index": [transition_1, transition_2], "vals": ["a", "b"]})
110+
.set_index("index")
111+
.reindex(["1", "2"])
112+
)
113+
tm.assert_frame_equal(
114+
df,
115+
DataFrame({"index": ["1", "2"], "vals": [None, None]}).set_index("index"),
116+
)
117+
81118

82119
class TestDataFrameSelectReindex:
83120
# These are specific reindex-based tests; other indexing tests should go in

pandas/tests/scalar/timestamp/test_timestamp.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,33 @@ def test_hash_equivalent(self):
445445
stamp = Timestamp(datetime(2011, 1, 1))
446446
assert d[stamp] == 5
447447

448+
@pytest.mark.parametrize(
449+
"timezone, year, month, day, hour",
450+
[["America/Chicago", 2013, 11, 3, 1], ["America/Santiago", 2021, 4, 3, 23]],
451+
)
452+
def test_hash_timestamp_with_fold(self, timezone, year, month, day, hour):
453+
# see gh-33931
454+
test_timezone = gettz(timezone)
455+
transition_1 = Timestamp(
456+
year=year,
457+
month=month,
458+
day=day,
459+
hour=hour,
460+
minute=0,
461+
fold=0,
462+
tzinfo=test_timezone,
463+
)
464+
transition_2 = Timestamp(
465+
year=year,
466+
month=month,
467+
day=day,
468+
hour=hour,
469+
minute=0,
470+
fold=1,
471+
tzinfo=test_timezone,
472+
)
473+
assert hash(transition_1) == hash(transition_2)
474+
448475
def test_tz_conversion_freq(self, tz_naive_fixture):
449476
# GH25241
450477
with tm.assert_produces_warning(FutureWarning, match="freq"):

0 commit comments

Comments
 (0)