@@ -102,6 +102,12 @@ def __init__(self, value=None, freq=None, ordinal=None,
102
102
converted = other .asfreq (freq )
103
103
self .ordinal = converted .ordinal
104
104
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
+
105
111
elif isinstance (value , compat .string_types ) or com .is_integer (value ):
106
112
if com .is_integer (value ):
107
113
value = str (value )
@@ -136,6 +142,8 @@ def __eq__(self, other):
136
142
if isinstance (other , Period ):
137
143
if other .freq != self .freq :
138
144
raise ValueError ("Cannot compare non-conforming periods" )
145
+ if self .ordinal == tslib .iNaT or other .ordinal == tslib .iNaT :
146
+ return False
139
147
return (self .ordinal == other .ordinal
140
148
and _gfc (self .freq ) == _gfc (other .freq ))
141
149
return NotImplemented
@@ -148,26 +156,38 @@ def __hash__(self):
148
156
149
157
def __add__ (self , other ):
150
158
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 )
152
164
else : # pragma: no cover
153
- raise TypeError ( other )
165
+ return NotImplemented
154
166
155
167
def __sub__ (self , other ):
156
168
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 )
158
174
if isinstance (other , Period ):
159
175
if other .freq != self .freq :
160
176
raise ValueError ("Cannot do arithmetic with "
161
177
"non-conforming periods" )
178
+ if self .ordinal == tslib .iNaT or other .ordinal == tslib .iNaT :
179
+ return Period (ordinal = tslib .iNaT , freq = self .freq )
162
180
return self .ordinal - other .ordinal
163
181
else : # pragma: no cover
164
- raise TypeError ( other )
182
+ return NotImplemented
165
183
166
184
def _comp_method (func , name ):
167
185
def f (self , other ):
168
186
if isinstance (other , Period ):
169
187
if other .freq != self .freq :
170
188
raise ValueError ("Cannot compare non-conforming periods" )
189
+ if self .ordinal == tslib .iNaT or other .ordinal == tslib .iNaT :
190
+ return False
171
191
return func (self .ordinal , other .ordinal )
172
192
else :
173
193
raise TypeError (other )
@@ -213,7 +233,10 @@ def start_time(self):
213
233
214
234
@property
215
235
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
217
240
return Timestamp (ordinal )
218
241
219
242
def to_timestamp (self , freq = None , how = 'start' , tz = None ):
@@ -480,6 +503,11 @@ def _period_index_cmp(opname):
480
503
Wrap comparison operations to convert datetime-like to datetime64
481
504
"""
482
505
def wrapper (self , other ):
506
+ if opname == '__ne__' :
507
+ fill_value = True
508
+ else :
509
+ fill_value = False
510
+
483
511
if isinstance (other , Period ):
484
512
func = getattr (self .values , opname )
485
513
if other .freq != self .freq :
@@ -489,12 +517,26 @@ def wrapper(self, other):
489
517
elif isinstance (other , PeriodIndex ):
490
518
if other .freq != self .freq :
491
519
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
493
529
else :
494
530
other = Period (other , freq = self .freq )
495
531
func = getattr (self .values , opname )
496
532
result = func (other .ordinal )
497
533
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
+
498
540
return result
499
541
return wrapper
500
542
@@ -712,7 +754,7 @@ def asof_locs(self, where, mask):
712
754
713
755
@property
714
756
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 )
716
758
717
759
def _array_values (self ):
718
760
return self .asobject
@@ -768,11 +810,7 @@ def asfreq(self, freq=None, how='E'):
768
810
769
811
end = how == 'E'
770
812
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 )
776
814
777
815
def to_datetime (self , dayfirst = False ):
778
816
return self .to_timestamp ()
@@ -868,16 +906,23 @@ def shift(self, n):
868
906
-------
869
907
shifted : PeriodIndex
870
908
"""
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 )
875
913
876
914
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
878
920
879
921
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
881
926
882
927
@property
883
928
def inferred_type (self ):
@@ -1207,8 +1252,11 @@ def _get_ordinal_range(start, end, periods, freq):
1207
1252
is_start_per = isinstance (start , Period )
1208
1253
is_end_per = isinstance (end , Period )
1209
1254
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 :
1211
1256
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' )
1212
1260
1213
1261
if freq is None :
1214
1262
if is_start_per :
0 commit comments