diff -r fcc61327c86c Lib/datetime.py --- a/Lib/datetime.py Fri Feb 22 08:29:34 2013 +0200 +++ b/Lib/datetime.py Sat Feb 23 21:19:29 2013 +0100 @@ -1059,6 +1059,25 @@ """timezone info object""" return self._tzinfo + def __add__(self, other): + "Add a time and a timedelta" + if not isinstance(other, timedelta): + return NotImplemented + + delta = timedelta(hours=self._hour, + minutes=self._minute, + seconds=self._second, + microseconds=self._microsecond) + + delta += other + hour, rem = divmod(delta.seconds, 3600) + minute, second = divmod(rem, 60) + if delta.days <= _MAXORDINAL: + return time(hour, minute, second, + delta.microseconds, + tzinfo=self._tzinfo) + raise OverflowError("result out of range") + # Standard conversions, __hash__ (and helpers) # Comparisons of time objects with other. diff -r fcc61327c86c Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py Fri Feb 22 08:29:34 2013 +0200 +++ b/Lib/test/datetimetester.py Sat Feb 23 21:19:29 2013 +0100 @@ -2330,6 +2330,21 @@ self.assertRaises(TypeError, self.theclass, hour_byte + base[1:]) + def test_computations(self): + a = self.theclass(0, 0, 0) + b = self.theclass(23, 59) + + minute = timedelta(minutes=1) + hour = timedelta(hours=1) + week = timedelta(days=7) + self.assertEqual(a + minute, self.theclass(0, 1, 0)) + self.assertEqual(b + minute + minute, self.theclass(0, 1)) + self.assertEqual(b + minute, self.theclass(0, 0)) + self.assertEqual(a + week, self.theclass(0)) + self.assertEqual(a + week, self.theclass(0)) + self.assertEqual(b + hour * 12, self.theclass(11, 59)) + + # A mixin for classes with a tzinfo= argument. Subclasses must define # theclass as a class atribute, and theclass(1, 1, 1, tzinfo=whatever) # must be legit (which is true for time and datetime). diff -r fcc61327c86c Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c Fri Feb 22 08:29:34 2013 +0200 +++ b/Modules/_datetimemodule.c Sat Feb 23 21:19:29 2013 +0100 @@ -3821,6 +3821,53 @@ return (TIME_GET_MINUTE(self)*60 - offsecs + TIME_GET_HOUR(self)*3600) != 0; } +/* Force all the time fields into range + * the day argument is there just because I don't know how to normalize the + * hours without it. + */ + +static void +normalize_time(int *hour, int *minute, int *second, int *microsecond) +{ + int day = 0; + normalize_pair(second, microsecond, 1000000); + normalize_pair(minute, second, 60); + normalize_pair(hour, minute, 60); + normalize_pair(&day, hour, 24); +} + +/* + * Time arithmetic + */ + +/* time + timedelta -> time + * +.*/ +static PyObject * +add_time_timedelta(PyDateTime_Time *time, PyDateTime_Delta *delta) +{ + int hour = TIME_GET_HOUR(time); + int minute = TIME_GET_MINUTE(time); + int second = TIME_GET_SECOND(time) + GET_TD_SECONDS(delta); + int microsecond = TIME_GET_MICROSECOND(time) + GET_TD_MICROSECONDS(delta); + + normalize_time(&hour, &minute, &second, µsecond); + + return new_time(hour, minute, second, microsecond, + HASTZINFO(time) ? time->tzinfo : Py_None); +} + +static PyObject * +time_add(PyObject *left, PyObject *right) +{ + if (PyDelta_Check(right)) { + /* time + delta */ + return add_time_timedelta((PyDateTime_Time *) left, + (PyDateTime_Delta *) right); + } + Py_RETURN_NOTIMPLEMENTED; +} + /* Pickle support, a simple use of __reduce__. */ /* Let basestate be the non-tzinfo data string. @@ -3889,7 +3936,7 @@ a tzinfo subclass. The remaining arguments may be ints or longs.\n"); static PyNumberMethods time_as_number = { - 0, /* nb_add */ + time_add, /* nb_add */ 0, /* nb_subtract */ 0, /* nb_multiply */ 0, /* nb_remainder */