doc/source/user_guide/timedeltas.rst
.. _timedeltas:
{{ header }}
.. _timedeltas.timedeltas:
Time deltas
Timedeltas are differences in times, expressed in difference units, e.g. days, hours, minutes, seconds. They can be both positive and negative.
Timedelta is a subclass of datetime.timedelta, and behaves in a similar manner,
but allows compatibility with np.timedelta64 types as well as a host of custom representation,
parsing, and attributes.
You can construct a Timedelta scalar through various arguments, including ISO 8601 Duration_ strings.
.. ipython:: python
import datetime
pd.Timedelta("1 days") pd.Timedelta("1 days 00:00:00") pd.Timedelta("1 days 2 hours") pd.Timedelta("-1 days 2 min 3us")
pd.Timedelta(days=1, seconds=1)
pd.Timedelta(1, unit="D")
pd.Timedelta(datetime.timedelta(days=1, seconds=1)) pd.Timedelta(np.timedelta64(1, "ms"))
pd.Timedelta("-1us")
pd.Timedelta("nan") pd.Timedelta("nat")
pd.Timedelta("P0DT0H1M0S") pd.Timedelta("P0DT0H0M0.000000123S")
:ref:DateOffsets<timeseries.offsets> (Hour, Minute, Second, Milli, Micro, Nano) can also be used in construction.
.. ipython:: python
pd.Timedelta(pd.offsets.Second(2))
Further, operations among the scalars yield another scalar Timedelta.
.. ipython:: python
pd.Timedelta(pd.offsets.Hour(48)) + pd.Timedelta(pd.offsets.Second(2)) + pd.Timedelta( "00:00:00.000123" )
to_timedelta
Using the top-level ``pd.to_timedelta``, you can convert a scalar, array, list,
or Series from a recognized timedelta format / value into a ``Timedelta`` type.
It will construct Series if the input is a Series, a scalar if the input is
scalar-like, otherwise it will output a ``TimedeltaIndex``.
You can parse a single string to a Timedelta:
.. ipython:: python
pd.to_timedelta("1 days 06:05:01.00003")
pd.to_timedelta("15.5us")
or a list/array of strings:
.. ipython:: python
pd.to_timedelta(["1 days 06:05:01.00003", "15.5us", "nan"])
The ``unit`` keyword argument specifies the unit of the Timedelta if the input
is numeric:
.. ipython:: python
pd.to_timedelta(np.arange(5), unit="s")
pd.to_timedelta(np.arange(5), unit="D")
.. warning::
If a string or array of strings is passed as an input then the ``unit`` keyword
argument will be ignored. If a string without units is passed then the default
unit of nanoseconds is assumed.
.. _timedeltas.limitations:
Timedelta limitations
pandas represents Timedeltas in nanosecond resolution using
64 bit integers. As such, the 64 bit integer limits determine
the Timedelta limits.
.. ipython:: python
pd.Timedelta.min pd.Timedelta.max
.. _timedeltas.operations:
You can operate on Series/DataFrames and construct timedelta64[ns] Series through
subtraction operations on datetime64[ns] Series, or Timestamps.
.. ipython:: python
s = pd.Series(pd.date_range("2012-1-1", periods=3, freq="D")) td = pd.Series([pd.Timedelta(days=i) for i in range(3)]) df = pd.DataFrame({"A": s, "B": td}) df df["C"] = df["A"] + df["B"] df df.dtypes
s - s.max() s - datetime.datetime(2011, 1, 1, 3, 5) s + datetime.timedelta(minutes=5) s + pd.offsets.Minute(5) s + pd.offsets.Minute(5) + pd.offsets.Milli(5)
Operations with scalars from a timedelta64[ns] series:
.. ipython:: python
y = s - s[0] y
Series of timedeltas with NaT values are supported:
.. ipython:: python
y = s - s.shift() y
Elements can be set to NaT using np.nan analogously to datetimes:
.. ipython:: python
y[1] = np.nan y
Operands can also appear in a reversed order (a singular object operated with a Series):
.. ipython:: python
s.max() - s datetime.datetime(2011, 1, 1, 3, 5) - s datetime.timedelta(minutes=5) + s
min, max and the corresponding idxmin, idxmax operations are supported on frames:
.. ipython:: python
A = s - pd.Timestamp("20120101") - pd.Timedelta("00:05:05") B = s - pd.Series(pd.date_range("2012-1-2", periods=3, freq="D"))
df = pd.DataFrame({"A": A, "B": B}) df
df.min() df.min(axis=1)
df.idxmin() df.idxmax()
min, max, idxmin, idxmax operations are supported on Series as well. A scalar result will be a Timedelta.
.. ipython:: python
df.min().max() df.min(axis=1).min()
df.min().idxmax() df.min(axis=1).idxmin()
You can fillna on timedeltas, passing a timedelta to get a particular value.
.. ipython:: python
y.fillna(pd.Timedelta(0)) y.fillna(pd.Timedelta(10, unit="s")) y.fillna(pd.Timedelta("-1 days, 00:00:05"))
You can also negate, multiply and use abs on Timedeltas:
.. ipython:: python
td1 = pd.Timedelta("-1 days 2 hours 3 seconds") td1 -1 * td1 -td1 abs(td1)
.. _timedeltas.timedeltas_reductions:
Numeric reduction operation for timedelta64[ns] will return Timedelta objects. As usual
NaT are skipped during evaluation.
.. ipython:: python
y2 = pd.Series( pd.to_timedelta(["-1 days +00:00:05", "nat", "-1 days +00:00:05", "1 days"]) ) y2 y2.mean() y2.median() y2.quantile(0.1) y2.sum()
.. _timedeltas.timedeltas_convert:
Timedelta Series and TimedeltaIndex, and Timedelta can be converted to other frequencies by astyping to a specific timedelta dtype.
.. ipython:: python
december = pd.Series(pd.date_range("20121201", periods=4)) january = pd.Series(pd.date_range("20130101", periods=4)) td = january - december
td[2] += datetime.timedelta(minutes=5, seconds=3) td[3] = np.nan td
td.astype("timedelta64[s]")
For timedelta64 resolutions other than the supported "s", "ms", "us", "ns", an alternative is to divide by another timedelta object. Note that division by the NumPy scalar is true division, while astyping is equivalent of floor division.
.. ipython:: python
td / np.timedelta64(1, "D")
Dividing or multiplying a timedelta64[ns] Series by an integer or integer Series
yields another timedelta64[ns] dtypes Series.
.. ipython:: python
td * -1 td * pd.Series([1, 2, 3, 4])
Rounded division (floor-division) of a timedelta64[ns] Series by a scalar
Timedelta gives a series of integers.
.. ipython:: python
td // pd.Timedelta(days=3, hours=4) pd.Timedelta(days=3, hours=4) // td
.. _timedeltas.mod_divmod:
The mod (%) and divmod operations are defined for Timedelta when operating with another timedelta-like or with a numeric argument.
.. ipython:: python
pd.Timedelta(hours=37) % datetime.timedelta(hours=2)
divmod(datetime.timedelta(hours=2), pd.Timedelta(minutes=11))
divmod(pd.Timedelta(hours=25), 86400000000000)
You can access various components of the Timedelta or TimedeltaIndex directly using the attributes days,seconds,microseconds,nanoseconds. These are identical to the values returned by datetime.timedelta, in that, for example, the .seconds attribute represents the number of seconds >= 0 and < 1 day. These are signed according to whether the Timedelta is signed.
These operations can also be directly accessed via the .dt property of the Series as well.
.. note::
Note that the attributes are NOT the displayed values of the Timedelta. Use .components to retrieve the displayed values.
For a Series:
.. ipython:: python
td.dt.days td.dt.seconds
You can access the value of the fields for a scalar Timedelta directly.
.. ipython:: python
tds = pd.Timedelta("31 days 5 min 3 sec") tds.days tds.seconds (-tds).seconds
You can use the .components property to access a reduced form of the timedelta. This returns a DataFrame indexed
similarly to the Series. These are the displayed values of the Timedelta.
.. ipython:: python
td.dt.components td.dt.components.seconds
.. _timedeltas.isoformat:
You can convert a Timedelta to an ISO 8601 Duration_ string with the
.isoformat method
.. ipython:: python
pd.Timedelta(
days=6, minutes=50, seconds=3, milliseconds=10, microseconds=10, nanoseconds=12
).isoformat()
.. _ISO 8601 Duration: https://en.wikipedia.org/wiki/ISO_8601#Durations
.. _timedeltas.index:
To generate an index with time delta, you can use either the :class:TimedeltaIndex or
the :func:timedelta_range constructor.
Using TimedeltaIndex you can pass string-like, Timedelta, timedelta,
or np.timedelta64 objects. Passing np.nan/pd.NaT/nat will represent missing values.
.. ipython:: python
pd.TimedeltaIndex( [ "1 days", "1 days, 00:00:05", np.timedelta64(2, "D"), datetime.timedelta(days=2, seconds=2), ] )
The string 'infer' can be passed in order to set the frequency of the index as the inferred frequency upon creation:
.. ipython:: python
pd.TimedeltaIndex(["0 days", "10 days", "20 days"], freq="infer")
Generating ranges of time deltas
Similar to :func:`date_range`, you can construct regular ranges of a ``TimedeltaIndex``
using :func:`timedelta_range`. The default frequency for ``timedelta_range`` is
calendar day:
.. ipython:: python
pd.timedelta_range(start="1 days", periods=5)
Various combinations of ``start``, ``end``, and ``periods`` can be used with
``timedelta_range``:
.. ipython:: python
pd.timedelta_range(start="1 days", end="5 days")
pd.timedelta_range(end="10 days", periods=4)
The ``freq`` parameter can passed a variety of :ref:`frequency aliases <timeseries.offset_aliases>`:
.. ipython:: python
pd.timedelta_range(start="1 days", end="2 days", freq="30min")
pd.timedelta_range(start="1 days", periods=5, freq="2D5h")
Specifying ``start``, ``end``, and ``periods`` will generate a range of evenly spaced
timedeltas from ``start`` to ``end`` inclusively, with ``periods`` number of elements
in the resulting ``TimedeltaIndex``:
.. ipython:: python
pd.timedelta_range("0 days", "4 days", periods=5)
pd.timedelta_range("0 days", "4 days", periods=10)
Using the TimedeltaIndex
~~~~~~~~~~~~~~~~~~~~~~~~
Similarly to other of the datetime-like indices, ``DatetimeIndex`` and ``PeriodIndex``, you can use
``TimedeltaIndex`` as the index of pandas objects.
.. ipython:: python
s = pd.Series(
np.arange(100),
index=pd.timedelta_range("1 days", periods=100, freq="h"),
)
s
Selections work similarly, with coercion on string-likes and slices:
.. ipython:: python
s["1 day":"2 day"]
s["1 day 01:00:00"]
s[pd.Timedelta("1 day 1h")]
Furthermore you can use partial string selection and the range will be inferred:
.. ipython:: python
s["1 day":"1 day 5 hours"]
Operations
~~~~~~~~~~
Finally, the combination of ``TimedeltaIndex`` with ``DatetimeIndex`` allow certain combination operations that are NaT preserving:
.. ipython:: python
tdi = pd.TimedeltaIndex(["1 days", pd.NaT, "2 days"])
tdi.to_list()
dti = pd.date_range("20130101", periods=3)
dti.to_list()
(dti + tdi).to_list()
(dti - tdi).to_list()
Conversions
~~~~~~~~~~~
Similarly to frequency conversion on a ``Series`` above, you can convert these indices to yield another Index.
.. ipython:: python
tdi / np.timedelta64(1, "s")
tdi.astype("timedelta64[s]")
Scalars type ops work as well. These can potentially return a *different* type of index.
.. ipython:: python
# adding or timedelta and date -> datelike
tdi + pd.Timestamp("20130101")
# subtraction of a date and a timedelta -> datelike
# note that trying to subtract a date from a Timedelta will raise an exception
(pd.Timestamp("20130101") - tdi).to_list()
# timedelta + timedelta -> timedelta
tdi + pd.Timedelta("10 days")
# division can result in a Timedelta if the divisor is an integer
tdi / 2
# or a float64 Index if the divisor is a Timedelta
tdi / tdi[0]
.. _timedeltas.resampling:
Resampling
----------
Similar to :ref:`timeseries resampling <timeseries.resampling>`, we can resample with a ``TimedeltaIndex``.
.. ipython:: python
s.resample("D").mean()