@@ -51,6 +51,15 @@ DT64NS_DTYPE = np.dtype('M8[ns]')
51
51
TD64NS_DTYPE = np.dtype(' m8[ns]' )
52
52
53
53
54
+ class OutOfBoundsTimedelta (ValueError ):
55
+ """
56
+ Raised when encountering a timedelta value that cannot be represented
57
+ as a timedelta64[ns].
58
+ """
59
+ # Timedelta analogue to OutOfBoundsDatetime
60
+ pass
61
+
62
+
54
63
# ----------------------------------------------------------------------
55
64
# Unit Conversion Helpers
56
65
@@ -228,11 +237,34 @@ def ensure_timedelta64ns(arr: ndarray, copy: bool=True):
228
237
229
238
Returns
230
239
-------
231
- result : ndarray with dtype timedelta64[ns]
232
-
240
+ ndarray[timedelta64[ns]]
233
241
"""
234
- return arr.astype(TD64NS_DTYPE, copy = copy)
235
- # TODO: check for overflows when going from a lower-resolution to nanos
242
+ assert arr.dtype.kind == " m" , arr.dtype
243
+
244
+ if arr.dtype == TD64NS_DTYPE:
245
+ return arr.copy() if copy else arr
246
+
247
+ # Re-use the datetime64 machinery to do an overflow-safe `astype`
248
+ dtype = arr.dtype.str.replace(" m8" , " M8" )
249
+ dummy = arr.view(dtype)
250
+ try :
251
+ dt64_result = ensure_datetime64ns(dummy, copy)
252
+ except OutOfBoundsDatetime as err:
253
+ # Re-write the exception in terms of timedelta64 instead of dt64
254
+
255
+ # Find the value that we are going to report as causing an overflow
256
+ tdmin = arr.min()
257
+ tdmax = arr.max()
258
+ if np.abs(tdmin) >= np.abs(tdmax):
259
+ bad_val = tdmin
260
+ else :
261
+ bad_val = tdmax
262
+
263
+ raise OutOfBoundsTimedelta(
264
+ f" Out of bounds for nanosecond {arr.dtype.name} {bad_val}"
265
+ )
266
+
267
+ return dt64_result.view(TD64NS_DTYPE)
236
268
237
269
238
270
# ----------------------------------------------------------------------
0 commit comments