From c43ed89ff6c5ee668bf61ea0c461cef05f235a3c Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sun, 10 Feb 2019 23:36:22 -0800 Subject: [PATCH 1/2] ENH: Support times with timezones in at_time --- pandas/core/indexes/datetimes.py | 13 ++++++------- pandas/tests/indexing/test_datetime.py | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index df91c71cfe238..5c591f3dd00ac 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -1302,20 +1302,19 @@ def indexer_at_time(self, time, asof=False): -------- indexer_between_time, DataFrame.at_time """ - from dateutil.parser import parse - if asof: raise NotImplementedError("'asof' argument is not supported") if isinstance(time, compat.string_types): + from dateutil.parser import parse time = parse(time).time() if time.tzinfo: - # TODO - raise NotImplementedError("argument 'time' with timezone info is " - "not supported") - - time_micros = self._get_time_micros() + if self.tz is None: + raise ValueError("Index must be timezone aware.") + time_micros = self.tz_convert(time.tzinfo)._get_time_micros() + else: + time_micros = self._get_time_micros() micros = _time_to_micros(time) return (micros == time_micros).nonzero()[0] diff --git a/pandas/tests/indexing/test_datetime.py b/pandas/tests/indexing/test_datetime.py index 11fb90ebd9bb9..c51ba69bb7673 100644 --- a/pandas/tests/indexing/test_datetime.py +++ b/pandas/tests/indexing/test_datetime.py @@ -1,7 +1,9 @@ -from datetime import datetime, timedelta +from datetime import datetime, time, timedelta from dateutil import tz import numpy as np +import pytest +import pytz import pandas as pd from pandas import DataFrame, Index, Series, Timestamp, date_range @@ -313,3 +315,23 @@ def test_loc_setitem_with_existing_dst(self): columns=['value'], dtype=object) tm.assert_frame_equal(result, expected) + + @pytest.mark.parametrize('hour', ['1:00', '1:00AM', time(1), + time(1, tzinfo=pytz.UTC)]) + def test_at_time(self, hour): + dti = pd.date_range('2018', periods=3, freq='H') + df = pd.DataFrame(list(range(len(dti))), index=dti) + if getattr(hour, 'tzinfo', None) is None: + result = df.at_time(hour) + expected = df.iloc[1:2] + tm.assert_frame_equal(result, expected) + else: + with pytest.raises(ValueError, match="Index must be timezone"): + df.at_time(hour) + + def test_at_time_tz(self): + dti = pd.date_range('2018', periods=3, freq='H', tz='US/Pacific') + df = pd.DataFrame(list(range(len(dti))), index=dti) + result = df.at_time(time(4, tzinfo=pytz.timezone('US/Eastern'))) + expected = df.iloc[1:2] + tm.assert_frame_equal(result, expected) From 9cb9f75deb77e0a356c29ce139759e8499593bae Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Mon, 11 Feb 2019 19:10:44 -0800 Subject: [PATCH 2/2] move test and add whatsnew --- doc/source/whatsnew/v0.25.0.rst | 2 +- pandas/tests/frame/test_timeseries.py | 23 +++++++++++++++++++++++ pandas/tests/indexing/test_datetime.py | 24 +----------------------- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 95362521f3b9f..74d25d420e1a1 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -20,7 +20,7 @@ Other Enhancements ^^^^^^^^^^^^^^^^^^ - :meth:`Timestamp.replace` now supports the ``fold`` argument to disambiguate DST transition times (:issue:`25017`) -- +- :meth:`DataFrame.at_time` and :meth:`Series.at_time` now support :meth:`datetime.time` objects with timezones (:issue:`24043`) - .. _whatsnew_0250.api_breaking: diff --git a/pandas/tests/frame/test_timeseries.py b/pandas/tests/frame/test_timeseries.py index bc37317f72802..31e81a9ca77c2 100644 --- a/pandas/tests/frame/test_timeseries.py +++ b/pandas/tests/frame/test_timeseries.py @@ -6,6 +6,7 @@ import numpy as np import pytest +import pytz from pandas.compat import product @@ -647,6 +648,28 @@ def test_at_time(self): rs = ts.at_time('16:00') assert len(rs) == 0 + @pytest.mark.parametrize('hour', ['1:00', '1:00AM', time(1), + time(1, tzinfo=pytz.UTC)]) + def test_at_time_errors(self, hour): + # GH 24043 + dti = pd.date_range('2018', periods=3, freq='H') + df = pd.DataFrame(list(range(len(dti))), index=dti) + if getattr(hour, 'tzinfo', None) is None: + result = df.at_time(hour) + expected = df.iloc[1:2] + tm.assert_frame_equal(result, expected) + else: + with pytest.raises(ValueError, match="Index must be timezone"): + df.at_time(hour) + + def test_at_time_tz(self): + # GH 24043 + dti = pd.date_range('2018', periods=3, freq='H', tz='US/Pacific') + df = pd.DataFrame(list(range(len(dti))), index=dti) + result = df.at_time(time(4, tzinfo=pytz.timezone('US/Eastern'))) + expected = df.iloc[1:2] + tm.assert_frame_equal(result, expected) + def test_at_time_raises(self): # GH20725 df = pd.DataFrame([[1, 2, 3], [4, 5, 6]]) diff --git a/pandas/tests/indexing/test_datetime.py b/pandas/tests/indexing/test_datetime.py index c51ba69bb7673..11fb90ebd9bb9 100644 --- a/pandas/tests/indexing/test_datetime.py +++ b/pandas/tests/indexing/test_datetime.py @@ -1,9 +1,7 @@ -from datetime import datetime, time, timedelta +from datetime import datetime, timedelta from dateutil import tz import numpy as np -import pytest -import pytz import pandas as pd from pandas import DataFrame, Index, Series, Timestamp, date_range @@ -315,23 +313,3 @@ def test_loc_setitem_with_existing_dst(self): columns=['value'], dtype=object) tm.assert_frame_equal(result, expected) - - @pytest.mark.parametrize('hour', ['1:00', '1:00AM', time(1), - time(1, tzinfo=pytz.UTC)]) - def test_at_time(self, hour): - dti = pd.date_range('2018', periods=3, freq='H') - df = pd.DataFrame(list(range(len(dti))), index=dti) - if getattr(hour, 'tzinfo', None) is None: - result = df.at_time(hour) - expected = df.iloc[1:2] - tm.assert_frame_equal(result, expected) - else: - with pytest.raises(ValueError, match="Index must be timezone"): - df.at_time(hour) - - def test_at_time_tz(self): - dti = pd.date_range('2018', periods=3, freq='H', tz='US/Pacific') - df = pd.DataFrame(list(range(len(dti))), index=dti) - result = df.at_time(time(4, tzinfo=pytz.timezone('US/Eastern'))) - expected = df.iloc[1:2] - tm.assert_frame_equal(result, expected)