Skip to content

Commit eedf0d5

Browse files
authored
BUG: Timestamp(ambiguous, tz=from_pytz) not raising (#55712)
1 parent ecf449b commit eedf0d5

File tree

4 files changed

+59
-1
lines changed

4 files changed

+59
-1
lines changed

doc/source/whatsnew/v2.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ Timedelta
342342
Timezones
343343
^^^^^^^^^
344344
- Bug in :class:`AbstractHolidayCalendar` where timezone data was not propagated when computing holiday observances (:issue:`54580`)
345+
- Bug in :class:`Timestamp` construction with an ambiguous value and a ``pytz`` timezone failing to raise ``pytz.AmbiguousTimeError`` (:issue:`55657`)
345346
-
346347

347348
Numeric

pandas/_libs/tslibs/conversion.pyx

+2-1
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,8 @@ cdef datetime _localize_pydatetime(datetime dt, tzinfo tz):
645645
"""
646646
try:
647647
# datetime.replace with pytz may be incorrect result
648-
return tz.localize(dt)
648+
# TODO: try to respect `fold` attribute
649+
return tz.localize(dt, is_dst=None)
649650
except AttributeError:
650651
return dt.replace(tzinfo=tz)
651652

pandas/tests/indexes/datetimes/test_constructors.py

+30
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,36 @@ def test_dti_convert_datetime_list(self, tzstr):
10131013
dr2 = DatetimeIndex(list(dr), name="foo", freq="D")
10141014
tm.assert_index_equal(dr, dr2)
10151015

1016+
def test_dti_ambiguous_matches_timestamp(self):
1017+
# GH#47471 check that we get the same raising behavior in the DTI
1018+
# constructor and Timestamp constructor
1019+
dtstr = "2013-11-03 01:59:59.999999"
1020+
dtobj = Timestamp(dtstr).to_pydatetime()
1021+
1022+
tz = pytz.timezone("US/Eastern")
1023+
with pytest.raises(pytz.AmbiguousTimeError, match=dtstr):
1024+
Timestamp(dtstr, tz=tz)
1025+
with pytest.raises(pytz.AmbiguousTimeError, match=dtstr):
1026+
Timestamp(dtobj, tz=tz)
1027+
with pytest.raises(pytz.AmbiguousTimeError, match=dtstr):
1028+
DatetimeIndex([dtstr], tz=tz)
1029+
with pytest.raises(pytz.AmbiguousTimeError, match=dtstr):
1030+
DatetimeIndex([dtobj], tz=tz)
1031+
1032+
tz2 = gettz("US/Eastern")
1033+
with pytest.raises(pytz.AmbiguousTimeError, match=dtstr):
1034+
Timestamp(dtstr, tz=tz2)
1035+
# FIXME: The Timestamp constructor here behaves differently than all
1036+
# the other cases bc with dateutil/zoneinfo tzinfos we implicitly
1037+
# get fold=0. Having this raise is not important, but having the
1038+
# behavior be consistent across cases is.
1039+
# with pytest.raises(pytz.AmbiguousTimeError, match=dtstr):
1040+
# Timestamp(dtobj, tz=tz2)
1041+
with pytest.raises(pytz.AmbiguousTimeError, match=dtstr):
1042+
DatetimeIndex([dtstr], tz=tz2)
1043+
with pytest.raises(pytz.AmbiguousTimeError, match=dtstr):
1044+
DatetimeIndex([dtobj], tz=tz2)
1045+
10161046
@pytest.mark.parametrize("tz", [None, "UTC", "US/Pacific"])
10171047
def test_dti_constructor_with_non_nano_dtype(self, tz):
10181048
# GH#55756, GH#54620

pandas/tests/tseries/offsets/test_dst.py

+26
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@
2929
YearBegin,
3030
YearEnd,
3131
)
32+
from pandas.errors import PerformanceWarning
3233

34+
from pandas import DatetimeIndex
35+
import pandas._testing as tm
3336
from pandas.util.version import Version
3437

3538
# error: Module has no attribute "__version__"
@@ -83,6 +86,29 @@ def _test_all_offsets(self, n, **kwds):
8386
def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset):
8487
offset = DateOffset(**{offset_name: offset_n})
8588

89+
if (
90+
offset_name in ["hour", "minute", "second", "microsecond"]
91+
and offset_n == 1
92+
and tstart == Timestamp("2013-11-03 01:59:59.999999-0500", tz="US/Eastern")
93+
):
94+
# This addition results in an ambiguous wall time
95+
err_msg = {
96+
"hour": "2013-11-03 01:59:59.999999",
97+
"minute": "2013-11-03 01:01:59.999999",
98+
"second": "2013-11-03 01:59:01.999999",
99+
"microsecond": "2013-11-03 01:59:59.000001",
100+
}[offset_name]
101+
with pytest.raises(pytz.AmbiguousTimeError, match=err_msg):
102+
tstart + offset
103+
# While we're here, let's check that we get the same behavior in a
104+
# vectorized path
105+
dti = DatetimeIndex([tstart])
106+
warn_msg = "Non-vectorized DateOffset"
107+
with pytest.raises(pytz.AmbiguousTimeError, match=err_msg):
108+
with tm.assert_produces_warning(PerformanceWarning, match=warn_msg):
109+
dti + offset
110+
return
111+
86112
t = tstart + offset
87113
if expected_utc_offset is not None:
88114
assert get_utc_offset_hours(t) == expected_utc_offset

0 commit comments

Comments
 (0)