Skip to content

Commit b0dac6c

Browse files
mroeschkejreback
authored andcommitted
ENH: Support times with timezones in at_time (#25280)
1 parent 2ce2196 commit b0dac6c

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

doc/source/whatsnew/v0.25.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Other Enhancements
2020
^^^^^^^^^^^^^^^^^^
2121

2222
- :meth:`Timestamp.replace` now supports the ``fold`` argument to disambiguate DST transition times (:issue:`25017`)
23-
-
23+
- :meth:`DataFrame.at_time` and :meth:`Series.at_time` now support :meth:`datetime.time` objects with timezones (:issue:`24043`)
2424
-
2525

2626
.. _whatsnew_0250.api_breaking:

pandas/core/indexes/datetimes.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -1302,20 +1302,19 @@ def indexer_at_time(self, time, asof=False):
13021302
--------
13031303
indexer_between_time, DataFrame.at_time
13041304
"""
1305-
from dateutil.parser import parse
1306-
13071305
if asof:
13081306
raise NotImplementedError("'asof' argument is not supported")
13091307

13101308
if isinstance(time, compat.string_types):
1309+
from dateutil.parser import parse
13111310
time = parse(time).time()
13121311

13131312
if time.tzinfo:
1314-
# TODO
1315-
raise NotImplementedError("argument 'time' with timezone info is "
1316-
"not supported")
1317-
1318-
time_micros = self._get_time_micros()
1313+
if self.tz is None:
1314+
raise ValueError("Index must be timezone aware.")
1315+
time_micros = self.tz_convert(time.tzinfo)._get_time_micros()
1316+
else:
1317+
time_micros = self._get_time_micros()
13191318
micros = _time_to_micros(time)
13201319
return (micros == time_micros).nonzero()[0]
13211320

pandas/tests/frame/test_timeseries.py

+23
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import numpy as np
88
import pytest
9+
import pytz
910

1011
from pandas.compat import product
1112

@@ -647,6 +648,28 @@ def test_at_time(self):
647648
rs = ts.at_time('16:00')
648649
assert len(rs) == 0
649650

651+
@pytest.mark.parametrize('hour', ['1:00', '1:00AM', time(1),
652+
time(1, tzinfo=pytz.UTC)])
653+
def test_at_time_errors(self, hour):
654+
# GH 24043
655+
dti = pd.date_range('2018', periods=3, freq='H')
656+
df = pd.DataFrame(list(range(len(dti))), index=dti)
657+
if getattr(hour, 'tzinfo', None) is None:
658+
result = df.at_time(hour)
659+
expected = df.iloc[1:2]
660+
tm.assert_frame_equal(result, expected)
661+
else:
662+
with pytest.raises(ValueError, match="Index must be timezone"):
663+
df.at_time(hour)
664+
665+
def test_at_time_tz(self):
666+
# GH 24043
667+
dti = pd.date_range('2018', periods=3, freq='H', tz='US/Pacific')
668+
df = pd.DataFrame(list(range(len(dti))), index=dti)
669+
result = df.at_time(time(4, tzinfo=pytz.timezone('US/Eastern')))
670+
expected = df.iloc[1:2]
671+
tm.assert_frame_equal(result, expected)
672+
650673
def test_at_time_raises(self):
651674
# GH20725
652675
df = pd.DataFrame([[1, 2, 3], [4, 5, 6]])

0 commit comments

Comments
 (0)