123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334 |
- # -*- coding: utf-8 -*-
- # Arithmetic tests for DataFrame/Series/Index/Array classes that should
- # behave identically.
- # Specifically for datetime64 and datetime64tz dtypes
- from datetime import datetime, timedelta
- from itertools import product, starmap
- import operator
- import warnings
- import numpy as np
- import pytest
- import pytz
- from pandas._libs.tslibs.conversion import localize_pydatetime
- from pandas._libs.tslibs.offsets import shift_months
- from pandas.compat.numpy import np_datetime64_compat
- from pandas.errors import NullFrequencyError, PerformanceWarning
- import pandas as pd
- from pandas import (
- DatetimeIndex, NaT, Period, Series, Timedelta, TimedeltaIndex, Timestamp,
- date_range)
- from pandas.core.indexes.datetimes import _to_M8
- import pandas.util.testing as tm
- def assert_all(obj):
- """
- Test helper to call call obj.all() the appropriate number of times on
- a Series or DataFrame.
- """
- if isinstance(obj, pd.DataFrame):
- assert obj.all().all()
- else:
- assert obj.all()
- # ------------------------------------------------------------------
- # Comparisons
- class TestDatetime64DataFrameComparison(object):
- @pytest.mark.parametrize('timestamps', [
- [pd.Timestamp('2012-01-01 13:00:00+00:00')] * 2,
- [pd.Timestamp('2012-01-01 13:00:00')] * 2])
- def test_tz_aware_scalar_comparison(self, timestamps):
- # GH#15966
- df = pd.DataFrame({'test': timestamps})
- expected = pd.DataFrame({'test': [False, False]})
- tm.assert_frame_equal(df == -1, expected)
- def test_dt64_nat_comparison(self):
- # GH#22242, GH#22163 DataFrame considered NaT == ts incorrectly
- ts = pd.Timestamp.now()
- df = pd.DataFrame([ts, pd.NaT])
- expected = pd.DataFrame([True, False])
- result = df == ts
- tm.assert_frame_equal(result, expected)
- class TestDatetime64SeriesComparison(object):
- # TODO: moved from tests.series.test_operators; needs cleanup
- @pytest.mark.parametrize('pair', [
- ([pd.Timestamp('2011-01-01'), NaT, pd.Timestamp('2011-01-03')],
- [NaT, NaT, pd.Timestamp('2011-01-03')]),
- ([pd.Timedelta('1 days'), NaT, pd.Timedelta('3 days')],
- [NaT, NaT, pd.Timedelta('3 days')]),
- ([pd.Period('2011-01', freq='M'), NaT,
- pd.Period('2011-03', freq='M')],
- [NaT, NaT, pd.Period('2011-03', freq='M')]),
- ])
- @pytest.mark.parametrize('reverse', [True, False])
- @pytest.mark.parametrize('box', [Series, pd.Index])
- @pytest.mark.parametrize('dtype', [None, object])
- def test_nat_comparisons(self, dtype, box, reverse, pair):
- l, r = pair
- if reverse:
- # add lhs / rhs switched data
- l, r = r, l
- left = Series(l, dtype=dtype)
- right = box(r, dtype=dtype)
- # Series, Index
- expected = Series([False, False, True])
- tm.assert_series_equal(left == right, expected)
- expected = Series([True, True, False])
- tm.assert_series_equal(left != right, expected)
- expected = Series([False, False, False])
- tm.assert_series_equal(left < right, expected)
- expected = Series([False, False, False])
- tm.assert_series_equal(left > right, expected)
- expected = Series([False, False, True])
- tm.assert_series_equal(left >= right, expected)
- expected = Series([False, False, True])
- tm.assert_series_equal(left <= right, expected)
- def test_comparison_invalid(self, box_with_array):
- # GH#4968
- # invalid date/int comparisons
- xbox = box_with_array if box_with_array is not pd.Index else np.ndarray
- ser = Series(range(5))
- ser2 = Series(pd.date_range('20010101', periods=5))
- ser = tm.box_expected(ser, box_with_array)
- ser2 = tm.box_expected(ser2, box_with_array)
- for (x, y) in [(ser, ser2), (ser2, ser)]:
- result = x == y
- expected = tm.box_expected([False] * 5, xbox)
- tm.assert_equal(result, expected)
- result = x != y
- expected = tm.box_expected([True] * 5, xbox)
- tm.assert_equal(result, expected)
- with pytest.raises(TypeError):
- x >= y
- with pytest.raises(TypeError):
- x > y
- with pytest.raises(TypeError):
- x < y
- with pytest.raises(TypeError):
- x <= y
- @pytest.mark.parametrize('data', [
- [Timestamp('2011-01-01'), NaT, Timestamp('2011-01-03')],
- [Timedelta('1 days'), NaT, Timedelta('3 days')],
- [Period('2011-01', freq='M'), NaT, Period('2011-03', freq='M')]
- ])
- @pytest.mark.parametrize('dtype', [None, object])
- def test_nat_comparisons_scalar(self, dtype, data, box_with_array):
- if box_with_array is tm.to_array and dtype is object:
- # dont bother testing ndarray comparison methods as this fails
- # on older numpys (since they check object identity)
- return
- xbox = box_with_array if box_with_array is not pd.Index else np.ndarray
- left = Series(data, dtype=dtype)
- left = tm.box_expected(left, box_with_array)
- expected = [False, False, False]
- expected = tm.box_expected(expected, xbox)
- tm.assert_equal(left == NaT, expected)
- tm.assert_equal(NaT == left, expected)
- expected = [True, True, True]
- expected = tm.box_expected(expected, xbox)
- tm.assert_equal(left != NaT, expected)
- tm.assert_equal(NaT != left, expected)
- expected = [False, False, False]
- expected = tm.box_expected(expected, xbox)
- tm.assert_equal(left < NaT, expected)
- tm.assert_equal(NaT > left, expected)
- tm.assert_equal(left <= NaT, expected)
- tm.assert_equal(NaT >= left, expected)
- tm.assert_equal(left > NaT, expected)
- tm.assert_equal(NaT < left, expected)
- tm.assert_equal(left >= NaT, expected)
- tm.assert_equal(NaT <= left, expected)
- def test_series_comparison_scalars(self):
- series = Series(date_range('1/1/2000', periods=10))
- val = datetime(2000, 1, 4)
- result = series > val
- expected = Series([x > val for x in series])
- tm.assert_series_equal(result, expected)
- val = series[5]
- result = series > val
- expected = Series([x > val for x in series])
- tm.assert_series_equal(result, expected)
- def test_dt64_ser_cmp_date_warning(self):
- # https://github.com/pandas-dev/pandas/issues/21359
- # Remove this test and enble invalid test below
- ser = pd.Series(pd.date_range('20010101', periods=10), name='dates')
- date = ser.iloc[0].to_pydatetime().date()
- with tm.assert_produces_warning(FutureWarning) as m:
- result = ser == date
- expected = pd.Series([True] + [False] * 9, name='dates')
- tm.assert_series_equal(result, expected)
- assert "Comparing Series of datetimes " in str(m[0].message)
- assert "will not compare equal" in str(m[0].message)
- with tm.assert_produces_warning(FutureWarning) as m:
- result = ser != date
- tm.assert_series_equal(result, ~expected)
- assert "will not compare equal" in str(m[0].message)
- with tm.assert_produces_warning(FutureWarning) as m:
- result = ser <= date
- tm.assert_series_equal(result, expected)
- assert "a TypeError will be raised" in str(m[0].message)
- with tm.assert_produces_warning(FutureWarning) as m:
- result = ser < date
- tm.assert_series_equal(result, pd.Series([False] * 10, name='dates'))
- assert "a TypeError will be raised" in str(m[0].message)
- with tm.assert_produces_warning(FutureWarning) as m:
- result = ser >= date
- tm.assert_series_equal(result, pd.Series([True] * 10, name='dates'))
- assert "a TypeError will be raised" in str(m[0].message)
- with tm.assert_produces_warning(FutureWarning) as m:
- result = ser > date
- tm.assert_series_equal(result, pd.Series([False] + [True] * 9,
- name='dates'))
- assert "a TypeError will be raised" in str(m[0].message)
- @pytest.mark.skip(reason="GH#21359")
- def test_dt64ser_cmp_date_invalid(self, box_with_array):
- # GH#19800 datetime.date comparison raises to
- # match DatetimeIndex/Timestamp. This also matches the behavior
- # of stdlib datetime.datetime
- ser = pd.date_range('20010101', periods=10)
- date = ser.iloc[0].to_pydatetime().date()
- ser = tm.box_expected(ser, box_with_array)
- assert not (ser == date).any()
- assert (ser != date).all()
- with pytest.raises(TypeError):
- ser > date
- with pytest.raises(TypeError):
- ser < date
- with pytest.raises(TypeError):
- ser >= date
- with pytest.raises(TypeError):
- ser <= date
- @pytest.mark.parametrize("left,right", [
- ("lt", "gt"),
- ("le", "ge"),
- ("eq", "eq"),
- ("ne", "ne"),
- ])
- def test_timestamp_compare_series(self, left, right):
- # see gh-4982
- # Make sure we can compare Timestamps on the right AND left hand side.
- ser = pd.Series(pd.date_range("20010101", periods=10), name="dates")
- s_nat = ser.copy(deep=True)
- ser[0] = pd.Timestamp("nat")
- ser[3] = pd.Timestamp("nat")
- left_f = getattr(operator, left)
- right_f = getattr(operator, right)
- # No NaT
- expected = left_f(ser, pd.Timestamp("20010109"))
- result = right_f(pd.Timestamp("20010109"), ser)
- tm.assert_series_equal(result, expected)
- # NaT
- expected = left_f(ser, pd.Timestamp("nat"))
- result = right_f(pd.Timestamp("nat"), ser)
- tm.assert_series_equal(result, expected)
- # Compare to Timestamp with series containing NaT
- expected = left_f(s_nat, pd.Timestamp("20010109"))
- result = right_f(pd.Timestamp("20010109"), s_nat)
- tm.assert_series_equal(result, expected)
- # Compare to NaT with series containing NaT
- expected = left_f(s_nat, pd.Timestamp("nat"))
- result = right_f(pd.Timestamp("nat"), s_nat)
- tm.assert_series_equal(result, expected)
- def test_dt64arr_timestamp_equality(self, box_with_array):
- # GH#11034
- xbox = box_with_array if box_with_array is not pd.Index else np.ndarray
- ser = pd.Series([pd.Timestamp('2000-01-29 01:59:00'), 'NaT'])
- ser = tm.box_expected(ser, box_with_array)
- result = ser != ser
- expected = tm.box_expected([False, True], xbox)
- tm.assert_equal(result, expected)
- result = ser != ser[0]
- expected = tm.box_expected([False, True], xbox)
- tm.assert_equal(result, expected)
- result = ser != ser[1]
- expected = tm.box_expected([True, True], xbox)
- tm.assert_equal(result, expected)
- result = ser == ser
- expected = tm.box_expected([True, False], xbox)
- tm.assert_equal(result, expected)
- result = ser == ser[0]
- expected = tm.box_expected([True, False], xbox)
- tm.assert_equal(result, expected)
- result = ser == ser[1]
- expected = tm.box_expected([False, False], xbox)
- tm.assert_equal(result, expected)
- @pytest.mark.parametrize('op', [operator.eq, operator.ne,
- operator.gt, operator.ge,
- operator.lt, operator.le])
- def test_comparison_tzawareness_compat(self, op):
- # GH#18162
- dr = pd.date_range('2016-01-01', periods=6)
- dz = dr.tz_localize('US/Pacific')
- # Check that there isn't a problem aware-aware and naive-naive do not
- # raise
- naive_series = Series(dr)
- aware_series = Series(dz)
- with pytest.raises(TypeError):
- op(dz, naive_series)
- with pytest.raises(TypeError):
- op(dr, aware_series)
- # TODO: implement _assert_tzawareness_compat for the reverse
- # comparison with the Series on the left-hand side
- class TestDatetimeIndexComparisons(object):
- # TODO: moved from tests.indexes.test_base; parametrize and de-duplicate
- @pytest.mark.parametrize("op", [
- operator.eq, operator.ne, operator.gt, operator.lt,
- operator.ge, operator.le
- ])
- def test_comparators(self, op):
- index = tm.makeDateIndex(100)
- element = index[len(index) // 2]
- element = _to_M8(element)
- arr = np.array(index)
- arr_result = op(arr, element)
- index_result = op(index, element)
- assert isinstance(index_result, np.ndarray)
- tm.assert_numpy_array_equal(arr_result, index_result)
- @pytest.mark.parametrize('other', [datetime(2016, 1, 1),
- Timestamp('2016-01-01'),
- np.datetime64('2016-01-01')])
- def test_dti_cmp_datetimelike(self, other, tz_naive_fixture):
- tz = tz_naive_fixture
- dti = pd.date_range('2016-01-01', periods=2, tz=tz)
- if tz is not None:
- if isinstance(other, np.datetime64):
- # no tzaware version available
- return
- other = localize_pydatetime(other, dti.tzinfo)
- result = dti == other
- expected = np.array([True, False])
- tm.assert_numpy_array_equal(result, expected)
- result = dti > other
- expected = np.array([False, True])
- tm.assert_numpy_array_equal(result, expected)
- result = dti >= other
- expected = np.array([True, True])
- tm.assert_numpy_array_equal(result, expected)
- result = dti < other
- expected = np.array([False, False])
- tm.assert_numpy_array_equal(result, expected)
- result = dti <= other
- expected = np.array([True, False])
- tm.assert_numpy_array_equal(result, expected)
- def dt64arr_cmp_non_datetime(self, tz_naive_fixture, box_with_array):
- # GH#19301 by convention datetime.date is not considered comparable
- # to Timestamp or DatetimeIndex. This may change in the future.
- tz = tz_naive_fixture
- dti = pd.date_range('2016-01-01', periods=2, tz=tz)
- dtarr = tm.box_expected(dti, box_with_array)
- other = datetime(2016, 1, 1).date()
- assert not (dtarr == other).any()
- assert (dtarr != other).all()
- with pytest.raises(TypeError):
- dtarr < other
- with pytest.raises(TypeError):
- dtarr <= other
- with pytest.raises(TypeError):
- dtarr > other
- with pytest.raises(TypeError):
- dtarr >= other
- @pytest.mark.parametrize('other', [None, np.nan, pd.NaT])
- def test_dti_eq_null_scalar(self, other, tz_naive_fixture):
- # GH#19301
- tz = tz_naive_fixture
- dti = pd.date_range('2016-01-01', periods=2, tz=tz)
- assert not (dti == other).any()
- @pytest.mark.parametrize('other', [None, np.nan, pd.NaT])
- def test_dti_ne_null_scalar(self, other, tz_naive_fixture):
- # GH#19301
- tz = tz_naive_fixture
- dti = pd.date_range('2016-01-01', periods=2, tz=tz)
- assert (dti != other).all()
- @pytest.mark.parametrize('other', [None, np.nan])
- def test_dti_cmp_null_scalar_inequality(self, tz_naive_fixture, other,
- box_with_array):
- # GH#19301
- tz = tz_naive_fixture
- dti = pd.date_range('2016-01-01', periods=2, tz=tz)
- # FIXME: ValueError with transpose
- dtarr = tm.box_expected(dti, box_with_array, transpose=False)
- with pytest.raises(TypeError):
- dtarr < other
- with pytest.raises(TypeError):
- dtarr <= other
- with pytest.raises(TypeError):
- dtarr > other
- with pytest.raises(TypeError):
- dtarr >= other
- @pytest.mark.parametrize('dtype', [None, object])
- def test_dti_cmp_nat(self, dtype, box_with_array):
- if box_with_array is tm.to_array and dtype is object:
- # dont bother testing ndarray comparison methods as this fails
- # on older numpys (since they check object identity)
- return
- xbox = box_with_array if box_with_array is not pd.Index else np.ndarray
- left = pd.DatetimeIndex([pd.Timestamp('2011-01-01'), pd.NaT,
- pd.Timestamp('2011-01-03')])
- right = pd.DatetimeIndex([pd.NaT, pd.NaT, pd.Timestamp('2011-01-03')])
- left = tm.box_expected(left, box_with_array)
- right = tm.box_expected(right, box_with_array)
- lhs, rhs = left, right
- if dtype is object:
- lhs, rhs = left.astype(object), right.astype(object)
- result = rhs == lhs
- expected = np.array([False, False, True])
- expected = tm.box_expected(expected, xbox)
- tm.assert_equal(result, expected)
- result = lhs != rhs
- expected = np.array([True, True, False])
- expected = tm.box_expected(expected, xbox)
- tm.assert_equal(result, expected)
- expected = np.array([False, False, False])
- expected = tm.box_expected(expected, xbox)
- tm.assert_equal(lhs == pd.NaT, expected)
- tm.assert_equal(pd.NaT == rhs, expected)
- expected = np.array([True, True, True])
- expected = tm.box_expected(expected, xbox)
- tm.assert_equal(lhs != pd.NaT, expected)
- tm.assert_equal(pd.NaT != lhs, expected)
- expected = np.array([False, False, False])
- expected = tm.box_expected(expected, xbox)
- tm.assert_equal(lhs < pd.NaT, expected)
- tm.assert_equal(pd.NaT > lhs, expected)
- def test_dti_cmp_nat_behaves_like_float_cmp_nan(self):
- fidx1 = pd.Index([1.0, np.nan, 3.0, np.nan, 5.0, 7.0])
- fidx2 = pd.Index([2.0, 3.0, np.nan, np.nan, 6.0, 7.0])
- didx1 = pd.DatetimeIndex(['2014-01-01', pd.NaT, '2014-03-01', pd.NaT,
- '2014-05-01', '2014-07-01'])
- didx2 = pd.DatetimeIndex(['2014-02-01', '2014-03-01', pd.NaT, pd.NaT,
- '2014-06-01', '2014-07-01'])
- darr = np.array([np_datetime64_compat('2014-02-01 00:00Z'),
- np_datetime64_compat('2014-03-01 00:00Z'),
- np_datetime64_compat('nat'), np.datetime64('nat'),
- np_datetime64_compat('2014-06-01 00:00Z'),
- np_datetime64_compat('2014-07-01 00:00Z')])
- cases = [(fidx1, fidx2), (didx1, didx2), (didx1, darr)]
- # Check pd.NaT is handles as the same as np.nan
- with tm.assert_produces_warning(None):
- for idx1, idx2 in cases:
- result = idx1 < idx2
- expected = np.array([True, False, False, False, True, False])
- tm.assert_numpy_array_equal(result, expected)
- result = idx2 > idx1
- expected = np.array([True, False, False, False, True, False])
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 <= idx2
- expected = np.array([True, False, False, False, True, True])
- tm.assert_numpy_array_equal(result, expected)
- result = idx2 >= idx1
- expected = np.array([True, False, False, False, True, True])
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 == idx2
- expected = np.array([False, False, False, False, False, True])
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 != idx2
- expected = np.array([True, True, True, True, True, False])
- tm.assert_numpy_array_equal(result, expected)
- with tm.assert_produces_warning(None):
- for idx1, val in [(fidx1, np.nan), (didx1, pd.NaT)]:
- result = idx1 < val
- expected = np.array([False, False, False, False, False, False])
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 > val
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 <= val
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 >= val
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 == val
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 != val
- expected = np.array([True, True, True, True, True, True])
- tm.assert_numpy_array_equal(result, expected)
- # Check pd.NaT is handles as the same as np.nan
- with tm.assert_produces_warning(None):
- for idx1, val in [(fidx1, 3), (didx1, datetime(2014, 3, 1))]:
- result = idx1 < val
- expected = np.array([True, False, False, False, False, False])
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 > val
- expected = np.array([False, False, False, False, True, True])
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 <= val
- expected = np.array([True, False, True, False, False, False])
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 >= val
- expected = np.array([False, False, True, False, True, True])
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 == val
- expected = np.array([False, False, True, False, False, False])
- tm.assert_numpy_array_equal(result, expected)
- result = idx1 != val
- expected = np.array([True, True, False, True, True, True])
- tm.assert_numpy_array_equal(result, expected)
- @pytest.mark.parametrize('op', [operator.eq, operator.ne,
- operator.gt, operator.ge,
- operator.lt, operator.le])
- def test_comparison_tzawareness_compat(self, op, box_with_array):
- # GH#18162
- dr = pd.date_range('2016-01-01', periods=6)
- dz = dr.tz_localize('US/Pacific')
- # FIXME: ValueError with transpose
- dr = tm.box_expected(dr, box_with_array, transpose=False)
- dz = tm.box_expected(dz, box_with_array, transpose=False)
- with pytest.raises(TypeError):
- op(dr, dz)
- if box_with_array is not pd.DataFrame:
- # DataFrame op is invalid until transpose bug is fixed
- with pytest.raises(TypeError):
- op(dr, list(dz))
- with pytest.raises(TypeError):
- op(dr, np.array(list(dz), dtype=object))
- with pytest.raises(TypeError):
- op(dz, dr)
- if box_with_array is not pd.DataFrame:
- # DataFrame op is invalid until transpose bug is fixed
- with pytest.raises(TypeError):
- op(dz, list(dr))
- with pytest.raises(TypeError):
- op(dz, np.array(list(dr), dtype=object))
- # Check that there isn't a problem aware-aware and naive-naive do not
- # raise
- assert_all(dr == dr)
- assert_all(dz == dz)
- if box_with_array is not pd.DataFrame:
- # DataFrame doesn't align the lists correctly unless we transpose,
- # which we cannot do at the moment
- assert (dr == list(dr)).all()
- assert (dz == list(dz)).all()
- # Check comparisons against scalar Timestamps
- ts = pd.Timestamp('2000-03-14 01:59')
- ts_tz = pd.Timestamp('2000-03-14 01:59', tz='Europe/Amsterdam')
- assert_all(dr > ts)
- with pytest.raises(TypeError):
- op(dr, ts_tz)
- assert_all(dz > ts_tz)
- with pytest.raises(TypeError):
- op(dz, ts)
- # GH#12601: Check comparison against Timestamps and DatetimeIndex
- with pytest.raises(TypeError):
- op(ts, dz)
- @pytest.mark.parametrize('op', [operator.eq, operator.ne,
- operator.gt, operator.ge,
- operator.lt, operator.le])
- @pytest.mark.parametrize('other', [datetime(2016, 1, 1),
- Timestamp('2016-01-01'),
- np.datetime64('2016-01-01')])
- def test_scalar_comparison_tzawareness(self, op, other, tz_aware_fixture,
- box_with_array):
- tz = tz_aware_fixture
- dti = pd.date_range('2016-01-01', periods=2, tz=tz)
- # FIXME: ValueError with transpose
- dtarr = tm.box_expected(dti, box_with_array, transpose=False)
- with pytest.raises(TypeError):
- op(dtarr, other)
- with pytest.raises(TypeError):
- op(other, dtarr)
- @pytest.mark.parametrize('op', [operator.eq, operator.ne,
- operator.gt, operator.ge,
- operator.lt, operator.le])
- def test_nat_comparison_tzawareness(self, op):
- # GH#19276
- # tzaware DatetimeIndex should not raise when compared to NaT
- dti = pd.DatetimeIndex(['2014-01-01', pd.NaT, '2014-03-01', pd.NaT,
- '2014-05-01', '2014-07-01'])
- expected = np.array([op == operator.ne] * len(dti))
- result = op(dti, pd.NaT)
- tm.assert_numpy_array_equal(result, expected)
- result = op(dti.tz_localize('US/Pacific'), pd.NaT)
- tm.assert_numpy_array_equal(result, expected)
- def test_dti_cmp_str(self, tz_naive_fixture):
- # GH#22074
- # regardless of tz, we expect these comparisons are valid
- tz = tz_naive_fixture
- rng = date_range('1/1/2000', periods=10, tz=tz)
- other = '1/1/2000'
- result = rng == other
- expected = np.array([True] + [False] * 9)
- tm.assert_numpy_array_equal(result, expected)
- result = rng != other
- expected = np.array([False] + [True] * 9)
- tm.assert_numpy_array_equal(result, expected)
- result = rng < other
- expected = np.array([False] * 10)
- tm.assert_numpy_array_equal(result, expected)
- result = rng <= other
- expected = np.array([True] + [False] * 9)
- tm.assert_numpy_array_equal(result, expected)
- result = rng > other
- expected = np.array([False] + [True] * 9)
- tm.assert_numpy_array_equal(result, expected)
- result = rng >= other
- expected = np.array([True] * 10)
- tm.assert_numpy_array_equal(result, expected)
- @pytest.mark.parametrize('other', ['foo', 99, 4.0,
- object(), timedelta(days=2)])
- def test_dt64arr_cmp_scalar_invalid(self, other, tz_naive_fixture,
- box_with_array):
- # GH#22074
- tz = tz_naive_fixture
- xbox = box_with_array if box_with_array is not pd.Index else np.ndarray
- rng = date_range('1/1/2000', periods=10, tz=tz)
- # FIXME: ValueError with transpose
- rng = tm.box_expected(rng, box_with_array, transpose=False)
- result = rng == other
- expected = np.array([False] * 10)
- expected = tm.box_expected(expected, xbox, transpose=False)
- tm.assert_equal(result, expected)
- result = rng != other
- expected = np.array([True] * 10)
- expected = tm.box_expected(expected, xbox, transpose=False)
- tm.assert_equal(result, expected)
- with pytest.raises(TypeError):
- rng < other
- with pytest.raises(TypeError):
- rng <= other
- with pytest.raises(TypeError):
- rng > other
- with pytest.raises(TypeError):
- rng >= other
- def test_dti_cmp_list(self):
- rng = date_range('1/1/2000', periods=10)
- result = rng == list(rng)
- expected = rng == rng
- tm.assert_numpy_array_equal(result, expected)
- @pytest.mark.parametrize('other', [
- pd.timedelta_range('1D', periods=10),
- pd.timedelta_range('1D', periods=10).to_series(),
- pd.timedelta_range('1D', periods=10).asi8.view('m8[ns]')
- ], ids=lambda x: type(x).__name__)
- def test_dti_cmp_tdi_tzawareness(self, other):
- # GH#22074
- # reversion test that we _don't_ call _assert_tzawareness_compat
- # when comparing against TimedeltaIndex
- dti = date_range('2000-01-01', periods=10, tz='Asia/Tokyo')
- result = dti == other
- expected = np.array([False] * 10)
- tm.assert_numpy_array_equal(result, expected)
- result = dti != other
- expected = np.array([True] * 10)
- tm.assert_numpy_array_equal(result, expected)
- with pytest.raises(TypeError):
- dti < other
- with pytest.raises(TypeError):
- dti <= other
- with pytest.raises(TypeError):
- dti > other
- with pytest.raises(TypeError):
- dti >= other
- def test_dti_cmp_object_dtype(self):
- # GH#22074
- dti = date_range('2000-01-01', periods=10, tz='Asia/Tokyo')
- other = dti.astype('O')
- result = dti == other
- expected = np.array([True] * 10)
- tm.assert_numpy_array_equal(result, expected)
- other = dti.tz_localize(None)
- with pytest.raises(TypeError):
- # tzawareness failure
- dti != other
- other = np.array(list(dti[:5]) + [Timedelta(days=1)] * 5)
- result = dti == other
- expected = np.array([True] * 5 + [False] * 5)
- tm.assert_numpy_array_equal(result, expected)
- with pytest.raises(TypeError):
- dti >= other
- # ------------------------------------------------------------------
- # Arithmetic
- class TestDatetime64Arithmetic(object):
- # This class is intended for "finished" tests that are fully parametrized
- # over DataFrame/Series/Index/DatetimeArray
- # -------------------------------------------------------------
- # Addition/Subtraction of timedelta-like
- def test_dt64arr_add_timedeltalike_scalar(self, tz_naive_fixture,
- two_hours, box_with_array):
- # GH#22005, GH#22163 check DataFrame doesn't raise TypeError
- tz = tz_naive_fixture
- rng = pd.date_range('2000-01-01', '2000-02-01', tz=tz)
- expected = pd.date_range('2000-01-01 02:00',
- '2000-02-01 02:00', tz=tz)
- # FIXME: calling with transpose=True raises ValueError
- rng = tm.box_expected(rng, box_with_array, transpose=False)
- expected = tm.box_expected(expected, box_with_array, transpose=False)
- result = rng + two_hours
- tm.assert_equal(result, expected)
- def test_dt64arr_iadd_timedeltalike_scalar(self, tz_naive_fixture,
- two_hours, box_with_array):
- tz = tz_naive_fixture
- rng = pd.date_range('2000-01-01', '2000-02-01', tz=tz)
- expected = pd.date_range('2000-01-01 02:00',
- '2000-02-01 02:00', tz=tz)
- # FIXME: calling with transpose=True raises ValueError
- rng = tm.box_expected(rng, box_with_array, transpose=False)
- expected = tm.box_expected(expected, box_with_array, transpose=False)
- rng += two_hours
- tm.assert_equal(rng, expected)
- def test_dt64arr_sub_timedeltalike_scalar(self, tz_naive_fixture,
- two_hours, box_with_array):
- tz = tz_naive_fixture
- rng = pd.date_range('2000-01-01', '2000-02-01', tz=tz)
- expected = pd.date_range('1999-12-31 22:00',
- '2000-01-31 22:00', tz=tz)
- # FIXME: calling with transpose=True raises ValueError
- rng = tm.box_expected(rng, box_with_array, transpose=False)
- expected = tm.box_expected(expected, box_with_array, transpose=False)
- result = rng - two_hours
- tm.assert_equal(result, expected)
- def test_dt64arr_isub_timedeltalike_scalar(self, tz_naive_fixture,
- two_hours, box_with_array):
- tz = tz_naive_fixture
- rng = pd.date_range('2000-01-01', '2000-02-01', tz=tz)
- expected = pd.date_range('1999-12-31 22:00',
- '2000-01-31 22:00', tz=tz)
- # FIXME: calling with transpose=True raises ValueError
- rng = tm.box_expected(rng, box_with_array, transpose=False)
- expected = tm.box_expected(expected, box_with_array, transpose=False)
- rng -= two_hours
- tm.assert_equal(rng, expected)
- def test_dt64arr_add_td64_scalar(self, box_with_array):
- # scalar timedeltas/np.timedelta64 objects
- # operate with np.timedelta64 correctly
- ser = Series([Timestamp('20130101 9:01'), Timestamp('20130101 9:02')])
- expected = Series([Timestamp('20130101 9:01:01'),
- Timestamp('20130101 9:02:01')])
- dtarr = tm.box_expected(ser, box_with_array)
- expected = tm.box_expected(expected, box_with_array)
- result = dtarr + np.timedelta64(1, 's')
- tm.assert_equal(result, expected)
- result = np.timedelta64(1, 's') + dtarr
- tm.assert_equal(result, expected)
- expected = Series([Timestamp('20130101 9:01:00.005'),
- Timestamp('20130101 9:02:00.005')])
- expected = tm.box_expected(expected, box_with_array)
- result = dtarr + np.timedelta64(5, 'ms')
- tm.assert_equal(result, expected)
- result = np.timedelta64(5, 'ms') + dtarr
- tm.assert_equal(result, expected)
- def test_dt64arr_add_sub_td64_nat(self, box_with_array, tz_naive_fixture):
- # GH#23320 special handling for timedelta64("NaT")
- tz = tz_naive_fixture
- dti = pd.date_range("1994-04-01", periods=9, tz=tz, freq="QS")
- other = np.timedelta64("NaT")
- expected = pd.DatetimeIndex(["NaT"] * 9, tz=tz)
- # FIXME: fails with transpose=True due to tz-aware DataFrame
- # transpose bug
- obj = tm.box_expected(dti, box_with_array, transpose=False)
- expected = tm.box_expected(expected, box_with_array, transpose=False)
- result = obj + other
- tm.assert_equal(result, expected)
- result = other + obj
- tm.assert_equal(result, expected)
- result = obj - other
- tm.assert_equal(result, expected)
- with pytest.raises(TypeError):
- other - obj
- def test_dt64arr_add_sub_td64ndarray(self, tz_naive_fixture,
- box_with_array):
- if box_with_array is pd.DataFrame:
- pytest.xfail("FIXME: ValueError with transpose; "
- "alignment error without")
- tz = tz_naive_fixture
- dti = pd.date_range('2016-01-01', periods=3, tz=tz)
- tdi = pd.TimedeltaIndex(['-1 Day', '-1 Day', '-1 Day'])
- tdarr = tdi.values
- expected = pd.date_range('2015-12-31', periods=3, tz=tz)
- dtarr = tm.box_expected(dti, box_with_array)
- expected = tm.box_expected(expected, box_with_array)
- result = dtarr + tdarr
- tm.assert_equal(result, expected)
- result = tdarr + dtarr
- tm.assert_equal(result, expected)
- expected = pd.date_range('2016-01-02', periods=3, tz=tz)
- expected = tm.box_expected(expected, box_with_array)
- result = dtarr - tdarr
- tm.assert_equal(result, expected)
- with pytest.raises(TypeError):
- tdarr - dtarr
- # -----------------------------------------------------------------
- # Subtraction of datetime-like scalars
- @pytest.mark.parametrize('ts', [
- pd.Timestamp('2013-01-01'),
- pd.Timestamp('2013-01-01').to_pydatetime(),
- pd.Timestamp('2013-01-01').to_datetime64()])
- def test_dt64arr_sub_dtscalar(self, box_with_array, ts):
- # GH#8554, GH#22163 DataFrame op should _not_ return dt64 dtype
- idx = pd.date_range('2013-01-01', periods=3)
- idx = tm.box_expected(idx, box_with_array)
- expected = pd.TimedeltaIndex(['0 Days', '1 Day', '2 Days'])
- expected = tm.box_expected(expected, box_with_array)
- result = idx - ts
- tm.assert_equal(result, expected)
- def test_dt64arr_sub_datetime64_not_ns(self, box_with_array):
- # GH#7996, GH#22163 ensure non-nano datetime64 is converted to nano
- # for DataFrame operation
- dt64 = np.datetime64('2013-01-01')
- assert dt64.dtype == 'datetime64[D]'
- dti = pd.date_range('20130101', periods=3)
- dtarr = tm.box_expected(dti, box_with_array)
- expected = pd.TimedeltaIndex(['0 Days', '1 Day', '2 Days'])
- expected = tm.box_expected(expected, box_with_array)
- result = dtarr - dt64
- tm.assert_equal(result, expected)
- result = dt64 - dtarr
- tm.assert_equal(result, -expected)
- def test_dt64arr_sub_timestamp(self, box_with_array):
- ser = pd.date_range('2014-03-17', periods=2, freq='D',
- tz='US/Eastern')
- ts = ser[0]
- # FIXME: transpose raises ValueError
- ser = tm.box_expected(ser, box_with_array, transpose=False)
- delta_series = pd.Series([np.timedelta64(0, 'D'),
- np.timedelta64(1, 'D')])
- expected = tm.box_expected(delta_series, box_with_array,
- transpose=False)
- tm.assert_equal(ser - ts, expected)
- tm.assert_equal(ts - ser, -expected)
- def test_dt64arr_sub_NaT(self, box_with_array):
- # GH#18808
- dti = pd.DatetimeIndex([pd.NaT, pd.Timestamp('19900315')])
- ser = tm.box_expected(dti, box_with_array, transpose=False)
- result = ser - pd.NaT
- expected = pd.Series([pd.NaT, pd.NaT], dtype='timedelta64[ns]')
- # FIXME: raises ValueError with transpose
- expected = tm.box_expected(expected, box_with_array, transpose=False)
- tm.assert_equal(result, expected)
- dti_tz = dti.tz_localize('Asia/Tokyo')
- ser_tz = tm.box_expected(dti_tz, box_with_array, transpose=False)
- result = ser_tz - pd.NaT
- expected = pd.Series([pd.NaT, pd.NaT], dtype='timedelta64[ns]')
- expected = tm.box_expected(expected, box_with_array, transpose=False)
- tm.assert_equal(result, expected)
- # -------------------------------------------------------------
- # Subtraction of datetime-like array-like
- def test_dt64arr_naive_sub_dt64ndarray(self, box_with_array):
- dti = pd.date_range('2016-01-01', periods=3, tz=None)
- dt64vals = dti.values
- dtarr = tm.box_expected(dti, box_with_array)
- expected = dtarr - dtarr
- result = dtarr - dt64vals
- tm.assert_equal(result, expected)
- result = dt64vals - dtarr
- tm.assert_equal(result, expected)
- def test_dt64arr_aware_sub_dt64ndarray_raises(self, tz_aware_fixture,
- box_with_array):
- if box_with_array is pd.DataFrame:
- pytest.xfail("FIXME: ValueError with transpose; "
- "alignment error without")
- tz = tz_aware_fixture
- dti = pd.date_range('2016-01-01', periods=3, tz=tz)
- dt64vals = dti.values
- dtarr = tm.box_expected(dti, box_with_array)
- with pytest.raises(TypeError):
- dtarr - dt64vals
- with pytest.raises(TypeError):
- dt64vals - dtarr
- # -------------------------------------------------------------
- # Addition of datetime-like others (invalid)
- def test_dt64arr_add_dt64ndarray_raises(self, tz_naive_fixture,
- box_with_array):
- if box_with_array is pd.DataFrame:
- pytest.xfail("FIXME: ValueError with transpose; "
- "alignment error without")
- tz = tz_naive_fixture
- dti = pd.date_range('2016-01-01', periods=3, tz=tz)
- dt64vals = dti.values
- dtarr = tm.box_expected(dti, box_with_array)
- with pytest.raises(TypeError):
- dtarr + dt64vals
- with pytest.raises(TypeError):
- dt64vals + dtarr
- def test_dt64arr_add_timestamp_raises(self, box_with_array):
- # GH#22163 ensure DataFrame doesn't cast Timestamp to i8
- idx = DatetimeIndex(['2011-01-01', '2011-01-02'])
- idx = tm.box_expected(idx, box_with_array)
- msg = "cannot add"
- with pytest.raises(TypeError, match=msg):
- idx + Timestamp('2011-01-01')
- with pytest.raises(TypeError, match=msg):
- Timestamp('2011-01-01') + idx
- # -------------------------------------------------------------
- # Other Invalid Addition/Subtraction
- @pytest.mark.parametrize('other', [3.14, np.array([2.0, 3.0])])
- def test_dt64arr_add_sub_float(self, other, box_with_array):
- dti = DatetimeIndex(['2011-01-01', '2011-01-02'], freq='D')
- dtarr = tm.box_expected(dti, box_with_array)
- with pytest.raises(TypeError):
- dtarr + other
- with pytest.raises(TypeError):
- other + dtarr
- with pytest.raises(TypeError):
- dtarr - other
- with pytest.raises(TypeError):
- other - dtarr
- @pytest.mark.parametrize('pi_freq', ['D', 'W', 'Q', 'H'])
- @pytest.mark.parametrize('dti_freq', [None, 'D'])
- def test_dt64arr_add_sub_parr(self, dti_freq, pi_freq,
- box_with_array, box_with_array2):
- # GH#20049 subtracting PeriodIndex should raise TypeError
- dti = pd.DatetimeIndex(['2011-01-01', '2011-01-02'], freq=dti_freq)
- pi = dti.to_period(pi_freq)
- dtarr = tm.box_expected(dti, box_with_array)
- parr = tm.box_expected(pi, box_with_array2)
- with pytest.raises(TypeError):
- dtarr + parr
- with pytest.raises(TypeError):
- parr + dtarr
- with pytest.raises(TypeError):
- dtarr - parr
- with pytest.raises(TypeError):
- parr - dtarr
- @pytest.mark.parametrize('dti_freq', [None, 'D'])
- def test_dt64arr_add_sub_period_scalar(self, dti_freq, box_with_array):
- # GH#13078
- # not supported, check TypeError
- per = pd.Period('2011-01-01', freq='D')
- idx = pd.DatetimeIndex(['2011-01-01', '2011-01-02'], freq=dti_freq)
- dtarr = tm.box_expected(idx, box_with_array)
- with pytest.raises(TypeError):
- dtarr + per
- with pytest.raises(TypeError):
- per + dtarr
- with pytest.raises(TypeError):
- dtarr - per
- with pytest.raises(TypeError):
- per - dtarr
- class TestDatetime64DateOffsetArithmetic(object):
- # -------------------------------------------------------------
- # Tick DateOffsets
- # TODO: parametrize over timezone?
- def test_dt64arr_series_add_tick_DateOffset(self, box_with_array):
- # GH#4532
- # operate with pd.offsets
- ser = Series([Timestamp('20130101 9:01'), Timestamp('20130101 9:02')])
- expected = Series([Timestamp('20130101 9:01:05'),
- Timestamp('20130101 9:02:05')])
- ser = tm.box_expected(ser, box_with_array)
- expected = tm.box_expected(expected, box_with_array)
- result = ser + pd.offsets.Second(5)
- tm.assert_equal(result, expected)
- result2 = pd.offsets.Second(5) + ser
- tm.assert_equal(result2, expected)
- def test_dt64arr_series_sub_tick_DateOffset(self, box_with_array):
- # GH#4532
- # operate with pd.offsets
- ser = Series([Timestamp('20130101 9:01'), Timestamp('20130101 9:02')])
- expected = Series([Timestamp('20130101 9:00:55'),
- Timestamp('20130101 9:01:55')])
- ser = tm.box_expected(ser, box_with_array)
- expected = tm.box_expected(expected, box_with_array)
- result = ser - pd.offsets.Second(5)
- tm.assert_equal(result, expected)
- result2 = -pd.offsets.Second(5) + ser
- tm.assert_equal(result2, expected)
- with pytest.raises(TypeError):
- pd.offsets.Second(5) - ser
- @pytest.mark.parametrize('cls_name', ['Day', 'Hour', 'Minute', 'Second',
- 'Milli', 'Micro', 'Nano'])
- def test_dt64arr_add_sub_tick_DateOffset_smoke(self, cls_name,
- box_with_array):
- # GH#4532
- # smoke tests for valid DateOffsets
- ser = Series([Timestamp('20130101 9:01'), Timestamp('20130101 9:02')])
- ser = tm.box_expected(ser, box_with_array)
- offset_cls = getattr(pd.offsets, cls_name)
- ser + offset_cls(5)
- offset_cls(5) + ser
- ser - offset_cls(5)
- def test_dti_add_tick_tzaware(self, tz_aware_fixture, box_with_array):
- # GH#21610, GH#22163 ensure DataFrame doesn't return object-dtype
- tz = tz_aware_fixture
- if tz == 'US/Pacific':
- dates = date_range('2012-11-01', periods=3, tz=tz)
- offset = dates + pd.offsets.Hour(5)
- assert dates[0] + pd.offsets.Hour(5) == offset[0]
- dates = date_range('2010-11-01 00:00',
- periods=3, tz=tz, freq='H')
- expected = DatetimeIndex(['2010-11-01 05:00', '2010-11-01 06:00',
- '2010-11-01 07:00'], freq='H', tz=tz)
- # FIXME: these raise ValueError with transpose=True
- dates = tm.box_expected(dates, box_with_array, transpose=False)
- expected = tm.box_expected(expected, box_with_array, transpose=False)
- # TODO: parametrize over the scalar being added? radd? sub?
- offset = dates + pd.offsets.Hour(5)
- tm.assert_equal(offset, expected)
- offset = dates + np.timedelta64(5, 'h')
- tm.assert_equal(offset, expected)
- offset = dates + timedelta(hours=5)
- tm.assert_equal(offset, expected)
- # -------------------------------------------------------------
- # RelativeDelta DateOffsets
- def test_dt64arr_add_sub_relativedelta_offsets(self, box_with_array):
- # GH#10699
- vec = DatetimeIndex([Timestamp('2000-01-05 00:15:00'),
- Timestamp('2000-01-31 00:23:00'),
- Timestamp('2000-01-01'),
- Timestamp('2000-03-31'),
- Timestamp('2000-02-29'),
- Timestamp('2000-12-31'),
- Timestamp('2000-05-15'),
- Timestamp('2001-06-15')])
- vec = tm.box_expected(vec, box_with_array)
- vec_items = vec.squeeze() if box_with_array is pd.DataFrame else vec
- # DateOffset relativedelta fastpath
- relative_kwargs = [('years', 2), ('months', 5), ('days', 3),
- ('hours', 5), ('minutes', 10), ('seconds', 2),
- ('microseconds', 5)]
- for i, kwd in enumerate(relative_kwargs):
- off = pd.DateOffset(**dict([kwd]))
- expected = DatetimeIndex([x + off for x in vec_items])
- expected = tm.box_expected(expected, box_with_array)
- tm.assert_equal(expected, vec + off)
- expected = DatetimeIndex([x - off for x in vec_items])
- expected = tm.box_expected(expected, box_with_array)
- tm.assert_equal(expected, vec - off)
- off = pd.DateOffset(**dict(relative_kwargs[:i + 1]))
- expected = DatetimeIndex([x + off for x in vec_items])
- expected = tm.box_expected(expected, box_with_array)
- tm.assert_equal(expected, vec + off)
- expected = DatetimeIndex([x - off for x in vec_items])
- expected = tm.box_expected(expected, box_with_array)
- tm.assert_equal(expected, vec - off)
- with pytest.raises(TypeError):
- off - vec
- # -------------------------------------------------------------
- # Non-Tick, Non-RelativeDelta DateOffsets
- # TODO: redundant with test_dt64arr_add_sub_DateOffset? that includes
- # tz-aware cases which this does not
- @pytest.mark.parametrize('cls_and_kwargs', [
- 'YearBegin', ('YearBegin', {'month': 5}),
- 'YearEnd', ('YearEnd', {'month': 5}),
- 'MonthBegin', 'MonthEnd',
- 'SemiMonthEnd', 'SemiMonthBegin',
- 'Week', ('Week', {'weekday': 3}),
- 'Week', ('Week', {'weekday': 6}),
- 'BusinessDay', 'BDay', 'QuarterEnd', 'QuarterBegin',
- 'CustomBusinessDay', 'CDay', 'CBMonthEnd',
- 'CBMonthBegin', 'BMonthBegin', 'BMonthEnd',
- 'BusinessHour', 'BYearBegin', 'BYearEnd',
- 'BQuarterBegin', ('LastWeekOfMonth', {'weekday': 2}),
- ('FY5253Quarter', {'qtr_with_extra_week': 1,
- 'startingMonth': 1,
- 'weekday': 2,
- 'variation': 'nearest'}),
- ('FY5253', {'weekday': 0, 'startingMonth': 2, 'variation': 'nearest'}),
- ('WeekOfMonth', {'weekday': 2, 'week': 2}),
- 'Easter', ('DateOffset', {'day': 4}),
- ('DateOffset', {'month': 5})])
- @pytest.mark.parametrize('normalize', [True, False])
- @pytest.mark.parametrize('n', [0, 5])
- def test_dt64arr_add_sub_DateOffsets(self, box_with_array,
- n, normalize, cls_and_kwargs):
- # GH#10699
- # assert vectorized operation matches pointwise operations
- if isinstance(cls_and_kwargs, tuple):
- # If cls_name param is a tuple, then 2nd entry is kwargs for
- # the offset constructor
- cls_name, kwargs = cls_and_kwargs
- else:
- cls_name = cls_and_kwargs
- kwargs = {}
- if n == 0 and cls_name in ['WeekOfMonth', 'LastWeekOfMonth',
- 'FY5253Quarter', 'FY5253']:
- # passing n = 0 is invalid for these offset classes
- return
- vec = DatetimeIndex([Timestamp('2000-01-05 00:15:00'),
- Timestamp('2000-01-31 00:23:00'),
- Timestamp('2000-01-01'),
- Timestamp('2000-03-31'),
- Timestamp('2000-02-29'),
- Timestamp('2000-12-31'),
- Timestamp('2000-05-15'),
- Timestamp('2001-06-15')])
- vec = tm.box_expected(vec, box_with_array)
- vec_items = vec.squeeze() if box_with_array is pd.DataFrame else vec
- offset_cls = getattr(pd.offsets, cls_name)
- with warnings.catch_warnings(record=True):
- # pandas.errors.PerformanceWarning: Non-vectorized DateOffset being
- # applied to Series or DatetimeIndex
- # we aren't testing that here, so ignore.
- warnings.simplefilter("ignore", PerformanceWarning)
- offset = offset_cls(n, normalize=normalize, **kwargs)
- expected = DatetimeIndex([x + offset for x in vec_items])
- expected = tm.box_expected(expected, box_with_array)
- tm.assert_equal(expected, vec + offset)
- expected = DatetimeIndex([x - offset for x in vec_items])
- expected = tm.box_expected(expected, box_with_array)
- tm.assert_equal(expected, vec - offset)
- expected = DatetimeIndex([offset + x for x in vec_items])
- expected = tm.box_expected(expected, box_with_array)
- tm.assert_equal(expected, offset + vec)
- with pytest.raises(TypeError):
- offset - vec
- def test_dt64arr_add_sub_DateOffset(self, box_with_array):
- # GH#10699
- s = date_range('2000-01-01', '2000-01-31', name='a')
- s = tm.box_expected(s, box_with_array)
- result = s + pd.DateOffset(years=1)
- result2 = pd.DateOffset(years=1) + s
- exp = date_range('2001-01-01', '2001-01-31', name='a')
- exp = tm.box_expected(exp, box_with_array)
- tm.assert_equal(result, exp)
- tm.assert_equal(result2, exp)
- result = s - pd.DateOffset(years=1)
- exp = date_range('1999-01-01', '1999-01-31', name='a')
- exp = tm.box_expected(exp, box_with_array)
- tm.assert_equal(result, exp)
- s = DatetimeIndex([Timestamp('2000-01-15 00:15:00', tz='US/Central'),
- Timestamp('2000-02-15', tz='US/Central')], name='a')
- # FIXME: ValueError with tzaware DataFrame transpose
- s = tm.box_expected(s, box_with_array, transpose=False)
- result = s + pd.offsets.Day()
- result2 = pd.offsets.Day() + s
- exp = DatetimeIndex([Timestamp('2000-01-16 00:15:00', tz='US/Central'),
- Timestamp('2000-02-16', tz='US/Central')],
- name='a')
- exp = tm.box_expected(exp, box_with_array, transpose=False)
- tm.assert_equal(result, exp)
- tm.assert_equal(result2, exp)
- s = DatetimeIndex([Timestamp('2000-01-15 00:15:00', tz='US/Central'),
- Timestamp('2000-02-15', tz='US/Central')], name='a')
- s = tm.box_expected(s, box_with_array, transpose=False)
- result = s + pd.offsets.MonthEnd()
- result2 = pd.offsets.MonthEnd() + s
- exp = DatetimeIndex([Timestamp('2000-01-31 00:15:00', tz='US/Central'),
- Timestamp('2000-02-29', tz='US/Central')],
- name='a')
- exp = tm.box_expected(exp, box_with_array, transpose=False)
- tm.assert_equal(result, exp)
- tm.assert_equal(result2, exp)
- # TODO: __sub__, __rsub__
- def test_dt64arr_add_mixed_offset_array(self, box_with_array):
- # GH#10699
- # array of offsets
- s = DatetimeIndex([Timestamp('2000-1-1'), Timestamp('2000-2-1')])
- s = tm.box_expected(s, box_with_array)
- warn = None if box_with_array is pd.DataFrame else PerformanceWarning
- with tm.assert_produces_warning(warn,
- clear=[pd.core.arrays.datetimelike]):
- other = pd.Index([pd.offsets.DateOffset(years=1),
- pd.offsets.MonthEnd()])
- other = tm.box_expected(other, box_with_array)
- result = s + other
- exp = DatetimeIndex([Timestamp('2001-1-1'),
- Timestamp('2000-2-29')])
- exp = tm.box_expected(exp, box_with_array)
- tm.assert_equal(result, exp)
- # same offset
- other = pd.Index([pd.offsets.DateOffset(years=1),
- pd.offsets.DateOffset(years=1)])
- other = tm.box_expected(other, box_with_array)
- result = s + other
- exp = DatetimeIndex([Timestamp('2001-1-1'),
- Timestamp('2001-2-1')])
- exp = tm.box_expected(exp, box_with_array)
- tm.assert_equal(result, exp)
- # TODO: overlap with test_dt64arr_add_mixed_offset_array?
- def test_dt64arr_add_sub_offset_ndarray(self, tz_naive_fixture,
- box_with_array):
- # GH#18849
- if box_with_array is pd.DataFrame:
- pytest.xfail("FIXME: ValueError with transpose; "
- "alignment error without")
- tz = tz_naive_fixture
- dti = pd.date_range('2017-01-01', periods=2, tz=tz)
- dtarr = tm.box_expected(dti, box_with_array)
- other = np.array([pd.offsets.MonthEnd(), pd.offsets.Day(n=2)])
- warn = None if box_with_array is pd.DataFrame else PerformanceWarning
- with tm.assert_produces_warning(warn,
- clear=[pd.core.arrays.datetimelike]):
- res = dtarr + other
- expected = DatetimeIndex([dti[n] + other[n] for n in range(len(dti))],
- name=dti.name, freq='infer')
- expected = tm.box_expected(expected, box_with_array)
- tm.assert_equal(res, expected)
- with tm.assert_produces_warning(warn,
- clear=[pd.core.arrays.datetimelike]):
- res2 = other + dtarr
- tm.assert_equal(res2, expected)
- with tm.assert_produces_warning(warn,
- clear=[pd.core.arrays.datetimelike]):
- res = dtarr - other
- expected = DatetimeIndex([dti[n] - other[n] for n in range(len(dti))],
- name=dti.name, freq='infer')
- expected = tm.box_expected(expected, box_with_array)
- tm.assert_equal(res, expected)
- class TestDatetime64OverflowHandling(object):
- # TODO: box + de-duplicate
- def test_dt64_overflow_masking(self, box_with_array):
- # GH#25317
- left = Series([Timestamp('1969-12-31')])
- right = Series([NaT])
- left = tm.box_expected(left, box_with_array)
- right = tm.box_expected(right, box_with_array)
- expected = TimedeltaIndex([NaT])
- expected = tm.box_expected(expected, box_with_array)
- result = left - right
- tm.assert_equal(result, expected)
- def test_dt64_series_arith_overflow(self):
- # GH#12534, fixed by GH#19024
- dt = pd.Timestamp('1700-01-31')
- td = pd.Timedelta('20000 Days')
- dti = pd.date_range('1949-09-30', freq='100Y', periods=4)
- ser = pd.Series(dti)
- with pytest.raises(OverflowError):
- ser - dt
- with pytest.raises(OverflowError):
- dt - ser
- with pytest.raises(OverflowError):
- ser + td
- with pytest.raises(OverflowError):
- td + ser
- ser.iloc[-1] = pd.NaT
- expected = pd.Series(['2004-10-03', '2104-10-04', '2204-10-04', 'NaT'],
- dtype='datetime64[ns]')
- res = ser + td
- tm.assert_series_equal(res, expected)
- res = td + ser
- tm.assert_series_equal(res, expected)
- ser.iloc[1:] = pd.NaT
- expected = pd.Series(['91279 Days', 'NaT', 'NaT', 'NaT'],
- dtype='timedelta64[ns]')
- res = ser - dt
- tm.assert_series_equal(res, expected)
- res = dt - ser
- tm.assert_series_equal(res, -expected)
- def test_datetimeindex_sub_timestamp_overflow(self):
- dtimax = pd.to_datetime(['now', pd.Timestamp.max])
- dtimin = pd.to_datetime(['now', pd.Timestamp.min])
- tsneg = Timestamp('1950-01-01')
- ts_neg_variants = [tsneg,
- tsneg.to_pydatetime(),
- tsneg.to_datetime64().astype('datetime64[ns]'),
- tsneg.to_datetime64().astype('datetime64[D]')]
- tspos = Timestamp('1980-01-01')
- ts_pos_variants = [tspos,
- tspos.to_pydatetime(),
- tspos.to_datetime64().astype('datetime64[ns]'),
- tspos.to_datetime64().astype('datetime64[D]')]
- for variant in ts_neg_variants:
- with pytest.raises(OverflowError):
- dtimax - variant
- expected = pd.Timestamp.max.value - tspos.value
- for variant in ts_pos_variants:
- res = dtimax - variant
- assert res[1].value == expected
- expected = pd.Timestamp.min.value - tsneg.value
- for variant in ts_neg_variants:
- res = dtimin - variant
- assert res[1].value == expected
- for variant in ts_pos_variants:
- with pytest.raises(OverflowError):
- dtimin - variant
- def test_datetimeindex_sub_datetimeindex_overflow(self):
- # GH#22492, GH#22508
- dtimax = pd.to_datetime(['now', pd.Timestamp.max])
- dtimin = pd.to_datetime(['now', pd.Timestamp.min])
- ts_neg = pd.to_datetime(['1950-01-01', '1950-01-01'])
- ts_pos = pd.to_datetime(['1980-01-01', '1980-01-01'])
- # General tests
- expected = pd.Timestamp.max.value - ts_pos[1].value
- result = dtimax - ts_pos
- assert result[1].value == expected
- expected = pd.Timestamp.min.value - ts_neg[1].value
- result = dtimin - ts_neg
- assert result[1].value == expected
- with pytest.raises(OverflowError):
- dtimax - ts_neg
- with pytest.raises(OverflowError):
- dtimin - ts_pos
- # Edge cases
- tmin = pd.to_datetime([pd.Timestamp.min])
- t1 = tmin + pd.Timedelta.max + pd.Timedelta('1us')
- with pytest.raises(OverflowError):
- t1 - tmin
- tmax = pd.to_datetime([pd.Timestamp.max])
- t2 = tmax + pd.Timedelta.min - pd.Timedelta('1us')
- with pytest.raises(OverflowError):
- tmax - t2
- class TestTimestampSeriesArithmetic(object):
- def test_empty_series_add_sub(self):
- # GH#13844
- a = Series(dtype='M8[ns]')
- b = Series(dtype='m8[ns]')
- tm.assert_series_equal(a, a + b)
- tm.assert_series_equal(a, a - b)
- tm.assert_series_equal(a, b + a)
- with pytest.raises(TypeError):
- b - a
- def test_operators_datetimelike(self):
- # ## timedelta64 ###
- td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
- td1.iloc[2] = np.nan
- # ## datetime64 ###
- dt1 = Series([pd.Timestamp('20111230'), pd.Timestamp('20120101'),
- pd.Timestamp('20120103')])
- dt1.iloc[2] = np.nan
- dt2 = Series([pd.Timestamp('20111231'), pd.Timestamp('20120102'),
- pd.Timestamp('20120104')])
- dt1 - dt2
- dt2 - dt1
- # ## datetime64 with timetimedelta ###
- dt1 + td1
- td1 + dt1
- dt1 - td1
- # TODO: Decide if this ought to work.
- # td1 - dt1
- # ## timetimedelta with datetime64 ###
- td1 + dt1
- dt1 + td1
- def test_dt64ser_sub_datetime_dtype(self):
- ts = Timestamp(datetime(1993, 1, 7, 13, 30, 00))
- dt = datetime(1993, 6, 22, 13, 30)
- ser = Series([ts])
- result = pd.to_timedelta(np.abs(ser - dt))
- assert result.dtype == 'timedelta64[ns]'
- # -------------------------------------------------------------
- # TODO: This next block of tests came from tests.series.test_operators,
- # needs to be de-duplicated and parametrized over `box` classes
- def test_operators_datetimelike_invalid(self, all_arithmetic_operators):
- # these are all TypeEror ops
- op_str = all_arithmetic_operators
- def check(get_ser, test_ser):
- # check that we are getting a TypeError
- # with 'operate' (from core/ops.py) for the ops that are not
- # defined
- op = getattr(get_ser, op_str, None)
- # Previously, _validate_for_numeric_binop in core/indexes/base.py
- # did this for us.
- with pytest.raises(TypeError,
- match='operate|[cC]annot|unsupported operand'):
- op(test_ser)
- # ## timedelta64 ###
- td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
- td1.iloc[2] = np.nan
- # ## datetime64 ###
- dt1 = Series([Timestamp('20111230'), Timestamp('20120101'),
- Timestamp('20120103')])
- dt1.iloc[2] = np.nan
- dt2 = Series([Timestamp('20111231'), Timestamp('20120102'),
- Timestamp('20120104')])
- if op_str not in ['__sub__', '__rsub__']:
- check(dt1, dt2)
- # ## datetime64 with timetimedelta ###
- # TODO(jreback) __rsub__ should raise?
- if op_str not in ['__add__', '__radd__', '__sub__']:
- check(dt1, td1)
- # 8260, 10763
- # datetime64 with tz
- tz = 'US/Eastern'
- dt1 = Series(date_range('2000-01-01 09:00:00', periods=5,
- tz=tz), name='foo')
- dt2 = dt1.copy()
- dt2.iloc[2] = np.nan
- td1 = Series(pd.timedelta_range('1 days 1 min', periods=5, freq='H'))
- td2 = td1.copy()
- td2.iloc[1] = np.nan
- if op_str not in ['__add__', '__radd__', '__sub__', '__rsub__']:
- check(dt2, td2)
- def test_sub_single_tz(self):
- # GH#12290
- s1 = Series([pd.Timestamp('2016-02-10', tz='America/Sao_Paulo')])
- s2 = Series([pd.Timestamp('2016-02-08', tz='America/Sao_Paulo')])
- result = s1 - s2
- expected = Series([Timedelta('2days')])
- tm.assert_series_equal(result, expected)
- result = s2 - s1
- expected = Series([Timedelta('-2days')])
- tm.assert_series_equal(result, expected)
- def test_dt64tz_series_sub_dtitz(self):
- # GH#19071 subtracting tzaware DatetimeIndex from tzaware Series
- # (with same tz) raises, fixed by #19024
- dti = pd.date_range('1999-09-30', periods=10, tz='US/Pacific')
- ser = pd.Series(dti)
- expected = pd.Series(pd.TimedeltaIndex(['0days'] * 10))
- res = dti - ser
- tm.assert_series_equal(res, expected)
- res = ser - dti
- tm.assert_series_equal(res, expected)
- def test_sub_datetime_compat(self):
- # see GH#14088
- s = Series([datetime(2016, 8, 23, 12, tzinfo=pytz.utc), pd.NaT])
- dt = datetime(2016, 8, 22, 12, tzinfo=pytz.utc)
- exp = Series([Timedelta('1 days'), pd.NaT])
- tm.assert_series_equal(s - dt, exp)
- tm.assert_series_equal(s - Timestamp(dt), exp)
- def test_dt64_series_add_mixed_tick_DateOffset(self):
- # GH#4532
- # operate with pd.offsets
- s = Series([Timestamp('20130101 9:01'), Timestamp('20130101 9:02')])
- result = s + pd.offsets.Milli(5)
- result2 = pd.offsets.Milli(5) + s
- expected = Series([Timestamp('20130101 9:01:00.005'),
- Timestamp('20130101 9:02:00.005')])
- tm.assert_series_equal(result, expected)
- tm.assert_series_equal(result2, expected)
- result = s + pd.offsets.Minute(5) + pd.offsets.Milli(5)
- expected = Series([Timestamp('20130101 9:06:00.005'),
- Timestamp('20130101 9:07:00.005')])
- tm.assert_series_equal(result, expected)
- def test_datetime64_ops_nat(self):
- # GH#11349
- datetime_series = Series([NaT, Timestamp('19900315')])
- nat_series_dtype_timestamp = Series([NaT, NaT], dtype='datetime64[ns]')
- single_nat_dtype_datetime = Series([NaT], dtype='datetime64[ns]')
- # subtraction
- tm.assert_series_equal(-NaT + datetime_series,
- nat_series_dtype_timestamp)
- with pytest.raises(TypeError):
- -single_nat_dtype_datetime + datetime_series
- tm.assert_series_equal(-NaT + nat_series_dtype_timestamp,
- nat_series_dtype_timestamp)
- with pytest.raises(TypeError):
- -single_nat_dtype_datetime + nat_series_dtype_timestamp
- # addition
- tm.assert_series_equal(nat_series_dtype_timestamp + NaT,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(NaT + nat_series_dtype_timestamp,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(nat_series_dtype_timestamp + NaT,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(NaT + nat_series_dtype_timestamp,
- nat_series_dtype_timestamp)
- # -------------------------------------------------------------
- # Invalid Operations
- # TODO: this block also needs to be de-duplicated and parametrized
- @pytest.mark.parametrize('dt64_series', [
- Series([Timestamp('19900315'), Timestamp('19900315')]),
- Series([pd.NaT, Timestamp('19900315')]),
- Series([pd.NaT, pd.NaT], dtype='datetime64[ns]')])
- @pytest.mark.parametrize('one', [1, 1.0, np.array(1)])
- def test_dt64_mul_div_numeric_invalid(self, one, dt64_series):
- # multiplication
- with pytest.raises(TypeError):
- dt64_series * one
- with pytest.raises(TypeError):
- one * dt64_series
- # division
- with pytest.raises(TypeError):
- dt64_series / one
- with pytest.raises(TypeError):
- one / dt64_series
- @pytest.mark.parametrize('op', ['__add__', '__radd__',
- '__sub__', '__rsub__'])
- @pytest.mark.parametrize('tz', [None, 'Asia/Tokyo'])
- def test_dt64_series_add_intlike(self, tz, op):
- # GH#19123
- dti = pd.DatetimeIndex(['2016-01-02', '2016-02-03', 'NaT'], tz=tz)
- ser = Series(dti)
- other = Series([20, 30, 40], dtype='uint8')
- method = getattr(ser, op)
- with pytest.raises(TypeError):
- method(1)
- with pytest.raises(TypeError):
- method(other)
- with pytest.raises(TypeError):
- method(other.values)
- with pytest.raises(TypeError):
- method(pd.Index(other))
- # -------------------------------------------------------------
- # Timezone-Centric Tests
- def test_operators_datetimelike_with_timezones(self):
- tz = 'US/Eastern'
- dt1 = Series(date_range('2000-01-01 09:00:00', periods=5,
- tz=tz), name='foo')
- dt2 = dt1.copy()
- dt2.iloc[2] = np.nan
- td1 = Series(pd.timedelta_range('1 days 1 min', periods=5, freq='H'))
- td2 = td1.copy()
- td2.iloc[1] = np.nan
- result = dt1 + td1[0]
- exp = (dt1.dt.tz_localize(None) + td1[0]).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- result = dt2 + td2[0]
- exp = (dt2.dt.tz_localize(None) + td2[0]).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- # odd numpy behavior with scalar timedeltas
- result = td1[0] + dt1
- exp = (dt1.dt.tz_localize(None) + td1[0]).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- result = td2[0] + dt2
- exp = (dt2.dt.tz_localize(None) + td2[0]).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- result = dt1 - td1[0]
- exp = (dt1.dt.tz_localize(None) - td1[0]).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- with pytest.raises(TypeError):
- td1[0] - dt1
- result = dt2 - td2[0]
- exp = (dt2.dt.tz_localize(None) - td2[0]).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- with pytest.raises(TypeError):
- td2[0] - dt2
- result = dt1 + td1
- exp = (dt1.dt.tz_localize(None) + td1).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- result = dt2 + td2
- exp = (dt2.dt.tz_localize(None) + td2).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- result = dt1 - td1
- exp = (dt1.dt.tz_localize(None) - td1).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- result = dt2 - td2
- exp = (dt2.dt.tz_localize(None) - td2).dt.tz_localize(tz)
- tm.assert_series_equal(result, exp)
- with pytest.raises(TypeError):
- td1 - dt1
- with pytest.raises(TypeError):
- td2 - dt2
- class TestDatetimeIndexArithmetic(object):
- # -------------------------------------------------------------
- # Binary operations DatetimeIndex and int
- def test_dti_add_int(self, tz_naive_fixture, one):
- # Variants of `one` for #19012
- tz = tz_naive_fixture
- rng = pd.date_range('2000-01-01 09:00', freq='H',
- periods=10, tz=tz)
- with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
- result = rng + one
- expected = pd.date_range('2000-01-01 10:00', freq='H',
- periods=10, tz=tz)
- tm.assert_index_equal(result, expected)
- def test_dti_iadd_int(self, tz_naive_fixture, one):
- tz = tz_naive_fixture
- rng = pd.date_range('2000-01-01 09:00', freq='H',
- periods=10, tz=tz)
- expected = pd.date_range('2000-01-01 10:00', freq='H',
- periods=10, tz=tz)
- with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
- rng += one
- tm.assert_index_equal(rng, expected)
- def test_dti_sub_int(self, tz_naive_fixture, one):
- tz = tz_naive_fixture
- rng = pd.date_range('2000-01-01 09:00', freq='H',
- periods=10, tz=tz)
- with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
- result = rng - one
- expected = pd.date_range('2000-01-01 08:00', freq='H',
- periods=10, tz=tz)
- tm.assert_index_equal(result, expected)
- def test_dti_isub_int(self, tz_naive_fixture, one):
- tz = tz_naive_fixture
- rng = pd.date_range('2000-01-01 09:00', freq='H',
- periods=10, tz=tz)
- expected = pd.date_range('2000-01-01 08:00', freq='H',
- periods=10, tz=tz)
- with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
- rng -= one
- tm.assert_index_equal(rng, expected)
- # -------------------------------------------------------------
- # __add__/__sub__ with integer arrays
- @pytest.mark.parametrize('freq', ['H', 'D'])
- @pytest.mark.parametrize('int_holder', [np.array, pd.Index])
- def test_dti_add_intarray_tick(self, int_holder, freq):
- # GH#19959
- dti = pd.date_range('2016-01-01', periods=2, freq=freq)
- other = int_holder([4, -1])
- with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
- expected = DatetimeIndex([dti[n] + other[n]
- for n in range(len(dti))])
- result = dti + other
- tm.assert_index_equal(result, expected)
- with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
- result = other + dti
- tm.assert_index_equal(result, expected)
- @pytest.mark.parametrize('freq', ['W', 'M', 'MS', 'Q'])
- @pytest.mark.parametrize('int_holder', [np.array, pd.Index])
- def test_dti_add_intarray_non_tick(self, int_holder, freq):
- # GH#19959
- dti = pd.date_range('2016-01-01', periods=2, freq=freq)
- other = int_holder([4, -1])
- with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
- expected = DatetimeIndex([dti[n] + other[n]
- for n in range(len(dti))])
- # tm.assert_produces_warning does not handle cases where we expect
- # two warnings, in this case PerformanceWarning and FutureWarning.
- # Until that is fixed, we don't catch either
- with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- result = dti + other
- tm.assert_index_equal(result, expected)
- with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- result = other + dti
- tm.assert_index_equal(result, expected)
- @pytest.mark.parametrize('int_holder', [np.array, pd.Index])
- def test_dti_add_intarray_no_freq(self, int_holder):
- # GH#19959
- dti = pd.DatetimeIndex(['2016-01-01', 'NaT', '2017-04-05 06:07:08'])
- other = int_holder([9, 4, -1])
- with pytest.raises(NullFrequencyError):
- dti + other
- with pytest.raises(NullFrequencyError):
- other + dti
- with pytest.raises(NullFrequencyError):
- dti - other
- with pytest.raises(TypeError):
- other - dti
- # -------------------------------------------------------------
- # Binary operations DatetimeIndex and TimedeltaIndex/array
- def test_dti_add_tdi(self, tz_naive_fixture):
- # GH#17558
- tz = tz_naive_fixture
- dti = DatetimeIndex([Timestamp('2017-01-01', tz=tz)] * 10)
- tdi = pd.timedelta_range('0 days', periods=10)
- expected = pd.date_range('2017-01-01', periods=10, tz=tz)
- # add with TimdeltaIndex
- result = dti + tdi
- tm.assert_index_equal(result, expected)
- result = tdi + dti
- tm.assert_index_equal(result, expected)
- # add with timedelta64 array
- result = dti + tdi.values
- tm.assert_index_equal(result, expected)
- result = tdi.values + dti
- tm.assert_index_equal(result, expected)
- def test_dti_iadd_tdi(self, tz_naive_fixture):
- # GH#17558
- tz = tz_naive_fixture
- dti = DatetimeIndex([Timestamp('2017-01-01', tz=tz)] * 10)
- tdi = pd.timedelta_range('0 days', periods=10)
- expected = pd.date_range('2017-01-01', periods=10, tz=tz)
- # iadd with TimdeltaIndex
- result = DatetimeIndex([Timestamp('2017-01-01', tz=tz)] * 10)
- result += tdi
- tm.assert_index_equal(result, expected)
- result = pd.timedelta_range('0 days', periods=10)
- result += dti
- tm.assert_index_equal(result, expected)
- # iadd with timedelta64 array
- result = DatetimeIndex([Timestamp('2017-01-01', tz=tz)] * 10)
- result += tdi.values
- tm.assert_index_equal(result, expected)
- result = pd.timedelta_range('0 days', periods=10)
- result += dti
- tm.assert_index_equal(result, expected)
- def test_dti_sub_tdi(self, tz_naive_fixture):
- # GH#17558
- tz = tz_naive_fixture
- dti = DatetimeIndex([Timestamp('2017-01-01', tz=tz)] * 10)
- tdi = pd.timedelta_range('0 days', periods=10)
- expected = pd.date_range('2017-01-01', periods=10, tz=tz, freq='-1D')
- # sub with TimedeltaIndex
- result = dti - tdi
- tm.assert_index_equal(result, expected)
- msg = 'cannot subtract .*TimedeltaArray'
- with pytest.raises(TypeError, match=msg):
- tdi - dti
- # sub with timedelta64 array
- result = dti - tdi.values
- tm.assert_index_equal(result, expected)
- msg = 'cannot subtract DatetimeArray from'
- with pytest.raises(TypeError, match=msg):
- tdi.values - dti
- def test_dti_isub_tdi(self, tz_naive_fixture):
- # GH#17558
- tz = tz_naive_fixture
- dti = DatetimeIndex([Timestamp('2017-01-01', tz=tz)] * 10)
- tdi = pd.timedelta_range('0 days', periods=10)
- expected = pd.date_range('2017-01-01', periods=10, tz=tz, freq='-1D')
- # isub with TimedeltaIndex
- result = DatetimeIndex([Timestamp('2017-01-01', tz=tz)] * 10)
- result -= tdi
- tm.assert_index_equal(result, expected)
- msg = 'cannot subtract .* from a TimedeltaArray'
- with pytest.raises(TypeError, match=msg):
- tdi -= dti
- # isub with timedelta64 array
- result = DatetimeIndex([Timestamp('2017-01-01', tz=tz)] * 10)
- result -= tdi.values
- tm.assert_index_equal(result, expected)
- msg = '|'.join(['cannot perform __neg__ with this index type:',
- 'ufunc subtract cannot use operands with types',
- 'cannot subtract DatetimeArray from'])
- with pytest.raises(TypeError, match=msg):
- tdi.values -= dti
- # -------------------------------------------------------------
- # Binary Operations DatetimeIndex and datetime-like
- # TODO: A couple other tests belong in this section. Move them in
- # A PR where there isn't already a giant diff.
- @pytest.mark.parametrize('addend', [
- datetime(2011, 1, 1),
- DatetimeIndex(['2011-01-01', '2011-01-02']),
- DatetimeIndex(['2011-01-01', '2011-01-02']).tz_localize('US/Eastern'),
- np.datetime64('2011-01-01'),
- Timestamp('2011-01-01')
- ], ids=lambda x: type(x).__name__)
- @pytest.mark.parametrize('tz', [None, 'US/Eastern'])
- def test_add_datetimelike_and_dti(self, addend, tz):
- # GH#9631
- dti = DatetimeIndex(['2011-01-01', '2011-01-02']).tz_localize(tz)
- msg = ('cannot add DatetimeArray and {0}'
- .format(type(addend).__name__)).replace('DatetimeIndex',
- 'DatetimeArray')
- with pytest.raises(TypeError, match=msg):
- dti + addend
- with pytest.raises(TypeError, match=msg):
- addend + dti
- # -------------------------------------------------------------
- def test_sub_dti_dti(self):
- # previously performed setop (deprecated in 0.16.0), now changed to
- # return subtraction -> TimeDeltaIndex (GH ...)
- dti = date_range('20130101', periods=3)
- dti_tz = date_range('20130101', periods=3).tz_localize('US/Eastern')
- dti_tz2 = date_range('20130101', periods=3).tz_localize('UTC')
- expected = TimedeltaIndex([0, 0, 0])
- result = dti - dti
- tm.assert_index_equal(result, expected)
- result = dti_tz - dti_tz
- tm.assert_index_equal(result, expected)
- with pytest.raises(TypeError):
- dti_tz - dti
- with pytest.raises(TypeError):
- dti - dti_tz
- with pytest.raises(TypeError):
- dti_tz - dti_tz2
- # isub
- dti -= dti
- tm.assert_index_equal(dti, expected)
- # different length raises ValueError
- dti1 = date_range('20130101', periods=3)
- dti2 = date_range('20130101', periods=4)
- with pytest.raises(ValueError):
- dti1 - dti2
- # NaN propagation
- dti1 = DatetimeIndex(['2012-01-01', np.nan, '2012-01-03'])
- dti2 = DatetimeIndex(['2012-01-02', '2012-01-03', np.nan])
- expected = TimedeltaIndex(['1 days', np.nan, np.nan])
- result = dti2 - dti1
- tm.assert_index_equal(result, expected)
- # -------------------------------------------------------------------
- # TODO: Most of this block is moved from series or frame tests, needs
- # cleanup, box-parametrization, and de-duplication
- @pytest.mark.parametrize('op', [operator.add, operator.sub])
- def test_timedelta64_equal_timedelta_supported_ops(self, op):
- ser = Series([Timestamp('20130301'),
- Timestamp('20130228 23:00:00'),
- Timestamp('20130228 22:00:00'),
- Timestamp('20130228 21:00:00')])
- intervals = ['D', 'h', 'm', 's', 'us']
- # TODO: unused
- # npy16_mappings = {'D': 24 * 60 * 60 * 1000000,
- # 'h': 60 * 60 * 1000000,
- # 'm': 60 * 1000000,
- # 's': 1000000,
- # 'us': 1}
- def timedelta64(*args):
- return sum(starmap(np.timedelta64, zip(args, intervals)))
- for d, h, m, s, us in product(*([range(2)] * 5)):
- nptd = timedelta64(d, h, m, s, us)
- pytd = timedelta(days=d, hours=h, minutes=m, seconds=s,
- microseconds=us)
- lhs = op(ser, nptd)
- rhs = op(ser, pytd)
- tm.assert_series_equal(lhs, rhs)
- def test_ops_nat_mixed_datetime64_timedelta64(self):
- # GH#11349
- timedelta_series = Series([NaT, Timedelta('1s')])
- datetime_series = Series([NaT, Timestamp('19900315')])
- nat_series_dtype_timedelta = Series([NaT, NaT],
- dtype='timedelta64[ns]')
- nat_series_dtype_timestamp = Series([NaT, NaT], dtype='datetime64[ns]')
- single_nat_dtype_datetime = Series([NaT], dtype='datetime64[ns]')
- single_nat_dtype_timedelta = Series([NaT], dtype='timedelta64[ns]')
- # subtraction
- tm.assert_series_equal(datetime_series - single_nat_dtype_datetime,
- nat_series_dtype_timedelta)
- tm.assert_series_equal(datetime_series - single_nat_dtype_timedelta,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(-single_nat_dtype_timedelta + datetime_series,
- nat_series_dtype_timestamp)
- # without a Series wrapping the NaT, it is ambiguous
- # whether it is a datetime64 or timedelta64
- # defaults to interpreting it as timedelta64
- tm.assert_series_equal(nat_series_dtype_timestamp -
- single_nat_dtype_datetime,
- nat_series_dtype_timedelta)
- tm.assert_series_equal(nat_series_dtype_timestamp -
- single_nat_dtype_timedelta,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(-single_nat_dtype_timedelta +
- nat_series_dtype_timestamp,
- nat_series_dtype_timestamp)
- with pytest.raises(TypeError):
- timedelta_series - single_nat_dtype_datetime
- # addition
- tm.assert_series_equal(nat_series_dtype_timestamp +
- single_nat_dtype_timedelta,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(single_nat_dtype_timedelta +
- nat_series_dtype_timestamp,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(nat_series_dtype_timestamp +
- single_nat_dtype_timedelta,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(single_nat_dtype_timedelta +
- nat_series_dtype_timestamp,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(nat_series_dtype_timedelta +
- single_nat_dtype_datetime,
- nat_series_dtype_timestamp)
- tm.assert_series_equal(single_nat_dtype_datetime +
- nat_series_dtype_timedelta,
- nat_series_dtype_timestamp)
- def test_ufunc_coercions(self):
- idx = date_range('2011-01-01', periods=3, freq='2D', name='x')
- delta = np.timedelta64(1, 'D')
- for result in [idx + delta, np.add(idx, delta)]:
- assert isinstance(result, DatetimeIndex)
- exp = date_range('2011-01-02', periods=3, freq='2D', name='x')
- tm.assert_index_equal(result, exp)
- assert result.freq == '2D'
- for result in [idx - delta, np.subtract(idx, delta)]:
- assert isinstance(result, DatetimeIndex)
- exp = date_range('2010-12-31', periods=3, freq='2D', name='x')
- tm.assert_index_equal(result, exp)
- assert result.freq == '2D'
- delta = np.array([np.timedelta64(1, 'D'), np.timedelta64(2, 'D'),
- np.timedelta64(3, 'D')])
- for result in [idx + delta, np.add(idx, delta)]:
- assert isinstance(result, DatetimeIndex)
- exp = DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-08'],
- freq='3D', name='x')
- tm.assert_index_equal(result, exp)
- assert result.freq == '3D'
- for result in [idx - delta, np.subtract(idx, delta)]:
- assert isinstance(result, DatetimeIndex)
- exp = DatetimeIndex(['2010-12-31', '2011-01-01', '2011-01-02'],
- freq='D', name='x')
- tm.assert_index_equal(result, exp)
- assert result.freq == 'D'
- @pytest.mark.parametrize('names', [('foo', None, None),
- ('baz', 'bar', None),
- ('bar', 'bar', 'bar')])
- @pytest.mark.parametrize('tz', [None, 'America/Chicago'])
- def test_dti_add_series(self, tz, names):
- # GH#13905
- index = DatetimeIndex(['2016-06-28 05:30', '2016-06-28 05:31'],
- tz=tz, name=names[0])
- ser = Series([Timedelta(seconds=5)] * 2,
- index=index, name=names[1])
- expected = Series(index + Timedelta(seconds=5),
- index=index, name=names[2])
- # passing name arg isn't enough when names[2] is None
- expected.name = names[2]
- assert expected.dtype == index.dtype
- result = ser + index
- tm.assert_series_equal(result, expected)
- result2 = index + ser
- tm.assert_series_equal(result2, expected)
- expected = index + Timedelta(seconds=5)
- result3 = ser.values + index
- tm.assert_index_equal(result3, expected)
- result4 = index + ser.values
- tm.assert_index_equal(result4, expected)
- @pytest.mark.parametrize('names', [(None, None, None),
- ('foo', 'bar', None),
- ('foo', 'foo', 'foo')])
- def test_dti_add_offset_index(self, tz_naive_fixture, names):
- # GH#18849, GH#19744
- tz = tz_naive_fixture
- dti = pd.date_range('2017-01-01', periods=2, tz=tz, name=names[0])
- other = pd.Index([pd.offsets.MonthEnd(), pd.offsets.Day(n=2)],
- name=names[1])
- with tm.assert_produces_warning(PerformanceWarning,
- clear=[pd.core.arrays.datetimelike]):
- res = dti + other
- expected = DatetimeIndex([dti[n] + other[n] for n in range(len(dti))],
- name=names[2], freq='infer')
- tm.assert_index_equal(res, expected)
- with tm.assert_produces_warning(PerformanceWarning,
- clear=[pd.core.arrays.datetimelike]):
- res2 = other + dti
- tm.assert_index_equal(res2, expected)
- @pytest.mark.parametrize('names', [(None, None, None),
- ('foo', 'bar', None),
- ('foo', 'foo', 'foo')])
- def test_dti_sub_offset_index(self, tz_naive_fixture, names):
- # GH#18824, GH#19744
- tz = tz_naive_fixture
- dti = pd.date_range('2017-01-01', periods=2, tz=tz, name=names[0])
- other = pd.Index([pd.offsets.MonthEnd(), pd.offsets.Day(n=2)],
- name=names[1])
- with tm.assert_produces_warning(PerformanceWarning,
- clear=[pd.core.arrays.datetimelike]):
- res = dti - other
- expected = DatetimeIndex([dti[n] - other[n] for n in range(len(dti))],
- name=names[2], freq='infer')
- tm.assert_index_equal(res, expected)
- @pytest.mark.parametrize('names', [(None, None, None),
- ('foo', 'bar', None),
- ('foo', 'foo', 'foo')])
- def test_dti_with_offset_series(self, tz_naive_fixture, names):
- # GH#18849
- tz = tz_naive_fixture
- dti = pd.date_range('2017-01-01', periods=2, tz=tz, name=names[0])
- other = Series([pd.offsets.MonthEnd(), pd.offsets.Day(n=2)],
- name=names[1])
- expected_add = Series([dti[n] + other[n] for n in range(len(dti))],
- name=names[2])
- with tm.assert_produces_warning(PerformanceWarning,
- clear=[pd.core.arrays.datetimelike]):
- res = dti + other
- tm.assert_series_equal(res, expected_add)
- with tm.assert_produces_warning(PerformanceWarning,
- clear=[pd.core.arrays.datetimelike]):
- res2 = other + dti
- tm.assert_series_equal(res2, expected_add)
- expected_sub = Series([dti[n] - other[n] for n in range(len(dti))],
- name=names[2])
- with tm.assert_produces_warning(PerformanceWarning,
- clear=[pd.core.arrays.datetimelike]):
- res3 = dti - other
- tm.assert_series_equal(res3, expected_sub)
- @pytest.mark.parametrize('years', [-1, 0, 1])
- @pytest.mark.parametrize('months', [-2, 0, 2])
- def test_shift_months(years, months):
- dti = DatetimeIndex([Timestamp('2000-01-05 00:15:00'),
- Timestamp('2000-01-31 00:23:00'),
- Timestamp('2000-01-01'),
- Timestamp('2000-02-29'),
- Timestamp('2000-12-31')])
- actual = DatetimeIndex(shift_months(dti.asi8, years * 12 + months))
- raw = [x + pd.offsets.DateOffset(years=years, months=months)
- for x in dti]
- expected = DatetimeIndex(raw)
- tm.assert_index_equal(actual, expected)
|