test_constructors.py 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  1. from datetime import (
  2. datetime,
  3. timedelta,
  4. timezone,
  5. )
  6. from functools import partial
  7. from operator import attrgetter
  8. import dateutil
  9. import numpy as np
  10. import pytest
  11. import pytz
  12. from pandas._libs.tslibs import (
  13. OutOfBoundsDatetime,
  14. astype_overflowsafe,
  15. )
  16. import pandas as pd
  17. from pandas import (
  18. DatetimeIndex,
  19. Index,
  20. Timestamp,
  21. date_range,
  22. offsets,
  23. to_datetime,
  24. )
  25. import pandas._testing as tm
  26. from pandas.core.arrays import (
  27. DatetimeArray,
  28. period_array,
  29. )
  30. class TestDatetimeIndex:
  31. def test_from_dt64_unsupported_unit(self):
  32. # GH#49292
  33. val = np.datetime64(1, "D")
  34. result = DatetimeIndex([val], tz="US/Pacific")
  35. expected = DatetimeIndex([val.astype("M8[s]")], tz="US/Pacific")
  36. tm.assert_index_equal(result, expected)
  37. def test_explicit_tz_none(self):
  38. # GH#48659
  39. dti = date_range("2016-01-01", periods=10, tz="UTC")
  40. msg = "Passed data is timezone-aware, incompatible with 'tz=None'"
  41. with pytest.raises(ValueError, match=msg):
  42. DatetimeIndex(dti, tz=None)
  43. with pytest.raises(ValueError, match=msg):
  44. DatetimeIndex(np.array(dti), tz=None)
  45. msg = "Cannot pass both a timezone-aware dtype and tz=None"
  46. with pytest.raises(ValueError, match=msg):
  47. DatetimeIndex([], dtype="M8[ns, UTC]", tz=None)
  48. @pytest.mark.parametrize(
  49. "dt_cls", [DatetimeIndex, DatetimeArray._from_sequence_not_strict]
  50. )
  51. def test_freq_validation_with_nat(self, dt_cls):
  52. # GH#11587 make sure we get a useful error message when generate_range
  53. # raises
  54. msg = (
  55. "Inferred frequency None from passed values does not conform "
  56. "to passed frequency D"
  57. )
  58. with pytest.raises(ValueError, match=msg):
  59. dt_cls([pd.NaT, Timestamp("2011-01-01")], freq="D")
  60. with pytest.raises(ValueError, match=msg):
  61. dt_cls([pd.NaT, Timestamp("2011-01-01")._value], freq="D")
  62. # TODO: better place for tests shared by DTI/TDI?
  63. @pytest.mark.parametrize(
  64. "index",
  65. [
  66. date_range("2016-01-01", periods=5, tz="US/Pacific"),
  67. pd.timedelta_range("1 Day", periods=5),
  68. ],
  69. )
  70. def test_shallow_copy_inherits_array_freq(self, index):
  71. # If we pass a DTA/TDA to shallow_copy and dont specify a freq,
  72. # we should inherit the array's freq, not our own.
  73. array = index._data
  74. arr = array[[0, 3, 2, 4, 1]]
  75. assert arr.freq is None
  76. result = index._shallow_copy(arr)
  77. assert result.freq is None
  78. def test_categorical_preserves_tz(self):
  79. # GH#18664 retain tz when going DTI-->Categorical-->DTI
  80. dti = DatetimeIndex(
  81. [pd.NaT, "2015-01-01", "1999-04-06 15:14:13", "2015-01-01"], tz="US/Eastern"
  82. )
  83. for dtobj in [dti, dti._data]:
  84. # works for DatetimeIndex or DatetimeArray
  85. ci = pd.CategoricalIndex(dtobj)
  86. carr = pd.Categorical(dtobj)
  87. cser = pd.Series(ci)
  88. for obj in [ci, carr, cser]:
  89. result = DatetimeIndex(obj)
  90. tm.assert_index_equal(result, dti)
  91. def test_dti_with_period_data_raises(self):
  92. # GH#23675
  93. data = pd.PeriodIndex(["2016Q1", "2016Q2"], freq="Q")
  94. with pytest.raises(TypeError, match="PeriodDtype data is invalid"):
  95. DatetimeIndex(data)
  96. with pytest.raises(TypeError, match="PeriodDtype data is invalid"):
  97. to_datetime(data)
  98. with pytest.raises(TypeError, match="PeriodDtype data is invalid"):
  99. DatetimeIndex(period_array(data))
  100. with pytest.raises(TypeError, match="PeriodDtype data is invalid"):
  101. to_datetime(period_array(data))
  102. def test_dti_with_timedelta64_data_raises(self):
  103. # GH#23675 deprecated, enforrced in GH#29794
  104. data = np.array([0], dtype="m8[ns]")
  105. msg = r"timedelta64\[ns\] cannot be converted to datetime64"
  106. with pytest.raises(TypeError, match=msg):
  107. DatetimeIndex(data)
  108. with pytest.raises(TypeError, match=msg):
  109. to_datetime(data)
  110. with pytest.raises(TypeError, match=msg):
  111. DatetimeIndex(pd.TimedeltaIndex(data))
  112. with pytest.raises(TypeError, match=msg):
  113. to_datetime(pd.TimedeltaIndex(data))
  114. def test_constructor_from_sparse_array(self):
  115. # https://github.com/pandas-dev/pandas/issues/35843
  116. values = [
  117. Timestamp("2012-05-01T01:00:00.000000"),
  118. Timestamp("2016-05-01T01:00:00.000000"),
  119. ]
  120. arr = pd.arrays.SparseArray(values)
  121. result = Index(arr)
  122. assert type(result) is Index
  123. assert result.dtype == arr.dtype
  124. def test_construction_caching(self):
  125. df = pd.DataFrame(
  126. {
  127. "dt": date_range("20130101", periods=3),
  128. "dttz": date_range("20130101", periods=3, tz="US/Eastern"),
  129. "dt_with_null": [
  130. Timestamp("20130101"),
  131. pd.NaT,
  132. Timestamp("20130103"),
  133. ],
  134. "dtns": date_range("20130101", periods=3, freq="ns"),
  135. }
  136. )
  137. assert df.dttz.dtype.tz.zone == "US/Eastern"
  138. @pytest.mark.parametrize(
  139. "kwargs",
  140. [{"tz": "dtype.tz"}, {"dtype": "dtype"}, {"dtype": "dtype", "tz": "dtype.tz"}],
  141. )
  142. def test_construction_with_alt(self, kwargs, tz_aware_fixture):
  143. tz = tz_aware_fixture
  144. i = date_range("20130101", periods=5, freq="H", tz=tz)
  145. kwargs = {key: attrgetter(val)(i) for key, val in kwargs.items()}
  146. result = DatetimeIndex(i, **kwargs)
  147. tm.assert_index_equal(i, result)
  148. @pytest.mark.parametrize(
  149. "kwargs",
  150. [{"tz": "dtype.tz"}, {"dtype": "dtype"}, {"dtype": "dtype", "tz": "dtype.tz"}],
  151. )
  152. def test_construction_with_alt_tz_localize(self, kwargs, tz_aware_fixture):
  153. tz = tz_aware_fixture
  154. i = date_range("20130101", periods=5, freq="H", tz=tz)
  155. i = i._with_freq(None)
  156. kwargs = {key: attrgetter(val)(i) for key, val in kwargs.items()}
  157. if "tz" in kwargs:
  158. result = DatetimeIndex(i.asi8, tz="UTC").tz_convert(kwargs["tz"])
  159. expected = DatetimeIndex(i, **kwargs)
  160. tm.assert_index_equal(result, expected)
  161. # localize into the provided tz
  162. i2 = DatetimeIndex(i.tz_localize(None).asi8, tz="UTC")
  163. expected = i.tz_localize(None).tz_localize("UTC")
  164. tm.assert_index_equal(i2, expected)
  165. # incompat tz/dtype
  166. msg = "cannot supply both a tz and a dtype with a tz"
  167. with pytest.raises(ValueError, match=msg):
  168. DatetimeIndex(i.tz_localize(None).asi8, dtype=i.dtype, tz="US/Pacific")
  169. def test_construction_index_with_mixed_timezones(self):
  170. # gh-11488: no tz results in DatetimeIndex
  171. result = Index([Timestamp("2011-01-01"), Timestamp("2011-01-02")], name="idx")
  172. exp = DatetimeIndex(
  173. [Timestamp("2011-01-01"), Timestamp("2011-01-02")], name="idx"
  174. )
  175. tm.assert_index_equal(result, exp, exact=True)
  176. assert isinstance(result, DatetimeIndex)
  177. assert result.tz is None
  178. # same tz results in DatetimeIndex
  179. result = Index(
  180. [
  181. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  182. Timestamp("2011-01-02 10:00", tz="Asia/Tokyo"),
  183. ],
  184. name="idx",
  185. )
  186. exp = DatetimeIndex(
  187. [Timestamp("2011-01-01 10:00"), Timestamp("2011-01-02 10:00")],
  188. tz="Asia/Tokyo",
  189. name="idx",
  190. )
  191. tm.assert_index_equal(result, exp, exact=True)
  192. assert isinstance(result, DatetimeIndex)
  193. assert result.tz is not None
  194. assert result.tz == exp.tz
  195. # same tz results in DatetimeIndex (DST)
  196. result = Index(
  197. [
  198. Timestamp("2011-01-01 10:00", tz="US/Eastern"),
  199. Timestamp("2011-08-01 10:00", tz="US/Eastern"),
  200. ],
  201. name="idx",
  202. )
  203. exp = DatetimeIndex(
  204. [Timestamp("2011-01-01 10:00"), Timestamp("2011-08-01 10:00")],
  205. tz="US/Eastern",
  206. name="idx",
  207. )
  208. tm.assert_index_equal(result, exp, exact=True)
  209. assert isinstance(result, DatetimeIndex)
  210. assert result.tz is not None
  211. assert result.tz == exp.tz
  212. # Different tz results in Index(dtype=object)
  213. result = Index(
  214. [
  215. Timestamp("2011-01-01 10:00"),
  216. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  217. ],
  218. name="idx",
  219. )
  220. exp = Index(
  221. [
  222. Timestamp("2011-01-01 10:00"),
  223. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  224. ],
  225. dtype="object",
  226. name="idx",
  227. )
  228. tm.assert_index_equal(result, exp, exact=True)
  229. assert not isinstance(result, DatetimeIndex)
  230. result = Index(
  231. [
  232. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  233. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  234. ],
  235. name="idx",
  236. )
  237. exp = Index(
  238. [
  239. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  240. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  241. ],
  242. dtype="object",
  243. name="idx",
  244. )
  245. tm.assert_index_equal(result, exp, exact=True)
  246. assert not isinstance(result, DatetimeIndex)
  247. # length = 1
  248. result = Index([Timestamp("2011-01-01")], name="idx")
  249. exp = DatetimeIndex([Timestamp("2011-01-01")], name="idx")
  250. tm.assert_index_equal(result, exp, exact=True)
  251. assert isinstance(result, DatetimeIndex)
  252. assert result.tz is None
  253. # length = 1 with tz
  254. result = Index([Timestamp("2011-01-01 10:00", tz="Asia/Tokyo")], name="idx")
  255. exp = DatetimeIndex(
  256. [Timestamp("2011-01-01 10:00")], tz="Asia/Tokyo", name="idx"
  257. )
  258. tm.assert_index_equal(result, exp, exact=True)
  259. assert isinstance(result, DatetimeIndex)
  260. assert result.tz is not None
  261. assert result.tz == exp.tz
  262. def test_construction_index_with_mixed_timezones_with_NaT(self):
  263. # see gh-11488
  264. result = Index(
  265. [pd.NaT, Timestamp("2011-01-01"), pd.NaT, Timestamp("2011-01-02")],
  266. name="idx",
  267. )
  268. exp = DatetimeIndex(
  269. [pd.NaT, Timestamp("2011-01-01"), pd.NaT, Timestamp("2011-01-02")],
  270. name="idx",
  271. )
  272. tm.assert_index_equal(result, exp, exact=True)
  273. assert isinstance(result, DatetimeIndex)
  274. assert result.tz is None
  275. # Same tz results in DatetimeIndex
  276. result = Index(
  277. [
  278. pd.NaT,
  279. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  280. pd.NaT,
  281. Timestamp("2011-01-02 10:00", tz="Asia/Tokyo"),
  282. ],
  283. name="idx",
  284. )
  285. exp = DatetimeIndex(
  286. [
  287. pd.NaT,
  288. Timestamp("2011-01-01 10:00"),
  289. pd.NaT,
  290. Timestamp("2011-01-02 10:00"),
  291. ],
  292. tz="Asia/Tokyo",
  293. name="idx",
  294. )
  295. tm.assert_index_equal(result, exp, exact=True)
  296. assert isinstance(result, DatetimeIndex)
  297. assert result.tz is not None
  298. assert result.tz == exp.tz
  299. # same tz results in DatetimeIndex (DST)
  300. result = Index(
  301. [
  302. Timestamp("2011-01-01 10:00", tz="US/Eastern"),
  303. pd.NaT,
  304. Timestamp("2011-08-01 10:00", tz="US/Eastern"),
  305. ],
  306. name="idx",
  307. )
  308. exp = DatetimeIndex(
  309. [Timestamp("2011-01-01 10:00"), pd.NaT, Timestamp("2011-08-01 10:00")],
  310. tz="US/Eastern",
  311. name="idx",
  312. )
  313. tm.assert_index_equal(result, exp, exact=True)
  314. assert isinstance(result, DatetimeIndex)
  315. assert result.tz is not None
  316. assert result.tz == exp.tz
  317. # different tz results in Index(dtype=object)
  318. result = Index(
  319. [
  320. pd.NaT,
  321. Timestamp("2011-01-01 10:00"),
  322. pd.NaT,
  323. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  324. ],
  325. name="idx",
  326. )
  327. exp = Index(
  328. [
  329. pd.NaT,
  330. Timestamp("2011-01-01 10:00"),
  331. pd.NaT,
  332. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  333. ],
  334. dtype="object",
  335. name="idx",
  336. )
  337. tm.assert_index_equal(result, exp, exact=True)
  338. assert not isinstance(result, DatetimeIndex)
  339. result = Index(
  340. [
  341. pd.NaT,
  342. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  343. pd.NaT,
  344. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  345. ],
  346. name="idx",
  347. )
  348. exp = Index(
  349. [
  350. pd.NaT,
  351. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  352. pd.NaT,
  353. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  354. ],
  355. dtype="object",
  356. name="idx",
  357. )
  358. tm.assert_index_equal(result, exp, exact=True)
  359. assert not isinstance(result, DatetimeIndex)
  360. # all NaT
  361. result = Index([pd.NaT, pd.NaT], name="idx")
  362. exp = DatetimeIndex([pd.NaT, pd.NaT], name="idx")
  363. tm.assert_index_equal(result, exp, exact=True)
  364. assert isinstance(result, DatetimeIndex)
  365. assert result.tz is None
  366. def test_construction_dti_with_mixed_timezones(self):
  367. # GH 11488 (not changed, added explicit tests)
  368. # no tz results in DatetimeIndex
  369. result = DatetimeIndex(
  370. [Timestamp("2011-01-01"), Timestamp("2011-01-02")], name="idx"
  371. )
  372. exp = DatetimeIndex(
  373. [Timestamp("2011-01-01"), Timestamp("2011-01-02")], name="idx"
  374. )
  375. tm.assert_index_equal(result, exp, exact=True)
  376. assert isinstance(result, DatetimeIndex)
  377. # same tz results in DatetimeIndex
  378. result = DatetimeIndex(
  379. [
  380. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  381. Timestamp("2011-01-02 10:00", tz="Asia/Tokyo"),
  382. ],
  383. name="idx",
  384. )
  385. exp = DatetimeIndex(
  386. [Timestamp("2011-01-01 10:00"), Timestamp("2011-01-02 10:00")],
  387. tz="Asia/Tokyo",
  388. name="idx",
  389. )
  390. tm.assert_index_equal(result, exp, exact=True)
  391. assert isinstance(result, DatetimeIndex)
  392. # same tz results in DatetimeIndex (DST)
  393. result = DatetimeIndex(
  394. [
  395. Timestamp("2011-01-01 10:00", tz="US/Eastern"),
  396. Timestamp("2011-08-01 10:00", tz="US/Eastern"),
  397. ],
  398. name="idx",
  399. )
  400. exp = DatetimeIndex(
  401. [Timestamp("2011-01-01 10:00"), Timestamp("2011-08-01 10:00")],
  402. tz="US/Eastern",
  403. name="idx",
  404. )
  405. tm.assert_index_equal(result, exp, exact=True)
  406. assert isinstance(result, DatetimeIndex)
  407. # tz mismatch affecting to tz-aware raises TypeError/ValueError
  408. msg = "cannot be converted to datetime64"
  409. with pytest.raises(ValueError, match=msg):
  410. DatetimeIndex(
  411. [
  412. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  413. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  414. ],
  415. name="idx",
  416. )
  417. # pre-2.0 this raised bc of awareness mismatch. in 2.0 with a tz#
  418. # specified we behave as if this was called pointwise, so
  419. # the naive Timestamp is treated as a wall time.
  420. dti = DatetimeIndex(
  421. [
  422. Timestamp("2011-01-01 10:00"),
  423. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  424. ],
  425. tz="Asia/Tokyo",
  426. name="idx",
  427. )
  428. expected = DatetimeIndex(
  429. [
  430. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  431. Timestamp("2011-01-02 10:00", tz="US/Eastern").tz_convert("Asia/Tokyo"),
  432. ],
  433. tz="Asia/Tokyo",
  434. name="idx",
  435. )
  436. tm.assert_index_equal(dti, expected)
  437. # pre-2.0 mixed-tz scalars raised even if a tz/dtype was specified.
  438. # as of 2.0 we successfully return the requested tz/dtype
  439. dti = DatetimeIndex(
  440. [
  441. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  442. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  443. ],
  444. tz="US/Eastern",
  445. name="idx",
  446. )
  447. expected = DatetimeIndex(
  448. [
  449. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo").tz_convert("US/Eastern"),
  450. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  451. ],
  452. tz="US/Eastern",
  453. name="idx",
  454. )
  455. tm.assert_index_equal(dti, expected)
  456. # same thing but pass dtype instead of tz
  457. dti = DatetimeIndex(
  458. [
  459. Timestamp("2011-01-01 10:00", tz="Asia/Tokyo"),
  460. Timestamp("2011-01-02 10:00", tz="US/Eastern"),
  461. ],
  462. dtype="M8[ns, US/Eastern]",
  463. name="idx",
  464. )
  465. tm.assert_index_equal(dti, expected)
  466. def test_construction_base_constructor(self):
  467. arr = [Timestamp("2011-01-01"), pd.NaT, Timestamp("2011-01-03")]
  468. tm.assert_index_equal(Index(arr), DatetimeIndex(arr))
  469. tm.assert_index_equal(Index(np.array(arr)), DatetimeIndex(np.array(arr)))
  470. arr = [np.nan, pd.NaT, Timestamp("2011-01-03")]
  471. tm.assert_index_equal(Index(arr), DatetimeIndex(arr))
  472. tm.assert_index_equal(Index(np.array(arr)), DatetimeIndex(np.array(arr)))
  473. def test_construction_outofbounds(self):
  474. # GH 13663
  475. dates = [
  476. datetime(3000, 1, 1),
  477. datetime(4000, 1, 1),
  478. datetime(5000, 1, 1),
  479. datetime(6000, 1, 1),
  480. ]
  481. exp = Index(dates, dtype=object)
  482. # coerces to object
  483. tm.assert_index_equal(Index(dates), exp)
  484. msg = "^Out of bounds nanosecond timestamp: 3000-01-01 00:00:00, at position 0$"
  485. with pytest.raises(OutOfBoundsDatetime, match=msg):
  486. # can't create DatetimeIndex
  487. DatetimeIndex(dates)
  488. def test_construction_with_ndarray(self):
  489. # GH 5152
  490. dates = [datetime(2013, 10, 7), datetime(2013, 10, 8), datetime(2013, 10, 9)]
  491. data = DatetimeIndex(dates, freq=offsets.BDay()).values
  492. result = DatetimeIndex(data, freq=offsets.BDay())
  493. expected = DatetimeIndex(["2013-10-07", "2013-10-08", "2013-10-09"], freq="B")
  494. tm.assert_index_equal(result, expected)
  495. def test_integer_values_and_tz_interpreted_as_utc(self):
  496. # GH-24559
  497. val = np.datetime64("2000-01-01 00:00:00", "ns")
  498. values = np.array([val.view("i8")])
  499. result = DatetimeIndex(values).tz_localize("US/Central")
  500. expected = DatetimeIndex(["2000-01-01T00:00:00"], tz="US/Central")
  501. tm.assert_index_equal(result, expected)
  502. # but UTC is *not* deprecated.
  503. with tm.assert_produces_warning(None):
  504. result = DatetimeIndex(values, tz="UTC")
  505. expected = DatetimeIndex(["2000-01-01T00:00:00"], tz="US/Central")
  506. def test_constructor_coverage(self):
  507. rng = date_range("1/1/2000", periods=10.5)
  508. exp = date_range("1/1/2000", periods=10)
  509. tm.assert_index_equal(rng, exp)
  510. msg = "periods must be a number, got foo"
  511. with pytest.raises(TypeError, match=msg):
  512. date_range(start="1/1/2000", periods="foo", freq="D")
  513. msg = r"DatetimeIndex\(\.\.\.\) must be called with a collection"
  514. with pytest.raises(TypeError, match=msg):
  515. DatetimeIndex("1/1/2000")
  516. # generator expression
  517. gen = (datetime(2000, 1, 1) + timedelta(i) for i in range(10))
  518. result = DatetimeIndex(gen)
  519. expected = DatetimeIndex(
  520. [datetime(2000, 1, 1) + timedelta(i) for i in range(10)]
  521. )
  522. tm.assert_index_equal(result, expected)
  523. # NumPy string array
  524. strings = np.array(["2000-01-01", "2000-01-02", "2000-01-03"])
  525. result = DatetimeIndex(strings)
  526. expected = DatetimeIndex(strings.astype("O"))
  527. tm.assert_index_equal(result, expected)
  528. from_ints = DatetimeIndex(expected.asi8)
  529. tm.assert_index_equal(from_ints, expected)
  530. # string with NaT
  531. strings = np.array(["2000-01-01", "2000-01-02", "NaT"])
  532. result = DatetimeIndex(strings)
  533. expected = DatetimeIndex(strings.astype("O"))
  534. tm.assert_index_equal(result, expected)
  535. from_ints = DatetimeIndex(expected.asi8)
  536. tm.assert_index_equal(from_ints, expected)
  537. # non-conforming
  538. msg = (
  539. "Inferred frequency None from passed values does not conform "
  540. "to passed frequency D"
  541. )
  542. with pytest.raises(ValueError, match=msg):
  543. DatetimeIndex(["2000-01-01", "2000-01-02", "2000-01-04"], freq="D")
  544. msg = (
  545. "Of the four parameters: start, end, periods, and freq, exactly "
  546. "three must be specified"
  547. )
  548. with pytest.raises(ValueError, match=msg):
  549. date_range(start="2011-01-01", freq="b")
  550. with pytest.raises(ValueError, match=msg):
  551. date_range(end="2011-01-01", freq="B")
  552. with pytest.raises(ValueError, match=msg):
  553. date_range(periods=10, freq="D")
  554. @pytest.mark.parametrize("freq", ["AS", "W-SUN"])
  555. def test_constructor_datetime64_tzformat(self, freq):
  556. # see GH#6572: ISO 8601 format results in stdlib timezone object
  557. idx = date_range(
  558. "2013-01-01T00:00:00-05:00", "2016-01-01T23:59:59-05:00", freq=freq
  559. )
  560. expected = date_range(
  561. "2013-01-01T00:00:00",
  562. "2016-01-01T23:59:59",
  563. freq=freq,
  564. tz=timezone(timedelta(minutes=-300)),
  565. )
  566. tm.assert_index_equal(idx, expected)
  567. # Unable to use `US/Eastern` because of DST
  568. expected_i8 = date_range(
  569. "2013-01-01T00:00:00", "2016-01-01T23:59:59", freq=freq, tz="America/Lima"
  570. )
  571. tm.assert_numpy_array_equal(idx.asi8, expected_i8.asi8)
  572. idx = date_range(
  573. "2013-01-01T00:00:00+09:00", "2016-01-01T23:59:59+09:00", freq=freq
  574. )
  575. expected = date_range(
  576. "2013-01-01T00:00:00",
  577. "2016-01-01T23:59:59",
  578. freq=freq,
  579. tz=timezone(timedelta(minutes=540)),
  580. )
  581. tm.assert_index_equal(idx, expected)
  582. expected_i8 = date_range(
  583. "2013-01-01T00:00:00", "2016-01-01T23:59:59", freq=freq, tz="Asia/Tokyo"
  584. )
  585. tm.assert_numpy_array_equal(idx.asi8, expected_i8.asi8)
  586. # Non ISO 8601 format results in dateutil.tz.tzoffset
  587. idx = date_range("2013/1/1 0:00:00-5:00", "2016/1/1 23:59:59-5:00", freq=freq)
  588. expected = date_range(
  589. "2013-01-01T00:00:00",
  590. "2016-01-01T23:59:59",
  591. freq=freq,
  592. tz=timezone(timedelta(minutes=-300)),
  593. )
  594. tm.assert_index_equal(idx, expected)
  595. # Unable to use `US/Eastern` because of DST
  596. expected_i8 = date_range(
  597. "2013-01-01T00:00:00", "2016-01-01T23:59:59", freq=freq, tz="America/Lima"
  598. )
  599. tm.assert_numpy_array_equal(idx.asi8, expected_i8.asi8)
  600. idx = date_range("2013/1/1 0:00:00+9:00", "2016/1/1 23:59:59+09:00", freq=freq)
  601. expected = date_range(
  602. "2013-01-01T00:00:00",
  603. "2016-01-01T23:59:59",
  604. freq=freq,
  605. tz=timezone(timedelta(minutes=540)),
  606. )
  607. tm.assert_index_equal(idx, expected)
  608. expected_i8 = date_range(
  609. "2013-01-01T00:00:00", "2016-01-01T23:59:59", freq=freq, tz="Asia/Tokyo"
  610. )
  611. tm.assert_numpy_array_equal(idx.asi8, expected_i8.asi8)
  612. def test_constructor_dtype(self):
  613. # passing a dtype with a tz should localize
  614. idx = DatetimeIndex(
  615. ["2013-01-01", "2013-01-02"], dtype="datetime64[ns, US/Eastern]"
  616. )
  617. expected = DatetimeIndex(["2013-01-01", "2013-01-02"]).tz_localize("US/Eastern")
  618. tm.assert_index_equal(idx, expected)
  619. idx = DatetimeIndex(["2013-01-01", "2013-01-02"], tz="US/Eastern")
  620. tm.assert_index_equal(idx, expected)
  621. def test_constructor_dtype_tz_mismatch_raises(self):
  622. # if we already have a tz and its not the same, then raise
  623. idx = DatetimeIndex(
  624. ["2013-01-01", "2013-01-02"], dtype="datetime64[ns, US/Eastern]"
  625. )
  626. msg = (
  627. "cannot supply both a tz and a timezone-naive dtype "
  628. r"\(i\.e\. datetime64\[ns\]\)"
  629. )
  630. with pytest.raises(ValueError, match=msg):
  631. DatetimeIndex(idx, dtype="datetime64[ns]")
  632. # this is effectively trying to convert tz's
  633. msg = "data is already tz-aware US/Eastern, unable to set specified tz: CET"
  634. with pytest.raises(TypeError, match=msg):
  635. DatetimeIndex(idx, dtype="datetime64[ns, CET]")
  636. msg = "cannot supply both a tz and a dtype with a tz"
  637. with pytest.raises(ValueError, match=msg):
  638. DatetimeIndex(idx, tz="CET", dtype="datetime64[ns, US/Eastern]")
  639. result = DatetimeIndex(idx, dtype="datetime64[ns, US/Eastern]")
  640. tm.assert_index_equal(idx, result)
  641. @pytest.mark.parametrize("dtype", [object, np.int32, np.int64])
  642. def test_constructor_invalid_dtype_raises(self, dtype):
  643. # GH 23986
  644. msg = "Unexpected value for 'dtype'"
  645. with pytest.raises(ValueError, match=msg):
  646. DatetimeIndex([1, 2], dtype=dtype)
  647. def test_constructor_name(self):
  648. idx = date_range(start="2000-01-01", periods=1, freq="A", name="TEST")
  649. assert idx.name == "TEST"
  650. def test_000constructor_resolution(self):
  651. # 2252
  652. t1 = Timestamp((1352934390 * 1000000000) + 1000000 + 1000 + 1)
  653. idx = DatetimeIndex([t1])
  654. assert idx.nanosecond[0] == t1.nanosecond
  655. def test_disallow_setting_tz(self):
  656. # GH 3746
  657. dti = DatetimeIndex(["2010"], tz="UTC")
  658. msg = "Cannot directly set timezone"
  659. with pytest.raises(AttributeError, match=msg):
  660. dti.tz = pytz.timezone("US/Pacific")
  661. @pytest.mark.parametrize(
  662. "tz",
  663. [
  664. None,
  665. "America/Los_Angeles",
  666. pytz.timezone("America/Los_Angeles"),
  667. Timestamp("2000", tz="America/Los_Angeles").tz,
  668. ],
  669. )
  670. def test_constructor_start_end_with_tz(self, tz):
  671. # GH 18595
  672. start = Timestamp("2013-01-01 06:00:00", tz="America/Los_Angeles")
  673. end = Timestamp("2013-01-02 06:00:00", tz="America/Los_Angeles")
  674. result = date_range(freq="D", start=start, end=end, tz=tz)
  675. expected = DatetimeIndex(
  676. ["2013-01-01 06:00:00", "2013-01-02 06:00:00"],
  677. tz="America/Los_Angeles",
  678. freq="D",
  679. )
  680. tm.assert_index_equal(result, expected)
  681. # Especially assert that the timezone is consistent for pytz
  682. assert pytz.timezone("America/Los_Angeles") is result.tz
  683. @pytest.mark.parametrize("tz", ["US/Pacific", "US/Eastern", "Asia/Tokyo"])
  684. def test_constructor_with_non_normalized_pytz(self, tz):
  685. # GH 18595
  686. non_norm_tz = Timestamp("2010", tz=tz).tz
  687. result = DatetimeIndex(["2010"], tz=non_norm_tz)
  688. assert pytz.timezone(tz) is result.tz
  689. def test_constructor_timestamp_near_dst(self):
  690. # GH 20854
  691. ts = [
  692. Timestamp("2016-10-30 03:00:00+0300", tz="Europe/Helsinki"),
  693. Timestamp("2016-10-30 03:00:00+0200", tz="Europe/Helsinki"),
  694. ]
  695. result = DatetimeIndex(ts)
  696. expected = DatetimeIndex([ts[0].to_pydatetime(), ts[1].to_pydatetime()])
  697. tm.assert_index_equal(result, expected)
  698. @pytest.mark.parametrize("klass", [Index, DatetimeIndex])
  699. @pytest.mark.parametrize("box", [np.array, partial(np.array, dtype=object), list])
  700. @pytest.mark.parametrize(
  701. "tz, dtype",
  702. [("US/Pacific", "datetime64[ns, US/Pacific]"), (None, "datetime64[ns]")],
  703. )
  704. def test_constructor_with_int_tz(self, klass, box, tz, dtype):
  705. # GH 20997, 20964
  706. ts = Timestamp("2018-01-01", tz=tz).as_unit("ns")
  707. result = klass(box([ts._value]), dtype=dtype)
  708. expected = klass([ts])
  709. assert result == expected
  710. def test_construction_int_rountrip(self, tz_naive_fixture):
  711. # GH 12619, GH#24559
  712. tz = tz_naive_fixture
  713. result = 1293858000000000000
  714. expected = DatetimeIndex([result], tz=tz).asi8[0]
  715. assert result == expected
  716. def test_construction_from_replaced_timestamps_with_dst(self):
  717. # GH 18785
  718. index = date_range(
  719. Timestamp(2000, 1, 1),
  720. Timestamp(2005, 1, 1),
  721. freq="MS",
  722. tz="Australia/Melbourne",
  723. )
  724. test = pd.DataFrame({"data": range(len(index))}, index=index)
  725. test = test.resample("Y").mean()
  726. result = DatetimeIndex([x.replace(month=6, day=1) for x in test.index])
  727. expected = DatetimeIndex(
  728. [
  729. "2000-06-01 00:00:00",
  730. "2001-06-01 00:00:00",
  731. "2002-06-01 00:00:00",
  732. "2003-06-01 00:00:00",
  733. "2004-06-01 00:00:00",
  734. "2005-06-01 00:00:00",
  735. ],
  736. tz="Australia/Melbourne",
  737. )
  738. tm.assert_index_equal(result, expected)
  739. def test_construction_with_tz_and_tz_aware_dti(self):
  740. # GH 23579
  741. dti = date_range("2016-01-01", periods=3, tz="US/Central")
  742. msg = "data is already tz-aware US/Central, unable to set specified tz"
  743. with pytest.raises(TypeError, match=msg):
  744. DatetimeIndex(dti, tz="Asia/Tokyo")
  745. def test_construction_with_nat_and_tzlocal(self):
  746. tz = dateutil.tz.tzlocal()
  747. result = DatetimeIndex(["2018", "NaT"], tz=tz)
  748. expected = DatetimeIndex([Timestamp("2018", tz=tz), pd.NaT])
  749. tm.assert_index_equal(result, expected)
  750. def test_constructor_with_ambiguous_keyword_arg(self):
  751. # GH 35297
  752. expected = DatetimeIndex(
  753. ["2020-11-01 01:00:00", "2020-11-02 01:00:00"],
  754. dtype="datetime64[ns, America/New_York]",
  755. freq="D",
  756. ambiguous=False,
  757. )
  758. # ambiguous keyword in start
  759. timezone = "America/New_York"
  760. start = Timestamp(year=2020, month=11, day=1, hour=1).tz_localize(
  761. timezone, ambiguous=False
  762. )
  763. result = date_range(start=start, periods=2, ambiguous=False)
  764. tm.assert_index_equal(result, expected)
  765. # ambiguous keyword in end
  766. timezone = "America/New_York"
  767. end = Timestamp(year=2020, month=11, day=2, hour=1).tz_localize(
  768. timezone, ambiguous=False
  769. )
  770. result = date_range(end=end, periods=2, ambiguous=False)
  771. tm.assert_index_equal(result, expected)
  772. def test_constructor_with_nonexistent_keyword_arg(self, warsaw):
  773. # GH 35297
  774. timezone = warsaw
  775. # nonexistent keyword in start
  776. start = Timestamp("2015-03-29 02:30:00").tz_localize(
  777. timezone, nonexistent="shift_forward"
  778. )
  779. result = date_range(start=start, periods=2, freq="H")
  780. expected = DatetimeIndex(
  781. [
  782. Timestamp("2015-03-29 03:00:00+02:00", tz=timezone),
  783. Timestamp("2015-03-29 04:00:00+02:00", tz=timezone),
  784. ]
  785. )
  786. tm.assert_index_equal(result, expected)
  787. # nonexistent keyword in end
  788. end = Timestamp("2015-03-29 02:30:00").tz_localize(
  789. timezone, nonexistent="shift_forward"
  790. )
  791. result = date_range(end=end, periods=2, freq="H")
  792. expected = DatetimeIndex(
  793. [
  794. Timestamp("2015-03-29 01:00:00+01:00", tz=timezone),
  795. Timestamp("2015-03-29 03:00:00+02:00", tz=timezone),
  796. ]
  797. )
  798. tm.assert_index_equal(result, expected)
  799. def test_constructor_no_precision_raises(self):
  800. # GH-24753, GH-24739
  801. msg = "with no precision is not allowed"
  802. with pytest.raises(ValueError, match=msg):
  803. DatetimeIndex(["2000"], dtype="datetime64")
  804. msg = "The 'datetime64' dtype has no unit. Please pass in"
  805. with pytest.raises(ValueError, match=msg):
  806. Index(["2000"], dtype="datetime64")
  807. def test_constructor_wrong_precision_raises(self):
  808. dti = DatetimeIndex(["2000"], dtype="datetime64[us]")
  809. assert dti.dtype == "M8[us]"
  810. assert dti[0] == Timestamp(2000, 1, 1)
  811. def test_index_constructor_with_numpy_object_array_and_timestamp_tz_with_nan(self):
  812. # GH 27011
  813. result = Index(np.array([Timestamp("2019", tz="UTC"), np.nan], dtype=object))
  814. expected = DatetimeIndex([Timestamp("2019", tz="UTC"), pd.NaT])
  815. tm.assert_index_equal(result, expected)
  816. class TestTimeSeries:
  817. def test_dti_constructor_preserve_dti_freq(self):
  818. rng = date_range("1/1/2000", "1/2/2000", freq="5min")
  819. rng2 = DatetimeIndex(rng)
  820. assert rng.freq == rng2.freq
  821. def test_explicit_none_freq(self):
  822. # Explicitly passing freq=None is respected
  823. rng = date_range("1/1/2000", "1/2/2000", freq="5min")
  824. result = DatetimeIndex(rng, freq=None)
  825. assert result.freq is None
  826. result = DatetimeIndex(rng._data, freq=None)
  827. assert result.freq is None
  828. dta = DatetimeArray(rng, freq=None)
  829. assert dta.freq is None
  830. def test_dti_constructor_years_only(self, tz_naive_fixture):
  831. tz = tz_naive_fixture
  832. # GH 6961
  833. rng1 = date_range("2014", "2015", freq="M", tz=tz)
  834. expected1 = date_range("2014-01-31", "2014-12-31", freq="M", tz=tz)
  835. rng2 = date_range("2014", "2015", freq="MS", tz=tz)
  836. expected2 = date_range("2014-01-01", "2015-01-01", freq="MS", tz=tz)
  837. rng3 = date_range("2014", "2020", freq="A", tz=tz)
  838. expected3 = date_range("2014-12-31", "2019-12-31", freq="A", tz=tz)
  839. rng4 = date_range("2014", "2020", freq="AS", tz=tz)
  840. expected4 = date_range("2014-01-01", "2020-01-01", freq="AS", tz=tz)
  841. for rng, expected in [
  842. (rng1, expected1),
  843. (rng2, expected2),
  844. (rng3, expected3),
  845. (rng4, expected4),
  846. ]:
  847. tm.assert_index_equal(rng, expected)
  848. def test_dti_constructor_small_int(self, any_int_numpy_dtype):
  849. # see gh-13721
  850. exp = DatetimeIndex(
  851. [
  852. "1970-01-01 00:00:00.00000000",
  853. "1970-01-01 00:00:00.00000001",
  854. "1970-01-01 00:00:00.00000002",
  855. ]
  856. )
  857. arr = np.array([0, 10, 20], dtype=any_int_numpy_dtype)
  858. tm.assert_index_equal(DatetimeIndex(arr), exp)
  859. def test_ctor_str_intraday(self):
  860. rng = DatetimeIndex(["1-1-2000 00:00:01"])
  861. assert rng[0].second == 1
  862. def test_is_(self):
  863. dti = date_range(start="1/1/2005", end="12/1/2005", freq="M")
  864. assert dti.is_(dti)
  865. assert dti.is_(dti.view())
  866. assert not dti.is_(dti.copy())
  867. def test_index_cast_datetime64_other_units(self):
  868. arr = np.arange(0, 100, 10, dtype=np.int64).view("M8[D]")
  869. idx = Index(arr)
  870. assert (idx.values == astype_overflowsafe(arr, dtype=np.dtype("M8[ns]"))).all()
  871. def test_constructor_int64_nocopy(self):
  872. # GH#1624
  873. arr = np.arange(1000, dtype=np.int64)
  874. index = DatetimeIndex(arr)
  875. arr[50:100] = -1
  876. assert (index.asi8[50:100] == -1).all()
  877. arr = np.arange(1000, dtype=np.int64)
  878. index = DatetimeIndex(arr, copy=True)
  879. arr[50:100] = -1
  880. assert (index.asi8[50:100] != -1).all()
  881. @pytest.mark.parametrize(
  882. "freq", ["M", "Q", "A", "D", "B", "BH", "T", "S", "L", "U", "H", "N", "C"]
  883. )
  884. def test_from_freq_recreate_from_data(self, freq):
  885. org = date_range(start="2001/02/01 09:00", freq=freq, periods=1)
  886. idx = DatetimeIndex(org, freq=freq)
  887. tm.assert_index_equal(idx, org)
  888. org = date_range(
  889. start="2001/02/01 09:00", freq=freq, tz="US/Pacific", periods=1
  890. )
  891. idx = DatetimeIndex(org, freq=freq, tz="US/Pacific")
  892. tm.assert_index_equal(idx, org)
  893. def test_datetimeindex_constructor_misc(self):
  894. arr = ["1/1/2005", "1/2/2005", "Jn 3, 2005", "2005-01-04"]
  895. msg = r"(\(')?Unknown datetime string format(:', 'Jn 3, 2005'\))?"
  896. with pytest.raises(ValueError, match=msg):
  897. DatetimeIndex(arr)
  898. arr = ["1/1/2005", "1/2/2005", "1/3/2005", "2005-01-04"]
  899. idx1 = DatetimeIndex(arr)
  900. arr = [datetime(2005, 1, 1), "1/2/2005", "1/3/2005", "2005-01-04"]
  901. idx2 = DatetimeIndex(arr)
  902. arr = [Timestamp(datetime(2005, 1, 1)), "1/2/2005", "1/3/2005", "2005-01-04"]
  903. idx3 = DatetimeIndex(arr)
  904. arr = np.array(["1/1/2005", "1/2/2005", "1/3/2005", "2005-01-04"], dtype="O")
  905. idx4 = DatetimeIndex(arr)
  906. idx5 = DatetimeIndex(["12/05/2007", "25/01/2008"], dayfirst=True)
  907. idx6 = DatetimeIndex(
  908. ["2007/05/12", "2008/01/25"], dayfirst=False, yearfirst=True
  909. )
  910. tm.assert_index_equal(idx5, idx6)
  911. for other in [idx2, idx3, idx4]:
  912. assert (idx1.values == other.values).all()
  913. sdate = datetime(1999, 12, 25)
  914. edate = datetime(2000, 1, 1)
  915. idx = date_range(start=sdate, freq="1B", periods=20)
  916. assert len(idx) == 20
  917. assert idx[0] == sdate + 0 * offsets.BDay()
  918. assert idx.freq == "B"
  919. idx1 = date_range(start=sdate, end=edate, freq="W-SUN")
  920. idx2 = date_range(start=sdate, end=edate, freq=offsets.Week(weekday=6))
  921. assert len(idx1) == len(idx2)
  922. assert idx1.freq == idx2.freq
  923. idx1 = date_range(start=sdate, end=edate, freq="QS")
  924. idx2 = date_range(
  925. start=sdate, end=edate, freq=offsets.QuarterBegin(startingMonth=1)
  926. )
  927. assert len(idx1) == len(idx2)
  928. assert idx1.freq == idx2.freq
  929. idx1 = date_range(start=sdate, end=edate, freq="BQ")
  930. idx2 = date_range(
  931. start=sdate, end=edate, freq=offsets.BQuarterEnd(startingMonth=12)
  932. )
  933. assert len(idx1) == len(idx2)
  934. assert idx1.freq == idx2.freq
  935. def test_pass_datetimeindex_to_index(self):
  936. # Bugs in #1396
  937. rng = date_range("1/1/2000", "3/1/2000")
  938. idx = Index(rng, dtype=object)
  939. expected = Index(rng.to_pydatetime(), dtype=object)
  940. tm.assert_numpy_array_equal(idx.values, expected.values)
  941. def test_date_range_tuple_freq_raises(self):
  942. # GH#34703
  943. edate = datetime(2000, 1, 1)
  944. with pytest.raises(TypeError, match="pass as a string instead"):
  945. date_range(end=edate, freq=("D", 5), periods=20)