Skip to content

Commit 80c005e

Browse files
authored
ENH: DatetimeIndex.indexer_between_time support non-nano (#47535)
1 parent fd1f643 commit 80c005e

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

pandas/core/indexes/datetimes.py

+17-3
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
)
2727
from pandas._libs.tslibs import (
2828
Resolution,
29+
periods_per_day,
2930
timezones,
3031
to_offset,
3132
)
33+
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
3234
from pandas._libs.tslibs.offsets import prefix_mapping
3335
from pandas._typing import (
3436
Dtype,
@@ -448,7 +450,7 @@ def _maybe_utc_convert(self, other: Index) -> tuple[DatetimeIndex, Index]:
448450

449451
# --------------------------------------------------------------------
450452

451-
def _get_time_micros(self) -> np.ndarray:
453+
def _get_time_micros(self) -> npt.NDArray[np.int64]:
452454
"""
453455
Return the number of microseconds since midnight.
454456
@@ -458,8 +460,20 @@ def _get_time_micros(self) -> np.ndarray:
458460
"""
459461
values = self._data._local_timestamps()
460462

461-
nanos = values % (24 * 3600 * 1_000_000_000)
462-
micros = nanos // 1000
463+
reso = self._data._reso
464+
ppd = periods_per_day(reso)
465+
466+
frac = values % ppd
467+
if reso == NpyDatetimeUnit.NPY_FR_ns.value:
468+
micros = frac // 1000
469+
elif reso == NpyDatetimeUnit.NPY_FR_us.value:
470+
micros = frac
471+
elif reso == NpyDatetimeUnit.NPY_FR_ms.value:
472+
micros = frac * 1000
473+
elif reso == NpyDatetimeUnit.NPY_FR_s.value:
474+
micros = frac * 1_000_000
475+
else: # pragma: no cover
476+
raise NotImplementedError(reso)
463477

464478
micros[self._isnan] = -1
465479
return micros

pandas/tests/indexes/datetimes/test_indexing.py

+29
Original file line numberDiff line numberDiff line change
@@ -777,3 +777,32 @@ def test_indexer_between_time(self):
777777
msg = r"Cannot convert arg \[datetime\.datetime\(2010, 1, 2, 1, 0\)\] to a time"
778778
with pytest.raises(ValueError, match=msg):
779779
rng.indexer_between_time(datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5))
780+
781+
@pytest.mark.parametrize("unit", ["us", "ms", "s"])
782+
def test_indexer_between_time_non_nano(self, unit):
783+
# For simple cases like this, the non-nano indexer_between_time
784+
# should match the nano result
785+
786+
rng = date_range("1/1/2000", "1/5/2000", freq="5min")
787+
arr_nano = rng._data._ndarray
788+
789+
arr = arr_nano.astype(f"M8[{unit}]")
790+
791+
dta = type(rng._data)._simple_new(arr, dtype=arr.dtype)
792+
dti = DatetimeIndex(dta)
793+
assert dti.dtype == arr.dtype
794+
795+
tic = time(1, 25)
796+
toc = time(2, 29)
797+
798+
result = dti.indexer_between_time(tic, toc)
799+
expected = rng.indexer_between_time(tic, toc)
800+
tm.assert_numpy_array_equal(result, expected)
801+
802+
# case with non-zero micros in arguments
803+
tic = time(1, 25, 0, 45678)
804+
toc = time(2, 29, 0, 1234)
805+
806+
result = dti.indexer_between_time(tic, toc)
807+
expected = rng.indexer_between_time(tic, toc)
808+
tm.assert_numpy_array_equal(result, expected)

0 commit comments

Comments
 (0)