Skip to content

Commit cf35e20

Browse files
committed
dt.time
1 parent 16e3ada commit cf35e20

File tree

9 files changed

+93
-14
lines changed

9 files changed

+93
-14
lines changed

pandas/core/arrays/datetimes.py

+28-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import numpy as np
1717

18+
from pandas._config import get_option
19+
1820
from pandas._libs import (
1921
lib,
2022
tslib,
@@ -1318,7 +1320,32 @@ def time(self) -> npt.NDArray[np.object_]:
13181320
# keeping their timezone and not using UTC
13191321
timestamps = self._local_timestamps()
13201322

1321-
return ints_to_pydatetime(timestamps, box="time", reso=self._creso)
1323+
result = ints_to_pydatetime(timestamps, box="time", reso=self._creso)
1324+
1325+
opt = get_option("future.infer_time")
1326+
if opt is None:
1327+
warnings.warn(
1328+
f"The behavior of {type(self).__name__}.time is deprecated. "
1329+
"In a future version, this will an array with pyarrow time "
1330+
"dtype instead of object dtype. To opt in to the future behavior, "
1331+
"set `pd.set_option('future.infer_time', True)`.",
1332+
FutureWarning,
1333+
stacklevel=find_stack_level(),
1334+
)
1335+
elif opt is True:
1336+
# TODO: optimize this to avoid going through ints_to_pydatetime
1337+
import pyarrow as pa
1338+
1339+
from pandas.core.arrays.arrow import ArrowDtype
1340+
1341+
pa_type = pa.time64(self.unit)
1342+
result[self.isna()] = None
1343+
obj = pa.array(result, type=pa_type)
1344+
dtype = ArrowDtype(obj.type)
1345+
out = dtype.construct_array_type()(obj)
1346+
return out
1347+
1348+
return result
13221349

13231350
@property
13241351
def timetz(self) -> npt.NDArray[np.object_]:

pandas/core/indexes/accessors.py

-2
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,6 @@ def _delegate_property_get(self, name: str): # type: ignore[override]
101101
elif not is_list_like(result):
102102
return result
103103

104-
result = np.asarray(result)
105-
106104
if self.orig is not None:
107105
index = self.orig.index
108106
else:

pandas/tests/arrays/test_datetimes.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,14 @@ def test_to_pydatetime(self, dta_dti):
155155
def test_time_date(self, dta_dti, meth):
156156
dta, dti = dta_dti
157157

158-
result = getattr(dta, meth)
159-
expected = getattr(dti, meth)
158+
warn = None
159+
msg = "In a future version, this will an array with pyarrow time dtype"
160+
if meth == "time":
161+
warn = FutureWarning
162+
163+
with tm.assert_produces_warning(warn, match=msg):
164+
result = getattr(dta, meth)
165+
expected = getattr(dti, meth)
160166
tm.assert_numpy_array_equal(result, expected)
161167

162168
def test_format_native_types(self, unit, dtype, dta_dti):

pandas/tests/generic/test_finalize.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import pytest
99

1010
import pandas as pd
11+
import pandas._testing as tm
1112

1213
# TODO:
1314
# * Binary methods (mul, div, etc.)
@@ -681,7 +682,14 @@ def test_datetime_method(method):
681682
def test_datetime_property(attr):
682683
s = pd.Series(pd.date_range("2000", periods=4))
683684
s.attrs = {"a": 1}
684-
result = getattr(s.dt, attr)
685+
686+
warn = None
687+
msg = "In a future version, this will an array with pyarrow time dtype"
688+
if attr == "time":
689+
warn = FutureWarning
690+
with tm.assert_produces_warning(warn, match=msg):
691+
result = getattr(s.dt, attr)
692+
685693
assert result.attrs == {"a": 1}
686694

687695

pandas/tests/indexes/datetimes/test_scalar_compat.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
class TestDatetimeIndexOps:
2525
def test_dti_time(self):
2626
rng = date_range("1/1/2000", freq="12min", periods=10)
27-
result = pd.Index(rng).time
27+
msg = "In a future version, this will an array with pyarrow time dtype"
28+
with tm.assert_produces_warning(FutureWarning, match=msg):
29+
result = pd.Index(rng).time
2830
expected = [t.time() for t in rng]
2931
assert (result == expected).all()
3032

pandas/tests/indexes/datetimes/test_timezones.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,10 @@ def test_time_accessor(self, dtype):
853853
expected = np.array([time(10, 20, 30), pd.NaT])
854854

855855
index = DatetimeIndex(["2018-06-04 10:20:30", pd.NaT], dtype=dtype)
856-
result = index.time
856+
857+
msg = "In a future version, this will an array with pyarrow time dtype"
858+
with tm.assert_produces_warning(FutureWarning, match=msg):
859+
result = index.time
857860

858861
tm.assert_numpy_array_equal(result, expected)
859862

pandas/tests/io/parser/test_parse_dates.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,9 @@ def test_date_col_as_index_col(all_parsers):
464464
if parser.engine == "pyarrow":
465465
# https://github.com/pandas-dev/pandas/issues/44231
466466
# pyarrow 6.0 starts to infer time type
467-
expected["X2"] = pd.to_datetime("1970-01-01" + expected["X2"]).dt.time
467+
msg = "In a future version, this will an array with pyarrow time dtype"
468+
with tm.assert_produces_warning(FutureWarning, match=msg):
469+
expected["X2"] = pd.to_datetime("1970-01-01" + expected["X2"]).dt.time
468470

469471
tm.assert_frame_equal(result, expected)
470472

pandas/tests/series/accessors/test_cat_accessor.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,12 @@ def test_dt_accessor_api_for_categorical(self, idx):
212212
tm.assert_equal(res, exp)
213213

214214
for attr in attr_names:
215-
res = getattr(cat.dt, attr)
216-
exp = getattr(ser.dt, attr)
215+
with warnings.catch_warnings():
216+
if attr == "time":
217+
# deprecated to return pyarrow time dtype
218+
warnings.simplefilter("ignore", FutureWarning)
219+
res = getattr(cat.dt, attr)
220+
exp = getattr(ser.dt, attr)
217221

218222
tm.assert_equal(res, exp)
219223

pandas/tests/series/accessors/test_dt_accessor.py

+32-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import pytz
1313

1414
from pandas._libs.tslibs.timezones import maybe_get_tz
15+
from pandas.compat import pa_version_under7p0
1516
from pandas.errors import SettingWithCopyError
1617

1718
from pandas.core.dtypes.common import (
@@ -89,8 +90,15 @@ def get_expected(ser, prop):
8990
return result
9091
return Series(result, index=ser.index, name=ser.name, dtype=result.dtype)
9192

92-
left = getattr(ser.dt, name)
93-
right = get_expected(ser, name)
93+
if name == "time":
94+
msg = "In a future version, this will an array with pyarrow time dtype"
95+
with tm.assert_produces_warning(FutureWarning, match=msg):
96+
left = getattr(ser.dt, name)
97+
right = get_expected(ser, name)
98+
else:
99+
left = getattr(ser.dt, name)
100+
right = get_expected(ser, name)
101+
94102
if not (is_list_like(left) and is_list_like(right)):
95103
assert left == right
96104
elif isinstance(left, DataFrame):
@@ -672,10 +680,31 @@ def test_valid_dt_with_missing_values(self):
672680
)
673681
tm.assert_series_equal(result, expected)
674682

675-
result = ser.dt.time
683+
msg = "In a future version, this will an array with pyarrow time"
684+
with tm.assert_produces_warning(FutureWarning, match=msg):
685+
result = ser.dt.time
676686
expected = Series([time(0), time(0), np.nan, time(0), time(0)], dtype="object")
677687
tm.assert_series_equal(result, expected)
678688

689+
with pd.option_context("future.infer_time", False):
690+
with tm.assert_produces_warning(None):
691+
result = ser.dt.time
692+
tm.assert_series_equal(result, expected)
693+
694+
if pa_version_under7p0:
695+
return
696+
697+
with pd.option_context("future.infer_time", True):
698+
with tm.assert_produces_warning(None):
699+
result_pa = ser.dt.time
700+
701+
import pyarrow as pa
702+
703+
pa_dtype = pa.time64("ns")
704+
dtype = pd.ArrowDtype(pa_dtype)
705+
expected_pa = expected.astype(dtype)
706+
tm.assert_series_equal(result_pa, expected_pa)
707+
679708
def test_dt_accessor_api(self):
680709
# GH 9322
681710
from pandas.core.indexes.accessors import (

0 commit comments

Comments
 (0)