test_timedelta64.py 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977
  1. # -*- coding: utf-8 -*-
  2. # Arithmetc tests for DataFrame/Series/Index/Array classes that should
  3. # behave identically.
  4. from datetime import datetime, timedelta
  5. import numpy as np
  6. import pytest
  7. from pandas.errors import NullFrequencyError, PerformanceWarning
  8. import pandas as pd
  9. from pandas import (
  10. DataFrame, DatetimeIndex, NaT, Series, Timedelta, TimedeltaIndex,
  11. Timestamp, timedelta_range)
  12. import pandas.util.testing as tm
  13. def get_upcast_box(box, vector):
  14. """
  15. Given two box-types, find the one that takes priority
  16. """
  17. if box is DataFrame or isinstance(vector, DataFrame):
  18. return DataFrame
  19. if box is Series or isinstance(vector, Series):
  20. return Series
  21. if box is pd.Index or isinstance(vector, pd.Index):
  22. return pd.Index
  23. return box
  24. # ------------------------------------------------------------------
  25. # Timedelta64[ns] dtype Comparisons
  26. class TestTimedelta64ArrayComparisons(object):
  27. # TODO: All of these need to be parametrized over box
  28. def test_compare_timedelta_series(self):
  29. # regresssion test for GH#5963
  30. s = pd.Series([timedelta(days=1), timedelta(days=2)])
  31. actual = s > timedelta(days=1)
  32. expected = pd.Series([False, True])
  33. tm.assert_series_equal(actual, expected)
  34. def test_tdi_cmp_str_invalid(self, box_with_array):
  35. # GH#13624
  36. xbox = box_with_array if box_with_array is not pd.Index else np.ndarray
  37. tdi = TimedeltaIndex(['1 day', '2 days'])
  38. tdarr = tm.box_expected(tdi, box_with_array)
  39. for left, right in [(tdarr, 'a'), ('a', tdarr)]:
  40. with pytest.raises(TypeError):
  41. left > right
  42. with pytest.raises(TypeError):
  43. left >= right
  44. with pytest.raises(TypeError):
  45. left < right
  46. with pytest.raises(TypeError):
  47. left <= right
  48. result = left == right
  49. expected = np.array([False, False], dtype=bool)
  50. expected = tm.box_expected(expected, xbox)
  51. tm.assert_equal(result, expected)
  52. result = left != right
  53. expected = np.array([True, True], dtype=bool)
  54. expected = tm.box_expected(expected, xbox)
  55. tm.assert_equal(result, expected)
  56. @pytest.mark.parametrize('dtype', [None, object])
  57. def test_comp_nat(self, dtype):
  58. left = pd.TimedeltaIndex([pd.Timedelta('1 days'), pd.NaT,
  59. pd.Timedelta('3 days')])
  60. right = pd.TimedeltaIndex([pd.NaT, pd.NaT, pd.Timedelta('3 days')])
  61. lhs, rhs = left, right
  62. if dtype is object:
  63. lhs, rhs = left.astype(object), right.astype(object)
  64. result = rhs == lhs
  65. expected = np.array([False, False, True])
  66. tm.assert_numpy_array_equal(result, expected)
  67. result = rhs != lhs
  68. expected = np.array([True, True, False])
  69. tm.assert_numpy_array_equal(result, expected)
  70. expected = np.array([False, False, False])
  71. tm.assert_numpy_array_equal(lhs == pd.NaT, expected)
  72. tm.assert_numpy_array_equal(pd.NaT == rhs, expected)
  73. expected = np.array([True, True, True])
  74. tm.assert_numpy_array_equal(lhs != pd.NaT, expected)
  75. tm.assert_numpy_array_equal(pd.NaT != lhs, expected)
  76. expected = np.array([False, False, False])
  77. tm.assert_numpy_array_equal(lhs < pd.NaT, expected)
  78. tm.assert_numpy_array_equal(pd.NaT > lhs, expected)
  79. def test_comparisons_nat(self):
  80. tdidx1 = pd.TimedeltaIndex(['1 day', pd.NaT, '1 day 00:00:01', pd.NaT,
  81. '1 day 00:00:01', '5 day 00:00:03'])
  82. tdidx2 = pd.TimedeltaIndex(['2 day', '2 day', pd.NaT, pd.NaT,
  83. '1 day 00:00:02', '5 days 00:00:03'])
  84. tdarr = np.array([np.timedelta64(2, 'D'),
  85. np.timedelta64(2, 'D'), np.timedelta64('nat'),
  86. np.timedelta64('nat'),
  87. np.timedelta64(1, 'D') + np.timedelta64(2, 's'),
  88. np.timedelta64(5, 'D') + np.timedelta64(3, 's')])
  89. cases = [(tdidx1, tdidx2), (tdidx1, tdarr)]
  90. # Check pd.NaT is handles as the same as np.nan
  91. for idx1, idx2 in cases:
  92. result = idx1 < idx2
  93. expected = np.array([True, False, False, False, True, False])
  94. tm.assert_numpy_array_equal(result, expected)
  95. result = idx2 > idx1
  96. expected = np.array([True, False, False, False, True, False])
  97. tm.assert_numpy_array_equal(result, expected)
  98. result = idx1 <= idx2
  99. expected = np.array([True, False, False, False, True, True])
  100. tm.assert_numpy_array_equal(result, expected)
  101. result = idx2 >= idx1
  102. expected = np.array([True, False, False, False, True, True])
  103. tm.assert_numpy_array_equal(result, expected)
  104. result = idx1 == idx2
  105. expected = np.array([False, False, False, False, False, True])
  106. tm.assert_numpy_array_equal(result, expected)
  107. result = idx1 != idx2
  108. expected = np.array([True, True, True, True, True, False])
  109. tm.assert_numpy_array_equal(result, expected)
  110. # TODO: better name
  111. def test_comparisons_coverage(self):
  112. rng = timedelta_range('1 days', periods=10)
  113. result = rng < rng[3]
  114. expected = np.array([True, True, True] + [False] * 7)
  115. tm.assert_numpy_array_equal(result, expected)
  116. # raise TypeError for now
  117. with pytest.raises(TypeError):
  118. rng < rng[3].value
  119. result = rng == list(rng)
  120. exp = rng == rng
  121. tm.assert_numpy_array_equal(result, exp)
  122. # ------------------------------------------------------------------
  123. # Timedelta64[ns] dtype Arithmetic Operations
  124. class TestTimedelta64ArithmeticUnsorted(object):
  125. # Tests moved from type-specific test files but not
  126. # yet sorted/parametrized/de-duplicated
  127. def test_ufunc_coercions(self):
  128. # normal ops are also tested in tseries/test_timedeltas.py
  129. idx = TimedeltaIndex(['2H', '4H', '6H', '8H', '10H'],
  130. freq='2H', name='x')
  131. for result in [idx * 2, np.multiply(idx, 2)]:
  132. assert isinstance(result, TimedeltaIndex)
  133. exp = TimedeltaIndex(['4H', '8H', '12H', '16H', '20H'],
  134. freq='4H', name='x')
  135. tm.assert_index_equal(result, exp)
  136. assert result.freq == '4H'
  137. for result in [idx / 2, np.divide(idx, 2)]:
  138. assert isinstance(result, TimedeltaIndex)
  139. exp = TimedeltaIndex(['1H', '2H', '3H', '4H', '5H'],
  140. freq='H', name='x')
  141. tm.assert_index_equal(result, exp)
  142. assert result.freq == 'H'
  143. idx = TimedeltaIndex(['2H', '4H', '6H', '8H', '10H'],
  144. freq='2H', name='x')
  145. for result in [-idx, np.negative(idx)]:
  146. assert isinstance(result, TimedeltaIndex)
  147. exp = TimedeltaIndex(['-2H', '-4H', '-6H', '-8H', '-10H'],
  148. freq='-2H', name='x')
  149. tm.assert_index_equal(result, exp)
  150. assert result.freq == '-2H'
  151. idx = TimedeltaIndex(['-2H', '-1H', '0H', '1H', '2H'],
  152. freq='H', name='x')
  153. for result in [abs(idx), np.absolute(idx)]:
  154. assert isinstance(result, TimedeltaIndex)
  155. exp = TimedeltaIndex(['2H', '1H', '0H', '1H', '2H'],
  156. freq=None, name='x')
  157. tm.assert_index_equal(result, exp)
  158. assert result.freq is None
  159. def test_subtraction_ops(self):
  160. # with datetimes/timedelta and tdi/dti
  161. tdi = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo')
  162. dti = pd.date_range('20130101', periods=3, name='bar')
  163. td = Timedelta('1 days')
  164. dt = Timestamp('20130101')
  165. pytest.raises(TypeError, lambda: tdi - dt)
  166. pytest.raises(TypeError, lambda: tdi - dti)
  167. pytest.raises(TypeError, lambda: td - dt)
  168. pytest.raises(TypeError, lambda: td - dti)
  169. result = dt - dti
  170. expected = TimedeltaIndex(['0 days', '-1 days', '-2 days'], name='bar')
  171. tm.assert_index_equal(result, expected)
  172. result = dti - dt
  173. expected = TimedeltaIndex(['0 days', '1 days', '2 days'], name='bar')
  174. tm.assert_index_equal(result, expected)
  175. result = tdi - td
  176. expected = TimedeltaIndex(['0 days', pd.NaT, '1 days'], name='foo')
  177. tm.assert_index_equal(result, expected, check_names=False)
  178. result = td - tdi
  179. expected = TimedeltaIndex(['0 days', pd.NaT, '-1 days'], name='foo')
  180. tm.assert_index_equal(result, expected, check_names=False)
  181. result = dti - td
  182. expected = DatetimeIndex(
  183. ['20121231', '20130101', '20130102'], name='bar')
  184. tm.assert_index_equal(result, expected, check_names=False)
  185. result = dt - tdi
  186. expected = DatetimeIndex(['20121231', pd.NaT, '20121230'], name='foo')
  187. tm.assert_index_equal(result, expected)
  188. def test_subtraction_ops_with_tz(self):
  189. # check that dt/dti subtraction ops with tz are validated
  190. dti = pd.date_range('20130101', periods=3)
  191. ts = Timestamp('20130101')
  192. dt = ts.to_pydatetime()
  193. dti_tz = pd.date_range('20130101', periods=3).tz_localize('US/Eastern')
  194. ts_tz = Timestamp('20130101').tz_localize('US/Eastern')
  195. ts_tz2 = Timestamp('20130101').tz_localize('CET')
  196. dt_tz = ts_tz.to_pydatetime()
  197. td = Timedelta('1 days')
  198. def _check(result, expected):
  199. assert result == expected
  200. assert isinstance(result, Timedelta)
  201. # scalars
  202. result = ts - ts
  203. expected = Timedelta('0 days')
  204. _check(result, expected)
  205. result = dt_tz - ts_tz
  206. expected = Timedelta('0 days')
  207. _check(result, expected)
  208. result = ts_tz - dt_tz
  209. expected = Timedelta('0 days')
  210. _check(result, expected)
  211. # tz mismatches
  212. pytest.raises(TypeError, lambda: dt_tz - ts)
  213. pytest.raises(TypeError, lambda: dt_tz - dt)
  214. pytest.raises(TypeError, lambda: dt_tz - ts_tz2)
  215. pytest.raises(TypeError, lambda: dt - dt_tz)
  216. pytest.raises(TypeError, lambda: ts - dt_tz)
  217. pytest.raises(TypeError, lambda: ts_tz2 - ts)
  218. pytest.raises(TypeError, lambda: ts_tz2 - dt)
  219. pytest.raises(TypeError, lambda: ts_tz - ts_tz2)
  220. # with dti
  221. pytest.raises(TypeError, lambda: dti - ts_tz)
  222. pytest.raises(TypeError, lambda: dti_tz - ts)
  223. pytest.raises(TypeError, lambda: dti_tz - ts_tz2)
  224. result = dti_tz - dt_tz
  225. expected = TimedeltaIndex(['0 days', '1 days', '2 days'])
  226. tm.assert_index_equal(result, expected)
  227. result = dt_tz - dti_tz
  228. expected = TimedeltaIndex(['0 days', '-1 days', '-2 days'])
  229. tm.assert_index_equal(result, expected)
  230. result = dti_tz - ts_tz
  231. expected = TimedeltaIndex(['0 days', '1 days', '2 days'])
  232. tm.assert_index_equal(result, expected)
  233. result = ts_tz - dti_tz
  234. expected = TimedeltaIndex(['0 days', '-1 days', '-2 days'])
  235. tm.assert_index_equal(result, expected)
  236. result = td - td
  237. expected = Timedelta('0 days')
  238. _check(result, expected)
  239. result = dti_tz - td
  240. expected = DatetimeIndex(
  241. ['20121231', '20130101', '20130102'], tz='US/Eastern')
  242. tm.assert_index_equal(result, expected)
  243. def test_dti_tdi_numeric_ops(self):
  244. # These are normally union/diff set-like ops
  245. tdi = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo')
  246. dti = pd.date_range('20130101', periods=3, name='bar')
  247. # TODO(wesm): unused?
  248. # td = Timedelta('1 days')
  249. # dt = Timestamp('20130101')
  250. result = tdi - tdi
  251. expected = TimedeltaIndex(['0 days', pd.NaT, '0 days'], name='foo')
  252. tm.assert_index_equal(result, expected)
  253. result = tdi + tdi
  254. expected = TimedeltaIndex(['2 days', pd.NaT, '4 days'], name='foo')
  255. tm.assert_index_equal(result, expected)
  256. result = dti - tdi # name will be reset
  257. expected = DatetimeIndex(['20121231', pd.NaT, '20130101'])
  258. tm.assert_index_equal(result, expected)
  259. def test_addition_ops(self):
  260. # with datetimes/timedelta and tdi/dti
  261. tdi = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo')
  262. dti = pd.date_range('20130101', periods=3, name='bar')
  263. td = Timedelta('1 days')
  264. dt = Timestamp('20130101')
  265. result = tdi + dt
  266. expected = DatetimeIndex(['20130102', pd.NaT, '20130103'], name='foo')
  267. tm.assert_index_equal(result, expected)
  268. result = dt + tdi
  269. expected = DatetimeIndex(['20130102', pd.NaT, '20130103'], name='foo')
  270. tm.assert_index_equal(result, expected)
  271. result = td + tdi
  272. expected = TimedeltaIndex(['2 days', pd.NaT, '3 days'], name='foo')
  273. tm.assert_index_equal(result, expected)
  274. result = tdi + td
  275. expected = TimedeltaIndex(['2 days', pd.NaT, '3 days'], name='foo')
  276. tm.assert_index_equal(result, expected)
  277. # unequal length
  278. pytest.raises(ValueError, lambda: tdi + dti[0:1])
  279. pytest.raises(ValueError, lambda: tdi[0:1] + dti)
  280. # random indexes
  281. with pytest.raises(NullFrequencyError):
  282. tdi + pd.Int64Index([1, 2, 3])
  283. # this is a union!
  284. # pytest.raises(TypeError, lambda : Int64Index([1,2,3]) + tdi)
  285. result = tdi + dti # name will be reset
  286. expected = DatetimeIndex(['20130102', pd.NaT, '20130105'])
  287. tm.assert_index_equal(result, expected)
  288. result = dti + tdi # name will be reset
  289. expected = DatetimeIndex(['20130102', pd.NaT, '20130105'])
  290. tm.assert_index_equal(result, expected)
  291. result = dt + td
  292. expected = Timestamp('20130102')
  293. assert result == expected
  294. result = td + dt
  295. expected = Timestamp('20130102')
  296. assert result == expected
  297. # TODO: Needs more informative name, probably split up into
  298. # more targeted tests
  299. @pytest.mark.parametrize('freq', ['D', 'B'])
  300. def test_timedelta(self, freq):
  301. index = pd.date_range('1/1/2000', periods=50, freq=freq)
  302. shifted = index + timedelta(1)
  303. back = shifted + timedelta(-1)
  304. tm.assert_index_equal(index, back)
  305. if freq == 'D':
  306. expected = pd.tseries.offsets.Day(1)
  307. assert index.freq == expected
  308. assert shifted.freq == expected
  309. assert back.freq == expected
  310. else: # freq == 'B'
  311. assert index.freq == pd.tseries.offsets.BusinessDay(1)
  312. assert shifted.freq is None
  313. assert back.freq == pd.tseries.offsets.BusinessDay(1)
  314. result = index - timedelta(1)
  315. expected = index + timedelta(-1)
  316. tm.assert_index_equal(result, expected)
  317. # GH#4134, buggy with timedeltas
  318. rng = pd.date_range('2013', '2014')
  319. s = Series(rng)
  320. result1 = rng - pd.offsets.Hour(1)
  321. result2 = DatetimeIndex(s - np.timedelta64(100000000))
  322. result3 = rng - np.timedelta64(100000000)
  323. result4 = DatetimeIndex(s - pd.offsets.Hour(1))
  324. tm.assert_index_equal(result1, result4)
  325. tm.assert_index_equal(result2, result3)
  326. class TestAddSubNaTMasking(object):
  327. # TODO: parametrize over boxes
  328. def test_tdi_add_timestamp_nat_masking(self):
  329. # GH#17991 checking for overflow-masking with NaT
  330. tdinat = pd.to_timedelta(['24658 days 11:15:00', 'NaT'])
  331. tsneg = Timestamp('1950-01-01')
  332. ts_neg_variants = [tsneg,
  333. tsneg.to_pydatetime(),
  334. tsneg.to_datetime64().astype('datetime64[ns]'),
  335. tsneg.to_datetime64().astype('datetime64[D]')]
  336. tspos = Timestamp('1980-01-01')
  337. ts_pos_variants = [tspos,
  338. tspos.to_pydatetime(),
  339. tspos.to_datetime64().astype('datetime64[ns]'),
  340. tspos.to_datetime64().astype('datetime64[D]')]
  341. for variant in ts_neg_variants + ts_pos_variants:
  342. res = tdinat + variant
  343. assert res[1] is pd.NaT
  344. def test_tdi_add_overflow(self):
  345. # See GH#14068
  346. msg = "too (big|large) to convert"
  347. with pytest.raises(OverflowError, match=msg):
  348. pd.to_timedelta(106580, 'D') + Timestamp('2000')
  349. with pytest.raises(OverflowError, match=msg):
  350. Timestamp('2000') + pd.to_timedelta(106580, 'D')
  351. _NaT = int(pd.NaT) + 1
  352. msg = "Overflow in int64 addition"
  353. with pytest.raises(OverflowError, match=msg):
  354. pd.to_timedelta([106580], 'D') + Timestamp('2000')
  355. with pytest.raises(OverflowError, match=msg):
  356. Timestamp('2000') + pd.to_timedelta([106580], 'D')
  357. with pytest.raises(OverflowError, match=msg):
  358. pd.to_timedelta([_NaT]) - Timedelta('1 days')
  359. with pytest.raises(OverflowError, match=msg):
  360. pd.to_timedelta(['5 days', _NaT]) - Timedelta('1 days')
  361. with pytest.raises(OverflowError, match=msg):
  362. (pd.to_timedelta([_NaT, '5 days', '1 hours']) -
  363. pd.to_timedelta(['7 seconds', _NaT, '4 hours']))
  364. # These should not overflow!
  365. exp = TimedeltaIndex([pd.NaT])
  366. result = pd.to_timedelta([pd.NaT]) - Timedelta('1 days')
  367. tm.assert_index_equal(result, exp)
  368. exp = TimedeltaIndex(['4 days', pd.NaT])
  369. result = pd.to_timedelta(['5 days', pd.NaT]) - Timedelta('1 days')
  370. tm.assert_index_equal(result, exp)
  371. exp = TimedeltaIndex([pd.NaT, pd.NaT, '5 hours'])
  372. result = (pd.to_timedelta([pd.NaT, '5 days', '1 hours']) +
  373. pd.to_timedelta(['7 seconds', pd.NaT, '4 hours']))
  374. tm.assert_index_equal(result, exp)
  375. class TestTimedeltaArraylikeAddSubOps(object):
  376. # Tests for timedelta64[ns] __add__, __sub__, __radd__, __rsub__
  377. # TODO: moved from frame tests; needs parametrization/de-duplication
  378. def test_td64_df_add_int_frame(self):
  379. # GH#22696 Check that we don't dispatch to numpy implementation,
  380. # which treats int64 as m8[ns]
  381. tdi = pd.timedelta_range('1', periods=3)
  382. df = tdi.to_frame()
  383. other = pd.DataFrame([1, 2, 3], index=tdi) # indexed like `df`
  384. with pytest.raises(TypeError):
  385. df + other
  386. with pytest.raises(TypeError):
  387. other + df
  388. with pytest.raises(TypeError):
  389. df - other
  390. with pytest.raises(TypeError):
  391. other - df
  392. # TODO: moved from tests.indexes.timedeltas.test_arithmetic; needs
  393. # parametrization+de-duplication
  394. def test_timedelta_ops_with_missing_values(self):
  395. # setup
  396. s1 = pd.to_timedelta(Series(['00:00:01']))
  397. s2 = pd.to_timedelta(Series(['00:00:02']))
  398. with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
  399. # Passing datetime64-dtype data to TimedeltaIndex is deprecated
  400. sn = pd.to_timedelta(Series([pd.NaT]))
  401. df1 = pd.DataFrame(['00:00:01']).apply(pd.to_timedelta)
  402. df2 = pd.DataFrame(['00:00:02']).apply(pd.to_timedelta)
  403. with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
  404. # Passing datetime64-dtype data to TimedeltaIndex is deprecated
  405. dfn = pd.DataFrame([pd.NaT]).apply(pd.to_timedelta)
  406. scalar1 = pd.to_timedelta('00:00:01')
  407. scalar2 = pd.to_timedelta('00:00:02')
  408. timedelta_NaT = pd.to_timedelta('NaT')
  409. actual = scalar1 + scalar1
  410. assert actual == scalar2
  411. actual = scalar2 - scalar1
  412. assert actual == scalar1
  413. actual = s1 + s1
  414. tm.assert_series_equal(actual, s2)
  415. actual = s2 - s1
  416. tm.assert_series_equal(actual, s1)
  417. actual = s1 + scalar1
  418. tm.assert_series_equal(actual, s2)
  419. actual = scalar1 + s1
  420. tm.assert_series_equal(actual, s2)
  421. actual = s2 - scalar1
  422. tm.assert_series_equal(actual, s1)
  423. actual = -scalar1 + s2
  424. tm.assert_series_equal(actual, s1)
  425. actual = s1 + timedelta_NaT
  426. tm.assert_series_equal(actual, sn)
  427. actual = timedelta_NaT + s1
  428. tm.assert_series_equal(actual, sn)
  429. actual = s1 - timedelta_NaT
  430. tm.assert_series_equal(actual, sn)
  431. actual = -timedelta_NaT + s1
  432. tm.assert_series_equal(actual, sn)
  433. with pytest.raises(TypeError):
  434. s1 + np.nan
  435. with pytest.raises(TypeError):
  436. np.nan + s1
  437. with pytest.raises(TypeError):
  438. s1 - np.nan
  439. with pytest.raises(TypeError):
  440. -np.nan + s1
  441. actual = s1 + pd.NaT
  442. tm.assert_series_equal(actual, sn)
  443. actual = s2 - pd.NaT
  444. tm.assert_series_equal(actual, sn)
  445. actual = s1 + df1
  446. tm.assert_frame_equal(actual, df2)
  447. actual = s2 - df1
  448. tm.assert_frame_equal(actual, df1)
  449. actual = df1 + s1
  450. tm.assert_frame_equal(actual, df2)
  451. actual = df2 - s1
  452. tm.assert_frame_equal(actual, df1)
  453. actual = df1 + df1
  454. tm.assert_frame_equal(actual, df2)
  455. actual = df2 - df1
  456. tm.assert_frame_equal(actual, df1)
  457. actual = df1 + scalar1
  458. tm.assert_frame_equal(actual, df2)
  459. actual = df2 - scalar1
  460. tm.assert_frame_equal(actual, df1)
  461. actual = df1 + timedelta_NaT
  462. tm.assert_frame_equal(actual, dfn)
  463. actual = df1 - timedelta_NaT
  464. tm.assert_frame_equal(actual, dfn)
  465. with pytest.raises(TypeError):
  466. df1 + np.nan
  467. with pytest.raises(TypeError):
  468. df1 - np.nan
  469. actual = df1 + pd.NaT # NaT is datetime, not timedelta
  470. tm.assert_frame_equal(actual, dfn)
  471. actual = df1 - pd.NaT
  472. tm.assert_frame_equal(actual, dfn)
  473. # TODO: moved from tests.series.test_operators, needs splitting, cleanup,
  474. # de-duplication, box-parametrization...
  475. def test_operators_timedelta64(self):
  476. # series ops
  477. v1 = pd.date_range('2012-1-1', periods=3, freq='D')
  478. v2 = pd.date_range('2012-1-2', periods=3, freq='D')
  479. rs = Series(v2) - Series(v1)
  480. xp = Series(1e9 * 3600 * 24,
  481. rs.index).astype('int64').astype('timedelta64[ns]')
  482. tm.assert_series_equal(rs, xp)
  483. assert rs.dtype == 'timedelta64[ns]'
  484. df = DataFrame(dict(A=v1))
  485. td = Series([timedelta(days=i) for i in range(3)])
  486. assert td.dtype == 'timedelta64[ns]'
  487. # series on the rhs
  488. result = df['A'] - df['A'].shift()
  489. assert result.dtype == 'timedelta64[ns]'
  490. result = df['A'] + td
  491. assert result.dtype == 'M8[ns]'
  492. # scalar Timestamp on rhs
  493. maxa = df['A'].max()
  494. assert isinstance(maxa, Timestamp)
  495. resultb = df['A'] - df['A'].max()
  496. assert resultb.dtype == 'timedelta64[ns]'
  497. # timestamp on lhs
  498. result = resultb + df['A']
  499. values = [Timestamp('20111230'), Timestamp('20120101'),
  500. Timestamp('20120103')]
  501. expected = Series(values, name='A')
  502. tm.assert_series_equal(result, expected)
  503. # datetimes on rhs
  504. result = df['A'] - datetime(2001, 1, 1)
  505. expected = Series(
  506. [timedelta(days=4017 + i) for i in range(3)], name='A')
  507. tm.assert_series_equal(result, expected)
  508. assert result.dtype == 'm8[ns]'
  509. d = datetime(2001, 1, 1, 3, 4)
  510. resulta = df['A'] - d
  511. assert resulta.dtype == 'm8[ns]'
  512. # roundtrip
  513. resultb = resulta + d
  514. tm.assert_series_equal(df['A'], resultb)
  515. # timedeltas on rhs
  516. td = timedelta(days=1)
  517. resulta = df['A'] + td
  518. resultb = resulta - td
  519. tm.assert_series_equal(resultb, df['A'])
  520. assert resultb.dtype == 'M8[ns]'
  521. # roundtrip
  522. td = timedelta(minutes=5, seconds=3)
  523. resulta = df['A'] + td
  524. resultb = resulta - td
  525. tm.assert_series_equal(df['A'], resultb)
  526. assert resultb.dtype == 'M8[ns]'
  527. # inplace
  528. value = rs[2] + np.timedelta64(timedelta(minutes=5, seconds=1))
  529. rs[2] += np.timedelta64(timedelta(minutes=5, seconds=1))
  530. assert rs[2] == value
  531. def test_timedelta64_ops_nat(self):
  532. # GH 11349
  533. timedelta_series = Series([NaT, Timedelta('1s')])
  534. nat_series_dtype_timedelta = Series([NaT, NaT],
  535. dtype='timedelta64[ns]')
  536. single_nat_dtype_timedelta = Series([NaT], dtype='timedelta64[ns]')
  537. # subtraction
  538. tm.assert_series_equal(timedelta_series - NaT,
  539. nat_series_dtype_timedelta)
  540. tm.assert_series_equal(-NaT + timedelta_series,
  541. nat_series_dtype_timedelta)
  542. tm.assert_series_equal(timedelta_series - single_nat_dtype_timedelta,
  543. nat_series_dtype_timedelta)
  544. tm.assert_series_equal(-single_nat_dtype_timedelta + timedelta_series,
  545. nat_series_dtype_timedelta)
  546. # addition
  547. tm.assert_series_equal(nat_series_dtype_timedelta + NaT,
  548. nat_series_dtype_timedelta)
  549. tm.assert_series_equal(NaT + nat_series_dtype_timedelta,
  550. nat_series_dtype_timedelta)
  551. tm.assert_series_equal(nat_series_dtype_timedelta +
  552. single_nat_dtype_timedelta,
  553. nat_series_dtype_timedelta)
  554. tm.assert_series_equal(single_nat_dtype_timedelta +
  555. nat_series_dtype_timedelta,
  556. nat_series_dtype_timedelta)
  557. tm.assert_series_equal(timedelta_series + NaT,
  558. nat_series_dtype_timedelta)
  559. tm.assert_series_equal(NaT + timedelta_series,
  560. nat_series_dtype_timedelta)
  561. tm.assert_series_equal(timedelta_series + single_nat_dtype_timedelta,
  562. nat_series_dtype_timedelta)
  563. tm.assert_series_equal(single_nat_dtype_timedelta + timedelta_series,
  564. nat_series_dtype_timedelta)
  565. tm.assert_series_equal(nat_series_dtype_timedelta + NaT,
  566. nat_series_dtype_timedelta)
  567. tm.assert_series_equal(NaT + nat_series_dtype_timedelta,
  568. nat_series_dtype_timedelta)
  569. tm.assert_series_equal(nat_series_dtype_timedelta +
  570. single_nat_dtype_timedelta,
  571. nat_series_dtype_timedelta)
  572. tm.assert_series_equal(single_nat_dtype_timedelta +
  573. nat_series_dtype_timedelta,
  574. nat_series_dtype_timedelta)
  575. # multiplication
  576. tm.assert_series_equal(nat_series_dtype_timedelta * 1.0,
  577. nat_series_dtype_timedelta)
  578. tm.assert_series_equal(1.0 * nat_series_dtype_timedelta,
  579. nat_series_dtype_timedelta)
  580. tm.assert_series_equal(timedelta_series * 1, timedelta_series)
  581. tm.assert_series_equal(1 * timedelta_series, timedelta_series)
  582. tm.assert_series_equal(timedelta_series * 1.5,
  583. Series([NaT, Timedelta('1.5s')]))
  584. tm.assert_series_equal(1.5 * timedelta_series,
  585. Series([NaT, Timedelta('1.5s')]))
  586. tm.assert_series_equal(timedelta_series * np.nan,
  587. nat_series_dtype_timedelta)
  588. tm.assert_series_equal(np.nan * timedelta_series,
  589. nat_series_dtype_timedelta)
  590. # division
  591. tm.assert_series_equal(timedelta_series / 2,
  592. Series([NaT, Timedelta('0.5s')]))
  593. tm.assert_series_equal(timedelta_series / 2.0,
  594. Series([NaT, Timedelta('0.5s')]))
  595. tm.assert_series_equal(timedelta_series / np.nan,
  596. nat_series_dtype_timedelta)
  597. # -------------------------------------------------------------
  598. # Invalid Operations
  599. def test_td64arr_add_str_invalid(self, box_with_array):
  600. # GH#13624
  601. tdi = TimedeltaIndex(['1 day', '2 days'])
  602. tdi = tm.box_expected(tdi, box_with_array)
  603. with pytest.raises(TypeError):
  604. tdi + 'a'
  605. with pytest.raises(TypeError):
  606. 'a' + tdi
  607. @pytest.mark.parametrize('other', [3.14, np.array([2.0, 3.0])])
  608. def test_td64arr_add_sub_float(self, box_with_array, other):
  609. tdi = TimedeltaIndex(['-1 days', '-1 days'])
  610. tdarr = tm.box_expected(tdi, box_with_array)
  611. with pytest.raises(TypeError):
  612. tdarr + other
  613. with pytest.raises(TypeError):
  614. other + tdarr
  615. with pytest.raises(TypeError):
  616. tdarr - other
  617. with pytest.raises(TypeError):
  618. other - tdarr
  619. @pytest.mark.parametrize('freq', [None, 'H'])
  620. def test_td64arr_sub_period(self, box_with_array, freq):
  621. # GH#13078
  622. # not supported, check TypeError
  623. p = pd.Period('2011-01-01', freq='D')
  624. idx = TimedeltaIndex(['1 hours', '2 hours'], freq=freq)
  625. idx = tm.box_expected(idx, box_with_array)
  626. with pytest.raises(TypeError):
  627. idx - p
  628. with pytest.raises(TypeError):
  629. p - idx
  630. @pytest.mark.parametrize('pi_freq', ['D', 'W', 'Q', 'H'])
  631. @pytest.mark.parametrize('tdi_freq', [None, 'H'])
  632. def test_td64arr_sub_pi(self, box_with_array, tdi_freq, pi_freq):
  633. # GH#20049 subtracting PeriodIndex should raise TypeError
  634. tdi = TimedeltaIndex(['1 hours', '2 hours'], freq=tdi_freq)
  635. dti = Timestamp('2018-03-07 17:16:40') + tdi
  636. pi = dti.to_period(pi_freq)
  637. # TODO: parametrize over box for pi?
  638. tdi = tm.box_expected(tdi, box_with_array)
  639. with pytest.raises(TypeError):
  640. tdi - pi
  641. # -------------------------------------------------------------
  642. # Binary operations td64 arraylike and datetime-like
  643. def test_td64arr_sub_timestamp_raises(self, box_with_array):
  644. idx = TimedeltaIndex(['1 day', '2 day'])
  645. idx = tm.box_expected(idx, box_with_array)
  646. msg = ("cannot subtract a datelike from|"
  647. "Could not operate|"
  648. "cannot perform operation")
  649. with pytest.raises(TypeError, match=msg):
  650. idx - Timestamp('2011-01-01')
  651. def test_td64arr_add_timestamp(self, box_with_array, tz_naive_fixture):
  652. # GH#23215
  653. # TODO: parametrize over scalar datetime types?
  654. tz = tz_naive_fixture
  655. other = Timestamp('2011-01-01', tz=tz)
  656. idx = TimedeltaIndex(['1 day', '2 day'])
  657. expected = DatetimeIndex(['2011-01-02', '2011-01-03'], tz=tz)
  658. # FIXME: fails with transpose=True because of tz-aware DataFrame
  659. # transpose bug
  660. idx = tm.box_expected(idx, box_with_array, transpose=False)
  661. expected = tm.box_expected(expected, box_with_array, transpose=False)
  662. result = idx + other
  663. tm.assert_equal(result, expected)
  664. result = other + idx
  665. tm.assert_equal(result, expected)
  666. def test_td64arr_add_sub_timestamp(self, box_with_array):
  667. # GH#11925
  668. ts = Timestamp('2012-01-01')
  669. # TODO: parametrize over types of datetime scalar?
  670. tdi = timedelta_range('1 day', periods=3)
  671. expected = pd.date_range('2012-01-02', periods=3)
  672. tdarr = tm.box_expected(tdi, box_with_array)
  673. expected = tm.box_expected(expected, box_with_array)
  674. tm.assert_equal(ts + tdarr, expected)
  675. tm.assert_equal(tdarr + ts, expected)
  676. expected2 = pd.date_range('2011-12-31', periods=3, freq='-1D')
  677. expected2 = tm.box_expected(expected2, box_with_array)
  678. tm.assert_equal(ts - tdarr, expected2)
  679. tm.assert_equal(ts + (-tdarr), expected2)
  680. with pytest.raises(TypeError):
  681. tdarr - ts
  682. def test_tdi_sub_dt64_array(self, box_with_array):
  683. dti = pd.date_range('2016-01-01', periods=3)
  684. tdi = dti - dti.shift(1)
  685. dtarr = dti.values
  686. expected = pd.DatetimeIndex(dtarr) - tdi
  687. tdi = tm.box_expected(tdi, box_with_array)
  688. expected = tm.box_expected(expected, box_with_array)
  689. with pytest.raises(TypeError):
  690. tdi - dtarr
  691. # TimedeltaIndex.__rsub__
  692. result = dtarr - tdi
  693. tm.assert_equal(result, expected)
  694. def test_tdi_add_dt64_array(self, box_with_array):
  695. dti = pd.date_range('2016-01-01', periods=3)
  696. tdi = dti - dti.shift(1)
  697. dtarr = dti.values
  698. expected = pd.DatetimeIndex(dtarr) + tdi
  699. tdi = tm.box_expected(tdi, box_with_array)
  700. expected = tm.box_expected(expected, box_with_array)
  701. result = tdi + dtarr
  702. tm.assert_equal(result, expected)
  703. result = dtarr + tdi
  704. tm.assert_equal(result, expected)
  705. def test_td64arr_add_datetime64_nat(self, box_with_array):
  706. # GH#23215
  707. other = np.datetime64('NaT')
  708. tdi = timedelta_range('1 day', periods=3)
  709. expected = pd.DatetimeIndex(["NaT", "NaT", "NaT"])
  710. tdser = tm.box_expected(tdi, box_with_array)
  711. expected = tm.box_expected(expected, box_with_array)
  712. tm.assert_equal(tdser + other, expected)
  713. tm.assert_equal(other + tdser, expected)
  714. # ------------------------------------------------------------------
  715. # Operations with int-like others
  716. def test_td64arr_add_int_series_invalid(self, box):
  717. tdser = pd.Series(['59 Days', '59 Days', 'NaT'], dtype='m8[ns]')
  718. tdser = tm.box_expected(tdser, box)
  719. err = TypeError if box is not pd.Index else NullFrequencyError
  720. int_ser = Series([2, 3, 4])
  721. with pytest.raises(err):
  722. tdser + int_ser
  723. with pytest.raises(err):
  724. int_ser + tdser
  725. with pytest.raises(err):
  726. tdser - int_ser
  727. with pytest.raises(err):
  728. int_ser - tdser
  729. def test_td64arr_add_intlike(self, box_with_array):
  730. # GH#19123
  731. tdi = TimedeltaIndex(['59 days', '59 days', 'NaT'])
  732. ser = tm.box_expected(tdi, box_with_array)
  733. err = TypeError
  734. if box_with_array in [pd.Index, tm.to_array]:
  735. err = NullFrequencyError
  736. other = Series([20, 30, 40], dtype='uint8')
  737. # TODO: separate/parametrize
  738. with pytest.raises(err):
  739. ser + 1
  740. with pytest.raises(err):
  741. ser - 1
  742. with pytest.raises(err):
  743. ser + other
  744. with pytest.raises(err):
  745. ser - other
  746. with pytest.raises(err):
  747. ser + np.array(other)
  748. with pytest.raises(err):
  749. ser - np.array(other)
  750. with pytest.raises(err):
  751. ser + pd.Index(other)
  752. with pytest.raises(err):
  753. ser - pd.Index(other)
  754. @pytest.mark.parametrize('scalar', [1, 1.5, np.array(2)])
  755. def test_td64arr_add_sub_numeric_scalar_invalid(self, box_with_array,
  756. scalar):
  757. box = box_with_array
  758. tdser = pd.Series(['59 Days', '59 Days', 'NaT'], dtype='m8[ns]')
  759. tdser = tm.box_expected(tdser, box)
  760. err = TypeError
  761. if box in [pd.Index, tm.to_array] and not isinstance(scalar, float):
  762. err = NullFrequencyError
  763. with pytest.raises(err):
  764. tdser + scalar
  765. with pytest.raises(err):
  766. scalar + tdser
  767. with pytest.raises(err):
  768. tdser - scalar
  769. with pytest.raises(err):
  770. scalar - tdser
  771. @pytest.mark.parametrize('dtype', ['int64', 'int32', 'int16',
  772. 'uint64', 'uint32', 'uint16', 'uint8',
  773. 'float64', 'float32', 'float16'])
  774. @pytest.mark.parametrize('vec', [
  775. np.array([1, 2, 3]),
  776. pd.Index([1, 2, 3]),
  777. Series([1, 2, 3])
  778. # TODO: Add DataFrame in here?
  779. ], ids=lambda x: type(x).__name__)
  780. def test_td64arr_add_sub_numeric_arr_invalid(self, box, vec, dtype):
  781. tdser = pd.Series(['59 Days', '59 Days', 'NaT'], dtype='m8[ns]')
  782. tdser = tm.box_expected(tdser, box)
  783. err = TypeError
  784. if box is pd.Index and not dtype.startswith('float'):
  785. err = NullFrequencyError
  786. vector = vec.astype(dtype)
  787. with pytest.raises(err):
  788. tdser + vector
  789. with pytest.raises(err):
  790. vector + tdser
  791. with pytest.raises(err):
  792. tdser - vector
  793. with pytest.raises(err):
  794. vector - tdser
  795. # ------------------------------------------------------------------
  796. # Operations with timedelta-like others
  797. # TODO: this was taken from tests.series.test_ops; de-duplicate
  798. @pytest.mark.parametrize('scalar_td', [timedelta(minutes=5, seconds=4),
  799. Timedelta(minutes=5, seconds=4),
  800. Timedelta('5m4s').to_timedelta64()])
  801. def test_operators_timedelta64_with_timedelta(self, scalar_td):
  802. # smoke tests
  803. td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
  804. td1.iloc[2] = np.nan
  805. td1 + scalar_td
  806. scalar_td + td1
  807. td1 - scalar_td
  808. scalar_td - td1
  809. td1 / scalar_td
  810. scalar_td / td1
  811. # TODO: this was taken from tests.series.test_ops; de-duplicate
  812. def test_timedelta64_operations_with_timedeltas(self):
  813. # td operate with td
  814. td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
  815. td2 = timedelta(minutes=5, seconds=4)
  816. result = td1 - td2
  817. expected = (Series([timedelta(seconds=0)] * 3) -
  818. Series([timedelta(seconds=1)] * 3))
  819. assert result.dtype == 'm8[ns]'
  820. tm.assert_series_equal(result, expected)
  821. result2 = td2 - td1
  822. expected = (Series([timedelta(seconds=1)] * 3) -
  823. Series([timedelta(seconds=0)] * 3))
  824. tm.assert_series_equal(result2, expected)
  825. # roundtrip
  826. tm.assert_series_equal(result + td2, td1)
  827. # Now again, using pd.to_timedelta, which should build
  828. # a Series or a scalar, depending on input.
  829. td1 = Series(pd.to_timedelta(['00:05:03'] * 3))
  830. td2 = pd.to_timedelta('00:05:04')
  831. result = td1 - td2
  832. expected = (Series([timedelta(seconds=0)] * 3) -
  833. Series([timedelta(seconds=1)] * 3))
  834. assert result.dtype == 'm8[ns]'
  835. tm.assert_series_equal(result, expected)
  836. result2 = td2 - td1
  837. expected = (Series([timedelta(seconds=1)] * 3) -
  838. Series([timedelta(seconds=0)] * 3))
  839. tm.assert_series_equal(result2, expected)
  840. # roundtrip
  841. tm.assert_series_equal(result + td2, td1)
  842. def test_td64arr_add_td64_array(self, box):
  843. dti = pd.date_range('2016-01-01', periods=3)
  844. tdi = dti - dti.shift(1)
  845. tdarr = tdi.values
  846. expected = 2 * tdi
  847. tdi = tm.box_expected(tdi, box)
  848. expected = tm.box_expected(expected, box)
  849. result = tdi + tdarr
  850. tm.assert_equal(result, expected)
  851. result = tdarr + tdi
  852. tm.assert_equal(result, expected)
  853. def test_td64arr_sub_td64_array(self, box):
  854. dti = pd.date_range('2016-01-01', periods=3)
  855. tdi = dti - dti.shift(1)
  856. tdarr = tdi.values
  857. expected = 0 * tdi
  858. tdi = tm.box_expected(tdi, box)
  859. expected = tm.box_expected(expected, box)
  860. result = tdi - tdarr
  861. tm.assert_equal(result, expected)
  862. result = tdarr - tdi
  863. tm.assert_equal(result, expected)
  864. # TODO: parametrize over [add, sub, radd, rsub]?
  865. @pytest.mark.parametrize('names', [(None, None, None),
  866. ('Egon', 'Venkman', None),
  867. ('NCC1701D', 'NCC1701D', 'NCC1701D')])
  868. def test_td64arr_add_sub_tdi(self, box, names):
  869. # GH#17250 make sure result dtype is correct
  870. # GH#19043 make sure names are propagated correctly
  871. if box is pd.DataFrame and names[1] == 'Venkman':
  872. pytest.skip("Name propagation for DataFrame does not behave like "
  873. "it does for Index/Series")
  874. tdi = TimedeltaIndex(['0 days', '1 day'], name=names[0])
  875. ser = Series([Timedelta(hours=3), Timedelta(hours=4)], name=names[1])
  876. expected = Series([Timedelta(hours=3), Timedelta(days=1, hours=4)],
  877. name=names[2])
  878. ser = tm.box_expected(ser, box)
  879. expected = tm.box_expected(expected, box)
  880. result = tdi + ser
  881. tm.assert_equal(result, expected)
  882. if box is not pd.DataFrame:
  883. assert result.dtype == 'timedelta64[ns]'
  884. else:
  885. assert result.dtypes[0] == 'timedelta64[ns]'
  886. result = ser + tdi
  887. tm.assert_equal(result, expected)
  888. if box is not pd.DataFrame:
  889. assert result.dtype == 'timedelta64[ns]'
  890. else:
  891. assert result.dtypes[0] == 'timedelta64[ns]'
  892. expected = Series([Timedelta(hours=-3), Timedelta(days=1, hours=-4)],
  893. name=names[2])
  894. expected = tm.box_expected(expected, box)
  895. result = tdi - ser
  896. tm.assert_equal(result, expected)
  897. if box is not pd.DataFrame:
  898. assert result.dtype == 'timedelta64[ns]'
  899. else:
  900. assert result.dtypes[0] == 'timedelta64[ns]'
  901. result = ser - tdi
  902. tm.assert_equal(result, -expected)
  903. if box is not pd.DataFrame:
  904. assert result.dtype == 'timedelta64[ns]'
  905. else:
  906. assert result.dtypes[0] == 'timedelta64[ns]'
  907. def test_td64arr_add_sub_td64_nat(self, box):
  908. # GH#23320 special handling for timedelta64("NaT")
  909. tdi = pd.TimedeltaIndex([NaT, Timedelta('1s')])
  910. other = np.timedelta64("NaT")
  911. expected = pd.TimedeltaIndex(["NaT"] * 2)
  912. obj = tm.box_expected(tdi, box)
  913. expected = tm.box_expected(expected, box)
  914. result = obj + other
  915. tm.assert_equal(result, expected)
  916. result = other + obj
  917. tm.assert_equal(result, expected)
  918. result = obj - other
  919. tm.assert_equal(result, expected)
  920. result = other - obj
  921. tm.assert_equal(result, expected)
  922. def test_td64arr_sub_NaT(self, box):
  923. # GH#18808
  924. ser = Series([NaT, Timedelta('1s')])
  925. expected = Series([NaT, NaT], dtype='timedelta64[ns]')
  926. ser = tm.box_expected(ser, box)
  927. expected = tm.box_expected(expected, box)
  928. res = ser - pd.NaT
  929. tm.assert_equal(res, expected)
  930. def test_td64arr_add_timedeltalike(self, two_hours, box):
  931. # only test adding/sub offsets as + is now numeric
  932. rng = timedelta_range('1 days', '10 days')
  933. expected = timedelta_range('1 days 02:00:00', '10 days 02:00:00',
  934. freq='D')
  935. rng = tm.box_expected(rng, box)
  936. expected = tm.box_expected(expected, box)
  937. result = rng + two_hours
  938. tm.assert_equal(result, expected)
  939. def test_td64arr_sub_timedeltalike(self, two_hours, box):
  940. # only test adding/sub offsets as - is now numeric
  941. rng = timedelta_range('1 days', '10 days')
  942. expected = timedelta_range('0 days 22:00:00', '9 days 22:00:00')
  943. rng = tm.box_expected(rng, box)
  944. expected = tm.box_expected(expected, box)
  945. result = rng - two_hours
  946. tm.assert_equal(result, expected)
  947. # ------------------------------------------------------------------
  948. # __add__/__sub__ with DateOffsets and arrays of DateOffsets
  949. # TODO: this was taken from tests.series.test_operators; de-duplicate
  950. def test_timedelta64_operations_with_DateOffset(self):
  951. # GH#10699
  952. td = Series([timedelta(minutes=5, seconds=3)] * 3)
  953. result = td + pd.offsets.Minute(1)
  954. expected = Series([timedelta(minutes=6, seconds=3)] * 3)
  955. tm.assert_series_equal(result, expected)
  956. result = td - pd.offsets.Minute(1)
  957. expected = Series([timedelta(minutes=4, seconds=3)] * 3)
  958. tm.assert_series_equal(result, expected)
  959. with tm.assert_produces_warning(PerformanceWarning):
  960. result = td + Series([pd.offsets.Minute(1), pd.offsets.Second(3),
  961. pd.offsets.Hour(2)])
  962. expected = Series([timedelta(minutes=6, seconds=3),
  963. timedelta(minutes=5, seconds=6),
  964. timedelta(hours=2, minutes=5, seconds=3)])
  965. tm.assert_series_equal(result, expected)
  966. result = td + pd.offsets.Minute(1) + pd.offsets.Second(12)
  967. expected = Series([timedelta(minutes=6, seconds=15)] * 3)
  968. tm.assert_series_equal(result, expected)
  969. # valid DateOffsets
  970. for do in ['Hour', 'Minute', 'Second', 'Day', 'Micro', 'Milli',
  971. 'Nano']:
  972. op = getattr(pd.offsets, do)
  973. td + op(5)
  974. op(5) + td
  975. td - op(5)
  976. op(5) - td
  977. @pytest.mark.parametrize('names', [(None, None, None),
  978. ('foo', 'bar', None),
  979. ('foo', 'foo', 'foo')])
  980. def test_td64arr_add_offset_index(self, names, box):
  981. # GH#18849, GH#19744
  982. if box is pd.DataFrame and names[1] == 'bar':
  983. pytest.skip("Name propagation for DataFrame does not behave like "
  984. "it does for Index/Series")
  985. tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'],
  986. name=names[0])
  987. other = pd.Index([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)],
  988. name=names[1])
  989. expected = TimedeltaIndex([tdi[n] + other[n] for n in range(len(tdi))],
  990. freq='infer', name=names[2])
  991. tdi = tm.box_expected(tdi, box)
  992. expected = tm.box_expected(expected, box)
  993. # The DataFrame operation is transposed and so operates as separate
  994. # scalar operations, which do not issue a PerformanceWarning
  995. warn = PerformanceWarning if box is not pd.DataFrame else None
  996. with tm.assert_produces_warning(warn):
  997. res = tdi + other
  998. tm.assert_equal(res, expected)
  999. with tm.assert_produces_warning(warn):
  1000. res2 = other + tdi
  1001. tm.assert_equal(res2, expected)
  1002. # TODO: combine with test_td64arr_add_offset_index by parametrizing
  1003. # over second box?
  1004. def test_td64arr_add_offset_array(self, box):
  1005. # GH#18849
  1006. tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'])
  1007. other = np.array([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)])
  1008. expected = TimedeltaIndex([tdi[n] + other[n] for n in range(len(tdi))],
  1009. freq='infer')
  1010. tdi = tm.box_expected(tdi, box)
  1011. expected = tm.box_expected(expected, box)
  1012. # The DataFrame operation is transposed and so operates as separate
  1013. # scalar operations, which do not issue a PerformanceWarning
  1014. warn = PerformanceWarning if box is not pd.DataFrame else None
  1015. with tm.assert_produces_warning(warn):
  1016. res = tdi + other
  1017. tm.assert_equal(res, expected)
  1018. with tm.assert_produces_warning(warn):
  1019. res2 = other + tdi
  1020. tm.assert_equal(res2, expected)
  1021. @pytest.mark.parametrize('names', [(None, None, None),
  1022. ('foo', 'bar', None),
  1023. ('foo', 'foo', 'foo')])
  1024. def test_td64arr_sub_offset_index(self, names, box):
  1025. # GH#18824, GH#19744
  1026. if box is pd.DataFrame and names[1] == 'bar':
  1027. pytest.skip("Name propagation for DataFrame does not behave like "
  1028. "it does for Index/Series")
  1029. tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'],
  1030. name=names[0])
  1031. other = pd.Index([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)],
  1032. name=names[1])
  1033. expected = TimedeltaIndex([tdi[n] - other[n] for n in range(len(tdi))],
  1034. freq='infer', name=names[2])
  1035. tdi = tm.box_expected(tdi, box)
  1036. expected = tm.box_expected(expected, box)
  1037. # The DataFrame operation is transposed and so operates as separate
  1038. # scalar operations, which do not issue a PerformanceWarning
  1039. warn = PerformanceWarning if box is not pd.DataFrame else None
  1040. with tm.assert_produces_warning(warn):
  1041. res = tdi - other
  1042. tm.assert_equal(res, expected)
  1043. def test_td64arr_sub_offset_array(self, box_with_array):
  1044. # GH#18824
  1045. tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'])
  1046. other = np.array([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)])
  1047. expected = TimedeltaIndex([tdi[n] - other[n] for n in range(len(tdi))],
  1048. freq='infer')
  1049. tdi = tm.box_expected(tdi, box_with_array)
  1050. expected = tm.box_expected(expected, box_with_array)
  1051. # The DataFrame operation is transposed and so operates as separate
  1052. # scalar operations, which do not issue a PerformanceWarning
  1053. warn = None if box_with_array is pd.DataFrame else PerformanceWarning
  1054. with tm.assert_produces_warning(warn):
  1055. res = tdi - other
  1056. tm.assert_equal(res, expected)
  1057. @pytest.mark.parametrize('names', [(None, None, None),
  1058. ('foo', 'bar', None),
  1059. ('foo', 'foo', 'foo')])
  1060. def test_td64arr_with_offset_series(self, names, box_df_fail):
  1061. # GH#18849
  1062. box = box_df_fail
  1063. box2 = Series if box in [pd.Index, tm.to_array] else box
  1064. tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'],
  1065. name=names[0])
  1066. other = Series([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)],
  1067. name=names[1])
  1068. expected_add = Series([tdi[n] + other[n] for n in range(len(tdi))],
  1069. name=names[2])
  1070. tdi = tm.box_expected(tdi, box)
  1071. expected_add = tm.box_expected(expected_add, box2)
  1072. with tm.assert_produces_warning(PerformanceWarning):
  1073. res = tdi + other
  1074. tm.assert_equal(res, expected_add)
  1075. with tm.assert_produces_warning(PerformanceWarning):
  1076. res2 = other + tdi
  1077. tm.assert_equal(res2, expected_add)
  1078. # TODO: separate/parametrize add/sub test?
  1079. expected_sub = Series([tdi[n] - other[n] for n in range(len(tdi))],
  1080. name=names[2])
  1081. expected_sub = tm.box_expected(expected_sub, box2)
  1082. with tm.assert_produces_warning(PerformanceWarning):
  1083. res3 = tdi - other
  1084. tm.assert_equal(res3, expected_sub)
  1085. @pytest.mark.parametrize('obox', [np.array, pd.Index, pd.Series])
  1086. def test_td64arr_addsub_anchored_offset_arraylike(self, obox,
  1087. box_with_array):
  1088. # GH#18824
  1089. tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'])
  1090. tdi = tm.box_expected(tdi, box_with_array)
  1091. anchored = obox([pd.offsets.MonthEnd(), pd.offsets.Day(n=2)])
  1092. # addition/subtraction ops with anchored offsets should issue
  1093. # a PerformanceWarning and _then_ raise a TypeError.
  1094. with pytest.raises(TypeError):
  1095. with tm.assert_produces_warning(PerformanceWarning):
  1096. tdi + anchored
  1097. with pytest.raises(TypeError):
  1098. with tm.assert_produces_warning(PerformanceWarning):
  1099. anchored + tdi
  1100. with pytest.raises(TypeError):
  1101. with tm.assert_produces_warning(PerformanceWarning):
  1102. tdi - anchored
  1103. with pytest.raises(TypeError):
  1104. with tm.assert_produces_warning(PerformanceWarning):
  1105. anchored - tdi
  1106. class TestTimedeltaArraylikeMulDivOps(object):
  1107. # Tests for timedelta64[ns]
  1108. # __mul__, __rmul__, __div__, __rdiv__, __floordiv__, __rfloordiv__
  1109. # TODO: Moved from tests.series.test_operators; needs cleanup
  1110. @pytest.mark.parametrize("m", [1, 3, 10])
  1111. @pytest.mark.parametrize("unit", ['D', 'h', 'm', 's', 'ms', 'us', 'ns'])
  1112. def test_timedelta64_conversions(self, m, unit):
  1113. startdate = Series(pd.date_range('2013-01-01', '2013-01-03'))
  1114. enddate = Series(pd.date_range('2013-03-01', '2013-03-03'))
  1115. ser = enddate - startdate
  1116. ser[2] = np.nan
  1117. # op
  1118. expected = Series([x / np.timedelta64(m, unit) for x in ser])
  1119. result = ser / np.timedelta64(m, unit)
  1120. tm.assert_series_equal(result, expected)
  1121. # reverse op
  1122. expected = Series([Timedelta(np.timedelta64(m, unit)) / x
  1123. for x in ser])
  1124. result = np.timedelta64(m, unit) / ser
  1125. tm.assert_series_equal(result, expected)
  1126. # ------------------------------------------------------------------
  1127. # Multiplication
  1128. # organized with scalar others first, then array-like
  1129. def test_td64arr_mul_int(self, box_with_array):
  1130. idx = TimedeltaIndex(np.arange(5, dtype='int64'))
  1131. idx = tm.box_expected(idx, box_with_array)
  1132. result = idx * 1
  1133. tm.assert_equal(result, idx)
  1134. result = 1 * idx
  1135. tm.assert_equal(result, idx)
  1136. def test_td64arr_mul_tdlike_scalar_raises(self, two_hours, box_with_array):
  1137. rng = timedelta_range('1 days', '10 days', name='foo')
  1138. rng = tm.box_expected(rng, box_with_array)
  1139. with pytest.raises(TypeError):
  1140. rng * two_hours
  1141. def test_tdi_mul_int_array_zerodim(self, box_with_array):
  1142. rng5 = np.arange(5, dtype='int64')
  1143. idx = TimedeltaIndex(rng5)
  1144. expected = TimedeltaIndex(rng5 * 5)
  1145. idx = tm.box_expected(idx, box_with_array)
  1146. expected = tm.box_expected(expected, box_with_array)
  1147. result = idx * np.array(5, dtype='int64')
  1148. tm.assert_equal(result, expected)
  1149. def test_tdi_mul_int_array(self, box_with_array):
  1150. rng5 = np.arange(5, dtype='int64')
  1151. idx = TimedeltaIndex(rng5)
  1152. expected = TimedeltaIndex(rng5 ** 2)
  1153. idx = tm.box_expected(idx, box_with_array)
  1154. expected = tm.box_expected(expected, box_with_array)
  1155. result = idx * rng5
  1156. tm.assert_equal(result, expected)
  1157. def test_tdi_mul_int_series(self, box_with_array):
  1158. box = box_with_array
  1159. xbox = pd.Series if box in [pd.Index, tm.to_array] else box
  1160. idx = TimedeltaIndex(np.arange(5, dtype='int64'))
  1161. expected = TimedeltaIndex(np.arange(5, dtype='int64') ** 2)
  1162. idx = tm.box_expected(idx, box)
  1163. expected = tm.box_expected(expected, xbox)
  1164. result = idx * pd.Series(np.arange(5, dtype='int64'))
  1165. tm.assert_equal(result, expected)
  1166. def test_tdi_mul_float_series(self, box_with_array):
  1167. box = box_with_array
  1168. xbox = pd.Series if box in [pd.Index, tm.to_array] else box
  1169. idx = TimedeltaIndex(np.arange(5, dtype='int64'))
  1170. idx = tm.box_expected(idx, box)
  1171. rng5f = np.arange(5, dtype='float64')
  1172. expected = TimedeltaIndex(rng5f * (rng5f + 1.0))
  1173. expected = tm.box_expected(expected, xbox)
  1174. result = idx * Series(rng5f + 1.0)
  1175. tm.assert_equal(result, expected)
  1176. # TODO: Put Series/DataFrame in others?
  1177. @pytest.mark.parametrize('other', [
  1178. np.arange(1, 11),
  1179. pd.Int64Index(range(1, 11)),
  1180. pd.UInt64Index(range(1, 11)),
  1181. pd.Float64Index(range(1, 11)),
  1182. pd.RangeIndex(1, 11)
  1183. ], ids=lambda x: type(x).__name__)
  1184. def test_tdi_rmul_arraylike(self, other, box_with_array):
  1185. box = box_with_array
  1186. xbox = get_upcast_box(box, other)
  1187. tdi = TimedeltaIndex(['1 Day'] * 10)
  1188. expected = timedelta_range('1 days', '10 days')
  1189. expected._data.freq = None
  1190. tdi = tm.box_expected(tdi, box)
  1191. expected = tm.box_expected(expected, xbox)
  1192. result = other * tdi
  1193. tm.assert_equal(result, expected)
  1194. commute = tdi * other
  1195. tm.assert_equal(commute, expected)
  1196. # ------------------------------------------------------------------
  1197. # __div__, __rdiv__
  1198. def test_td64arr_div_nat_invalid(self, box_with_array):
  1199. # don't allow division by NaT (maybe could in the future)
  1200. rng = timedelta_range('1 days', '10 days', name='foo')
  1201. rng = tm.box_expected(rng, box_with_array)
  1202. with pytest.raises(TypeError, match='true_divide cannot use operands'):
  1203. rng / pd.NaT
  1204. with pytest.raises(TypeError, match='Cannot divide NaTType by'):
  1205. pd.NaT / rng
  1206. def test_td64arr_div_td64nat(self, box_with_array):
  1207. # GH#23829
  1208. rng = timedelta_range('1 days', '10 days',)
  1209. rng = tm.box_expected(rng, box_with_array)
  1210. other = np.timedelta64('NaT')
  1211. expected = np.array([np.nan] * 10)
  1212. expected = tm.box_expected(expected, box_with_array)
  1213. result = rng / other
  1214. tm.assert_equal(result, expected)
  1215. result = other / rng
  1216. tm.assert_equal(result, expected)
  1217. def test_td64arr_div_int(self, box_with_array):
  1218. idx = TimedeltaIndex(np.arange(5, dtype='int64'))
  1219. idx = tm.box_expected(idx, box_with_array)
  1220. result = idx / 1
  1221. tm.assert_equal(result, idx)
  1222. with pytest.raises(TypeError, match='Cannot divide'):
  1223. # GH#23829
  1224. 1 / idx
  1225. def test_td64arr_div_tdlike_scalar(self, two_hours, box_with_array):
  1226. # GH#20088, GH#22163 ensure DataFrame returns correct dtype
  1227. rng = timedelta_range('1 days', '10 days', name='foo')
  1228. expected = pd.Float64Index((np.arange(10) + 1) * 12, name='foo')
  1229. rng = tm.box_expected(rng, box_with_array)
  1230. expected = tm.box_expected(expected, box_with_array)
  1231. result = rng / two_hours
  1232. tm.assert_equal(result, expected)
  1233. result = two_hours / rng
  1234. expected = 1 / expected
  1235. tm.assert_equal(result, expected)
  1236. def test_td64arr_div_tdlike_scalar_with_nat(self, two_hours,
  1237. box_with_array):
  1238. rng = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo')
  1239. expected = pd.Float64Index([12, np.nan, 24], name='foo')
  1240. rng = tm.box_expected(rng, box_with_array)
  1241. expected = tm.box_expected(expected, box_with_array)
  1242. result = rng / two_hours
  1243. tm.assert_equal(result, expected)
  1244. result = two_hours / rng
  1245. expected = 1 / expected
  1246. tm.assert_equal(result, expected)
  1247. def test_td64arr_div_td64_ndarray(self, box_with_array):
  1248. # GH#22631
  1249. rng = TimedeltaIndex(['1 days', pd.NaT, '2 days'])
  1250. expected = pd.Float64Index([12, np.nan, 24])
  1251. rng = tm.box_expected(rng, box_with_array)
  1252. expected = tm.box_expected(expected, box_with_array)
  1253. other = np.array([2, 4, 2], dtype='m8[h]')
  1254. result = rng / other
  1255. tm.assert_equal(result, expected)
  1256. result = rng / tm.box_expected(other, box_with_array)
  1257. tm.assert_equal(result, expected)
  1258. result = rng / other.astype(object)
  1259. tm.assert_equal(result, expected)
  1260. result = rng / list(other)
  1261. tm.assert_equal(result, expected)
  1262. # reversed op
  1263. expected = 1 / expected
  1264. result = other / rng
  1265. tm.assert_equal(result, expected)
  1266. result = tm.box_expected(other, box_with_array) / rng
  1267. tm.assert_equal(result, expected)
  1268. result = other.astype(object) / rng
  1269. tm.assert_equal(result, expected)
  1270. result = list(other) / rng
  1271. tm.assert_equal(result, expected)
  1272. def test_tdarr_div_length_mismatch(self, box_with_array):
  1273. rng = TimedeltaIndex(['1 days', pd.NaT, '2 days'])
  1274. mismatched = [1, 2, 3, 4]
  1275. rng = tm.box_expected(rng, box_with_array)
  1276. for obj in [mismatched, mismatched[:2]]:
  1277. # one shorter, one longer
  1278. for other in [obj, np.array(obj), pd.Index(obj)]:
  1279. with pytest.raises(ValueError):
  1280. rng / other
  1281. with pytest.raises(ValueError):
  1282. other / rng
  1283. # ------------------------------------------------------------------
  1284. # __floordiv__, __rfloordiv__
  1285. def test_td64arr_floordiv_tdscalar(self, box_with_array, scalar_td):
  1286. # GH#18831
  1287. td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
  1288. td1.iloc[2] = np.nan
  1289. expected = Series([0, 0, np.nan])
  1290. td1 = tm.box_expected(td1, box_with_array, transpose=False)
  1291. expected = tm.box_expected(expected, box_with_array, transpose=False)
  1292. result = td1 // scalar_td
  1293. tm.assert_equal(result, expected)
  1294. def test_td64arr_rfloordiv_tdscalar(self, box_with_array, scalar_td):
  1295. # GH#18831
  1296. td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
  1297. td1.iloc[2] = np.nan
  1298. expected = Series([1, 1, np.nan])
  1299. td1 = tm.box_expected(td1, box_with_array, transpose=False)
  1300. expected = tm.box_expected(expected, box_with_array, transpose=False)
  1301. result = scalar_td // td1
  1302. tm.assert_equal(result, expected)
  1303. def test_td64arr_rfloordiv_tdscalar_explicit(self, box_with_array,
  1304. scalar_td):
  1305. # GH#18831
  1306. td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
  1307. td1.iloc[2] = np.nan
  1308. expected = Series([1, 1, np.nan])
  1309. td1 = tm.box_expected(td1, box_with_array, transpose=False)
  1310. expected = tm.box_expected(expected, box_with_array, transpose=False)
  1311. # We can test __rfloordiv__ using this syntax,
  1312. # see `test_timedelta_rfloordiv`
  1313. result = td1.__rfloordiv__(scalar_td)
  1314. tm.assert_equal(result, expected)
  1315. def test_td64arr_floordiv_int(self, box_with_array):
  1316. idx = TimedeltaIndex(np.arange(5, dtype='int64'))
  1317. idx = tm.box_expected(idx, box_with_array)
  1318. result = idx // 1
  1319. tm.assert_equal(result, idx)
  1320. pattern = ('floor_divide cannot use operands|'
  1321. 'Cannot divide int by Timedelta*')
  1322. with pytest.raises(TypeError, match=pattern):
  1323. 1 // idx
  1324. def test_td64arr_floordiv_tdlike_scalar(self, two_hours, box_with_array):
  1325. tdi = timedelta_range('1 days', '10 days', name='foo')
  1326. expected = pd.Int64Index((np.arange(10) + 1) * 12, name='foo')
  1327. tdi = tm.box_expected(tdi, box_with_array)
  1328. expected = tm.box_expected(expected, box_with_array)
  1329. result = tdi // two_hours
  1330. tm.assert_equal(result, expected)
  1331. # TODO: Is this redundant with test_td64arr_floordiv_tdlike_scalar?
  1332. @pytest.mark.parametrize('scalar_td', [
  1333. timedelta(minutes=10, seconds=7),
  1334. Timedelta('10m7s'),
  1335. Timedelta('10m7s').to_timedelta64()
  1336. ], ids=lambda x: type(x).__name__)
  1337. def test_td64arr_rfloordiv_tdlike_scalar(self, scalar_td, box_with_array):
  1338. # GH#19125
  1339. tdi = TimedeltaIndex(['00:05:03', '00:05:03', pd.NaT], freq=None)
  1340. expected = pd.Index([2.0, 2.0, np.nan])
  1341. tdi = tm.box_expected(tdi, box_with_array, transpose=False)
  1342. expected = tm.box_expected(expected, box_with_array, transpose=False)
  1343. res = tdi.__rfloordiv__(scalar_td)
  1344. tm.assert_equal(res, expected)
  1345. expected = pd.Index([0.0, 0.0, np.nan])
  1346. expected = tm.box_expected(expected, box_with_array, transpose=False)
  1347. res = tdi // (scalar_td)
  1348. tm.assert_equal(res, expected)
  1349. # ------------------------------------------------------------------
  1350. # mod, divmod
  1351. # TODO: operations with timedelta-like arrays, numeric arrays,
  1352. # reversed ops
  1353. def test_td64arr_mod_tdscalar(self, box_with_array, three_days):
  1354. tdi = timedelta_range('1 Day', '9 days')
  1355. tdarr = tm.box_expected(tdi, box_with_array)
  1356. expected = TimedeltaIndex(['1 Day', '2 Days', '0 Days'] * 3)
  1357. expected = tm.box_expected(expected, box_with_array)
  1358. result = tdarr % three_days
  1359. tm.assert_equal(result, expected)
  1360. if box_with_array is pd.DataFrame:
  1361. pytest.xfail("DataFrame does not have __divmod__ or __rdivmod__")
  1362. result = divmod(tdarr, three_days)
  1363. tm.assert_equal(result[1], expected)
  1364. tm.assert_equal(result[0], tdarr // three_days)
  1365. def test_td64arr_mod_int(self, box_with_array):
  1366. tdi = timedelta_range('1 ns', '10 ns', periods=10)
  1367. tdarr = tm.box_expected(tdi, box_with_array)
  1368. expected = TimedeltaIndex(['1 ns', '0 ns'] * 5)
  1369. expected = tm.box_expected(expected, box_with_array)
  1370. result = tdarr % 2
  1371. tm.assert_equal(result, expected)
  1372. with pytest.raises(TypeError):
  1373. 2 % tdarr
  1374. if box_with_array is pd.DataFrame:
  1375. pytest.xfail("DataFrame does not have __divmod__ or __rdivmod__")
  1376. result = divmod(tdarr, 2)
  1377. tm.assert_equal(result[1], expected)
  1378. tm.assert_equal(result[0], tdarr // 2)
  1379. def test_td64arr_rmod_tdscalar(self, box_with_array, three_days):
  1380. tdi = timedelta_range('1 Day', '9 days')
  1381. tdarr = tm.box_expected(tdi, box_with_array)
  1382. expected = ['0 Days', '1 Day', '0 Days'] + ['3 Days'] * 6
  1383. expected = TimedeltaIndex(expected)
  1384. expected = tm.box_expected(expected, box_with_array)
  1385. result = three_days % tdarr
  1386. tm.assert_equal(result, expected)
  1387. if box_with_array is pd.DataFrame:
  1388. pytest.xfail("DataFrame does not have __divmod__ or __rdivmod__")
  1389. result = divmod(three_days, tdarr)
  1390. tm.assert_equal(result[1], expected)
  1391. tm.assert_equal(result[0], three_days // tdarr)
  1392. # ------------------------------------------------------------------
  1393. # Operations with invalid others
  1394. def test_td64arr_mul_tdscalar_invalid(self, box_with_array, scalar_td):
  1395. td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
  1396. td1.iloc[2] = np.nan
  1397. td1 = tm.box_expected(td1, box_with_array)
  1398. # check that we are getting a TypeError
  1399. # with 'operate' (from core/ops.py) for the ops that are not
  1400. # defined
  1401. pattern = 'operate|unsupported|cannot|not supported'
  1402. with pytest.raises(TypeError, match=pattern):
  1403. td1 * scalar_td
  1404. with pytest.raises(TypeError, match=pattern):
  1405. scalar_td * td1
  1406. def test_td64arr_mul_too_short_raises(self, box_with_array):
  1407. idx = TimedeltaIndex(np.arange(5, dtype='int64'))
  1408. idx = tm.box_expected(idx, box_with_array)
  1409. with pytest.raises(TypeError):
  1410. idx * idx[:3]
  1411. with pytest.raises(ValueError):
  1412. idx * np.array([1, 2])
  1413. def test_td64arr_mul_td64arr_raises(self, box_with_array):
  1414. idx = TimedeltaIndex(np.arange(5, dtype='int64'))
  1415. idx = tm.box_expected(idx, box_with_array)
  1416. with pytest.raises(TypeError):
  1417. idx * idx
  1418. # ------------------------------------------------------------------
  1419. # Operations with numeric others
  1420. @pytest.mark.parametrize('one', [1, np.array(1), 1.0, np.array(1.0)])
  1421. def test_td64arr_mul_numeric_scalar(self, box_with_array, one):
  1422. # GH#4521
  1423. # divide/multiply by integers
  1424. tdser = pd.Series(['59 Days', '59 Days', 'NaT'], dtype='m8[ns]')
  1425. expected = Series(['-59 Days', '-59 Days', 'NaT'],
  1426. dtype='timedelta64[ns]')
  1427. tdser = tm.box_expected(tdser, box_with_array)
  1428. expected = tm.box_expected(expected, box_with_array)
  1429. result = tdser * (-one)
  1430. tm.assert_equal(result, expected)
  1431. result = (-one) * tdser
  1432. tm.assert_equal(result, expected)
  1433. expected = Series(['118 Days', '118 Days', 'NaT'],
  1434. dtype='timedelta64[ns]')
  1435. expected = tm.box_expected(expected, box_with_array)
  1436. result = tdser * (2 * one)
  1437. tm.assert_equal(result, expected)
  1438. result = (2 * one) * tdser
  1439. tm.assert_equal(result, expected)
  1440. @pytest.mark.parametrize('two', [2, 2.0, np.array(2), np.array(2.0)])
  1441. def test_td64arr_div_numeric_scalar(self, box_with_array, two):
  1442. # GH#4521
  1443. # divide/multiply by integers
  1444. tdser = pd.Series(['59 Days', '59 Days', 'NaT'], dtype='m8[ns]')
  1445. expected = Series(['29.5D', '29.5D', 'NaT'], dtype='timedelta64[ns]')
  1446. tdser = tm.box_expected(tdser, box_with_array)
  1447. expected = tm.box_expected(expected, box_with_array)
  1448. result = tdser / two
  1449. tm.assert_equal(result, expected)
  1450. with pytest.raises(TypeError, match='Cannot divide'):
  1451. two / tdser
  1452. @pytest.mark.parametrize('dtype', ['int64', 'int32', 'int16',
  1453. 'uint64', 'uint32', 'uint16', 'uint8',
  1454. 'float64', 'float32', 'float16'])
  1455. @pytest.mark.parametrize('vector', [np.array([20, 30, 40]),
  1456. pd.Index([20, 30, 40]),
  1457. Series([20, 30, 40])],
  1458. ids=lambda x: type(x).__name__)
  1459. def test_td64arr_rmul_numeric_array(self, box_with_array, vector, dtype):
  1460. # GH#4521
  1461. # divide/multiply by integers
  1462. xbox = get_upcast_box(box_with_array, vector)
  1463. tdser = pd.Series(['59 Days', '59 Days', 'NaT'], dtype='m8[ns]')
  1464. vector = vector.astype(dtype)
  1465. expected = Series(['1180 Days', '1770 Days', 'NaT'],
  1466. dtype='timedelta64[ns]')
  1467. tdser = tm.box_expected(tdser, box_with_array)
  1468. expected = tm.box_expected(expected, xbox)
  1469. result = tdser * vector
  1470. tm.assert_equal(result, expected)
  1471. result = vector * tdser
  1472. tm.assert_equal(result, expected)
  1473. @pytest.mark.parametrize('dtype', ['int64', 'int32', 'int16',
  1474. 'uint64', 'uint32', 'uint16', 'uint8',
  1475. 'float64', 'float32', 'float16'])
  1476. @pytest.mark.parametrize('vector', [np.array([20, 30, 40]),
  1477. pd.Index([20, 30, 40]),
  1478. Series([20, 30, 40])],
  1479. ids=lambda x: type(x).__name__)
  1480. def test_td64arr_div_numeric_array(self, box_with_array, vector, dtype):
  1481. # GH#4521
  1482. # divide/multiply by integers
  1483. xbox = get_upcast_box(box_with_array, vector)
  1484. tdser = pd.Series(['59 Days', '59 Days', 'NaT'], dtype='m8[ns]')
  1485. vector = vector.astype(dtype)
  1486. expected = Series(['2.95D', '1D 23H 12m', 'NaT'],
  1487. dtype='timedelta64[ns]')
  1488. tdser = tm.box_expected(tdser, box_with_array)
  1489. expected = tm.box_expected(expected, xbox)
  1490. result = tdser / vector
  1491. tm.assert_equal(result, expected)
  1492. pattern = ('true_divide cannot use operands|'
  1493. 'cannot perform __div__|'
  1494. 'cannot perform __truediv__|'
  1495. 'unsupported operand|'
  1496. 'Cannot divide')
  1497. with pytest.raises(TypeError, match=pattern):
  1498. vector / tdser
  1499. if not isinstance(vector, pd.Index):
  1500. # Index.__rdiv__ won't try to operate elementwise, just raises
  1501. result = tdser / vector.astype(object)
  1502. if box_with_array is pd.DataFrame:
  1503. expected = [tdser.iloc[0, n] / vector[n]
  1504. for n in range(len(vector))]
  1505. else:
  1506. expected = [tdser[n] / vector[n] for n in range(len(tdser))]
  1507. expected = tm.box_expected(expected, xbox)
  1508. tm.assert_equal(result, expected)
  1509. with pytest.raises(TypeError, match=pattern):
  1510. vector.astype(object) / tdser
  1511. @pytest.mark.parametrize('names', [(None, None, None),
  1512. ('Egon', 'Venkman', None),
  1513. ('NCC1701D', 'NCC1701D', 'NCC1701D')])
  1514. def test_td64arr_mul_int_series(self, box_df_fail, names):
  1515. # GH#19042 test for correct name attachment
  1516. box = box_df_fail # broadcasts along wrong axis, but doesn't raise
  1517. tdi = TimedeltaIndex(['0days', '1day', '2days', '3days', '4days'],
  1518. name=names[0])
  1519. # TODO: Should we be parametrizing over types for `ser` too?
  1520. ser = Series([0, 1, 2, 3, 4], dtype=np.int64, name=names[1])
  1521. expected = Series(['0days', '1day', '4days', '9days', '16days'],
  1522. dtype='timedelta64[ns]',
  1523. name=names[2])
  1524. tdi = tm.box_expected(tdi, box)
  1525. box = Series if (box is pd.Index and type(ser) is Series) else box
  1526. expected = tm.box_expected(expected, box)
  1527. result = ser * tdi
  1528. tm.assert_equal(result, expected)
  1529. # The direct operation tdi * ser still needs to be fixed.
  1530. result = ser.__rmul__(tdi)
  1531. tm.assert_equal(result, expected)
  1532. # TODO: Should we be parametrizing over types for `ser` too?
  1533. @pytest.mark.parametrize('names', [(None, None, None),
  1534. ('Egon', 'Venkman', None),
  1535. ('NCC1701D', 'NCC1701D', 'NCC1701D')])
  1536. def test_float_series_rdiv_td64arr(self, box_with_array, names):
  1537. # GH#19042 test for correct name attachment
  1538. # TODO: the direct operation TimedeltaIndex / Series still
  1539. # needs to be fixed.
  1540. box = box_with_array
  1541. tdi = TimedeltaIndex(['0days', '1day', '2days', '3days', '4days'],
  1542. name=names[0])
  1543. ser = Series([1.5, 3, 4.5, 6, 7.5], dtype=np.float64, name=names[1])
  1544. xname = names[2] if box is not tm.to_array else names[1]
  1545. expected = Series([tdi[n] / ser[n] for n in range(len(ser))],
  1546. dtype='timedelta64[ns]',
  1547. name=xname)
  1548. xbox = box
  1549. if box in [pd.Index, tm.to_array] and type(ser) is Series:
  1550. xbox = Series
  1551. tdi = tm.box_expected(tdi, box)
  1552. expected = tm.box_expected(expected, xbox)
  1553. result = ser.__rdiv__(tdi)
  1554. if box is pd.DataFrame:
  1555. # TODO: Should we skip this case sooner or test something else?
  1556. assert result is NotImplemented
  1557. else:
  1558. tm.assert_equal(result, expected)
  1559. class TestTimedeltaArraylikeInvalidArithmeticOps(object):
  1560. def test_td64arr_pow_invalid(self, scalar_td, box_with_array):
  1561. td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
  1562. td1.iloc[2] = np.nan
  1563. td1 = tm.box_expected(td1, box_with_array)
  1564. # check that we are getting a TypeError
  1565. # with 'operate' (from core/ops.py) for the ops that are not
  1566. # defined
  1567. pattern = 'operate|unsupported|cannot|not supported'
  1568. with pytest.raises(TypeError, match=pattern):
  1569. scalar_td ** td1
  1570. with pytest.raises(TypeError, match=pattern):
  1571. td1 ** scalar_td