@@ -38,7 +38,10 @@ from pandas._libs.tslibs.conversion cimport (
38
38
cast_from_unit,
39
39
precision_from_unit,
40
40
)
41
- from pandas._libs.tslibs.dtypes cimport npy_unit_to_abbrev
41
+ from pandas._libs.tslibs.dtypes cimport (
42
+ get_supported_reso,
43
+ npy_unit_to_abbrev,
44
+ )
42
45
from pandas._libs.tslibs.nattype cimport (
43
46
NPY_NAT,
44
47
c_NaT as NaT,
@@ -939,6 +942,7 @@ cdef _timedelta_from_value_and_reso(int64_t value, NPY_DATETIMEUNIT reso):
939
942
cdef:
940
943
_Timedelta td_base
941
944
945
+ assert value != NPY_NAT
942
946
# For millisecond and second resos, we cannot actually pass int(value) because
943
947
# many cases would fall outside of the pytimedelta implementation bounds.
944
948
# We pass 0 instead, and override seconds, microseconds, days.
@@ -1704,10 +1708,27 @@ class Timedelta(_Timedelta):
1704
1708
elif PyDelta_Check(value):
1705
1709
value = convert_to_timedelta64(value, ' ns' )
1706
1710
elif is_timedelta64_object(value):
1707
- if get_timedelta64_value(value) == NPY_NAT:
1711
+ # Retain the resolution if possible, otherwise cast to the nearest
1712
+ # supported resolution.
1713
+ new_value = get_timedelta64_value(value)
1714
+ if new_value == NPY_NAT:
1708
1715
# i.e. np.timedelta64("NaT")
1709
1716
return NaT
1710
- value = ensure_td64ns(value)
1717
+
1718
+ reso = get_datetime64_unit(value)
1719
+ new_reso = get_supported_reso(reso)
1720
+ if reso != NPY_DATETIMEUNIT.NPY_FR_GENERIC:
1721
+ try :
1722
+ new_value = convert_reso(
1723
+ get_timedelta64_value(value),
1724
+ reso,
1725
+ new_reso,
1726
+ round_ok = True ,
1727
+ )
1728
+ except (OverflowError , OutOfBoundsDatetime) as err:
1729
+ raise OutOfBoundsTimedelta(value) from err
1730
+ return cls ._from_value_and_reso(new_value, reso = new_reso)
1731
+
1711
1732
elif is_tick_object(value):
1712
1733
value = np.timedelta64(value.nanos, ' ns' )
1713
1734
elif is_integer_object(value) or is_float_object(value):
@@ -1917,9 +1938,15 @@ class Timedelta(_Timedelta):
1917
1938
1918
1939
if other.dtype.kind == ' m' :
1919
1940
# also timedelta-like
1920
- if self ._reso != NPY_FR_ns:
1921
- raise NotImplementedError
1922
- return _broadcast_floordiv_td64(self .value, other, _floordiv)
1941
+ # TODO: could suppress
1942
+ # RuntimeWarning: invalid value encountered in floor_divide
1943
+ result = self .asm8 // other
1944
+ mask = other.view(" i8" ) == NPY_NAT
1945
+ if mask.any():
1946
+ # We differ from numpy here
1947
+ result = result.astype(" f8" )
1948
+ result[mask] = np.nan
1949
+ return result
1923
1950
1924
1951
elif other.dtype.kind in [' i' , ' u' , ' f' ]:
1925
1952
if other.ndim == 0 :
@@ -1951,9 +1978,15 @@ class Timedelta(_Timedelta):
1951
1978
1952
1979
if other.dtype.kind == ' m' :
1953
1980
# also timedelta-like
1954
- if self ._reso != NPY_FR_ns:
1955
- raise NotImplementedError
1956
- return _broadcast_floordiv_td64(self .value, other, _rfloordiv)
1981
+ # TODO: could suppress
1982
+ # RuntimeWarning: invalid value encountered in floor_divide
1983
+ result = other // self .asm8
1984
+ mask = other.view(" i8" ) == NPY_NAT
1985
+ if mask.any():
1986
+ # We differ from numpy here
1987
+ result = result.astype(" f8" )
1988
+ result[mask] = np.nan
1989
+ return result
1957
1990
1958
1991
# Includes integer array // Timedelta, disallowed in GH#19761
1959
1992
raise TypeError (f' Invalid dtype {other.dtype} for __floordiv__' )
@@ -2003,45 +2036,3 @@ cdef bint _should_cast_to_timedelta(object obj):
2003
2036
return (
2004
2037
is_any_td_scalar(obj) or obj is None or obj is NaT or isinstance (obj, str )
2005
2038
)
2006
-
2007
-
2008
- cdef _floordiv(int64_t value, right):
2009
- return value // right
2010
-
2011
-
2012
- cdef _rfloordiv(int64_t value, right):
2013
- # analogous to referencing operator.div, but there is no operator.rfloordiv
2014
- return right // value
2015
-
2016
-
2017
- cdef _broadcast_floordiv_td64(
2018
- int64_t value,
2019
- ndarray other,
2020
- object (* operation)(int64_t value, object right)
2021
- ):
2022
- """
2023
- Boilerplate code shared by Timedelta.__floordiv__ and
2024
- Timedelta.__rfloordiv__ because np.timedelta64 does not implement these.
2025
-
2026
- Parameters
2027
- ----------
2028
- value : int64_t; `self.value` from a Timedelta object
2029
- other : ndarray[timedelta64[ns]]
2030
- operation : function, either _floordiv or _rfloordiv
2031
-
2032
- Returns
2033
- -------
2034
- result : varies based on `other`
2035
- """
2036
- # assumes other.dtype.kind == 'm', i.e. other is timedelta-like
2037
- # assumes other.ndim != 0
2038
-
2039
- # We need to watch out for np.timedelta64('NaT').
2040
- mask = other.view(' i8' ) == NPY_NAT
2041
-
2042
- res = operation(value, other.astype(' m8[ns]' , copy = False ).astype(' i8' ))
2043
-
2044
- if mask.any():
2045
- res = res.astype(' f8' )
2046
- res[mask] = np.nan
2047
- return res
0 commit comments