[Python-checkins] r80290 - in python/branches/py3k: Doc/library/datetime.rst Lib/test/test_datetime.py Misc/NEWS Modules/datetimemodule.c
mark.dickinson
python-checkins at python.org
Wed Apr 21 00:32:49 CEST 2010
Author: mark.dickinson
Date: Wed Apr 21 00:32:49 2010
New Revision: 80290
Log:
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 Alexander Belopolsky.
Modified:
python/branches/py3k/Doc/library/datetime.rst
python/branches/py3k/Lib/test/test_datetime.py
python/branches/py3k/Misc/NEWS
python/branches/py3k/Modules/datetimemodule.c
Modified: python/branches/py3k/Doc/library/datetime.rst
==============================================================================
--- python/branches/py3k/Doc/library/datetime.rst (original)
+++ python/branches/py3k/Doc/library/datetime.rst Wed Apr 21 00:32:49 2010
@@ -220,8 +220,20 @@
| | In general, *t1* \* i == *t1* \* (i-1) + *t1* |
| | is true. (1) |
+--------------------------------+-----------------------------------------------+
-| ``t1 = t2 // i`` | The floor is computed and the remainder (if |
-| | any) is thrown away. (3) |
+| ``f = t2 / t3`` | Division (3) of *t2* by *t3*. Returns a |
+| | :class:`float` object. |
++--------------------------------+-----------------------------------------------+
+| ``t1 = t2 // i`` or | The floor is computed and the remainder (if |
+| ``t1 = t2 // t3`` | any) is thrown away. In the second case, an |
+| | integer is returned (3) |
++--------------------------------+-----------------------------------------------+
+| ``t1 = t2 % t3`` | The remainder is computed as a |
+| | :class:`timedelta` object. (3) |
++--------------------------------+-----------------------------------------------+
+| ``q, r = divmod(t1, t2)`` | Computes the quotient and the remainder: |
+| | ``q = t1 // t2`` (3) and ``r = t1 % t2``. |
+| | q is an integer and r is a :class:`timedelta` |
+| | object. |
+--------------------------------+-----------------------------------------------+
| ``+t1`` | Returns a :class:`timedelta` object with the |
| | same value. (2) |
@@ -252,6 +264,12 @@
certain additions and subtractions with :class:`date` and :class:`datetime`
objects (see below).
+.. versionadded:: 3.2
+ Floor division and true division of a :class:`timedelta` object by
+ another :class:`timedelta` object are now supported, as are
+ remainder operations and the :func:`divmod` function.
+
+
Comparisons of :class:`timedelta` objects are supported with the
:class:`timedelta` object representing the smaller duration considered to be the
smaller timedelta. In order to stop mixed-type comparisons from falling back to
Modified: python/branches/py3k/Lib/test/test_datetime.py
==============================================================================
--- python/branches/py3k/Lib/test/test_datetime.py (original)
+++ python/branches/py3k/Lib/test/test_datetime.py Wed Apr 21 00:32:49 2010
@@ -7,7 +7,7 @@
import pickle
import unittest
-from operator import lt, le, gt, ge, eq, ne
+from operator import lt, le, gt, ge, eq, ne, truediv, floordiv, mod
from test import support
@@ -469,6 +469,58 @@
self.assertEqual(str(t3), str(t4))
self.assertEqual(t4.as_hours(), -1)
+ def test_division(self):
+ t = timedelta(hours=1, minutes=24, seconds=19)
+ second = timedelta(seconds=1)
+ self.assertEqual(t / second, 5059.0)
+ self.assertEqual(t // second, 5059)
+
+ t = timedelta(minutes=2, seconds=30)
+ minute = timedelta(minutes=1)
+ self.assertEqual(t / minute, 2.5)
+ self.assertEqual(t // minute, 2)
+
+ zerotd = timedelta(0)
+ self.assertRaises(ZeroDivisionError, truediv, t, zerotd)
+ self.assertRaises(ZeroDivisionError, floordiv, t, zerotd)
+
+ self.assertRaises(TypeError, truediv, t, 2)
+ # note: floor division of a timedelta by an integer *is*
+ # currently permitted.
+
+ def test_remainder(self):
+ t = timedelta(minutes=2, seconds=30)
+ minute = timedelta(minutes=1)
+ r = t % minute
+ self.assertEqual(r, timedelta(seconds=30))
+
+ t = timedelta(minutes=-2, seconds=30)
+ r = t % minute
+ self.assertEqual(r, timedelta(seconds=30))
+
+ zerotd = timedelta(0)
+ self.assertRaises(ZeroDivisionError, mod, t, zerotd)
+
+ self.assertRaises(TypeError, mod, t, 10)
+
+ def test_divmod(self):
+ t = timedelta(minutes=2, seconds=30)
+ minute = timedelta(minutes=1)
+ q, r = divmod(t, minute)
+ self.assertEqual(q, 2)
+ self.assertEqual(r, timedelta(seconds=30))
+
+ t = timedelta(minutes=-2, seconds=30)
+ q, r = divmod(t, minute)
+ self.assertEqual(q, -2)
+ self.assertEqual(r, timedelta(seconds=30))
+
+ zerotd = timedelta(0)
+ self.assertRaises(ZeroDivisionError, divmod, t, zerotd)
+
+ self.assertRaises(TypeError, divmod, t, 10)
+
+
#############################################################################
# date tests
Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS (original)
+++ python/branches/py3k/Misc/NEWS Wed Apr 21 00:32:49 2010
@@ -966,6 +966,10 @@
Extension Modules
-----------------
+- Issue #2706: Allow division of a timedelta by another timedelta:
+ timedelta / timedelta, timedelta % timedelta, timedelta // timedelta
+ and divmod(timedelta, timedelta) are all supported.
+
- Issue #8314: Fix unsigned long long bug in libffi on Sparc v8.
- Issue #8300: When passing a non-integer argument to struct.pack with any
Modified: python/branches/py3k/Modules/datetimemodule.c
==============================================================================
--- python/branches/py3k/Modules/datetimemodule.c (original)
+++ python/branches/py3k/Modules/datetimemodule.c Wed Apr 21 00:32:49 2010
@@ -1666,6 +1666,52 @@
}
static PyObject *
+divide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right)
+{
+ PyObject *pyus_left;
+ PyObject *pyus_right;
+ PyObject *result;
+
+ pyus_left = delta_to_microseconds(left);
+ if (pyus_left == NULL)
+ return NULL;
+
+ pyus_right = delta_to_microseconds(right);
+ if (pyus_right == NULL) {
+ Py_DECREF(pyus_left);
+ return NULL;
+ }
+
+ result = PyNumber_FloorDivide(pyus_left, pyus_right);
+ Py_DECREF(pyus_left);
+ Py_DECREF(pyus_right);
+ return result;
+}
+
+static PyObject *
+truedivide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right)
+{
+ PyObject *pyus_left;
+ PyObject *pyus_right;
+ PyObject *result;
+
+ pyus_left = delta_to_microseconds(left);
+ if (pyus_left == NULL)
+ return NULL;
+
+ pyus_right = delta_to_microseconds(right);
+ if (pyus_right == NULL) {
+ Py_DECREF(pyus_left);
+ return NULL;
+ }
+
+ result = PyNumber_TrueDivide(pyus_left, pyus_right);
+ Py_DECREF(pyus_left);
+ Py_DECREF(pyus_right);
+ return result;
+}
+
+static PyObject *
delta_add(PyObject *left, PyObject *right)
{
PyObject *result = Py_NotImplemented;
@@ -1810,6 +1856,27 @@
result = divide_timedelta_int(
(PyDateTime_Delta *)left,
right);
+ else if (PyDelta_Check(right))
+ result = divide_timedelta_timedelta(
+ (PyDateTime_Delta *)left,
+ (PyDateTime_Delta *)right);
+ }
+
+ if (result == Py_NotImplemented)
+ Py_INCREF(result);
+ return result;
+}
+
+static PyObject *
+delta_truedivide(PyObject *left, PyObject *right)
+{
+ PyObject *result = Py_NotImplemented;
+
+ if (PyDelta_Check(left)) {
+ if (PyDelta_Check(right))
+ result = truedivide_timedelta_timedelta(
+ (PyDateTime_Delta *)left,
+ (PyDateTime_Delta *)right);
}
if (result == Py_NotImplemented)
@@ -1817,6 +1884,83 @@
return result;
}
+static PyObject *
+delta_remainder(PyObject *left, PyObject *right)
+{
+ PyObject *pyus_left;
+ PyObject *pyus_right;
+ PyObject *pyus_remainder;
+ PyObject *remainder;
+
+ if (!PyDelta_Check(left) || !PyDelta_Check(right)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ pyus_left = delta_to_microseconds((PyDateTime_Delta *)left);
+ if (pyus_left == NULL)
+ return NULL;
+
+ pyus_right = delta_to_microseconds((PyDateTime_Delta *)right);
+ if (pyus_right == NULL) {
+ Py_DECREF(pyus_left);
+ return NULL;
+ }
+
+ pyus_remainder = PyNumber_Remainder(pyus_left, pyus_right);
+ Py_DECREF(pyus_left);
+ Py_DECREF(pyus_right);
+ if (pyus_remainder == NULL)
+ return NULL;
+
+ remainder = microseconds_to_delta(pyus_remainder);
+ if (remainder == NULL) {
+ Py_DECREF(divmod);
+ return NULL;
+ }
+
+ return remainder;
+}
+
+static PyObject *
+delta_divmod(PyObject *left, PyObject *right)
+{
+ PyObject *pyus_left;
+ PyObject *pyus_right;
+ PyObject *divmod;
+ PyObject *microseconds, *delta;
+
+ if (!PyDelta_Check(left) || !PyDelta_Check(right)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ pyus_left = delta_to_microseconds((PyDateTime_Delta *)left);
+ if (pyus_left == NULL)
+ return NULL;
+
+ pyus_right = delta_to_microseconds((PyDateTime_Delta *)right);
+ if (pyus_right == NULL) {
+ Py_DECREF(pyus_left);
+ return NULL;
+ }
+
+ divmod = PyNumber_Divmod(pyus_left, pyus_right);
+ Py_DECREF(pyus_left);
+ Py_DECREF(pyus_right);
+ if (divmod == NULL)
+ return NULL;
+
+ microseconds = PyTuple_GetItem(divmod, 1);
+ delta = microseconds_to_delta(microseconds);
+ if (delta == NULL) {
+ Py_DECREF(divmod);
+ return NULL;
+ }
+ PyTuple_SetItem(divmod, 1, delta);
+ return divmod;
+}
+
/* Fold in the value of the tag ("seconds", "weeks", etc) component of a
* timedelta constructor. sofar is the # of microseconds accounted for
* so far, and there are factor microseconds per current unit, the number
@@ -2108,8 +2252,8 @@
delta_add, /* nb_add */
delta_subtract, /* nb_subtract */
delta_multiply, /* nb_multiply */
- 0, /* nb_remainder */
- 0, /* nb_divmod */
+ delta_remainder, /* nb_remainder */
+ delta_divmod, /* nb_divmod */
0, /* nb_power */
(unaryfunc)delta_negative, /* nb_negative */
(unaryfunc)delta_positive, /* nb_positive */
@@ -2135,7 +2279,7 @@
0, /*nb_inplace_xor*/
0, /*nb_inplace_or*/
delta_divide, /* nb_floor_divide */
- 0, /* nb_true_divide */
+ delta_truedivide, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
};
More information about the Python-checkins
mailing list