Skip to content

Commit cd8dc38

Browse files
authored
DEPR: inconsistent string parsing in DatetimeIndex.indexer_at_time (#62945)
1 parent a3c208d commit cd8dc38

File tree

4 files changed

+54
-3
lines changed

4 files changed

+54
-3
lines changed

doc/source/whatsnew/v3.0.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ Other Deprecations
737737
- Deprecated using ``epoch`` date format in :meth:`DataFrame.to_json` and :meth:`Series.to_json`, use ``iso`` instead. (:issue:`57063`)
738738
- Deprecated allowing ``fill_value`` that cannot be held in the original dtype (excepting NA values for integer and bool dtypes) in :meth:`Series.unstack` and :meth:`DataFrame.unstack` (:issue:`12189`, :issue:`53868`)
739739
- Deprecated allowing ``fill_value`` that cannot be held in the original dtype (excepting NA values for integer and bool dtypes) in :meth:`Series.shift` and :meth:`DataFrame.shift` (:issue:`53802`)
740+
- Deprecated allowing strings representing full dates in :meth:`DataFrame.at_time` and :meth:`Series.at_time` (:issue:`50839`)
740741
- Deprecated backward-compatibility behavior for :meth:`DataFrame.select_dtypes` matching "str" dtype when ``np.object_`` is specified (:issue:`61916`)
741742
- Deprecated option "future.no_silent_downcasting", as it is no longer used. In a future version accessing this option will raise (:issue:`59502`)
742743
- Deprecated silent casting of non-datetime 'other' to datetime in :meth:`Series.combine_first` (:issue:`62931`)

pandas/core/indexes/datetimes.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,37 @@ def indexer_at_time(self, time, asof: bool = False) -> npt.NDArray[np.intp]:
767767
if isinstance(time, str):
768768
from dateutil.parser import parse
769769

770-
time = parse(time).time()
770+
orig = time
771+
try:
772+
alt = to_time(time)
773+
except ValueError:
774+
warnings.warn(
775+
# GH#50839
776+
f"The string '{orig}' cannot be parsed using pd.core.tools.to_time "
777+
f"and in a future version will raise. "
778+
"Use an unambiguous time string format or explicitly cast to "
779+
"`datetime.time` before calling.",
780+
Pandas4Warning,
781+
stacklevel=find_stack_level(),
782+
)
783+
time = parse(time).time()
784+
else:
785+
try:
786+
time = parse(time).time()
787+
except ValueError:
788+
# e.g. '23550' raises dateutil.parser._parser.ParserError
789+
time = alt
790+
if alt != time:
791+
warnings.warn(
792+
# GH#50839
793+
f"The string '{orig}' is currently parsed as {time} "
794+
f"but in a future version will be parsed as {alt}, consistent"
795+
"with `between_time` behavior. To avoid this warning, "
796+
"use an unambiguous string format or explicitly cast to "
797+
"`datetime.time` before calling.",
798+
Pandas4Warning,
799+
stacklevel=find_stack_level(),
800+
)
771801

772802
if time.tzinfo:
773803
if self.tz is None:

pandas/tests/frame/methods/test_at_time.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import pytest
99

1010
from pandas._libs.tslibs import timezones
11+
from pandas.errors import Pandas4Warning
1112

1213
from pandas import (
1314
DataFrame,
@@ -132,3 +133,21 @@ def test_at_time_datetimeindex(self):
132133
tm.assert_frame_equal(result, expected)
133134
tm.assert_frame_equal(result, expected2)
134135
assert len(result) == 4
136+
137+
def test_at_time_ambiguous_format_deprecation(self):
138+
# GH#50839
139+
rng = date_range("1/1/2000", "1/5/2000", freq="125min")
140+
ts = DataFrame(list(range(len(rng))), index=rng)
141+
142+
msg1 = "The string '.*' cannot be parsed"
143+
with tm.assert_produces_warning(Pandas4Warning, match=msg1):
144+
ts.at_time("2022-12-12 00:00:00")
145+
with tm.assert_produces_warning(Pandas4Warning, match=msg1):
146+
ts.at_time("2022-12-12 00:00:00 +09:00")
147+
with tm.assert_produces_warning(Pandas4Warning, match=msg1):
148+
ts.at_time("2022-12-12 00:00:00.000000")
149+
150+
# The dateutil parser raises on these, so we can give the future behavior
151+
# immediately using pd.core.tools.to_time
152+
ts.at_time("235500")
153+
ts.at_time("115500PM")

pandas/tests/generic/test_finalize.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44

55
from copy import deepcopy
6+
from datetime import time
67
import operator
78
import re
89

@@ -280,12 +281,12 @@
280281
(
281282
pd.Series,
282283
(1, pd.date_range("2000", periods=4)),
283-
operator.methodcaller("at_time", "12:00"),
284+
operator.methodcaller("at_time", time(12)),
284285
),
285286
(
286287
pd.DataFrame,
287288
({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
288-
operator.methodcaller("at_time", "12:00"),
289+
operator.methodcaller("at_time", time(12)),
289290
),
290291
(
291292
pd.Series,

0 commit comments

Comments
 (0)