Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7c186e2

Browse files
committed
Issue #2706: Add support for dividing a timedelta by another timedelta.
Adds support for the three division operations: - timedelta / timedelta -> float - timedelta // timedelta -> int - timedelta % timedelta -> timedelta also adds support for divmod(timedelta, timedelta). Patch by Victor Stinner, adapted for py3k and extended by Alexander Belopolsky.
1 parent 50eb60e commit 7c186e2

4 files changed

Lines changed: 224 additions & 6 deletions

File tree

Doc/library/datetime.rst

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,20 @@ Supported operations:
220220
| | In general, *t1* \* i == *t1* \* (i-1) + *t1* |
221221
| | is true. (1) |
222222
+--------------------------------+-----------------------------------------------+
223-
| ``t1 = t2 // i`` | The floor is computed and the remainder (if |
224-
| | any) is thrown away. (3) |
223+
| ``f = t2 / t3`` | Division (3) of *t2* by *t3*. Returns a |
224+
| | :class:`float` object. |
225+
+--------------------------------+-----------------------------------------------+
226+
| ``t1 = t2 // i`` or | The floor is computed and the remainder (if |
227+
| ``t1 = t2 // t3`` | any) is thrown away. In the second case, an |
228+
| | integer is returned (3) |
229+
+--------------------------------+-----------------------------------------------+
230+
| ``t1 = t2 % t3`` | The remainder is computed as a |
231+
| | :class:`timedelta` object. (3) |
232+
+--------------------------------+-----------------------------------------------+
233+
| ``q, r = divmod(t1, t2)`` | Computes the quotient and the remainder: |
234+
| | ``q = t1 // t2`` (3) and ``r = t1 % t2``. |
235+
| | q is an integer and r is a :class:`timedelta` |
236+
| | object. |
225237
+--------------------------------+-----------------------------------------------+
226238
| ``+t1`` | Returns a :class:`timedelta` object with the |
227239
| | same value. (2) |
@@ -252,6 +264,12 @@ In addition to the operations listed above :class:`timedelta` objects support
252264
certain additions and subtractions with :class:`date` and :class:`datetime`
253265
objects (see below).
254266

267+
.. versionadded:: 3.2
268+
Floor division and true division of a :class:`timedelta` object by
269+
another :class:`timedelta` object are now supported, as are
270+
remainder operations and the :func:`divmod` function.
271+
272+
255273
Comparisons of :class:`timedelta` objects are supported with the
256274
:class:`timedelta` object representing the smaller duration considered to be the
257275
smaller timedelta. In order to stop mixed-type comparisons from falling back to

Lib/test/test_datetime.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import pickle
88
import unittest
99

10-
from operator import lt, le, gt, ge, eq, ne
10+
from operator import lt, le, gt, ge, eq, ne, truediv, floordiv, mod
1111

1212
from test import support
1313

@@ -469,6 +469,58 @@ def as_hours(self):
469469
self.assertEqual(str(t3), str(t4))
470470
self.assertEqual(t4.as_hours(), -1)
471471

472+
def test_division(self):
473+
t = timedelta(hours=1, minutes=24, seconds=19)
474+
second = timedelta(seconds=1)
475+
self.assertEqual(t / second, 5059.0)
476+
self.assertEqual(t // second, 5059)
477+
478+
t = timedelta(minutes=2, seconds=30)
479+
minute = timedelta(minutes=1)
480+
self.assertEqual(t / minute, 2.5)
481+
self.assertEqual(t // minute, 2)
482+
483+
zerotd = timedelta(0)
484+
self.assertRaises(ZeroDivisionError, truediv, t, zerotd)
485+
self.assertRaises(ZeroDivisionError, floordiv, t, zerotd)
486+
487+
self.assertRaises(TypeError, truediv, t, 2)
488+
# note: floor division of a timedelta by an integer *is*
489+
# currently permitted.
490+
491+
def test_remainder(self):
492+
t = timedelta(minutes=2, seconds=30)
493+
minute = timedelta(minutes=1)
494+
r = t % minute
495+
self.assertEqual(r, timedelta(seconds=30))
496+
497+
t = timedelta(minutes=-2, seconds=30)
498+
r = t % minute
499+
self.assertEqual(r, timedelta(seconds=30))
500+
501+
zerotd = timedelta(0)
502+
self.assertRaises(ZeroDivisionError, mod, t, zerotd)
503+
504+
self.assertRaises(TypeError, mod, t, 10)
505+
506+
def test_divmod(self):
507+
t = timedelta(minutes=2, seconds=30)
508+
minute = timedelta(minutes=1)
509+
q, r = divmod(t, minute)
510+
self.assertEqual(q, 2)
511+
self.assertEqual(r, timedelta(seconds=30))
512+
513+
t = timedelta(minutes=-2, seconds=30)
514+
q, r = divmod(t, minute)
515+
self.assertEqual(q, -2)
516+
self.assertEqual(r, timedelta(seconds=30))
517+
518+
zerotd = timedelta(0)
519+
self.assertRaises(ZeroDivisionError, divmod, t, zerotd)
520+
521+
self.assertRaises(TypeError, divmod, t, 10)
522+
523+
472524
#############################################################################
473525
# date tests
474526

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,10 @@ Library
966966
Extension Modules
967967
-----------------
968968

969+
- Issue #2706: Allow division of a timedelta by another timedelta:
970+
timedelta / timedelta, timedelta % timedelta, timedelta // timedelta
971+
and divmod(timedelta, timedelta) are all supported.
972+
969973
- Issue #8314: Fix unsigned long long bug in libffi on Sparc v8.
970974

971975
- Issue #8300: When passing a non-integer argument to struct.pack with any

Modules/datetimemodule.c

Lines changed: 147 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,52 @@ divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj)
16651665
return result;
16661666
}
16671667

1668+
static PyObject *
1669+
divide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right)
1670+
{
1671+
PyObject *pyus_left;
1672+
PyObject *pyus_right;
1673+
PyObject *result;
1674+
1675+
pyus_left = delta_to_microseconds(left);
1676+
if (pyus_left == NULL)
1677+
return NULL;
1678+
1679+
pyus_right = delta_to_microseconds(right);
1680+
if (pyus_right == NULL) {
1681+
Py_DECREF(pyus_left);
1682+
return NULL;
1683+
}
1684+
1685+
result = PyNumber_FloorDivide(pyus_left, pyus_right);
1686+
Py_DECREF(pyus_left);
1687+
Py_DECREF(pyus_right);
1688+
return result;
1689+
}
1690+
1691+
static PyObject *
1692+
truedivide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right)
1693+
{
1694+
PyObject *pyus_left;
1695+
PyObject *pyus_right;
1696+
PyObject *result;
1697+
1698+
pyus_left = delta_to_microseconds(left);
1699+
if (pyus_left == NULL)
1700+
return NULL;
1701+
1702+
pyus_right = delta_to_microseconds(right);
1703+
if (pyus_right == NULL) {
1704+
Py_DECREF(pyus_left);
1705+
return NULL;
1706+
}
1707+
1708+
result = PyNumber_TrueDivide(pyus_left, pyus_right);
1709+
Py_DECREF(pyus_left);
1710+
Py_DECREF(pyus_right);
1711+
return result;
1712+
}
1713+
16681714
static PyObject *
16691715
delta_add(PyObject *left, PyObject *right)
16701716
{
@@ -1810,13 +1856,111 @@ delta_divide(PyObject *left, PyObject *right)
18101856
result = divide_timedelta_int(
18111857
(PyDateTime_Delta *)left,
18121858
right);
1859+
else if (PyDelta_Check(right))
1860+
result = divide_timedelta_timedelta(
1861+
(PyDateTime_Delta *)left,
1862+
(PyDateTime_Delta *)right);
1863+
}
1864+
1865+
if (result == Py_NotImplemented)
1866+
Py_INCREF(result);
1867+
return result;
1868+
}
1869+
1870+
static PyObject *
1871+
delta_truedivide(PyObject *left, PyObject *right)
1872+
{
1873+
PyObject *result = Py_NotImplemented;
1874+
1875+
if (PyDelta_Check(left)) {
1876+
if (PyDelta_Check(right))
1877+
result = truedivide_timedelta_timedelta(
1878+
(PyDateTime_Delta *)left,
1879+
(PyDateTime_Delta *)right);
18131880
}
18141881

18151882
if (result == Py_NotImplemented)
18161883
Py_INCREF(result);
18171884
return result;
18181885
}
18191886

1887+
static PyObject *
1888+
delta_remainder(PyObject *left, PyObject *right)
1889+
{
1890+
PyObject *pyus_left;
1891+
PyObject *pyus_right;
1892+
PyObject *pyus_remainder;
1893+
PyObject *remainder;
1894+
1895+
if (!PyDelta_Check(left) || !PyDelta_Check(right)) {
1896+
Py_INCREF(Py_NotImplemented);
1897+
return Py_NotImplemented;
1898+
}
1899+
1900+
pyus_left = delta_to_microseconds((PyDateTime_Delta *)left);
1901+
if (pyus_left == NULL)
1902+
return NULL;
1903+
1904+
pyus_right = delta_to_microseconds((PyDateTime_Delta *)right);
1905+
if (pyus_right == NULL) {
1906+
Py_DECREF(pyus_left);
1907+
return NULL;
1908+
}
1909+
1910+
pyus_remainder = PyNumber_Remainder(pyus_left, pyus_right);
1911+
Py_DECREF(pyus_left);
1912+
Py_DECREF(pyus_right);
1913+
if (pyus_remainder == NULL)
1914+
return NULL;
1915+
1916+
remainder = microseconds_to_delta(pyus_remainder);
1917+
if (remainder == NULL) {
1918+
Py_DECREF(divmod);
1919+
return NULL;
1920+
}
1921+
1922+
return remainder;
1923+
}
1924+
1925+
static PyObject *
1926+
delta_divmod(PyObject *left, PyObject *right)
1927+
{
1928+
PyObject *pyus_left;
1929+
PyObject *pyus_right;
1930+
PyObject *divmod;
1931+
PyObject *microseconds, *delta;
1932+
1933+
if (!PyDelta_Check(left) || !PyDelta_Check(right)) {
1934+
Py_INCREF(Py_NotImplemented);
1935+
return Py_NotImplemented;
1936+
}
1937+
1938+
pyus_left = delta_to_microseconds((PyDateTime_Delta *)left);
1939+
if (pyus_left == NULL)
1940+
return NULL;
1941+
1942+
pyus_right = delta_to_microseconds((PyDateTime_Delta *)right);
1943+
if (pyus_right == NULL) {
1944+
Py_DECREF(pyus_left);
1945+
return NULL;
1946+
}
1947+
1948+
divmod = PyNumber_Divmod(pyus_left, pyus_right);
1949+
Py_DECREF(pyus_left);
1950+
Py_DECREF(pyus_right);
1951+
if (divmod == NULL)
1952+
return NULL;
1953+
1954+
microseconds = PyTuple_GetItem(divmod, 1);
1955+
delta = microseconds_to_delta(microseconds);
1956+
if (delta == NULL) {
1957+
Py_DECREF(divmod);
1958+
return NULL;
1959+
}
1960+
PyTuple_SetItem(divmod, 1, delta);
1961+
return divmod;
1962+
}
1963+
18201964
/* Fold in the value of the tag ("seconds", "weeks", etc) component of a
18211965
* timedelta constructor. sofar is the # of microseconds accounted for
18221966
* so far, and there are factor microseconds per current unit, the number
@@ -2108,8 +2252,8 @@ static PyNumberMethods delta_as_number = {
21082252
delta_add, /* nb_add */
21092253
delta_subtract, /* nb_subtract */
21102254
delta_multiply, /* nb_multiply */
2111-
0, /* nb_remainder */
2112-
0, /* nb_divmod */
2255+
delta_remainder, /* nb_remainder */
2256+
delta_divmod, /* nb_divmod */
21132257
0, /* nb_power */
21142258
(unaryfunc)delta_negative, /* nb_negative */
21152259
(unaryfunc)delta_positive, /* nb_positive */
@@ -2135,7 +2279,7 @@ static PyNumberMethods delta_as_number = {
21352279
0, /*nb_inplace_xor*/
21362280
0, /*nb_inplace_or*/
21372281
delta_divide, /* nb_floor_divide */
2138-
0, /* nb_true_divide */
2282+
delta_truedivide, /* nb_true_divide */
21392283
0, /* nb_inplace_floor_divide */
21402284
0, /* nb_inplace_true_divide */
21412285
};

0 commit comments

Comments
 (0)