Skip to content

Commit 0dffbdf

Browse files
authored
BUG: get_loc with time object matching NaT micros (#35114)
1 parent acedb80 commit 0dffbdf

File tree

4 files changed

+28
-28
lines changed

4 files changed

+28
-28
lines changed

doc/source/whatsnew/v1.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,7 @@ Indexing
978978
- Bug in :meth:`DataFrame.loc` with dictionary of values changes columns with dtype of ``int`` to ``float`` (:issue:`34573`)
979979
- Bug in :meth:`Series.loc` when used with a :class:`MultiIndex` would raise an IndexingError when accessing a None value (:issue:`34318`)
980980
- Bug in :meth:`DataFrame.reset_index` and :meth:`Series.reset_index` would not preserve data types on an empty :class:`DataFrame` or :class:`Series` with a :class:`MultiIndex` (:issue:`19602`)
981+
- Bug in :class:`Series` and :class:`DataFrame` indexing with a ``time`` key on a :class:`DatetimeIndex` with ``NaT`` entries (:issue:`35114`)
981982

982983
Missing
983984
^^^^^^^

pandas/_libs/tslibs/fields.pyx

-22
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ from pandas._config.localization import set_locale
1616

1717
from pandas._libs.tslibs.ccalendar import MONTHS_FULL, DAYS_FULL
1818
from pandas._libs.tslibs.ccalendar cimport (
19-
DAY_NANOS,
2019
get_days_in_month, is_leapyear, dayofweek, get_week_of_year,
2120
get_day_of_year, get_iso_calendar, iso_calendar_t,
2221
month_offset,
@@ -28,27 +27,6 @@ from pandas._libs.tslibs.nattype cimport NPY_NAT
2827
from pandas._libs.tslibs.strptime import LocaleTime
2928

3029

31-
def get_time_micros(const int64_t[:] dtindex):
32-
"""
33-
Return the number of microseconds in the time component of a
34-
nanosecond timestamp.
35-
36-
Parameters
37-
----------
38-
dtindex : ndarray[int64_t]
39-
40-
Returns
41-
-------
42-
micros : ndarray[int64_t]
43-
"""
44-
cdef:
45-
ndarray[int64_t] micros
46-
47-
micros = np.mod(dtindex, DAY_NANOS, dtype=np.int64)
48-
micros //= 1000
49-
return micros
50-
51-
5230
@cython.wraparound(False)
5331
@cython.boundscheck(False)
5432
def build_field_sarray(const int64_t[:] dtindex):

pandas/core/indexes/datetimes.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import numpy as np
77

88
from pandas._libs import NaT, Period, Timestamp, index as libindex, lib, tslib
9-
from pandas._libs.tslibs import Resolution, fields, parsing, timezones, to_offset
9+
from pandas._libs.tslibs import Resolution, parsing, timezones, to_offset
1010
from pandas._libs.tslibs.offsets import prefix_mapping
1111
from pandas._typing import DtypeObj, Label
1212
from pandas.errors import InvalidIndexError
@@ -86,7 +86,6 @@ def _new_DatetimeIndex(cls, d):
8686
"tzinfo",
8787
"dtype",
8888
"to_pydatetime",
89-
"_local_timestamps",
9089
"_has_same_tz",
9190
"_format_native_types",
9291
"date",
@@ -380,10 +379,22 @@ def union_many(self, others):
380379
# --------------------------------------------------------------------
381380

382381
def _get_time_micros(self):
382+
"""
383+
Return the number of microseconds since midnight.
384+
385+
Returns
386+
-------
387+
ndarray[int64_t]
388+
"""
383389
values = self.asi8
384390
if self.tz is not None and not timezones.is_utc(self.tz):
385391
values = self._data._local_timestamps()
386-
return fields.get_time_micros(values)
392+
393+
nanos = values % (24 * 3600 * 1_000_000_000)
394+
micros = nanos // 1000
395+
396+
micros[self._isnan] = -1
397+
return micros
387398

388399
def to_series(self, keep_tz=lib.no_default, index=None, name=None):
389400
"""
@@ -1094,6 +1105,6 @@ def bdate_range(
10941105
)
10951106

10961107

1097-
def _time_to_micros(time):
1098-
seconds = time.hour * 60 * 60 + 60 * time.minute + time.second
1099-
return 1000000 * seconds + time.microsecond
1108+
def _time_to_micros(time_obj: time) -> int:
1109+
seconds = time_obj.hour * 60 * 60 + 60 * time_obj.minute + time_obj.second
1110+
return 1_000_000 * seconds + time_obj.microsecond

pandas/tests/indexes/datetimes/test_indexing.py

+10
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,16 @@ def test_get_loc(self):
471471
with pytest.raises(NotImplementedError, match=msg):
472472
idx.get_loc(time(12, 30), method="pad")
473473

474+
def test_get_loc_time_nat(self):
475+
# GH#35114
476+
# Case where key's total microseconds happens to match iNaT % 1e6 // 1000
477+
tic = time(minute=12, second=43, microsecond=145224)
478+
dti = pd.DatetimeIndex([pd.NaT])
479+
480+
loc = dti.get_loc(tic)
481+
expected = np.array([], dtype=np.intp)
482+
tm.assert_numpy_array_equal(loc, expected)
483+
474484
def test_get_loc_tz_aware(self):
475485
# https://github.com/pandas-dev/pandas/issues/32140
476486
dti = pd.date_range(

0 commit comments

Comments
 (0)