123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- """
- timedelta support tools
- """
- from __future__ import annotations
- from datetime import timedelta
- from typing import (
- TYPE_CHECKING,
- overload,
- )
- import numpy as np
- from pandas._libs import lib
- from pandas._libs.tslibs import (
- NaT,
- NaTType,
- )
- from pandas._libs.tslibs.timedeltas import (
- Timedelta,
- parse_timedelta_unit,
- )
- from pandas.core.dtypes.common import is_list_like
- from pandas.core.dtypes.generic import (
- ABCIndex,
- ABCSeries,
- )
- from pandas.core.arrays.timedeltas import sequence_to_td64ns
- if TYPE_CHECKING:
- from pandas._libs.tslibs.timedeltas import UnitChoices
- from pandas._typing import (
- ArrayLike,
- DateTimeErrorChoices,
- )
- from pandas import (
- Index,
- Series,
- TimedeltaIndex,
- )
- @overload
- def to_timedelta(
- arg: str | float | timedelta,
- unit: UnitChoices | None = ...,
- errors: DateTimeErrorChoices = ...,
- ) -> Timedelta:
- ...
- @overload
- def to_timedelta(
- arg: Series,
- unit: UnitChoices | None = ...,
- errors: DateTimeErrorChoices = ...,
- ) -> Series:
- ...
- @overload
- def to_timedelta(
- arg: list | tuple | range | ArrayLike | Index,
- unit: UnitChoices | None = ...,
- errors: DateTimeErrorChoices = ...,
- ) -> TimedeltaIndex:
- ...
- def to_timedelta(
- arg: str
- | int
- | float
- | timedelta
- | list
- | tuple
- | range
- | ArrayLike
- | Index
- | Series,
- unit: UnitChoices | None = None,
- errors: DateTimeErrorChoices = "raise",
- ) -> Timedelta | TimedeltaIndex | Series:
- """
- Convert argument to timedelta.
- Timedeltas are absolute differences in times, expressed in difference
- units (e.g. days, hours, minutes, seconds). This method converts
- an argument from a recognized timedelta format / value into
- a Timedelta type.
- Parameters
- ----------
- arg : str, timedelta, list-like or Series
- The data to be converted to timedelta.
- .. versionchanged:: 2.0
- Strings with units 'M', 'Y' and 'y' do not represent
- unambiguous timedelta values and will raise an exception.
- unit : str, optional
- Denotes the unit of the arg for numeric `arg`. Defaults to ``"ns"``.
- Possible values:
- * 'W'
- * 'D' / 'days' / 'day'
- * 'hours' / 'hour' / 'hr' / 'h'
- * 'm' / 'minute' / 'min' / 'minutes' / 'T'
- * 'S' / 'seconds' / 'sec' / 'second'
- * 'ms' / 'milliseconds' / 'millisecond' / 'milli' / 'millis' / 'L'
- * 'us' / 'microseconds' / 'microsecond' / 'micro' / 'micros' / 'U'
- * 'ns' / 'nanoseconds' / 'nano' / 'nanos' / 'nanosecond' / 'N'
- .. versionchanged:: 1.1.0
- Must not be specified when `arg` context strings and
- ``errors="raise"``.
- errors : {'ignore', 'raise', 'coerce'}, default 'raise'
- - If 'raise', then invalid parsing will raise an exception.
- - If 'coerce', then invalid parsing will be set as NaT.
- - If 'ignore', then invalid parsing will return the input.
- Returns
- -------
- timedelta
- If parsing succeeded.
- Return type depends on input:
- - list-like: TimedeltaIndex of timedelta64 dtype
- - Series: Series of timedelta64 dtype
- - scalar: Timedelta
- See Also
- --------
- DataFrame.astype : Cast argument to a specified dtype.
- to_datetime : Convert argument to datetime.
- convert_dtypes : Convert dtypes.
- Notes
- -----
- If the precision is higher than nanoseconds, the precision of the duration is
- truncated to nanoseconds for string inputs.
- Examples
- --------
- Parsing a single string to a Timedelta:
- >>> pd.to_timedelta('1 days 06:05:01.00003')
- Timedelta('1 days 06:05:01.000030')
- >>> pd.to_timedelta('15.5us')
- Timedelta('0 days 00:00:00.000015500')
- Parsing a list or array of strings:
- >>> pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan'])
- TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015500', NaT],
- dtype='timedelta64[ns]', freq=None)
- Converting numbers by specifying the `unit` keyword argument:
- >>> pd.to_timedelta(np.arange(5), unit='s')
- TimedeltaIndex(['0 days 00:00:00', '0 days 00:00:01', '0 days 00:00:02',
- '0 days 00:00:03', '0 days 00:00:04'],
- dtype='timedelta64[ns]', freq=None)
- >>> pd.to_timedelta(np.arange(5), unit='d')
- TimedeltaIndex(['0 days', '1 days', '2 days', '3 days', '4 days'],
- dtype='timedelta64[ns]', freq=None)
- """
- if unit is not None:
- unit = parse_timedelta_unit(unit)
- if errors not in ("ignore", "raise", "coerce"):
- raise ValueError("errors must be one of 'ignore', 'raise', or 'coerce'.")
- if unit in {"Y", "y", "M"}:
- raise ValueError(
- "Units 'M', 'Y', and 'y' are no longer supported, as they do not "
- "represent unambiguous timedelta values durations."
- )
- if arg is None:
- return arg
- elif isinstance(arg, ABCSeries):
- values = _convert_listlike(arg._values, unit=unit, errors=errors)
- return arg._constructor(values, index=arg.index, name=arg.name)
- elif isinstance(arg, ABCIndex):
- return _convert_listlike(arg, unit=unit, errors=errors, name=arg.name)
- elif isinstance(arg, np.ndarray) and arg.ndim == 0:
- # extract array scalar and process below
- # error: Incompatible types in assignment (expression has type "object",
- # variable has type "Union[str, int, float, timedelta, List[Any],
- # Tuple[Any, ...], Union[Union[ExtensionArray, ndarray[Any, Any]], Index,
- # Series]]") [assignment]
- arg = lib.item_from_zerodim(arg) # type: ignore[assignment]
- elif is_list_like(arg) and getattr(arg, "ndim", 1) == 1:
- return _convert_listlike(arg, unit=unit, errors=errors)
- elif getattr(arg, "ndim", 1) > 1:
- raise TypeError(
- "arg must be a string, timedelta, list, tuple, 1-d array, or Series"
- )
- if isinstance(arg, str) and unit is not None:
- raise ValueError("unit must not be specified if the input is/contains a str")
- # ...so it must be a scalar value. Return scalar.
- return _coerce_scalar_to_timedelta_type(arg, unit=unit, errors=errors)
- def _coerce_scalar_to_timedelta_type(
- r, unit: UnitChoices | None = "ns", errors: DateTimeErrorChoices = "raise"
- ):
- """Convert string 'r' to a timedelta object."""
- result: Timedelta | NaTType
- try:
- result = Timedelta(r, unit)
- except ValueError:
- if errors == "raise":
- raise
- if errors == "ignore":
- return r
- # coerce
- result = NaT
- return result
- def _convert_listlike(
- arg, unit=None, errors: DateTimeErrorChoices = "raise", name=None
- ):
- """Convert a list of objects to a timedelta index object."""
- if isinstance(arg, (list, tuple)) or not hasattr(arg, "dtype"):
- # This is needed only to ensure that in the case where we end up
- # returning arg (errors == "ignore"), and where the input is a
- # generator, we return a useful list-like instead of a
- # used-up generator
- if not hasattr(arg, "__array__"):
- arg = list(arg)
- arg = np.array(arg, dtype=object)
- try:
- td64arr = sequence_to_td64ns(arg, unit=unit, errors=errors, copy=False)[0]
- except ValueError:
- if errors == "ignore":
- return arg
- else:
- # This else-block accounts for the cases when errors='raise'
- # and errors='coerce'. If errors == 'raise', these errors
- # should be raised. If errors == 'coerce', we shouldn't
- # expect any errors to be raised, since all parsing errors
- # cause coercion to pd.NaT. However, if an error / bug is
- # introduced that causes an Exception to be raised, we would
- # like to surface it.
- raise
- from pandas import TimedeltaIndex
- value = TimedeltaIndex(td64arr, unit="ns", name=name)
- return value
|