Skip to content

Commit 475e391

Browse files
jquinonjreback
authored andcommitted
Add timetz attribute to DatetimeIndex (pandas-dev#22132)
1 parent ec58e4e commit 475e391

File tree

9 files changed

+65
-4
lines changed

9 files changed

+65
-4
lines changed

doc/source/api.rst

+2
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ These can be accessed like ``Series.dt.<property>``.
545545

546546
Series.dt.date
547547
Series.dt.time
548+
Series.dt.timetz
548549
Series.dt.year
549550
Series.dt.month
550551
Series.dt.day
@@ -1739,6 +1740,7 @@ Time/Date Components
17391740
DatetimeIndex.nanosecond
17401741
DatetimeIndex.date
17411742
DatetimeIndex.time
1743+
DatetimeIndex.timetz
17421744
DatetimeIndex.dayofyear
17431745
DatetimeIndex.weekofyear
17441746
DatetimeIndex.week

doc/source/timeseries.rst

+1
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ There are several time/date properties that one can access from ``Timestamp`` or
724724
nanosecond,"The nanoseconds of the datetime"
725725
date,"Returns datetime.date (does not contain timezone information)"
726726
time,"Returns datetime.time (does not contain timezone information)"
727+
timetz,"Returns datetime.time as local time with timezone information"
727728
dayofyear,"The ordinal day of year"
728729
weekofyear,"The week ordinal of the year"
729730
week,"The week ordinal of the year"

doc/source/whatsnew/v0.24.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ Other Enhancements
181181
The default compression for ``to_csv``, ``to_json``, and ``to_pickle`` methods has been updated to ``'infer'`` (:issue:`22004`).
182182
- :func:`to_timedelta` now supports iso-formated timedelta strings (:issue:`21877`)
183183
- :class:`Series` and :class:`DataFrame` now support :class:`Iterable` in constructor (:issue:`2193`)
184+
- :class:`DatetimeIndex` gained :attr:`DatetimeIndex.timetz` attribute. Returns local time with timezone information. (:issue:`21358`)
184185

185186
.. _whatsnew_0240.api_breaking:
186187

pandas/_libs/tslib.pyx

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ cdef inline object create_time_from_ts(
7272
int64_t value, npy_datetimestruct dts,
7373
object tz, object freq):
7474
""" convenience routine to construct a datetime.time from its parts """
75-
return time(dts.hour, dts.min, dts.sec, dts.us)
75+
return time(dts.hour, dts.min, dts.sec, dts.us, tz)
7676

7777

7878
def ints_to_pydatetime(int64_t[:] arr, tz=None, freq=None, box="datetime"):

pandas/core/arrays/datetimes.py

+8
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,14 @@ def time(self):
856856

857857
return tslib.ints_to_pydatetime(timestamps, box="time")
858858

859+
@property
860+
def timetz(self):
861+
"""
862+
Returns numpy array of datetime.time also containing timezone
863+
information. The time part of the Timestamps.
864+
"""
865+
return tslib.ints_to_pydatetime(self.asi8, self.tz, box="time")
866+
859867
@property
860868
def date(self):
861869
"""

pandas/core/indexes/datetimes.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class DatetimeIndex(DatetimeArrayMixin, DatelikeOps, TimelikeOps,
170170
nanosecond
171171
date
172172
time
173+
timetz
173174
dayofyear
174175
weekofyear
175176
week
@@ -260,7 +261,7 @@ def _add_comparison_methods(cls):
260261
'dayofyear', 'quarter', 'days_in_month',
261262
'daysinmonth', 'microsecond',
262263
'nanosecond']
263-
_other_ops = ['date', 'time']
264+
_other_ops = ['date', 'time', 'timetz']
264265
_datetimelike_ops = _field_ops + _object_ops + _bool_ops + _other_ops
265266
_datetimelike_methods = ['to_period', 'tz_localize',
266267
'tz_convert',

pandas/tests/indexes/datetimes/test_timezones.py

+14
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,20 @@ def test_time_accessor(self, dtype):
731731

732732
tm.assert_numpy_array_equal(result, expected)
733733

734+
def test_timetz_accessor(self, tz_naive_fixture):
735+
# GH21358
736+
if tz_naive_fixture is not None:
737+
tz = dateutil.tz.gettz(tz_naive_fixture)
738+
else:
739+
tz = None
740+
741+
expected = np.array([time(10, 20, 30, tzinfo=tz), pd.NaT])
742+
743+
index = DatetimeIndex(['2018-06-04 10:20:30', pd.NaT], tz=tz)
744+
result = index.timetz
745+
746+
tm.assert_numpy_array_equal(result, expected)
747+
734748
def test_dti_drop_dont_lose_tz(self):
735749
# GH#2621
736750
ind = date_range("2012-12-01", periods=10, tz="utc")

pandas/tests/scalar/timestamp/test_timezones.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""
33
Tests for Timestamp timezone-related methods
44
"""
5-
from datetime import date, timedelta
5+
from datetime import datetime, date, timedelta
66

77
from distutils.version import LooseVersion
88
import pytest
@@ -290,3 +290,20 @@ def test_timestamp_add_timedelta_push_over_dst_boundary(self, tz):
290290
expected = Timestamp('3/11/2012 05:00', tz=tz)
291291

292292
assert result == expected
293+
294+
def test_timestamp_timetz_equivalent_with_datetime_tz(self,
295+
tz_naive_fixture):
296+
# GH21358
297+
if tz_naive_fixture is not None:
298+
tz = dateutil.tz.gettz(tz_naive_fixture)
299+
else:
300+
tz = None
301+
302+
stamp = Timestamp('2018-06-04 10:20:30', tz=tz)
303+
_datetime = datetime(2018, 6, 4, hour=10,
304+
minute=20, second=30, tzinfo=tz)
305+
306+
result = stamp.timetz()
307+
expected = _datetime.timetz()
308+
309+
assert result == expected

pandas/tests/series/test_datetime_values.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import calendar
66
import pytest
77

8-
from datetime import datetime, date
8+
from datetime import datetime, time, date
99

1010
import numpy as np
1111
import pandas as pd
@@ -16,6 +16,8 @@
1616
PeriodIndex, DatetimeIndex, TimedeltaIndex)
1717
import pandas.core.common as com
1818

19+
import dateutil
20+
1921
from pandas.util.testing import assert_series_equal
2022
import pandas.util.testing as tm
2123

@@ -459,3 +461,18 @@ def test_datetime_understood(self):
459461
expected = pd.Series(pd.to_datetime([
460462
'2011-12-26', '2011-12-27', '2011-12-28']))
461463
tm.assert_series_equal(result, expected)
464+
465+
def test_dt_timetz_accessor(self, tz_naive_fixture):
466+
# GH21358
467+
if tz_naive_fixture is not None:
468+
tz = dateutil.tz.gettz(tz_naive_fixture)
469+
else:
470+
tz = None
471+
472+
dtindex = pd.DatetimeIndex(['2014-04-04 23:56', '2014-07-18 21:24',
473+
'2015-11-22 22:14'], tz=tz)
474+
s = Series(dtindex)
475+
expected = Series([time(23, 56, tzinfo=tz), time(21, 24, tzinfo=tz),
476+
time(22, 14, tzinfo=tz)])
477+
result = s.dt.timetz
478+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)