2
2
Base and utility classes for tseries type pandas objects.
3
3
"""
4
4
import warnings
5
-
5
+ import operator
6
6
from datetime import datetime , timedelta
7
7
8
8
from pandas import compat
9
9
from pandas .compat .numpy import function as nv
10
10
from pandas .core .tools .timedeltas import to_timedelta
11
11
12
12
import 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
+
13
19
from pandas .core .dtypes .common import (
14
20
_ensure_int64 ,
15
21
is_dtype_equal ,
25
31
is_integer_dtype ,
26
32
is_object_dtype ,
27
33
is_string_dtype ,
34
+ is_period_dtype ,
28
35
is_timedelta64_dtype )
29
36
from pandas .core .dtypes .generic import (
30
37
ABCIndex , ABCSeries , ABCPeriodIndex , ABCIndexClass )
31
38
from pandas .core .dtypes .missing import isna
32
39
from pandas .core import common as com , algorithms , ops
33
40
from pandas .core .algorithms import checked_add_with_arr
34
- from pandas .errors import NullFrequencyError
41
+ from pandas .errors import NullFrequencyError , PerformanceWarning
35
42
import 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
40
43
41
44
from pandas .core .indexes .base import Index , _index_shared_docs
42
45
from pandas .util ._decorators import Appender , cache_readonly
@@ -637,13 +640,33 @@ def _sub_datelike(self, other):
637
640
def _sub_period (self , other ):
638
641
return NotImplemented
639
642
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
643
646
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 )
647
670
648
671
@classmethod
649
672
def _add_datetimelike_methods (cls ):
@@ -660,26 +683,31 @@ def __add__(self, other):
660
683
other = lib .item_from_zerodim (other )
661
684
if isinstance (other , ABCSeries ):
662
685
return NotImplemented
663
- elif is_timedelta64_dtype (other ):
686
+
687
+ # scalar others
688
+ elif isinstance (other , (DateOffset , timedelta , np .timedelta64 )):
664
689
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]
666
700
result = self ._add_delta (other )
667
701
elif is_offsetlike (other ):
668
702
# Array/Index of DateOffset objects
669
- result = self ._add_offset_array (other )
703
+ result = self ._addsub_offset_array (other , operator . add )
670
704
elif isinstance (self , TimedeltaIndex ) and isinstance (other , Index ):
671
705
if hasattr (other , '_add_delta' ):
672
706
# i.e. DatetimeIndex, TimedeltaIndex, or PeriodIndex
673
707
result = other ._add_delta (self )
674
708
else :
675
709
raise TypeError ("cannot add TimedeltaIndex and {typ}"
676
710
.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 )
683
711
elif isinstance (other , Index ):
684
712
result = self ._add_datelike (other )
685
713
elif is_integer_dtype (other ) and self .freq is None :
@@ -709,28 +737,33 @@ def __sub__(self, other):
709
737
other = lib .item_from_zerodim (other )
710
738
if isinstance (other , ABCSeries ):
711
739
return NotImplemented
712
- elif is_timedelta64_dtype (other ):
740
+
741
+ # scalar others
742
+ elif isinstance (other , (DateOffset , timedelta , np .timedelta64 )):
713
743
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]
715
756
result = self ._add_delta (- other )
716
757
elif is_offsetlike (other ):
717
758
# Array/Index of DateOffset objects
718
- result = self ._sub_offset_array (other )
759
+ result = self ._addsub_offset_array (other , operator . sub )
719
760
elif isinstance (self , TimedeltaIndex ) and isinstance (other , Index ):
720
761
# We checked above for timedelta64_dtype(other) so this
721
762
# must be invalid.
722
763
raise TypeError ("cannot subtract TimedeltaIndex and {typ}"
723
764
.format (typ = type (other ).__name__ ))
724
765
elif isinstance (other , DatetimeIndex ):
725
766
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 )
734
767
elif isinstance (other , Index ):
735
768
raise TypeError ("cannot subtract {typ1} and {typ2}"
736
769
.format (typ1 = type (self ).__name__ ,
0 commit comments