@@ -102,6 +102,12 @@ def __init__(self, value=None, freq=None, ordinal=None,
102102 converted = other .asfreq (freq )
103103 self .ordinal = converted .ordinal
104104
105+ elif com ._is_null_datelike_scalar (value ) or value in tslib ._nat_strings :
106+ self .ordinal = tslib .iNaT
107+ if freq is None :
108+ raise ValueError ("If value is NaT, freq cannot be None "
109+ "because it cannot be inferred" )
110+
105111 elif isinstance (value , compat .string_types ) or com .is_integer (value ):
106112 if com .is_integer (value ):
107113 value = str (value )
@@ -136,6 +142,8 @@ def __eq__(self, other):
136142 if isinstance (other , Period ):
137143 if other .freq != self .freq :
138144 raise ValueError ("Cannot compare non-conforming periods" )
145+ if self .ordinal == tslib .iNaT or other .ordinal == tslib .iNaT :
146+ return False
139147 return (self .ordinal == other .ordinal
140148 and _gfc (self .freq ) == _gfc (other .freq ))
141149 return NotImplemented
@@ -148,26 +156,38 @@ def __hash__(self):
148156
149157 def __add__ (self , other ):
150158 if com .is_integer (other ):
151- return Period (ordinal = self .ordinal + other , freq = self .freq )
159+ if self .ordinal == tslib .iNaT :
160+ ordinal = self .ordinal
161+ else :
162+ ordinal = self .ordinal + other
163+ return Period (ordinal = ordinal , freq = self .freq )
152164 else : # pragma: no cover
153- raise TypeError ( other )
165+ return NotImplemented
154166
155167 def __sub__ (self , other ):
156168 if com .is_integer (other ):
157- return Period (ordinal = self .ordinal - other , freq = self .freq )
169+ if self .ordinal == tslib .iNaT :
170+ ordinal = self .ordinal
171+ else :
172+ ordinal = self .ordinal - other
173+ return Period (ordinal = ordinal , freq = self .freq )
158174 if isinstance (other , Period ):
159175 if other .freq != self .freq :
160176 raise ValueError ("Cannot do arithmetic with "
161177 "non-conforming periods" )
178+ if self .ordinal == tslib .iNaT or other .ordinal == tslib .iNaT :
179+ return Period (ordinal = tslib .iNaT , freq = self .freq )
162180 return self .ordinal - other .ordinal
163181 else : # pragma: no cover
164- raise TypeError ( other )
182+ return NotImplemented
165183
166184 def _comp_method (func , name ):
167185 def f (self , other ):
168186 if isinstance (other , Period ):
169187 if other .freq != self .freq :
170188 raise ValueError ("Cannot compare non-conforming periods" )
189+ if self .ordinal == tslib .iNaT or other .ordinal == tslib .iNaT :
190+ return False
171191 return func (self .ordinal , other .ordinal )
172192 else :
173193 raise TypeError (other )
@@ -213,7 +233,10 @@ def start_time(self):
213233
214234 @property
215235 def end_time (self ):
216- ordinal = (self + 1 ).start_time .value - 1
236+ if self .ordinal == tslib .iNaT :
237+ ordinal = self .ordinal
238+ else :
239+ ordinal = (self + 1 ).start_time .value - 1
217240 return Timestamp (ordinal )
218241
219242 def to_timestamp (self , freq = None , how = 'start' , tz = None ):
@@ -480,6 +503,11 @@ def _period_index_cmp(opname):
480503 Wrap comparison operations to convert datetime-like to datetime64
481504 """
482505 def wrapper (self , other ):
506+ if opname == '__ne__' :
507+ fill_value = True
508+ else :
509+ fill_value = False
510+
483511 if isinstance (other , Period ):
484512 func = getattr (self .values , opname )
485513 if other .freq != self .freq :
@@ -489,12 +517,26 @@ def wrapper(self, other):
489517 elif isinstance (other , PeriodIndex ):
490518 if other .freq != self .freq :
491519 raise AssertionError ("Frequencies must be equal" )
492- return getattr (self .values , opname )(other .values )
520+
521+ result = getattr (self .values , opname )(other .values )
522+
523+ mask = (com .mask_missing (self .values , tslib .iNaT ) |
524+ com .mask_missing (other .values , tslib .iNaT ))
525+ if mask .any ():
526+ result [mask ] = fill_value
527+
528+ return result
493529 else :
494530 other = Period (other , freq = self .freq )
495531 func = getattr (self .values , opname )
496532 result = func (other .ordinal )
497533
534+ if other .ordinal == tslib .iNaT :
535+ result .fill (fill_value )
536+ mask = self .values == tslib .iNaT
537+ if mask .any ():
538+ result [mask ] = fill_value
539+
498540 return result
499541 return wrapper
500542
@@ -712,7 +754,7 @@ def asof_locs(self, where, mask):
712754
713755 @property
714756 def asobject (self ):
715- return Index (self ._box_values (self .values ), dtype = object )
757+ return Index (self ._box_values (self .values ), name = self . name , dtype = object )
716758
717759 def _array_values (self ):
718760 return self .asobject
@@ -768,11 +810,7 @@ def asfreq(self, freq=None, how='E'):
768810
769811 end = how == 'E'
770812 new_data = tslib .period_asfreq_arr (self .values , base1 , base2 , end )
771-
772- result = new_data .view (PeriodIndex )
773- result .name = self .name
774- result .freq = freq
775- return result
813+ return self ._simple_new (new_data , self .name , freq = freq )
776814
777815 def to_datetime (self , dayfirst = False ):
778816 return self .to_timestamp ()
@@ -868,16 +906,23 @@ def shift(self, n):
868906 -------
869907 shifted : PeriodIndex
870908 """
871- if n == 0 :
872- return self
873-
874- return PeriodIndex (data = self . values + n , freq = self .freq )
909+ mask = self . values == tslib . iNaT
910+ values = self . values + n
911+ values [ mask ] = tslib . iNaT
912+ return PeriodIndex (data = values , name = self . name , freq = self .freq )
875913
876914 def __add__ (self , other ):
877- return PeriodIndex (ordinal = self .values + other , freq = self .freq )
915+ try :
916+ return self .shift (other )
917+ except TypeError :
918+ # self.values + other raises TypeError for invalid input
919+ return NotImplemented
878920
879921 def __sub__ (self , other ):
880- return PeriodIndex (ordinal = self .values - other , freq = self .freq )
922+ try :
923+ return self .shift (- other )
924+ except TypeError :
925+ return NotImplemented
881926
882927 @property
883928 def inferred_type (self ):
@@ -1207,8 +1252,11 @@ def _get_ordinal_range(start, end, periods, freq):
12071252 is_start_per = isinstance (start , Period )
12081253 is_end_per = isinstance (end , Period )
12091254
1210- if is_start_per and is_end_per and ( start .freq != end .freq ) :
1255+ if is_start_per and is_end_per and start .freq != end .freq :
12111256 raise ValueError ('Start and end must have same freq' )
1257+ if ((is_start_per and start .ordinal == tslib .iNaT ) or
1258+ (is_end_per and end .ordinal == tslib .iNaT )):
1259+ raise ValueError ('Start and end must not be NaT' )
12121260
12131261 if freq is None :
12141262 if is_start_per :
0 commit comments