@@ -92,6 +92,9 @@ cdef class _NaT(datetime):
9292 # int64_t value
9393 # object freq
9494
95+ # higher than np.ndarray and np.matrix
96+ __array_priority__ = 100
97+
9598 def __hash__ (_NaT self ):
9699 # py3k needs this defined here
97100 return hash (self .value)
@@ -103,61 +106,102 @@ cdef class _NaT(datetime):
103106 if ndim == - 1 :
104107 return _nat_scalar_rules[op]
105108
106- if ndim == 0 :
109+ elif util.is_array(other):
110+ result = np.empty(other.shape, dtype = np.bool_)
111+ result.fill(_nat_scalar_rules[op])
112+ return result
113+
114+ elif ndim == 0 :
107115 if is_datetime64_object(other):
108116 return _nat_scalar_rules[op]
109117 else :
110118 raise TypeError (' Cannot compare type %r with type %r ' %
111119 (type (self ).__name__, type (other).__name__))
120+
112121 # Note: instead of passing "other, self, _reverse_ops[op]", we observe
113122 # that `_nat_scalar_rules` is invariant under `_reverse_ops`,
114123 # rendering it unnecessary.
115124 return PyObject_RichCompare(other, self , op)
116125
117126 def __add__ (self , other ):
127+ if self is not c_NaT:
128+ # cython __radd__ semantics
129+ self , other = other, self
130+
118131 if PyDateTime_Check(other):
119132 return c_NaT
120-
133+ elif PyDelta_Check(other):
134+ return c_NaT
135+ elif is_datetime64_object(other) or is_timedelta64_object(other):
136+ return c_NaT
121137 elif hasattr (other, ' delta' ):
122138 # Timedelta, offsets.Tick, offsets.Week
123139 return c_NaT
124- elif getattr (other, ' _typ' , None ) in [' dateoffset' , ' series' ,
125- ' period' , ' datetimeindex' ,
126- ' datetimearray' ,
127- ' timedeltaindex' ,
128- ' timedeltaarray' ]:
129- # Duplicate logic in _Timestamp.__add__ to avoid needing
130- # to subclass; allows us to @final(_Timestamp.__add__)
131- return NotImplemented
132- return c_NaT
140+
141+ elif is_integer_object(other) or util.is_period_object(other):
142+ # For Period compat
143+ # TODO: the integer behavior is deprecated, remove it
144+ return c_NaT
145+
146+ elif util.is_array(other):
147+ if other.dtype.kind in ' mM' :
148+ # If we are adding to datetime64, we treat NaT as timedelta
149+ # Either way, result dtype is datetime64
150+ result = np.empty(other.shape, dtype = " datetime64[ns]" )
151+ result.fill(" NaT" )
152+ return result
153+
154+ return NotImplemented
133155
134156 def __sub__ (self , other ):
135157 # Duplicate some logic from _Timestamp.__sub__ to avoid needing
136158 # to subclass; allows us to @final(_Timestamp.__sub__)
159+ cdef:
160+ bint is_rsub = False
161+
162+ if self is not c_NaT:
163+ # cython __rsub__ semantics
164+ self , other = other, self
165+ is_rsub = True
166+
137167 if PyDateTime_Check(other):
138- return NaT
168+ return c_NaT
139169 elif PyDelta_Check(other):
140- return NaT
170+ return c_NaT
171+ elif is_datetime64_object(other) or is_timedelta64_object(other):
172+ return c_NaT
173+ elif hasattr (other, ' delta' ):
174+ # offsets.Tick, offsets.Week
175+ return c_NaT
141176
142- elif getattr (other, ' _typ' , None ) == ' datetimeindex' :
143- # a Timestamp-DatetimeIndex -> yields a negative TimedeltaIndex
144- return - other.__sub__ (self )
177+ elif is_integer_object(other) or util.is_period_object(other):
178+ # For Period compat
179+ # TODO: the integer behavior is deprecated, remove it
180+ return c_NaT
145181
146- elif getattr (other, ' _typ' , None ) == ' timedeltaindex' :
147- # a Timestamp-TimedeltaIndex -> yields a negative TimedeltaIndex
148- return (- other).__add__(self )
182+ elif util.is_array(other):
183+ if other.dtype.kind == ' m' :
184+ if not is_rsub:
185+ # NaT - timedelta64 we treat NaT as datetime64, so result
186+ # is datetime64
187+ result = np.empty(other.shape, dtype = " datetime64[ns]" )
188+ result.fill(" NaT" )
189+ return result
190+
191+ # timedelta64 - NaT we have to treat NaT as timedelta64
192+ # for this to be meaningful, and the result is timedelta64
193+ result = np.empty(other.shape, dtype = " timedelta64[ns]" )
194+ result.fill(" NaT" )
195+ return result
196+
197+ elif other.dtype.kind == ' M' :
198+ # We treat NaT as a datetime, so regardless of whether this is
199+ # NaT - other or other - NaT, the result is timedelta64
200+ result = np.empty(other.shape, dtype = " timedelta64[ns]" )
201+ result.fill(" NaT" )
202+ return result
149203
150- elif hasattr (other, ' delta' ):
151- # offsets.Tick, offsets.Week
152- neg_other = - other
153- return self + neg_other
154-
155- elif getattr (other, ' _typ' , None ) in [' period' , ' series' ,
156- ' periodindex' , ' dateoffset' ,
157- ' datetimearray' ,
158- ' timedeltaarray' ]:
159- return NotImplemented
160- return NaT
204+ return NotImplemented
161205
162206 def __pos__ (self ):
163207 return NaT
0 commit comments