def __rfloordiv__(self, other): if isinstance(other, (ABCSeries, ABCDataFrame, ABCIndexClass)): return NotImplemented other = lib.item_from_zerodim(other) if is_scalar(other): if isinstance(other, (timedelta, np.timedelta64, Tick)): other = Timedelta(other) if other is NaT: # treat this specifically as timedelta-NaT result = np.empty(self.shape, dtype=np.float64) result.fill(np.nan) return result # dispatch to Timedelta implementation result = other.__floordiv__(self._data) return result raise TypeError("Cannot divide {typ} by {cls}" .format(typ=type(other).__name__, cls=type(self).__name__)) if not hasattr(other, "dtype"): # list, tuple other = np.array(other) if len(other) != len(self): raise ValueError("Cannot divide with unequal lengths") elif is_timedelta64_dtype(other): other = type(self)(other) # numpy timedelta64 does not natively support floordiv, so operate # on the i8 values result = other.asi8 // self.asi8 mask = self._isnan | other._isnan if mask.any(): result = result.astype(np.int64) result[mask] = np.nan return result elif is_object_dtype(other): result = [other[n] // self[n] for n in range(len(self))] result = np.array(result) return result else: dtype = getattr(other, "dtype", type(other).__name__) raise TypeError("Cannot divide {typ} by {cls}" .format(typ=dtype, cls=type(self).__name__))
def wrapper(self, other): other = lib.item_from_zerodim(other) if isinstance(other, (ABCDataFrame, ABCSeries, ABCIndexClass)): return NotImplemented if _is_convertible_to_td(other) or other is NaT: try: other = Timedelta(other) except ValueError: # failed to parse as timedelta return ops.invalid_comparison(self, other, op) result = op(self.view('i8'), other.value) if isna(other): result.fill(nat_result) elif not is_list_like(other): return ops.invalid_comparison(self, other, op) elif len(other) != len(self): raise ValueError("Lengths must match") else: try: other = type(self)._from_sequence(other)._data except (ValueError, TypeError): return ops.invalid_comparison(self, other, op) result = op(self.view('i8'), other.view('i8')) result = com.values_from_object(result) o_mask = np.array(isna(other)) if o_mask.any(): result[o_mask] = nat_result if self._hasnans: result[self._isnan] = nat_result return result
def _box_func(self, x) -> Union[Timedelta, NaTType]: return Timedelta(x, unit="ns")
def __floordiv__(self, other): if isinstance(other, (ABCSeries, ABCDataFrame, ABCIndexClass)): return NotImplemented other = lib.item_from_zerodim(other) if is_scalar(other): if isinstance(other, (timedelta, np.timedelta64, Tick)): other = Timedelta(other) if other is NaT: # treat this specifically as timedelta-NaT result = np.empty(self.shape, dtype=np.float64) result.fill(np.nan) return result # dispatch to Timedelta implementation result = other.__rfloordiv__(self._data) return result # at this point we should only have numeric scalars; anything # else will raise result = self.asi8 // other result[self._isnan] = iNaT freq = None if self.freq is not None: # Note: freq gets division, not floor-division freq = self.freq / other return type(self)(result.view('m8[ns]'), freq=freq) if not hasattr(other, "dtype"): # list, tuple other = np.array(other) if len(other) != len(self): raise ValueError("Cannot divide with unequal lengths") elif is_timedelta64_dtype(other): other = type(self)(other) # numpy timedelta64 does not natively support floordiv, so operate # on the i8 values result = self.asi8 // other.asi8 mask = self._isnan | other._isnan if mask.any(): result = result.astype(np.int64) result[mask] = np.nan return result elif is_object_dtype(other): result = [self[n] // other[n] for n in range(len(self))] result = np.array(result) if lib.infer_dtype(result, skipna=False) == 'timedelta': result, _ = sequence_to_td64ns(result) return type(self)(result) return result elif is_integer_dtype(other) or is_float_dtype(other): result = self._data // other return type(self)(result) else: dtype = getattr(other, "dtype", type(other).__name__) raise TypeError("Cannot divide {typ} by {cls}" .format(typ=dtype, cls=type(self).__name__))
def __floordiv__(self, other): if is_scalar(other): if isinstance(other, (timedelta, np.timedelta64, Tick)): other = Timedelta(other) if other is NaT: # treat this specifically as timedelta-NaT result = np.empty(self.shape, dtype=np.float64) result.fill(np.nan) return result # dispatch to Timedelta implementation result = other.__rfloordiv__(self._data) return result # at this point we should only have numeric scalars; anything # else will raise result = self.asi8 // other result[self._isnan] = iNaT freq = None if self.freq is not None: # Note: freq gets division, not floor-division freq = self.freq / other if freq.nanos == 0 and self.freq.nanos != 0: # e.g. if self.freq is Nano(1) then dividing by 2 # rounds down to zero freq = None return type(self)(result.view("m8[ns]"), freq=freq) if not hasattr(other, "dtype"): # list, tuple other = np.array(other) if len(other) != len(self): raise ValueError("Cannot divide with unequal lengths") elif is_timedelta64_dtype(other.dtype): other = type(self)(other) # numpy timedelta64 does not natively support floordiv, so operate # on the i8 values result = self.asi8 // other.asi8 mask = self._isnan | other._isnan if mask.any(): result = result.astype(np.int64) result[mask] = np.nan return result elif is_object_dtype(other.dtype): result = [self[n] // other[n] for n in range(len(self))] result = np.array(result) if lib.infer_dtype(result, skipna=False) == "timedelta": result, _ = sequence_to_td64ns(result) return type(self)(result) return result elif is_integer_dtype(other.dtype) or is_float_dtype(other.dtype): result = self._data // other return type(self)(result) else: dtype = getattr(other, "dtype", type(other).__name__) raise TypeError(f"Cannot divide {dtype} by {type(self).__name__}")
def _box_func(self): return lambda x: Timedelta(x, unit="ns")
def __floordiv__(self, other): if isinstance(other, (ABCSeries, ABCDataFrame, ABCIndexClass)): return NotImplemented other = lib.item_from_zerodim(other) if is_scalar(other): if isinstance(other, (timedelta, np.timedelta64, Tick)): other = Timedelta(other) if other is NaT: # treat this specifically as timedelta-NaT result = np.empty(self.shape, dtype=np.float64) result.fill(np.nan) return result # dispatch to Timedelta implementation result = other.__rfloordiv__(self._data) return result # at this point we should only have numeric scalars; anything # else will raise result = self.asi8 // other result[self._isnan] = iNaT freq = None if self.freq is not None: # Note: freq gets division, not floor-division freq = self.freq / other return type(self)(result.view('m8[ns]'), freq=freq) if not hasattr(other, "dtype"): # list, tuple other = np.array(other) if len(other) != len(self): raise ValueError("Cannot divide with unequal lengths") elif is_timedelta64_dtype(other): other = type(self)(other) # numpy timedelta64 does not natively support floordiv, so operate # on the i8 values result = self.asi8 // other.asi8 mask = self._isnan | other._isnan if mask.any(): result = result.astype(np.int64) result[mask] = np.nan return result elif is_object_dtype(other): result = [self[n] // other[n] for n in range(len(self))] result = np.array(result) if lib.infer_dtype(result) == 'timedelta': result, _ = sequence_to_td64ns(result) return type(self)(result) return result elif is_integer_dtype(other) or is_float_dtype(other): result = self._data // other return type(self)(result) else: dtype = getattr(other, "dtype", type(other).__name__) raise TypeError("Cannot divide {typ} by {cls}".format( typ=dtype, cls=type(self).__name__))
def _scalar_from_string(self, value) -> Timedelta | NaTType: return Timedelta(value)
def _adjust_to_origin(arg, origin, unit): """ Helper function for to_datetime. Adjust input argument to the specified origin Parameters ---------- arg : list, tuple, ndarray, Series, Index date to be adjusted origin : 'julian' or Timestamp origin offset for the arg unit : str passed unit from to_datetime, must be 'D' Returns ------- ndarray or scalar of adjusted date(s) """ if origin == "julian": original = arg j0 = Timestamp(0).to_julian_date() if unit != "D": raise ValueError("unit must be 'D' for origin='julian'") try: arg = arg - j0 except TypeError as err: raise ValueError( "incompatible 'arg' type for given 'origin'='julian'") from err # preemptively check this for a nice range j_max = Timestamp.max.to_julian_date() - j0 j_min = Timestamp.min.to_julian_date() - j0 if np.any(arg > j_max) or np.any(arg < j_min): raise OutOfBoundsDatetime( f"{original} is Out of Bounds for origin='julian'") else: # arg must be numeric if not ((is_scalar(arg) and (is_integer(arg) or is_float(arg))) or is_numeric_dtype(np.asarray(arg))): raise ValueError( f"'{arg}' is not compatible with origin='{origin}'; " "it must be numeric with a unit specified") # we are going to offset back to unix / epoch time try: offset = Timestamp(origin) except OutOfBoundsDatetime as err: raise OutOfBoundsDatetime( f"origin {origin} is Out of Bounds") from err except ValueError as err: raise ValueError( f"origin {origin} cannot be converted to a Timestamp") from err if offset.tz is not None: raise ValueError(f"origin offset {offset} must be tz-naive") td_offset = offset - Timestamp(0) # convert the offset to the unit of the arg # this should be lossless in terms of precision ioffset = td_offset // Timedelta(1, unit=unit) # scalars & ndarray-like can handle the addition if is_list_like(arg) and not isinstance( arg, (ABCSeries, Index, np.ndarray)): arg = np.asarray(arg) arg = arg + ioffset return arg
def to_offset(freq): """ Return DateOffset object from string or tuple representation or datetime.timedelta object Parameters ---------- freq : str, tuple, datetime.timedelta, DateOffset or None Returns ------- delta : DateOffset None if freq is None Raises ------ ValueError If freq is an invalid frequency See Also -------- pandas.DateOffset Examples -------- >>> to_offset('5min') <5 * Minutes> >>> to_offset('1D1H') <25 * Hours> >>> to_offset(('W', 2)) <2 * Weeks: weekday=6> >>> to_offset((2, 'B')) <2 * BusinessDays> >>> to_offset(datetime.timedelta(days=1)) <Day> >>> to_offset(Hour()) <Hour> """ if freq is None: return None if isinstance(freq, DateOffset): return freq if isinstance(freq, tuple): name = freq[0] stride = freq[1] if isinstance(stride, compat.string_types): name, stride = stride, name name, _ = libfreqs._base_and_stride(name) delta = get_offset(name) * stride elif isinstance(freq, timedelta): delta = None freq = Timedelta(freq) try: for name in freq.components._fields: offset = _name_to_offset_map[name] stride = getattr(freq.components, name) if stride != 0: offset = stride * offset if delta is None: delta = offset else: delta = delta + offset except Exception: raise ValueError(libfreqs.INVALID_FREQ_ERR_MSG.format(freq)) else: delta = None stride_sign = None try: splitted = re.split(libfreqs.opattern, freq) if splitted[-1] != '' and not splitted[-1].isspace(): # the last element must be blank raise ValueError('last element must be blank') for sep, stride, name in zip(splitted[0::4], splitted[1::4], splitted[2::4]): if sep != '' and not sep.isspace(): raise ValueError('separator must be spaces') prefix = libfreqs._lite_rule_alias.get(name) or name if stride_sign is None: stride_sign = -1 if stride.startswith('-') else 1 if not stride: stride = 1 if prefix in Resolution._reso_str_bump_map.keys(): stride, name = Resolution.get_stride_from_decimal( float(stride), prefix) stride = int(stride) offset = get_offset(name) offset = offset * int(np.fabs(stride) * stride_sign) if delta is None: delta = offset else: delta = delta + offset except Exception: raise ValueError(libfreqs.INVALID_FREQ_ERR_MSG.format(freq)) if delta is None: raise ValueError(libfreqs.INVALID_FREQ_ERR_MSG.format(freq)) return delta
def _scalar_from_string(self, value) -> Union[Timedelta, NaTType]: return Timedelta(value)
def __init__( self, obj: FrameOrSeries, com: Optional[float] = None, span: Optional[float] = None, halflife: Optional[Union[float, TimedeltaConvertibleTypes]] = None, alpha: Optional[float] = None, min_periods: int = 0, adjust: bool = True, ignore_na: bool = False, axis: Axis = 0, times: Optional[Union[str, np.ndarray, FrameOrSeries]] = None, ): super().__init__( obj=obj, min_periods=max(int(min_periods), 1), on=None, center=False, closed=None, method="single", axis=axis, ) self.com = com self.span = span self.halflife = halflife self.alpha = alpha self.adjust = adjust self.ignore_na = ignore_na self.times = times if self.times is not None: if not self.adjust: raise NotImplementedError( "times is not supported with adjust=False.") if isinstance(self.times, str): self.times = self._selected_obj[self.times] if not is_datetime64_ns_dtype(self.times): raise ValueError("times must be datetime64[ns] dtype.") # error: Argument 1 to "len" has incompatible type "Union[str, ndarray, # FrameOrSeries, None]"; expected "Sized" if len(self.times) != len(obj): # type: ignore[arg-type] raise ValueError( "times must be the same length as the object.") if not isinstance(self.halflife, (str, datetime.timedelta)): raise ValueError( "halflife must be a string or datetime.timedelta object") if isna(self.times).any(): raise ValueError("Cannot convert NaT values to integer") # error: Item "str" of "Union[str, ndarray, FrameOrSeries, None]" has no # attribute "view" # error: Item "None" of "Union[str, ndarray, FrameOrSeries, None]" has no # attribute "view" _times = np.asarray( self.times.view(np.int64), dtype=np.float64 # type: ignore[union-attr] ) _halflife = float(Timedelta(self.halflife).value) self._deltas = np.diff(_times) / _halflife # Halflife is no longer applicable when calculating COM # But allow COM to still be calculated if the user passes other decay args if common.count_not_none(self.com, self.span, self.alpha) > 0: self._com = get_center_of_mass(self.com, self.span, None, self.alpha) else: self._com = 1.0 else: if self.halflife is not None and isinstance( self.halflife, (str, datetime.timedelta)): raise ValueError( "halflife can only be a timedelta convertible argument if " "times is not None.") # Without times, points are equally spaced self._deltas = np.ones(max(len(self.obj) - 1, 0), dtype=np.float64) self._com = get_center_of_mass( # error: Argument 3 to "get_center_of_mass" has incompatible type # "Union[float, Any, None, timedelta64, signedinteger[_64Bit]]"; # expected "Optional[float]" self.com, self.span, self.halflife, # type: ignore[arg-type] self.alpha, )
def test_to_offset_pd_timedelta(kwargs, expected): # see gh-9064 td = Timedelta(**kwargs) result = to_offset(td) assert result == expected
def _box_func(self, x: np.timedelta64) -> Timedelta | NaTType: y = x.view("i8") if y == NaT.value: return NaT return Timedelta._from_value_and_reso(y, reso=self._reso)
def __truediv__(self, other): # timedelta / X is well-defined for timedelta-like or numeric X if isinstance(other, self._recognized_scalars): other = Timedelta(other) # mypy assumes that __new__ returns an instance of the class # github.com/python/mypy/issues/1020 if cast("Timedelta | NaTType", other) is NaT: # specifically timedelta64-NaT result = np.empty(self.shape, dtype=np.float64) result.fill(np.nan) return result # otherwise, dispatch to Timedelta implementation return self._ndarray / other elif lib.is_scalar(other): # assume it is numeric result = self._ndarray / other freq = None if self.freq is not None: # Tick division is not implemented, so operate on Timedelta freq = self.freq.delta / other freq = to_offset(freq) return type(self)._simple_new(result, dtype=result.dtype, freq=freq) if not hasattr(other, "dtype"): # e.g. list, tuple other = np.array(other) if len(other) != len(self): raise ValueError("Cannot divide vectors with unequal lengths") elif is_timedelta64_dtype(other.dtype): # let numpy handle it return self._ndarray / other elif is_object_dtype(other.dtype): # We operate on raveled arrays to avoid problems in inference # on NaT # TODO: tests with non-nano srav = self.ravel() orav = other.ravel() result_list = [srav[n] / orav[n] for n in range(len(srav))] result = np.array(result_list).reshape(self.shape) # We need to do dtype inference in order to keep DataFrame ops # behavior consistent with Series behavior inferred = lib.infer_dtype(result, skipna=False) if inferred == "timedelta": flat = result.ravel() result = type(self)._from_sequence(flat).reshape(result.shape) elif inferred == "floating": result = result.astype(float) elif inferred == "datetime": # GH#39750 this occurs when result is all-NaT, in which case # we want to interpret these NaTs as td64. # We construct an all-td64NaT result. # error: Incompatible types in assignment (expression has type # "TimedeltaArray", variable has type "ndarray[Any, # dtype[floating[_64Bit]]]") result = self * np.nan # type: ignore[assignment] return result else: result = self._ndarray / other return type(self)._simple_new(result, dtype=result.dtype)
class TestTimestampArithmetic: def test_overflow_offset(self): # no overflow expected stamp = Timestamp("2000/1/1") offset_no_overflow = to_offset("D") * 100 expected = Timestamp("2000/04/10") assert stamp + offset_no_overflow == expected assert offset_no_overflow + stamp == expected expected = Timestamp("1999/09/23") assert stamp - offset_no_overflow == expected def test_overflow_offset_raises(self): # xref https://github.com/statsmodels/statsmodels/issues/3374 # ends up multiplying really large numbers which overflow stamp = Timestamp("2017-01-13 00:00:00") offset_overflow = 20169940 * offsets.Day(1) msg = ("the add operation between " r"\<-?\d+ \* Days\> and \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} " "will overflow") lmsg = "|".join([ "Python int too large to convert to C long", "int too big to convert" ]) with pytest.raises(OverflowError, match=lmsg): stamp + offset_overflow with pytest.raises(OverflowError, match=msg): offset_overflow + stamp with pytest.raises(OverflowError, match=lmsg): stamp - offset_overflow # xref https://github.com/pandas-dev/pandas/issues/14080 # used to crash, so check for proper overflow exception stamp = Timestamp("2000/1/1") offset_overflow = to_offset("D") * 100**5 with pytest.raises(OverflowError, match=lmsg): stamp + offset_overflow with pytest.raises(OverflowError, match=msg): offset_overflow + stamp with pytest.raises(OverflowError, match=lmsg): stamp - offset_overflow def test_overflow_timestamp_raises(self): # https://github.com/pandas-dev/pandas/issues/31774 msg = "Result is too large" a = Timestamp("2101-01-01 00:00:00") b = Timestamp("1688-01-01 00:00:00") with pytest.raises(OutOfBoundsDatetime, match=msg): a - b # but we're OK for timestamp and datetime.datetime assert (a - b.to_pydatetime()) == (a.to_pydatetime() - b) def test_delta_preserve_nanos(self): val = Timestamp(1337299200000000123) result = val + timedelta(1) assert result.nanosecond == val.nanosecond def test_rsub_dtscalars(self, tz_naive_fixture): # In particular, check that datetime64 - Timestamp works GH#28286 td = Timedelta(1235345642000) ts = Timestamp.now(tz_naive_fixture) other = ts + td assert other - ts == td assert other.to_pydatetime() - ts == td if tz_naive_fixture is None: assert other.to_datetime64() - ts == td else: msg = "subtraction must have" with pytest.raises(TypeError, match=msg): other.to_datetime64() - ts def test_timestamp_sub_datetime(self): dt = datetime(2013, 10, 12) ts = Timestamp(datetime(2013, 10, 13)) assert (ts - dt).days == 1 assert (dt - ts).days == -1 def test_addition_subtraction_types(self): # Assert on the types resulting from Timestamp +/- various date/time # objects dt = datetime(2014, 3, 4) td = timedelta(seconds=1) # build a timestamp with a frequency, since then it supports # addition/subtraction of integers with tm.assert_produces_warning(FutureWarning, match="The 'freq' argument"): # freq deprecated ts = Timestamp(dt, freq="D") msg = "Addition/subtraction of integers" with pytest.raises(TypeError, match=msg): # GH#22535 add/sub with integers is deprecated ts + 1 with pytest.raises(TypeError, match=msg): ts - 1 # Timestamp + datetime not supported, though subtraction is supported # and yields timedelta more tests in tseries/base/tests/test_base.py assert type(ts - dt) == Timedelta assert type(ts + td) == Timestamp assert type(ts - td) == Timestamp # Timestamp +/- datetime64 not supported, so not tested (could possibly # assert error raised?) td64 = np.timedelta64(1, "D") assert type(ts + td64) == Timestamp assert type(ts - td64) == Timestamp @pytest.mark.parametrize( "freq, td, td64", [ ("S", timedelta(seconds=1), np.timedelta64(1, "s")), ("min", timedelta(minutes=1), np.timedelta64(1, "m")), ("H", timedelta(hours=1), np.timedelta64(1, "h")), ("D", timedelta(days=1), np.timedelta64(1, "D")), ("W", timedelta(weeks=1), np.timedelta64(1, "W")), ("M", None, np.timedelta64(1, "M")), ], ) @pytest.mark.filterwarnings( "ignore:Timestamp.freq is deprecated:FutureWarning") @pytest.mark.filterwarnings("ignore:The 'freq' argument:FutureWarning") def test_addition_subtraction_preserve_frequency(self, freq, td, td64): ts = Timestamp("2014-03-05 00:00:00", freq=freq) original_freq = ts.freq assert (ts + 1 * original_freq).freq == original_freq assert (ts - 1 * original_freq).freq == original_freq if td is not None: # timedelta does not support months as unit assert (ts + td).freq == original_freq assert (ts - td).freq == original_freq assert (ts + td64).freq == original_freq assert (ts - td64).freq == original_freq @pytest.mark.parametrize( "td", [Timedelta(hours=3), np.timedelta64(3, "h"), timedelta(hours=3)]) def test_radd_tdscalar(self, td): # GH#24775 timedelta64+Timestamp should not raise ts = Timestamp.now() assert td + ts == ts + td @pytest.mark.parametrize( "other,expected_difference", [ (np.timedelta64(-123, "ns"), -123), (np.timedelta64(1234567898, "ns"), 1234567898), (np.timedelta64(-123, "us"), -123000), (np.timedelta64(-123, "ms"), -123000000), ], ) def test_timestamp_add_timedelta64_unit(self, other, expected_difference): ts = Timestamp(datetime.utcnow()) result = ts + other valdiff = result.value - ts.value assert valdiff == expected_difference @pytest.mark.parametrize( "ts", [ Timestamp("1776-07-04"), Timestamp("1776-07-04", tz="UTC"), ], ) @pytest.mark.parametrize( "other", [ 1, np.int64(1), np.array([1, 2], dtype=np.int32), np.array([3, 4], dtype=np.uint64), ], ) def test_add_int_with_freq(self, ts, other): msg = "Addition/subtraction of integers and integer-arrays" with pytest.raises(TypeError, match=msg): ts + other with pytest.raises(TypeError, match=msg): other + ts with pytest.raises(TypeError, match=msg): ts - other msg = "unsupported operand type" with pytest.raises(TypeError, match=msg): other - ts @pytest.mark.parametrize("shape", [(6, ), (2, 3)]) def test_addsub_m8ndarray(self, shape): # GH#33296 ts = Timestamp("2020-04-04 15:45") other = np.arange(6).astype("m8[h]").reshape(shape) result = ts + other ex_stamps = [ts + Timedelta(hours=n) for n in range(6)] expected = np.array([x.asm8 for x in ex_stamps], dtype="M8[ns]").reshape(shape) tm.assert_numpy_array_equal(result, expected) result = other + ts tm.assert_numpy_array_equal(result, expected) result = ts - other ex_stamps = [ts - Timedelta(hours=n) for n in range(6)] expected = np.array([x.asm8 for x in ex_stamps], dtype="M8[ns]").reshape(shape) tm.assert_numpy_array_equal(result, expected) msg = r"unsupported operand type\(s\) for -: 'numpy.ndarray' and 'Timestamp'" with pytest.raises(TypeError, match=msg): other - ts @pytest.mark.parametrize("shape", [(6, ), (2, 3)]) def test_addsub_m8ndarray_tzaware(self, shape): # GH#33296 ts = Timestamp("2020-04-04 15:45", tz="US/Pacific") other = np.arange(6).astype("m8[h]").reshape(shape) result = ts + other ex_stamps = [ts + Timedelta(hours=n) for n in range(6)] expected = np.array(ex_stamps).reshape(shape) tm.assert_numpy_array_equal(result, expected) result = other + ts tm.assert_numpy_array_equal(result, expected) result = ts - other ex_stamps = [ts - Timedelta(hours=n) for n in range(6)] expected = np.array(ex_stamps).reshape(shape) tm.assert_numpy_array_equal(result, expected) msg = r"unsupported operand type\(s\) for -: 'numpy.ndarray' and 'Timestamp'" with pytest.raises(TypeError, match=msg): other - ts
def _box_func(self, x) -> Timedelta | NaTType: return Timedelta(x, unit="ns")
def to_offset(freq) -> Optional[DateOffset]: """ Return DateOffset object from string or tuple representation or datetime.timedelta object. Parameters ---------- freq : str, tuple, datetime.timedelta, DateOffset or None Returns ------- DateOffset None if freq is None. Raises ------ ValueError If freq is an invalid frequency See Also -------- DateOffset Examples -------- >>> to_offset("5min") <5 * Minutes> >>> to_offset("1D1H") <25 * Hours> >>> to_offset(("W", 2)) <2 * Weeks: weekday=6> >>> to_offset((2, "B")) <2 * BusinessDays> >>> to_offset(pd.Timedelta(days=1)) <Day> >>> to_offset(Hour()) <Hour> """ if freq is None: return None if isinstance(freq, DateOffset): return freq if isinstance(freq, tuple): name = freq[0] stride = freq[1] if isinstance(stride, str): name, stride = stride, name name, _ = libfreqs._base_and_stride(name) delta = _get_offset(name) * stride elif isinstance(freq, timedelta): delta = None freq = Timedelta(freq) try: for name in freq.components._fields: offset = _name_to_offset_map[name] stride = getattr(freq.components, name) if stride != 0: offset = stride * offset if delta is None: delta = offset else: delta = delta + offset except ValueError as err: raise ValueError(libfreqs.INVALID_FREQ_ERR_MSG.format(freq)) from err else: delta = None stride_sign = None try: split = re.split(libfreqs.opattern, freq) if split[-1] != "" and not split[-1].isspace(): # the last element must be blank raise ValueError("last element must be blank") for sep, stride, name in zip(split[0::4], split[1::4], split[2::4]): if sep != "" and not sep.isspace(): raise ValueError("separator must be spaces") prefix = libfreqs._lite_rule_alias.get(name) or name if stride_sign is None: stride_sign = -1 if stride.startswith("-") else 1 if not stride: stride = 1 if prefix in Resolution._reso_str_bump_map.keys(): stride, name = Resolution.get_stride_from_decimal( float(stride), prefix ) stride = int(stride) offset = _get_offset(name) offset = offset * int(np.fabs(stride) * stride_sign) if delta is None: delta = offset else: delta = delta + offset except (ValueError, TypeError) as err: raise ValueError(libfreqs.INVALID_FREQ_ERR_MSG.format(freq)) from err if delta is None: raise ValueError(libfreqs.INVALID_FREQ_ERR_MSG.format(freq)) return delta
def __rmod__(self, other): # Note: This is a naive implementation, can likely be optimized if isinstance(other, self._recognized_scalars): other = Timedelta(other) return other - (other // self) * self
def __truediv__(self, other): # timedelta / X is well-defined for timedelta-like or numeric X if isinstance(other, self._recognized_scalars): other = Timedelta(other) if other is NaT: # specifically timedelta64-NaT result = np.empty(self.shape, dtype=np.float64) result.fill(np.nan) return result # otherwise, dispatch to Timedelta implementation return self._ndarray / other elif lib.is_scalar(other): # assume it is numeric result = self._ndarray / other freq = None if self.freq is not None: # Tick division is not implemented, so operate on Timedelta freq = self.freq.delta / other return type(self)(result, freq=freq) if not hasattr(other, "dtype"): # e.g. list, tuple other = np.array(other) if len(other) != len(self): raise ValueError("Cannot divide vectors with unequal lengths") elif is_timedelta64_dtype(other.dtype): # let numpy handle it return self._ndarray / other elif is_object_dtype(other.dtype): # We operate on raveled arrays to avoid problems in inference # on NaT srav = self.ravel() orav = other.ravel() result = [srav[n] / orav[n] for n in range(len(srav))] result = np.array(result).reshape(self.shape) # We need to do dtype inference in order to keep DataFrame ops # behavior consistent with Series behavior inferred = lib.infer_dtype(result, skipna=False) if inferred == "timedelta": flat = result.ravel() result = type(self)._from_sequence(flat).reshape(result.shape) elif inferred == "floating": result = result.astype(float) elif inferred == "datetime": # GH#39750 this occurs when result is all-NaT, in which case # we want to interpret these NaTs as td64. # We construct an all-td64NaT result. result = self * np.nan return result else: result = self._ndarray / other return type(self)(result)
def convert_value(self, v) -> "TermValue": """ convert the expression that is in the term to something that is accepted by pytables """ def stringify(value): if self.encoding is not None: encoder = partial(pprint_thing_encoded, encoding=self.encoding) else: encoder = pprint_thing return encoder(value) kind = _ensure_decoded(self.kind) meta = _ensure_decoded(self.meta) if kind == "datetime64" or kind == "datetime": if isinstance(v, (int, float)): v = stringify(v) v = _ensure_decoded(v) v = Timestamp(v) if v.tz is not None: v = v.tz_convert("UTC") return TermValue(v, v.value, kind) elif kind == "timedelta64" or kind == "timedelta": v = Timedelta(v, unit="s").value return TermValue(int(v), v, kind) elif meta == "category": metadata = com.values_from_object(self.metadata) result = metadata.searchsorted(v, side="left") # result returns 0 if v is first element or if v is not in metadata # check that metadata contains v if not result and v not in metadata: result = -1 return TermValue(result, result, "integer") elif kind == "integer": v = int(float(v)) return TermValue(v, v, kind) elif kind == "float": v = float(v) return TermValue(v, v, kind) elif kind == "bool": if isinstance(v, str): v = not v.strip().lower() in [ "false", "f", "no", "n", "none", "0", "[]", "{}", "", ] else: v = bool(v) return TermValue(v, v, kind) elif isinstance(v, str): # string quoting return TermValue(v, stringify(v), "string") else: raise TypeError( "Cannot compare {v} of type {typ} to {kind} column".format( v=v, typ=type(v), kind=kind ) )
def __floordiv__(self, other): if is_scalar(other): if isinstance(other, self._recognized_scalars): other = Timedelta(other) if other is NaT: # treat this specifically as timedelta-NaT result = np.empty(self.shape, dtype=np.float64) result.fill(np.nan) return result # dispatch to Timedelta implementation result = other.__rfloordiv__(self._ndarray) return result # at this point we should only have numeric scalars; anything # else will raise result = self._ndarray // other freq = None if self.freq is not None: # Note: freq gets division, not floor-division freq = self.freq / other if freq.nanos == 0 and self.freq.nanos != 0: # e.g. if self.freq is Nano(1) then dividing by 2 # rounds down to zero freq = None return type(self)(result, freq=freq) if not hasattr(other, "dtype"): # list, tuple other = np.array(other) if len(other) != len(self): raise ValueError("Cannot divide with unequal lengths") elif is_timedelta64_dtype(other.dtype): other = type(self)(other) # numpy timedelta64 does not natively support floordiv, so operate # on the i8 values result = self.asi8 // other.asi8 mask = self._isnan | other._isnan if mask.any(): result = result.astype(np.float64) np.putmask(result, mask, np.nan) return result elif is_object_dtype(other.dtype): # error: Incompatible types in assignment (expression has type # "List[Any]", variable has type "ndarray") srav = self.ravel() orav = other.ravel() res_list = [srav[n] // orav[n] for n in range(len(srav))] result_flat = np.asarray(res_list) inferred = lib.infer_dtype(result_flat, skipna=False) result = result_flat.reshape(self.shape) if inferred == "timedelta": result, _ = sequence_to_td64ns(result) return type(self)(result) if inferred == "datetime": # GH#39750 occurs when result is all-NaT, which in this # case should be interpreted as td64nat. This can only # occur when self is all-td64nat return self * np.nan return result elif is_integer_dtype(other.dtype) or is_float_dtype(other.dtype): result = self._ndarray // other return type(self)(result) else: dtype = getattr(other, "dtype", type(other).__name__) raise TypeError(f"Cannot divide {dtype} by {type(self).__name__}")
def _scalar_from_string(self, value): return Timedelta(value)
def convert_value(self, v) -> TermValue: """ convert the expression that is in the term to something that is accepted by pytables """ def stringify(value): if self.encoding is not None: return pprint_thing_encoded(value, encoding=self.encoding) return pprint_thing(value) kind = ensure_decoded(self.kind) meta = ensure_decoded(self.meta) if kind == "datetime64" or kind == "datetime": if isinstance(v, (int, float)): v = stringify(v) v = ensure_decoded(v) v = Timestamp(v) if v.tz is not None: v = v.tz_convert("UTC") return TermValue(v, v.value, kind) elif kind == "timedelta64" or kind == "timedelta": if isinstance(v, str): v = Timedelta(v).value else: v = Timedelta(v, unit="s").value return TermValue(int(v), v, kind) elif meta == "category": metadata = extract_array(self.metadata, extract_numpy=True) if v not in metadata: result = -1 else: # error: Incompatible types in assignment (expression has type # "Union[Any, ndarray]", variable has type "int") result = metadata.searchsorted( # type: ignore[assignment] v, side="left") return TermValue(result, result, "integer") elif kind == "integer": v = int(float(v)) return TermValue(v, v, kind) elif kind == "float": v = float(v) return TermValue(v, v, kind) elif kind == "bool": if isinstance(v, str): v = not v.strip().lower() in [ "false", "f", "no", "n", "none", "0", "[]", "{}", "", ] else: v = bool(v) return TermValue(v, v, kind) elif isinstance(v, str): # string quoting return TermValue(v, stringify(v), "string") else: raise TypeError( f"Cannot compare {v} of type {type(v)} to {kind} column")
def __mod__(self, other): # Note: This is a naive implementation, can likely be optimized if isinstance(other, (timedelta, np.timedelta64, Tick)): other = Timedelta(other) return self - (self // other) * other
def _parse_with_reso(self, label: str): # the "with_reso" is a no-op for TimedeltaIndex parsed = Timedelta(label) return parsed, None
def _parsed_string_to_bounds(self, reso, parsed: Timedelta): # reso is unused, included to match signature of DTI/PI lbound = parsed.round(parsed.resolution_string) rbound = lbound + to_offset(parsed.resolution_string) - Timedelta(1, "ns") return lbound, rbound
def __init__( self, obj, com: Optional[float] = None, span: Optional[float] = None, halflife: Optional[Union[float, TimedeltaConvertibleTypes]] = None, alpha: Optional[float] = None, min_periods: int = 0, adjust: bool = True, ignore_na: bool = False, axis: int = 0, times: Optional[Union[str, np.ndarray, FrameOrSeries]] = None, ): super().__init__( obj=obj, min_periods=max(int(min_periods), 1), on=None, center=False, closed=None, method="single", axis=axis, ) self.com = com self.span = span self.halflife = halflife self.alpha = alpha self.adjust = adjust self.ignore_na = ignore_na self.times = times if self.times is not None: if isinstance(self.times, str): self.times = self._selected_obj[self.times] if not is_datetime64_ns_dtype(self.times): raise ValueError("times must be datetime64[ns] dtype.") if len(self.times) != len(obj): raise ValueError("times must be the same length as the object.") if not isinstance(self.halflife, (str, datetime.timedelta)): raise ValueError( "halflife must be a string or datetime.timedelta object" ) if isna(self.times).any(): raise ValueError("Cannot convert NaT values to integer") _times = np.asarray(self.times.view(np.int64), dtype=np.float64) _halflife = float(Timedelta(self.halflife).value) self._deltas = np.diff(_times) / _halflife # Halflife is no longer applicable when calculating COM # But allow COM to still be calculated if the user passes other decay args if common.count_not_none(self.com, self.span, self.alpha) > 0: self._com = get_center_of_mass(self.com, self.span, None, self.alpha) else: self._com = 1.0 else: if self.halflife is not None and isinstance( self.halflife, (str, datetime.timedelta) ): raise ValueError( "halflife can only be a timedelta convertible argument if " "times is not None." ) # Without times, points are equally spaced self._deltas = np.ones(max(len(self.obj) - 1, 0), dtype=np.float64) self._com = get_center_of_mass( self.com, self.span, self.halflife, self.alpha )