@@ -950,14 +950,18 @@ cdef _timedelta_from_value_and_reso(int64_t value, NPY_DATETIMEUNIT reso):
950
950
cdef:
951
951
_Timedelta td_base
952
952
953
+ # For millisecond and second resos, we cannot actually pass int(value) because
954
+ # many cases would fall outside of the pytimedelta implementation bounds.
955
+ # We pass 0 instead, and override seconds, microseconds, days.
956
+ # In principle we could pass 0 for ns and us too.
953
957
if reso == NPY_FR_ns:
954
958
td_base = _Timedelta.__new__ (Timedelta, microseconds = int (value) // 1000 )
955
959
elif reso == NPY_DATETIMEUNIT.NPY_FR_us:
956
960
td_base = _Timedelta.__new__ (Timedelta, microseconds = int (value))
957
961
elif reso == NPY_DATETIMEUNIT.NPY_FR_ms:
958
- td_base = _Timedelta.__new__ (Timedelta, milliseconds = int (value) )
962
+ td_base = _Timedelta.__new__ (Timedelta, milliseconds = 0 )
959
963
elif reso == NPY_DATETIMEUNIT.NPY_FR_s:
960
- td_base = _Timedelta.__new__ (Timedelta, seconds = int (value) )
964
+ td_base = _Timedelta.__new__ (Timedelta, seconds = 0 )
961
965
# Other resolutions are disabled but could potentially be implemented here:
962
966
# elif reso == NPY_DATETIMEUNIT.NPY_FR_m:
963
967
# td_base = _Timedelta.__new__(Timedelta, minutes=int(value))
@@ -977,6 +981,34 @@ cdef _timedelta_from_value_and_reso(int64_t value, NPY_DATETIMEUNIT reso):
977
981
return td_base
978
982
979
983
984
+ class MinMaxReso :
985
+ """
986
+ We need to define min/max/resolution on both the Timedelta _instance_
987
+ and Timedelta class. On an instance, these depend on the object's _reso.
988
+ On the class, we default to the values we would get with nanosecond _reso.
989
+ """
990
+ def __init__ (self , name ):
991
+ self ._name = name
992
+
993
+ def __get__ (self , obj , type = None ):
994
+ if self ._name == " min" :
995
+ val = np.iinfo(np.int64).min + 1
996
+ elif self ._name == " max" :
997
+ val = np.iinfo(np.int64).max
998
+ else :
999
+ assert self ._name == " resolution"
1000
+ val = 1
1001
+
1002
+ if obj is None :
1003
+ # i.e. this is on the class, default to nanos
1004
+ return Timedelta(val)
1005
+ else :
1006
+ return Timedelta._from_value_and_reso(val, obj._reso)
1007
+
1008
+ def __set__ (self , obj , value ):
1009
+ raise AttributeError (f" {self._name} is not settable." )
1010
+
1011
+
980
1012
# Similar to Timestamp/datetime, this is a construction requirement for
981
1013
# timedeltas that we need to do object instantiation in python. This will
982
1014
# serve as a C extension type that shadows the Python class, where we do any
@@ -990,6 +1022,36 @@ cdef class _Timedelta(timedelta):
990
1022
991
1023
# higher than np.ndarray and np.matrix
992
1024
__array_priority__ = 100
1025
+ min = MinMaxReso(" min" )
1026
+ max = MinMaxReso(" max" )
1027
+ resolution = MinMaxReso(" resolution" )
1028
+
1029
+ @property
1030
+ def days (self ) -> int: # TODO(cython3 ): make cdef property
1031
+ # NB: using the python C-API PyDateTime_DELTA_GET_DAYS will fail
1032
+ # (or be incorrect)
1033
+ self ._ensure_components()
1034
+ return self ._d
1035
+
1036
+ @property
1037
+ def seconds (self ) -> int: # TODO(cython3 ): make cdef property
1038
+ # NB: using the python C-API PyDateTime_DELTA_GET_SECONDS will fail
1039
+ # (or be incorrect)
1040
+ self ._ensure_components()
1041
+ return self ._h * 3600 + self ._m * 60 + self ._s
1042
+
1043
+ @property
1044
+ def microseconds (self ) -> int: # TODO(cython3 ): make cdef property
1045
+ # NB: using the python C-API PyDateTime_DELTA_GET_MICROSECONDS will fail
1046
+ # (or be incorrect)
1047
+ self ._ensure_components()
1048
+ return self ._ms * 1000 + self ._us
1049
+
1050
+ def total_seconds (self ) -> float:
1051
+ """Total seconds in the duration."""
1052
+ # We need to override bc we overrided days/seconds/microseconds
1053
+ # TODO: add nanos/1e9?
1054
+ return self.days * 24 * 3600 + self.seconds + self.microseconds / 1_000_000
993
1055
994
1056
@property
995
1057
def freq(self ) -> None:
@@ -1979,9 +2041,3 @@ cdef _broadcast_floordiv_td64(
1979
2041
res = res.astype(' f8' )
1980
2042
res[mask] = np.nan
1981
2043
return res
1982
-
1983
-
1984
- # resolution in ns
1985
- Timedelta.min = Timedelta(np.iinfo(np.int64).min + 1 )
1986
- Timedelta.max = Timedelta(np.iinfo(np.int64).max)
1987
- Timedelta.resolution = Timedelta(nanoseconds = 1 )
0 commit comments