Index: Misc/NEWS =================================================================== --- Misc/NEWS (Revision 54538) +++ Misc/NEWS (Arbeitskopie) @@ -11,6 +11,9 @@ Core and builtins ----------------- +- Patches #1665292: datetime.timedelta objects can be cast to and compared + with ints, floats and longs. The numbers are considered as amount of + seconds. - Patch #1682205: a TypeError while unpacking an iterable is no longer masked by a generic one with the message "unpack non-sequence". Index: Doc/lib/libdatetime.tex =================================================================== --- Doc/lib/libdatetime.tex (Revision 54538) +++ Doc/lib/libdatetime.tex (Arbeitskopie) @@ -232,6 +232,12 @@ {equivalent to +\var{t} when \code{t.days >= 0}, and to -\var{t} when \code{t.days < 0}. (2)} + \lineii{int(\var{t}) or long(\var{t})} + {converts to seconds, equivalent to \var{t.days} * 86400 + + \var{t.seconds}} + \lineii{float(\var{t})} + {converts to seconds, equivalent to \var{t.days} * 86400.0 + + \var{t.seconds} + \var{t.microseconds}/1000000.0} \end{tableii} \noindent Notes: @@ -255,8 +261,10 @@ \class{datetime} objects (see below). Comparisons of \class{timedelta} objects are supported with the +\class{timedelta} object, \class{int}, \class{long} and \class{float}. A \class{timedelta} object representing the smaller duration considered -to be the smaller timedelta. +to be the smaller timedelta. When comparing to a number the number is +considered as amount of seconds. In order to stop mixed-type comparisons from falling back to the default comparison by object address, when a \class{timedelta} object is compared to an object of a different type, \exception{TypeError} is Index: Lib/test/test_datetime.py =================================================================== --- Lib/test/test_datetime.py (Revision 54538) +++ Lib/test/test_datetime.py (Arbeitskopie) @@ -26,6 +26,7 @@ # An arbitrary collection of objects of non-datetime types, for testing # mixed-type comparisons. OTHERSTUFF = (10, 10L, 34.5, "abc", {}, [], ()) +DELTASTUFF = ("abc", {}, [], ()) ############################################################################# @@ -334,7 +335,7 @@ self.assertEqual(cmp(t1, t2), -1) self.assertEqual(cmp(t2, t1), 1) - for badarg in OTHERSTUFF: + for badarg in DELTASTUFF: self.assertEqual(t1 == badarg, False) self.assertEqual(t1 != badarg, True) self.assertEqual(badarg == t1, False) @@ -349,6 +350,32 @@ self.assertRaises(TypeError, lambda: badarg > t1) self.assertRaises(TypeError, lambda: badarg >= t1) + pos = timedelta(1) + neg = timedelta(-1) + nul = timedelta(0) + + for num in (0, 0L, 0.0): + self.failUnless(nul == num) + self.failIf(nul != num) + self.failIf(nul < num) + self.failIf(nul > num) + self.failUnless(nul <= num) + self.failUnless(nul >= num) + + self.failIf(pos == num) + self.failUnless(pos != num) + self.failIf(pos < num) + self.failUnless(pos > num) + self.failIf(pos <= num) + self.failUnless(pos >= num) + + self.failIf(neg == num) + self.failUnless(neg != num) + self.failUnless(neg < num) + self.failIf(neg > num) + self.failUnless(neg <= num) + self.failIf(neg >= num) + def test_str(self): td = timedelta eq = self.assertEqual @@ -475,6 +502,36 @@ self.assertEqual(str(t3), str(t4)) self.assertEqual(t4.as_hours(), -1) + def test_intfloat(self): + td = timedelta + eq = self.assertEqual + aeq = self.failUnlessAlmostEqual + + s = td(seconds=1) + d = td(days=1) + dsm = td(days=1, seconds=1, microseconds=1000) + ms = td(microseconds=1) + m_d = td(days=-1) + + eq(int(s), 1) + eq(int(d), 86400) + eq(int(dsm), 86401) + eq(int(ms), 0) + eq(int(m_d), -86400) + + eq(long(s), 1L) + eq(long(d), 86400L) + eq(long(dsm), 86401L) + eq(long(ms), 0L) + eq(int(m_d), -86400L) + + aeq(float(s), 1.0) + aeq(float(d), 86400.0) + aeq(float(dsm), 86401.001) + aeq(float(ms), 0.000001) + aeq(float(m_d), -86400.0) + + ############################################################################# # date tests Index: Modules/datetimemodule.c =================================================================== --- Modules/datetimemodule.c (Revision 54538) +++ Modules/datetimemodule.c (Arbeitskopie) @@ -93,6 +93,8 @@ */ #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12) +#define DIFF_TO_INT(V) (((V) == 0) ? 0 : (((V) > 0) ? 1 : -1)) + /* Forward declarations. */ static PyTypeObject PyDateTime_DateType; static PyTypeObject PyDateTime_DateTimeType; @@ -806,7 +808,7 @@ * result. tzinfo must be an instance of the tzinfo class. If the method * returns None, this returns 0 and sets *none to 1. If the method doesn't * return None or timedelta, TypeError is raised and this returns -1. If it - * returnsa timedelta and the value is out of range or isn't a whole number + * returns a timedelta and the value is out of range or isn't a whole number * of minutes, ValueError is raised and this returns -1. * Else *none is set to 0 and the integer method result is returned. */ @@ -1413,6 +1415,7 @@ return result; } + /* Raises a "can't compare" TypeError and returns NULL. */ static PyObject * cmperror(PyObject *a, PyObject *b) @@ -1648,6 +1651,23 @@ } static PyObject * +delta_int(PyDateTime_Delta *self) +{ + long seconds = (GET_TD_DAYS(self) * 86400 + + GET_TD_SECONDS(self)); + return PyInt_FromLong(seconds); +} + +static PyObject * +delta_float(PyDateTime_Delta *self) +{ + double seconds = ((double)GET_TD_DAYS(self) * 86400.0 + + (double)GET_TD_SECONDS(self) + + (double)GET_TD_MICROSECONDS(self) / 1000000.0); + return PyFloat_FromDouble(seconds); +} + +static PyObject * delta_negative(PyDateTime_Delta *self) { return new_delta(-GET_TD_DAYS(self), @@ -1723,6 +1743,25 @@ GET_TD_MICROSECONDS(other); } } + else if (PyLong_Check(other)) { + long seconds = (GET_TD_DAYS(self) * 86400 + + GET_TD_SECONDS(self)); + long result = seconds - PyLong_AsLong(other); + diff = DIFF_TO_INT(result); + } + else if (PyInt_Check(other)) { + long seconds = (GET_TD_DAYS(self) * 86400 + + GET_TD_SECONDS(self)); + long result = seconds - PyLong_AsLong(other); + diff = DIFF_TO_INT(result); + } + else if (PyFloat_Check(other)) { + double seconds = (GET_TD_DAYS(self) * 86400.0 + + GET_TD_SECONDS(self) + + GET_TD_MICROSECONDS(self) / 1000000.0); + double result = seconds - PyFloat_AsDouble(other); + diff = DIFF_TO_INT(result); + } else if (op == Py_EQ || op == Py_NE) diff = 1; /* any non-zero value will do */ @@ -2100,9 +2139,9 @@ 0, /*nb_xor*/ 0, /*nb_or*/ 0, /*nb_coerce*/ - 0, /*nb_int*/ - 0, /*nb_long*/ - 0, /*nb_float*/ + (unaryfunc)delta_int, /*nb_int*/ + (unaryfunc)delta_int, /*nb_long*/ + (unaryfunc)delta_float, /*nb_float*/ 0, /*nb_oct*/ 0, /*nb_hex*/ 0, /*nb_inplace_add*/