@@ -92,6 +92,9 @@ cdef class _NaT(datetime):
92
92
# int64_t value
93
93
# object freq
94
94
95
+ # higher than np.ndarray and np.matrix
96
+ __array_priority__ = 100
97
+
95
98
def __hash__ (_NaT self ):
96
99
# py3k needs this defined here
97
100
return hash (self .value)
@@ -103,61 +106,102 @@ cdef class _NaT(datetime):
103
106
if ndim == - 1 :
104
107
return _nat_scalar_rules[op]
105
108
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 :
107
115
if is_datetime64_object(other):
108
116
return _nat_scalar_rules[op]
109
117
else :
110
118
raise TypeError (' Cannot compare type %r with type %r ' %
111
119
(type (self ).__name__, type (other).__name__))
120
+
112
121
# Note: instead of passing "other, self, _reverse_ops[op]", we observe
113
122
# that `_nat_scalar_rules` is invariant under `_reverse_ops`,
114
123
# rendering it unnecessary.
115
124
return PyObject_RichCompare(other, self , op)
116
125
117
126
def __add__ (self , other ):
127
+ if self is not c_NaT:
128
+ # cython __radd__ semantics
129
+ self , other = other, self
130
+
118
131
if PyDateTime_Check(other):
119
132
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
121
137
elif hasattr (other, ' delta' ):
122
138
# Timedelta, offsets.Tick, offsets.Week
123
139
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
133
155
134
156
def __sub__ (self , other ):
135
157
# Duplicate some logic from _Timestamp.__sub__ to avoid needing
136
158
# 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
+
137
167
if PyDateTime_Check(other):
138
- return NaT
168
+ return c_NaT
139
169
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
141
176
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
145
181
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
149
203
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
161
205
162
206
def __pos__ (self ):
163
207
return NaT
0 commit comments