22Base and utility classes for tseries type pandas objects.
33"""
44import warnings
5-
5+ import operator
66from datetime import datetime , timedelta
77
88from pandas import compat
99from pandas .compat .numpy import function as nv
1010from pandas .core .tools .timedeltas import to_timedelta
1111
1212import numpy as np
13+
14+ from pandas ._libs import lib , iNaT , NaT
15+ from pandas ._libs .tslibs .period import Period
16+ from pandas ._libs .tslibs .timedeltas import delta_to_nanoseconds
17+ from pandas ._libs .tslibs .timestamps import round_ns
18+
1319from pandas .core .dtypes .common import (
1420 _ensure_int64 ,
1521 is_dtype_equal ,
2531 is_integer_dtype ,
2632 is_object_dtype ,
2733 is_string_dtype ,
34+ is_period_dtype ,
2835 is_timedelta64_dtype )
2936from pandas .core .dtypes .generic import (
3037 ABCIndex , ABCSeries , ABCPeriodIndex , ABCIndexClass )
3138from pandas .core .dtypes .missing import isna
3239from pandas .core import common as com , algorithms , ops
3340from pandas .core .algorithms import checked_add_with_arr
34- from pandas .errors import NullFrequencyError
41+ from pandas .errors import NullFrequencyError , PerformanceWarning
3542import pandas .io .formats .printing as printing
36- from pandas ._libs import lib , iNaT , NaT
37- from pandas ._libs .tslibs .period import Period
38- from pandas ._libs .tslibs .timedeltas import delta_to_nanoseconds
39- from pandas ._libs .tslibs .timestamps import round_ns
4043
4144from pandas .core .indexes .base import Index , _index_shared_docs
4245from pandas .util ._decorators import Appender , cache_readonly
@@ -637,13 +640,33 @@ def _sub_datelike(self, other):
637640 def _sub_period (self , other ):
638641 return NotImplemented
639642
640- def _add_offset_array (self , other ):
641- # Array/Index of DateOffset objects
642- return NotImplemented
643+ def _addsub_offset_array (self , other , op ):
644+ """
645+ Add or subtract array-like of DateOffset objects
643646
644- def _sub_offset_array (self , other ):
645- # Array/Index of DateOffset objects
646- return NotImplemented
647+ Parameters
648+ ----------
649+ other : Index, np.ndarray
650+ object-dtype containing pd.DateOffset objects
651+ op : {operator.add, operator.sub}
652+
653+ Returns
654+ -------
655+ result : same class as self
656+ """
657+ assert op in [operator .add , operator .sub ]
658+ if len (other ) == 1 :
659+ return op (self , other [0 ])
660+
661+ warnings .warn ("Adding/subtracting array of DateOffsets to "
662+ "{cls} not vectorized"
663+ .format (cls = type (self ).__name__ ), PerformanceWarning )
664+
665+ res_values = op (self .astype ('O' ).values , np .array (other ))
666+ kwargs = {}
667+ if not is_period_dtype (self ):
668+ kwargs ['freq' ] = 'infer'
669+ return self ._constructor (res_values , ** kwargs )
647670
648671 @classmethod
649672 def _add_datetimelike_methods (cls ):
@@ -660,26 +683,31 @@ def __add__(self, other):
660683 other = lib .item_from_zerodim (other )
661684 if isinstance (other , ABCSeries ):
662685 return NotImplemented
663- elif is_timedelta64_dtype (other ):
686+
687+ # scalar others
688+ elif isinstance (other , (DateOffset , timedelta , np .timedelta64 )):
664689 result = self ._add_delta (other )
665- elif isinstance (other , (DateOffset , timedelta )):
690+ elif isinstance (other , (datetime , np .datetime64 )):
691+ result = self ._add_datelike (other )
692+ elif is_integer (other ):
693+ # This check must come after the check for np.timedelta64
694+ # as is_integer returns True for these
695+ result = self .shift (other )
696+
697+ # array-like others
698+ elif is_timedelta64_dtype (other ):
699+ # TimedeltaIndex, ndarray[timedelta64]
666700 result = self ._add_delta (other )
667701 elif is_offsetlike (other ):
668702 # Array/Index of DateOffset objects
669- result = self ._add_offset_array (other )
703+ result = self ._addsub_offset_array (other , operator . add )
670704 elif isinstance (self , TimedeltaIndex ) and isinstance (other , Index ):
671705 if hasattr (other , '_add_delta' ):
672706 # i.e. DatetimeIndex, TimedeltaIndex, or PeriodIndex
673707 result = other ._add_delta (self )
674708 else :
675709 raise TypeError ("cannot add TimedeltaIndex and {typ}"
676710 .format (typ = type (other )))
677- elif is_integer (other ):
678- # This check must come after the check for timedelta64_dtype
679- # or else it will incorrectly catch np.timedelta64 objects
680- result = self .shift (other )
681- elif isinstance (other , (datetime , np .datetime64 )):
682- result = self ._add_datelike (other )
683711 elif isinstance (other , Index ):
684712 result = self ._add_datelike (other )
685713 elif is_integer_dtype (other ) and self .freq is None :
@@ -709,28 +737,33 @@ def __sub__(self, other):
709737 other = lib .item_from_zerodim (other )
710738 if isinstance (other , ABCSeries ):
711739 return NotImplemented
712- elif is_timedelta64_dtype (other ):
740+
741+ # scalar others
742+ elif isinstance (other , (DateOffset , timedelta , np .timedelta64 )):
713743 result = self ._add_delta (- other )
714- elif isinstance (other , (DateOffset , timedelta )):
744+ elif isinstance (other , (datetime , np .datetime64 )):
745+ result = self ._sub_datelike (other )
746+ elif is_integer (other ):
747+ # This check must come after the check for np.timedelta64
748+ # as is_integer returns True for these
749+ result = self .shift (- other )
750+ elif isinstance (other , Period ):
751+ result = self ._sub_period (other )
752+
753+ # array-like others
754+ elif is_timedelta64_dtype (other ):
755+ # TimedeltaIndex, ndarray[timedelta64]
715756 result = self ._add_delta (- other )
716757 elif is_offsetlike (other ):
717758 # Array/Index of DateOffset objects
718- result = self ._sub_offset_array (other )
759+ result = self ._addsub_offset_array (other , operator . sub )
719760 elif isinstance (self , TimedeltaIndex ) and isinstance (other , Index ):
720761 # We checked above for timedelta64_dtype(other) so this
721762 # must be invalid.
722763 raise TypeError ("cannot subtract TimedeltaIndex and {typ}"
723764 .format (typ = type (other ).__name__ ))
724765 elif isinstance (other , DatetimeIndex ):
725766 result = self ._sub_datelike (other )
726- elif is_integer (other ):
727- # This check must come after the check for timedelta64_dtype
728- # or else it will incorrectly catch np.timedelta64 objects
729- result = self .shift (- other )
730- elif isinstance (other , (datetime , np .datetime64 )):
731- result = self ._sub_datelike (other )
732- elif isinstance (other , Period ):
733- result = self ._sub_period (other )
734767 elif isinstance (other , Index ):
735768 raise TypeError ("cannot subtract {typ1} and {typ2}"
736769 .format (typ1 = type (self ).__name__ ,
0 commit comments