test_indexing.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. from datetime import (
  2. date,
  3. datetime,
  4. time,
  5. timedelta,
  6. )
  7. import numpy as np
  8. import pytest
  9. import pandas as pd
  10. from pandas import (
  11. DatetimeIndex,
  12. Index,
  13. Timestamp,
  14. bdate_range,
  15. date_range,
  16. notna,
  17. )
  18. import pandas._testing as tm
  19. from pandas.tseries.frequencies import to_offset
  20. START, END = datetime(2009, 1, 1), datetime(2010, 1, 1)
  21. class TestGetItem:
  22. def test_getitem_slice_keeps_name(self):
  23. # GH4226
  24. st = Timestamp("2013-07-01 00:00:00", tz="America/Los_Angeles")
  25. et = Timestamp("2013-07-02 00:00:00", tz="America/Los_Angeles")
  26. dr = date_range(st, et, freq="H", name="timebucket")
  27. assert dr[1:].name == dr.name
  28. def test_getitem(self):
  29. idx1 = date_range("2011-01-01", "2011-01-31", freq="D", name="idx")
  30. idx2 = date_range(
  31. "2011-01-01", "2011-01-31", freq="D", tz="Asia/Tokyo", name="idx"
  32. )
  33. for idx in [idx1, idx2]:
  34. result = idx[0]
  35. assert result == Timestamp("2011-01-01", tz=idx.tz)
  36. result = idx[0:5]
  37. expected = date_range(
  38. "2011-01-01", "2011-01-05", freq="D", tz=idx.tz, name="idx"
  39. )
  40. tm.assert_index_equal(result, expected)
  41. assert result.freq == expected.freq
  42. result = idx[0:10:2]
  43. expected = date_range(
  44. "2011-01-01", "2011-01-09", freq="2D", tz=idx.tz, name="idx"
  45. )
  46. tm.assert_index_equal(result, expected)
  47. assert result.freq == expected.freq
  48. result = idx[-20:-5:3]
  49. expected = date_range(
  50. "2011-01-12", "2011-01-24", freq="3D", tz=idx.tz, name="idx"
  51. )
  52. tm.assert_index_equal(result, expected)
  53. assert result.freq == expected.freq
  54. result = idx[4::-1]
  55. expected = DatetimeIndex(
  56. ["2011-01-05", "2011-01-04", "2011-01-03", "2011-01-02", "2011-01-01"],
  57. freq="-1D",
  58. tz=idx.tz,
  59. name="idx",
  60. )
  61. tm.assert_index_equal(result, expected)
  62. assert result.freq == expected.freq
  63. @pytest.mark.parametrize("freq", ["B", "C"])
  64. def test_dti_business_getitem(self, freq):
  65. rng = bdate_range(START, END, freq=freq)
  66. smaller = rng[:5]
  67. exp = DatetimeIndex(rng.view(np.ndarray)[:5], freq=freq)
  68. tm.assert_index_equal(smaller, exp)
  69. assert smaller.freq == exp.freq
  70. assert smaller.freq == rng.freq
  71. sliced = rng[::5]
  72. assert sliced.freq == to_offset(freq) * 5
  73. fancy_indexed = rng[[4, 3, 2, 1, 0]]
  74. assert len(fancy_indexed) == 5
  75. assert isinstance(fancy_indexed, DatetimeIndex)
  76. assert fancy_indexed.freq is None
  77. # 32-bit vs. 64-bit platforms
  78. assert rng[4] == rng[np.int_(4)]
  79. @pytest.mark.parametrize("freq", ["B", "C"])
  80. def test_dti_business_getitem_matplotlib_hackaround(self, freq):
  81. rng = bdate_range(START, END, freq=freq)
  82. with pytest.raises(ValueError, match="Multi-dimensional indexing"):
  83. # GH#30588 multi-dimensional indexing deprecated
  84. rng[:, None]
  85. def test_getitem_int_list(self):
  86. dti = date_range(start="1/1/2005", end="12/1/2005", freq="M")
  87. dti2 = dti[[1, 3, 5]]
  88. v1 = dti2[0]
  89. v2 = dti2[1]
  90. v3 = dti2[2]
  91. assert v1 == Timestamp("2/28/2005")
  92. assert v2 == Timestamp("4/30/2005")
  93. assert v3 == Timestamp("6/30/2005")
  94. # getitem with non-slice drops freq
  95. assert dti2.freq is None
  96. class TestWhere:
  97. def test_where_doesnt_retain_freq(self):
  98. dti = date_range("20130101", periods=3, freq="D", name="idx")
  99. cond = [True, True, False]
  100. expected = DatetimeIndex([dti[0], dti[1], dti[0]], freq=None, name="idx")
  101. result = dti.where(cond, dti[::-1])
  102. tm.assert_index_equal(result, expected)
  103. def test_where_other(self):
  104. # other is ndarray or Index
  105. i = date_range("20130101", periods=3, tz="US/Eastern")
  106. for arr in [np.nan, pd.NaT]:
  107. result = i.where(notna(i), other=arr)
  108. expected = i
  109. tm.assert_index_equal(result, expected)
  110. i2 = i.copy()
  111. i2 = Index([pd.NaT, pd.NaT] + i[2:].tolist())
  112. result = i.where(notna(i2), i2)
  113. tm.assert_index_equal(result, i2)
  114. i2 = i.copy()
  115. i2 = Index([pd.NaT, pd.NaT] + i[2:].tolist())
  116. result = i.where(notna(i2), i2._values)
  117. tm.assert_index_equal(result, i2)
  118. def test_where_invalid_dtypes(self):
  119. dti = date_range("20130101", periods=3, tz="US/Eastern")
  120. tail = dti[2:].tolist()
  121. i2 = Index([pd.NaT, pd.NaT] + tail)
  122. mask = notna(i2)
  123. # passing tz-naive ndarray to tzaware DTI
  124. result = dti.where(mask, i2.values)
  125. expected = Index([pd.NaT.asm8, pd.NaT.asm8] + tail, dtype=object)
  126. tm.assert_index_equal(result, expected)
  127. # passing tz-aware DTI to tznaive DTI
  128. naive = dti.tz_localize(None)
  129. result = naive.where(mask, i2)
  130. expected = Index([i2[0], i2[1]] + naive[2:].tolist(), dtype=object)
  131. tm.assert_index_equal(result, expected)
  132. pi = i2.tz_localize(None).to_period("D")
  133. result = dti.where(mask, pi)
  134. expected = Index([pi[0], pi[1]] + tail, dtype=object)
  135. tm.assert_index_equal(result, expected)
  136. tda = i2.asi8.view("timedelta64[ns]")
  137. result = dti.where(mask, tda)
  138. expected = Index([tda[0], tda[1]] + tail, dtype=object)
  139. assert isinstance(expected[0], np.timedelta64)
  140. tm.assert_index_equal(result, expected)
  141. result = dti.where(mask, i2.asi8)
  142. expected = Index([pd.NaT._value, pd.NaT._value] + tail, dtype=object)
  143. assert isinstance(expected[0], int)
  144. tm.assert_index_equal(result, expected)
  145. # non-matching scalar
  146. td = pd.Timedelta(days=4)
  147. result = dti.where(mask, td)
  148. expected = Index([td, td] + tail, dtype=object)
  149. assert expected[0] is td
  150. tm.assert_index_equal(result, expected)
  151. def test_where_mismatched_nat(self, tz_aware_fixture):
  152. tz = tz_aware_fixture
  153. dti = date_range("2013-01-01", periods=3, tz=tz)
  154. cond = np.array([True, False, True])
  155. tdnat = np.timedelta64("NaT", "ns")
  156. expected = Index([dti[0], tdnat, dti[2]], dtype=object)
  157. assert expected[1] is tdnat
  158. result = dti.where(cond, tdnat)
  159. tm.assert_index_equal(result, expected)
  160. def test_where_tz(self):
  161. i = date_range("20130101", periods=3, tz="US/Eastern")
  162. result = i.where(notna(i))
  163. expected = i
  164. tm.assert_index_equal(result, expected)
  165. i2 = i.copy()
  166. i2 = Index([pd.NaT, pd.NaT] + i[2:].tolist())
  167. result = i.where(notna(i2))
  168. expected = i2
  169. tm.assert_index_equal(result, expected)
  170. class TestTake:
  171. def test_take_nan_first_datetime(self):
  172. index = DatetimeIndex([pd.NaT, Timestamp("20130101"), Timestamp("20130102")])
  173. result = index.take([-1, 0, 1])
  174. expected = DatetimeIndex([index[-1], index[0], index[1]])
  175. tm.assert_index_equal(result, expected)
  176. def test_take(self):
  177. # GH#10295
  178. idx1 = date_range("2011-01-01", "2011-01-31", freq="D", name="idx")
  179. idx2 = date_range(
  180. "2011-01-01", "2011-01-31", freq="D", tz="Asia/Tokyo", name="idx"
  181. )
  182. for idx in [idx1, idx2]:
  183. result = idx.take([0])
  184. assert result == Timestamp("2011-01-01", tz=idx.tz)
  185. result = idx.take([0, 1, 2])
  186. expected = date_range(
  187. "2011-01-01", "2011-01-03", freq="D", tz=idx.tz, name="idx"
  188. )
  189. tm.assert_index_equal(result, expected)
  190. assert result.freq == expected.freq
  191. result = idx.take([0, 2, 4])
  192. expected = date_range(
  193. "2011-01-01", "2011-01-05", freq="2D", tz=idx.tz, name="idx"
  194. )
  195. tm.assert_index_equal(result, expected)
  196. assert result.freq == expected.freq
  197. result = idx.take([7, 4, 1])
  198. expected = date_range(
  199. "2011-01-08", "2011-01-02", freq="-3D", tz=idx.tz, name="idx"
  200. )
  201. tm.assert_index_equal(result, expected)
  202. assert result.freq == expected.freq
  203. result = idx.take([3, 2, 5])
  204. expected = DatetimeIndex(
  205. ["2011-01-04", "2011-01-03", "2011-01-06"],
  206. freq=None,
  207. tz=idx.tz,
  208. name="idx",
  209. )
  210. tm.assert_index_equal(result, expected)
  211. assert result.freq is None
  212. result = idx.take([-3, 2, 5])
  213. expected = DatetimeIndex(
  214. ["2011-01-29", "2011-01-03", "2011-01-06"],
  215. freq=None,
  216. tz=idx.tz,
  217. name="idx",
  218. )
  219. tm.assert_index_equal(result, expected)
  220. assert result.freq is None
  221. def test_take_invalid_kwargs(self):
  222. idx = date_range("2011-01-01", "2011-01-31", freq="D", name="idx")
  223. indices = [1, 6, 5, 9, 10, 13, 15, 3]
  224. msg = r"take\(\) got an unexpected keyword argument 'foo'"
  225. with pytest.raises(TypeError, match=msg):
  226. idx.take(indices, foo=2)
  227. msg = "the 'out' parameter is not supported"
  228. with pytest.raises(ValueError, match=msg):
  229. idx.take(indices, out=indices)
  230. msg = "the 'mode' parameter is not supported"
  231. with pytest.raises(ValueError, match=msg):
  232. idx.take(indices, mode="clip")
  233. # TODO: This method came from test_datetime; de-dup with version above
  234. @pytest.mark.parametrize("tz", [None, "US/Eastern", "Asia/Tokyo"])
  235. def test_take2(self, tz):
  236. dates = [
  237. datetime(2010, 1, 1, 14),
  238. datetime(2010, 1, 1, 15),
  239. datetime(2010, 1, 1, 17),
  240. datetime(2010, 1, 1, 21),
  241. ]
  242. idx = date_range(
  243. start="2010-01-01 09:00",
  244. end="2010-02-01 09:00",
  245. freq="H",
  246. tz=tz,
  247. name="idx",
  248. )
  249. expected = DatetimeIndex(dates, freq=None, name="idx", tz=tz)
  250. taken1 = idx.take([5, 6, 8, 12])
  251. taken2 = idx[[5, 6, 8, 12]]
  252. for taken in [taken1, taken2]:
  253. tm.assert_index_equal(taken, expected)
  254. assert isinstance(taken, DatetimeIndex)
  255. assert taken.freq is None
  256. assert taken.tz == expected.tz
  257. assert taken.name == expected.name
  258. def test_take_fill_value(self):
  259. # GH#12631
  260. idx = DatetimeIndex(["2011-01-01", "2011-02-01", "2011-03-01"], name="xxx")
  261. result = idx.take(np.array([1, 0, -1]))
  262. expected = DatetimeIndex(["2011-02-01", "2011-01-01", "2011-03-01"], name="xxx")
  263. tm.assert_index_equal(result, expected)
  264. # fill_value
  265. result = idx.take(np.array([1, 0, -1]), fill_value=True)
  266. expected = DatetimeIndex(["2011-02-01", "2011-01-01", "NaT"], name="xxx")
  267. tm.assert_index_equal(result, expected)
  268. # allow_fill=False
  269. result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True)
  270. expected = DatetimeIndex(["2011-02-01", "2011-01-01", "2011-03-01"], name="xxx")
  271. tm.assert_index_equal(result, expected)
  272. msg = (
  273. "When allow_fill=True and fill_value is not None, "
  274. "all indices must be >= -1"
  275. )
  276. with pytest.raises(ValueError, match=msg):
  277. idx.take(np.array([1, 0, -2]), fill_value=True)
  278. with pytest.raises(ValueError, match=msg):
  279. idx.take(np.array([1, 0, -5]), fill_value=True)
  280. msg = "out of bounds"
  281. with pytest.raises(IndexError, match=msg):
  282. idx.take(np.array([1, -5]))
  283. def test_take_fill_value_with_timezone(self):
  284. idx = DatetimeIndex(
  285. ["2011-01-01", "2011-02-01", "2011-03-01"], name="xxx", tz="US/Eastern"
  286. )
  287. result = idx.take(np.array([1, 0, -1]))
  288. expected = DatetimeIndex(
  289. ["2011-02-01", "2011-01-01", "2011-03-01"], name="xxx", tz="US/Eastern"
  290. )
  291. tm.assert_index_equal(result, expected)
  292. # fill_value
  293. result = idx.take(np.array([1, 0, -1]), fill_value=True)
  294. expected = DatetimeIndex(
  295. ["2011-02-01", "2011-01-01", "NaT"], name="xxx", tz="US/Eastern"
  296. )
  297. tm.assert_index_equal(result, expected)
  298. # allow_fill=False
  299. result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True)
  300. expected = DatetimeIndex(
  301. ["2011-02-01", "2011-01-01", "2011-03-01"], name="xxx", tz="US/Eastern"
  302. )
  303. tm.assert_index_equal(result, expected)
  304. msg = (
  305. "When allow_fill=True and fill_value is not None, "
  306. "all indices must be >= -1"
  307. )
  308. with pytest.raises(ValueError, match=msg):
  309. idx.take(np.array([1, 0, -2]), fill_value=True)
  310. with pytest.raises(ValueError, match=msg):
  311. idx.take(np.array([1, 0, -5]), fill_value=True)
  312. msg = "out of bounds"
  313. with pytest.raises(IndexError, match=msg):
  314. idx.take(np.array([1, -5]))
  315. class TestGetLoc:
  316. def test_get_loc_key_unit_mismatch(self):
  317. idx = date_range("2000-01-01", periods=3)
  318. key = idx[1].as_unit("ms")
  319. loc = idx.get_loc(key)
  320. assert loc == 1
  321. assert key in idx
  322. def test_get_loc_key_unit_mismatch_not_castable(self):
  323. dta = date_range("2000-01-01", periods=3)._data.astype("M8[s]")
  324. dti = DatetimeIndex(dta)
  325. key = dta[0].as_unit("ns") + pd.Timedelta(1)
  326. with pytest.raises(
  327. KeyError, match=r"Timestamp\('2000-01-01 00:00:00.000000001'\)"
  328. ):
  329. dti.get_loc(key)
  330. assert key not in dti
  331. def test_get_loc_time_obj(self):
  332. # time indexing
  333. idx = date_range("2000-01-01", periods=24, freq="H")
  334. result = idx.get_loc(time(12))
  335. expected = np.array([12])
  336. tm.assert_numpy_array_equal(result, expected, check_dtype=False)
  337. result = idx.get_loc(time(12, 30))
  338. expected = np.array([])
  339. tm.assert_numpy_array_equal(result, expected, check_dtype=False)
  340. def test_get_loc_time_obj2(self):
  341. # GH#8667
  342. from pandas._libs.index import _SIZE_CUTOFF
  343. ns = _SIZE_CUTOFF + np.array([-100, 100], dtype=np.int64)
  344. key = time(15, 11, 30)
  345. start = key.hour * 3600 + key.minute * 60 + key.second
  346. step = 24 * 3600
  347. for n in ns:
  348. idx = date_range("2014-11-26", periods=n, freq="S")
  349. ts = pd.Series(np.random.randn(n), index=idx)
  350. locs = np.arange(start, n, step, dtype=np.intp)
  351. result = ts.index.get_loc(key)
  352. tm.assert_numpy_array_equal(result, locs)
  353. tm.assert_series_equal(ts[key], ts.iloc[locs])
  354. left, right = ts.copy(), ts.copy()
  355. left[key] *= -10
  356. right.iloc[locs] *= -10
  357. tm.assert_series_equal(left, right)
  358. def test_get_loc_time_nat(self):
  359. # GH#35114
  360. # Case where key's total microseconds happens to match iNaT % 1e6 // 1000
  361. tic = time(minute=12, second=43, microsecond=145224)
  362. dti = DatetimeIndex([pd.NaT])
  363. loc = dti.get_loc(tic)
  364. expected = np.array([], dtype=np.intp)
  365. tm.assert_numpy_array_equal(loc, expected)
  366. def test_get_loc_nat(self):
  367. # GH#20464
  368. index = DatetimeIndex(["1/3/2000", "NaT"])
  369. assert index.get_loc(pd.NaT) == 1
  370. assert index.get_loc(None) == 1
  371. assert index.get_loc(np.nan) == 1
  372. assert index.get_loc(pd.NA) == 1
  373. assert index.get_loc(np.datetime64("NaT")) == 1
  374. with pytest.raises(KeyError, match="NaT"):
  375. index.get_loc(np.timedelta64("NaT"))
  376. @pytest.mark.parametrize("key", [pd.Timedelta(0), pd.Timedelta(1), timedelta(0)])
  377. def test_get_loc_timedelta_invalid_key(self, key):
  378. # GH#20464
  379. dti = date_range("1970-01-01", periods=10)
  380. msg = "Cannot index DatetimeIndex with [Tt]imedelta"
  381. with pytest.raises(TypeError, match=msg):
  382. dti.get_loc(key)
  383. def test_get_loc_reasonable_key_error(self):
  384. # GH#1062
  385. index = DatetimeIndex(["1/3/2000"])
  386. with pytest.raises(KeyError, match="2000"):
  387. index.get_loc("1/1/2000")
  388. def test_get_loc_year_str(self):
  389. rng = date_range("1/1/2000", "1/1/2010")
  390. result = rng.get_loc("2009")
  391. expected = slice(3288, 3653)
  392. assert result == expected
  393. class TestContains:
  394. def test_dti_contains_with_duplicates(self):
  395. d = datetime(2011, 12, 5, 20, 30)
  396. ix = DatetimeIndex([d, d])
  397. assert d in ix
  398. @pytest.mark.parametrize(
  399. "vals",
  400. [
  401. [0, 1, 0],
  402. [0, 0, -1],
  403. [0, -1, -1],
  404. ["2015", "2015", "2016"],
  405. ["2015", "2015", "2014"],
  406. ],
  407. )
  408. def test_contains_nonunique(self, vals):
  409. # GH#9512
  410. idx = DatetimeIndex(vals)
  411. assert idx[0] in idx
  412. class TestGetIndexer:
  413. def test_get_indexer_date_objs(self):
  414. rng = date_range("1/1/2000", periods=20)
  415. result = rng.get_indexer(rng.map(lambda x: x.date()))
  416. expected = rng.get_indexer(rng)
  417. tm.assert_numpy_array_equal(result, expected)
  418. def test_get_indexer(self):
  419. idx = date_range("2000-01-01", periods=3)
  420. exp = np.array([0, 1, 2], dtype=np.intp)
  421. tm.assert_numpy_array_equal(idx.get_indexer(idx), exp)
  422. target = idx[0] + pd.to_timedelta(["-1 hour", "12 hours", "1 day 1 hour"])
  423. tm.assert_numpy_array_equal(
  424. idx.get_indexer(target, "pad"), np.array([-1, 0, 1], dtype=np.intp)
  425. )
  426. tm.assert_numpy_array_equal(
  427. idx.get_indexer(target, "backfill"), np.array([0, 1, 2], dtype=np.intp)
  428. )
  429. tm.assert_numpy_array_equal(
  430. idx.get_indexer(target, "nearest"), np.array([0, 1, 1], dtype=np.intp)
  431. )
  432. tm.assert_numpy_array_equal(
  433. idx.get_indexer(target, "nearest", tolerance=pd.Timedelta("1 hour")),
  434. np.array([0, -1, 1], dtype=np.intp),
  435. )
  436. tol_raw = [
  437. pd.Timedelta("1 hour"),
  438. pd.Timedelta("1 hour"),
  439. pd.Timedelta("1 hour").to_timedelta64(),
  440. ]
  441. tm.assert_numpy_array_equal(
  442. idx.get_indexer(
  443. target, "nearest", tolerance=[np.timedelta64(x) for x in tol_raw]
  444. ),
  445. np.array([0, -1, 1], dtype=np.intp),
  446. )
  447. tol_bad = [
  448. pd.Timedelta("2 hour").to_timedelta64(),
  449. pd.Timedelta("1 hour").to_timedelta64(),
  450. "foo",
  451. ]
  452. msg = "Could not convert 'foo' to NumPy timedelta"
  453. with pytest.raises(ValueError, match=msg):
  454. idx.get_indexer(target, "nearest", tolerance=tol_bad)
  455. with pytest.raises(ValueError, match="abbreviation w/o a number"):
  456. idx.get_indexer(idx[[0]], method="nearest", tolerance="foo")
  457. @pytest.mark.parametrize(
  458. "target",
  459. [
  460. [date(2020, 1, 1), Timestamp("2020-01-02")],
  461. [Timestamp("2020-01-01"), date(2020, 1, 2)],
  462. ],
  463. )
  464. def test_get_indexer_mixed_dtypes(self, target):
  465. # https://github.com/pandas-dev/pandas/issues/33741
  466. values = DatetimeIndex([Timestamp("2020-01-01"), Timestamp("2020-01-02")])
  467. result = values.get_indexer(target)
  468. expected = np.array([0, 1], dtype=np.intp)
  469. tm.assert_numpy_array_equal(result, expected)
  470. @pytest.mark.parametrize(
  471. "target, positions",
  472. [
  473. ([date(9999, 1, 1), Timestamp("2020-01-01")], [-1, 0]),
  474. ([Timestamp("2020-01-01"), date(9999, 1, 1)], [0, -1]),
  475. ([date(9999, 1, 1), date(9999, 1, 1)], [-1, -1]),
  476. ],
  477. )
  478. def test_get_indexer_out_of_bounds_date(self, target, positions):
  479. values = DatetimeIndex([Timestamp("2020-01-01"), Timestamp("2020-01-02")])
  480. result = values.get_indexer(target)
  481. expected = np.array(positions, dtype=np.intp)
  482. tm.assert_numpy_array_equal(result, expected)
  483. def test_get_indexer_pad_requires_monotonicity(self):
  484. rng = date_range("1/1/2000", "3/1/2000", freq="B")
  485. # neither monotonic increasing or decreasing
  486. rng2 = rng[[1, 0, 2]]
  487. msg = "index must be monotonic increasing or decreasing"
  488. with pytest.raises(ValueError, match=msg):
  489. rng2.get_indexer(rng, method="pad")
  490. class TestMaybeCastSliceBound:
  491. def test_maybe_cast_slice_bounds_empty(self):
  492. # GH#14354
  493. empty_idx = date_range(freq="1H", periods=0, end="2015")
  494. right = empty_idx._maybe_cast_slice_bound("2015-01-02", "right")
  495. exp = Timestamp("2015-01-02 23:59:59.999999999")
  496. assert right == exp
  497. left = empty_idx._maybe_cast_slice_bound("2015-01-02", "left")
  498. exp = Timestamp("2015-01-02 00:00:00")
  499. assert left == exp
  500. def test_maybe_cast_slice_duplicate_monotonic(self):
  501. # https://github.com/pandas-dev/pandas/issues/16515
  502. idx = DatetimeIndex(["2017", "2017"])
  503. result = idx._maybe_cast_slice_bound("2017-01-01", "left")
  504. expected = Timestamp("2017-01-01")
  505. assert result == expected
  506. class TestGetSliceBounds:
  507. @pytest.mark.parametrize("box", [date, datetime, Timestamp])
  508. @pytest.mark.parametrize("side, expected", [("left", 4), ("right", 5)])
  509. def test_get_slice_bounds_datetime_within(
  510. self, box, side, expected, tz_aware_fixture
  511. ):
  512. # GH 35690
  513. tz = tz_aware_fixture
  514. index = bdate_range("2000-01-03", "2000-02-11").tz_localize(tz)
  515. key = box(year=2000, month=1, day=7)
  516. if tz is not None:
  517. with pytest.raises(TypeError, match="Cannot compare tz-naive"):
  518. # GH#36148 we require tzawareness-compat as of 2.0
  519. index.get_slice_bound(key, side=side)
  520. else:
  521. result = index.get_slice_bound(key, side=side)
  522. assert result == expected
  523. @pytest.mark.parametrize("box", [datetime, Timestamp])
  524. @pytest.mark.parametrize("side", ["left", "right"])
  525. @pytest.mark.parametrize("year, expected", [(1999, 0), (2020, 30)])
  526. def test_get_slice_bounds_datetime_outside(
  527. self, box, side, year, expected, tz_aware_fixture
  528. ):
  529. # GH 35690
  530. tz = tz_aware_fixture
  531. index = bdate_range("2000-01-03", "2000-02-11").tz_localize(tz)
  532. key = box(year=year, month=1, day=7)
  533. if tz is not None:
  534. with pytest.raises(TypeError, match="Cannot compare tz-naive"):
  535. # GH#36148 we require tzawareness-compat as of 2.0
  536. index.get_slice_bound(key, side=side)
  537. else:
  538. result = index.get_slice_bound(key, side=side)
  539. assert result == expected
  540. @pytest.mark.parametrize("box", [datetime, Timestamp])
  541. def test_slice_datetime_locs(self, box, tz_aware_fixture):
  542. # GH 34077
  543. tz = tz_aware_fixture
  544. index = DatetimeIndex(["2010-01-01", "2010-01-03"]).tz_localize(tz)
  545. key = box(2010, 1, 1)
  546. if tz is not None:
  547. with pytest.raises(TypeError, match="Cannot compare tz-naive"):
  548. # GH#36148 we require tzawareness-compat as of 2.0
  549. index.slice_locs(key, box(2010, 1, 2))
  550. else:
  551. result = index.slice_locs(key, box(2010, 1, 2))
  552. expected = (0, 1)
  553. assert result == expected
  554. class TestIndexerBetweenTime:
  555. def test_indexer_between_time(self):
  556. # GH#11818
  557. rng = date_range("1/1/2000", "1/5/2000", freq="5min")
  558. msg = r"Cannot convert arg \[datetime\.datetime\(2010, 1, 2, 1, 0\)\] to a time"
  559. with pytest.raises(ValueError, match=msg):
  560. rng.indexer_between_time(datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5))
  561. @pytest.mark.parametrize("unit", ["us", "ms", "s"])
  562. def test_indexer_between_time_non_nano(self, unit):
  563. # For simple cases like this, the non-nano indexer_between_time
  564. # should match the nano result
  565. rng = date_range("1/1/2000", "1/5/2000", freq="5min")
  566. arr_nano = rng._data._ndarray
  567. arr = arr_nano.astype(f"M8[{unit}]")
  568. dta = type(rng._data)._simple_new(arr, dtype=arr.dtype)
  569. dti = DatetimeIndex(dta)
  570. assert dti.dtype == arr.dtype
  571. tic = time(1, 25)
  572. toc = time(2, 29)
  573. result = dti.indexer_between_time(tic, toc)
  574. expected = rng.indexer_between_time(tic, toc)
  575. tm.assert_numpy_array_equal(result, expected)
  576. # case with non-zero micros in arguments
  577. tic = time(1, 25, 0, 45678)
  578. toc = time(2, 29, 0, 1234)
  579. result = dti.indexer_between_time(tic, toc)
  580. expected = rng.indexer_between_time(tic, toc)
  581. tm.assert_numpy_array_equal(result, expected)