@@ -1161,14 +1161,16 @@ def _add_datetimelike_scalar(self, other) -> DatetimeArray:
1161
1161
from pandas .core .arrays .datetimes import tz_to_dtype
1162
1162
1163
1163
assert other is not NaT
1164
- other = Timestamp (other )
1165
- if other is NaT :
1164
+ if isna (other ):
1165
+ # i.e. np.datetime64(" NaT")
1166
1166
# In this case we specifically interpret NaT as a datetime, not
1167
1167
# the timedelta interpretation we would get by returning self + NaT
1168
1168
result = self ._ndarray + NaT .to_datetime64 ().astype (f"M8[{ self ._unit } ]" )
1169
1169
# Preserve our resolution
1170
1170
return DatetimeArray ._simple_new (result , dtype = result .dtype )
1171
1171
1172
+ other = Timestamp (other )
1173
+
1172
1174
if self ._reso != other ._reso :
1173
1175
# Just as with Timestamp/Timedelta, we cast to the higher resolution
1174
1176
if self ._reso < other ._reso :
@@ -1177,22 +1179,24 @@ def _add_datetimelike_scalar(self, other) -> DatetimeArray:
1177
1179
else :
1178
1180
other = other ._as_unit (self ._unit )
1179
1181
1180
- i8 = self .asi8
1181
- result = checked_add_with_arr (i8 , other .value , arr_mask = self ._isnan )
1182
+ other_i8 , o_mask = self ._get_i8_values_and_mask (other )
1183
+ result = checked_add_with_arr (
1184
+ self .asi8 , other_i8 , arr_mask = self ._isnan , b_mask = o_mask
1185
+ )
1186
+ res_values = result .view (f"M8[{ self ._unit } ]" )
1182
1187
1183
1188
dtype = tz_to_dtype (tz = other .tz , unit = self ._unit )
1184
1189
res_values = result .view (f"M8[{ self ._unit } ]" )
1185
- return DatetimeArray ._simple_new (res_values , dtype = dtype , freq = self .freq )
1190
+ new_freq = self ._get_arithmetic_result_freq (other )
1191
+ return DatetimeArray ._simple_new (res_values , dtype = dtype , freq = new_freq )
1186
1192
1187
1193
@final
1188
- def _add_datetime_arraylike (self , other ) -> DatetimeArray :
1194
+ def _add_datetime_arraylike (self , other : DatetimeArray ) -> DatetimeArray :
1189
1195
if not is_timedelta64_dtype (self .dtype ):
1190
1196
raise TypeError (
1191
1197
f"cannot add { type (self ).__name__ } and { type (other ).__name__ } "
1192
1198
)
1193
1199
1194
- # At this point we have already checked that other.dtype is datetime64
1195
- other = ensure_wrapped_if_datetimelike (other )
1196
1200
# defer to DatetimeArray.__add__
1197
1201
return other + self
1198
1202
@@ -1220,15 +1224,14 @@ def _sub_datetimelike_scalar(self, other: datetime | np.datetime64):
1220
1224
return self ._sub_datetimelike (other )
1221
1225
1222
1226
@final
1223
- def _sub_datetime_arraylike (self , other ):
1227
+ def _sub_datetime_arraylike (self , other : DatetimeArray ):
1224
1228
if self .dtype .kind != "M" :
1225
1229
raise TypeError (f"cannot subtract a datelike from a { type (self ).__name__ } " )
1226
1230
1227
1231
if len (self ) != len (other ):
1228
1232
raise ValueError ("cannot add indices of unequal length" )
1229
1233
1230
1234
self = cast ("DatetimeArray" , self )
1231
- other = ensure_wrapped_if_datetimelike (other )
1232
1235
1233
1236
if other ._reso != self ._reso :
1234
1237
if other ._reso < self ._reso :
@@ -1259,16 +1262,6 @@ def _sub_datetimelike(self, other: Timestamp | DatetimeArray) -> TimedeltaArray:
1259
1262
new_freq = self ._get_arithmetic_result_freq (other )
1260
1263
return TimedeltaArray ._simple_new (res_m8 , dtype = res_m8 .dtype , freq = new_freq )
1261
1264
1262
- @final
1263
- def _sub_period (self , other : Period ) -> npt .NDArray [np .object_ ]:
1264
- if not is_period_dtype (self .dtype ):
1265
- raise TypeError (f"cannot subtract Period from a { type (self ).__name__ } " )
1266
-
1267
- # If the operation is well-defined, we return an object-dtype ndarray
1268
- # of DateOffsets. Null entries are filled with pd.NaT
1269
- self ._check_compatible_with (other )
1270
- return self ._sub_periodlike (other )
1271
-
1272
1265
@final
1273
1266
def _add_period (self , other : Period ) -> PeriodArray :
1274
1267
if not is_timedelta64_dtype (self .dtype ):
@@ -1303,9 +1296,7 @@ def _add_timedeltalike_scalar(self, other):
1303
1296
other = Timedelta (other )._as_unit (self ._unit )
1304
1297
return self ._add_timedeltalike (other )
1305
1298
1306
- def _add_timedelta_arraylike (
1307
- self , other : TimedeltaArray | npt .NDArray [np .timedelta64 ]
1308
- ):
1299
+ def _add_timedelta_arraylike (self , other : TimedeltaArray ):
1309
1300
"""
1310
1301
Add a delta of a TimedeltaIndex
1311
1302
@@ -1318,8 +1309,6 @@ def _add_timedelta_arraylike(
1318
1309
if len (self ) != len (other ):
1319
1310
raise ValueError ("cannot add indices of unequal length" )
1320
1311
1321
- other = ensure_wrapped_if_datetimelike (other )
1322
- other = cast ("TimedeltaArray" , other )
1323
1312
self = cast ("DatetimeArray | TimedeltaArray" , self )
1324
1313
1325
1314
if self ._reso != other ._reso :
@@ -1379,21 +1368,17 @@ def _sub_nat(self):
1379
1368
return result .view ("timedelta64[ns]" )
1380
1369
1381
1370
@final
1382
- def _sub_period_array (self , other : PeriodArray ) -> npt .NDArray [np .object_ ]:
1371
+ def _sub_periodlike (self , other : Period | PeriodArray ) -> npt .NDArray [np .object_ ]:
1372
+ # If the operation is well-defined, we return an object-dtype ndarray
1373
+ # of DateOffsets. Null entries are filled with pd.NaT
1383
1374
if not is_period_dtype (self .dtype ):
1384
1375
raise TypeError (
1385
- f"cannot subtract { other . dtype } -dtype from { type (self ).__name__ } "
1376
+ f"cannot subtract { type ( other ). __name__ } from { type (self ).__name__ } "
1386
1377
)
1387
1378
1388
1379
self = cast ("PeriodArray" , self )
1389
- self ._require_matching_freq (other )
1390
-
1391
- return self ._sub_periodlike (other )
1380
+ self ._check_compatible_with (other )
1392
1381
1393
- @final
1394
- def _sub_periodlike (self , other : Period | PeriodArray ) -> npt .NDArray [np .object_ ]:
1395
- # caller is responsible for calling
1396
- # require_matching_freq/check_compatible_with
1397
1382
other_i8 , o_mask = self ._get_i8_values_and_mask (other )
1398
1383
new_i8_data = checked_add_with_arr (
1399
1384
self .asi8 , - other_i8 , arr_mask = self ._isnan , b_mask = o_mask
@@ -1488,6 +1473,7 @@ def _time_shift(
1488
1473
@unpack_zerodim_and_defer ("__add__" )
1489
1474
def __add__ (self , other ):
1490
1475
other_dtype = getattr (other , "dtype" , None )
1476
+ other = ensure_wrapped_if_datetimelike (other )
1491
1477
1492
1478
# scalar others
1493
1479
if other is NaT :
@@ -1548,6 +1534,7 @@ def __radd__(self, other):
1548
1534
def __sub__ (self , other ):
1549
1535
1550
1536
other_dtype = getattr (other , "dtype" , None )
1537
+ other = ensure_wrapped_if_datetimelike (other )
1551
1538
1552
1539
# scalar others
1553
1540
if other is NaT :
@@ -1569,7 +1556,7 @@ def __sub__(self, other):
1569
1556
)
1570
1557
1571
1558
elif isinstance (other , Period ):
1572
- result = self ._sub_period (other )
1559
+ result = self ._sub_periodlike (other )
1573
1560
1574
1561
# array-like others
1575
1562
elif is_timedelta64_dtype (other_dtype ):
@@ -1583,7 +1570,7 @@ def __sub__(self, other):
1583
1570
result = self ._sub_datetime_arraylike (other )
1584
1571
elif is_period_dtype (other_dtype ):
1585
1572
# PeriodIndex
1586
- result = self ._sub_period_array (other )
1573
+ result = self ._sub_periodlike (other )
1587
1574
elif is_integer_dtype (other_dtype ):
1588
1575
if not is_period_dtype (self .dtype ):
1589
1576
raise integer_op_not_supported (self )
0 commit comments