*** Doc/lib/libdatetime.tex1 2005-02-03 21:53:06.000000000 -0500 --- Doc/lib/libdatetime.tex 2005-02-03 22:11:52.000000000 -0500 *************** *** 1059,1069 **** Supported operations: ! \begin{itemize} ! \item ! comparison of \class{time} to \class{time}, ! where \var{a} is considered less than \var{b} when \var{a} precedes ! \var{b} in time. If one comparand is naive and the other is aware, \exception{TypeError} is raised. If both comparands are aware, and have the same \member{tzinfo} member, the common \member{tzinfo} member is ignored and the base times are compared. If both --- 1059,1122 ---- Supported operations: ! \begin{tableii}{c|l}{code}{Operation}{Result} ! \lineii{\var{time2} = \var{time1} + \var{timedelta}}{(1)} ! ! \lineii{\var{time2} = \var{time1} - \var{timedelta}}{(2)} ! ! \lineii{\var{timedelta} = \var{time1} - \var{time2}}{(3)} ! ! \lineii{\var{time1} < \var{time2}} ! {Compares \class{time} to \class{time}. ! (4)} ! ! \end{tableii} ! ! \begin{description} ! ! \item[(1)] ! ! time2 is a duration of timedelta removed from time1, moving ! forward in time if \code{\var{timedelta}.days} > 0, or backward if ! \code{\var{timedelta}.days} < 0. The result has the same \member{tzinfo} member ! as the input time, and time2 - time1 == timedelta after. ! Note that no time zone adjustments are done even if the input is an ! aware object. ! ! \item[(2)] ! Computes the time2 such that time2 + timedelta == time1. ! As for addition, the result has the same \member{tzinfo} member ! as the input time, and no time zone adjustments are done even ! if the input is aware. ! This isn't quite equivalent to time1 + (-timedelta), because ! -timedelta in isolation can overflow in cases where ! time1 - timedelta does not. ! ! \item[(3)] ! Subtraction of a \class{time} from a ! \class{time} is defined only if both ! operands are naive, or if both are aware. If one is aware and the ! other is naive, \exception{TypeError} is raised. ! ! If both are naive, or both are aware and have the same \member{tzinfo} ! member, the \member{tzinfo} members are ignored, and the result is ! a \class{timedelta} object \var{t} such that ! \code{\var{time2} + \var{t} == \var{time1}}. No time zone ! adjustments are done in this case. ! ! If both are aware and have different \member{tzinfo} members, ! \code{a-b} acts as if \var{a} and \var{b} were first converted to ! naive UTC times first. The result is ! \code{(\var{a}.replace(tzinfo=None) - \var{a}.utcoffset()) - ! (\var{b}.replace(tzinfo=None) - \var{b}.utcoffset())} ! except that the implementation never overflows. ! ! \item[(4)] ! ! \var{time1} is considered less than \var{time2} ! when \var{time1} precedes \var{time2} in time. ! ! If one comparand is naive and the other is aware, \exception{TypeError} is raised. If both comparands are aware, and have the same \member{tzinfo} member, the common \member{tzinfo} member is ignored and the base times are compared. If both *************** *** 1076,1093 **** raised unless the comparison is \code{==} or \code{!=}. The latter cases return \constant{False} or \constant{True}, respectively. ! \item ! hash, use as dict key ! \item ! efficient pickling ! ! \item ! in Boolean contexts, a \class{time} object is considered to be ! true if and only if, after converting it to minutes and ! subtracting \method{utcoffset()} (or \code{0} if that's ! \code{None}), the result is non-zero. ! \end{itemize} Instance methods: --- 1129,1141 ---- raised unless the comparison is \code{==} or \code{!=}. The latter cases return \constant{False} or \constant{True}, respectively. ! \end{description} ! \class{time} objects are hashable (usable as dictionary keys), ! support efficient pickling, and in Boolean contexts, a \class{time} ! object is considered to be true if and only if, after converting it to ! minutes and subtracting \method{utcoffset()} (or \code{0} if that's ! \code{None}), the result is non-zero. Instance methods: *** Modules/datetimemodule.c1 2005-02-03 21:50:40.000000000 -0500 --- Modules/datetimemodule.c 2005-02-03 21:51:07.000000000 -0500 *************** *** 559,564 **** --- 559,577 ---- return result; } + /* Force all the time fields into range. The parameters are both + * inputs and outputs. Cannot fail. + */ + static void + normalize_time(int *day, int *hour, int *minute, int *second, + int *microsecond) + { + normalize_pair(second, microsecond, 1000000); + normalize_pair(minute, second, 60); + normalize_pair(hour, minute, 60); + normalize_pair(day, hour, 24); + } + /* Force all the datetime fields into range. The parameters are both * inputs and outputs. Returns < 0 on error. */ *************** *** 567,576 **** int *hour, int *minute, int *second, int *microsecond) { ! normalize_pair(second, microsecond, 1000000); ! normalize_pair(minute, second, 60); ! normalize_pair(hour, minute, 60); ! normalize_pair(day, hour, 24); return normalize_date(year, month, day); } --- 580,586 ---- int *hour, int *minute, int *second, int *microsecond) { ! normalize_time(day, hour, minute, second, microsecond); return normalize_date(year, month, day); } *************** *** 3276,3281 **** --- 3286,3398 ---- } /* + * Time arithmetic. + */ + + /* time + timedelta -> time. If arg negate is true, subtract the timedelta + * instead. + */ + static PyObject * + add_time_timedelta(PyDateTime_Time *time, PyDateTime_Delta *delta, int negate) + { + int delta_s = GET_TD_SECONDS(delta); + int delta_us = GET_TD_MICROSECONDS(delta); + int day; /* ignored */ + int hour = TIME_GET_HOUR(time); + int minute = TIME_GET_MINUTE(time); + int second = TIME_GET_SECOND(time) + (negate ? -delta_s : delta_s); + int microsecond = TIME_GET_MICROSECOND(time) + (negate ? -delta_us : delta_us); + + normalize_time(&day, &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 (PyDateTime_Check(left) || PyDateTime_Check(right)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if (PyTime_Check(left)) { + /* time + ??? */ + if (PyDelta_Check(right)) + /* time + delta */ + return add_time_timedelta((PyDateTime_Time *) left, + (PyDateTime_Delta *) right, + 0); + } + else { + /* ??? + time + * 'right' must be one of us, or we wouldn't have been called + */ + if (PyDelta_Check(left)) + /* delta + time */ + return add_time_timedelta((PyDateTime_Time *) right, + (PyDateTime_Delta *) left, + 0); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + static PyObject * + time_subtract(PyObject *left, PyObject *right) + { + if (PyDateTime_Check(left) || PyDateTime_Check(right)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if (PyTime_Check(left)) { + if (PyTime_Check(right)) { + /* time - time */ + naivety n1, n2; + int offset1, offset2; + int delta_s, delta_us; + if (classify_two_utcoffsets(left, &offset1, &n1, left, + right, &offset2, &n2, + right) < 0) + return NULL; + assert(n1 != OFFSET_UNKNOWN && n2 != OFFSET_UNKNOWN); + if (n1 != n2) { + PyErr_SetString(PyExc_TypeError, + "can't subtract offset-naive and " + "offset-aware times"); + return NULL; + } + + /* These can't overflow, since the values are + * normalized. At most this gives the number of + * seconds in one day. + */ + delta_s = (TIME_GET_HOUR(left) - + TIME_GET_HOUR(right)) * 3600 + + (TIME_GET_MINUTE(left) - + TIME_GET_MINUTE(right)) * 60 + + (TIME_GET_SECOND(left) - + TIME_GET_SECOND(right)); + delta_us = TIME_GET_MICROSECOND(left) - + TIME_GET_MICROSECOND(right); + /* (left - offset1) - (right - offset2) = + * (left - right) + (offset2 - offset1) + */ + delta_s += (offset2 - offset1) * 60; + + return new_delta(0, delta_s, delta_us, 1); + } + if (PyDelta_Check(right)) { + /* time - delta */ + return add_time_timedelta((PyDateTime_Date *) left, + (PyDateTime_Delta *) right, + 1); + } + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + /* * Miscellaneous methods. */ *************** *** 3502,3509 **** a tzinfo subclass. The remaining arguments may be ints or longs.\n"); static PyNumberMethods time_as_number = { ! 0, /* nb_add */ ! 0, /* nb_subtract */ 0, /* nb_multiply */ 0, /* nb_divide */ 0, /* nb_remainder */ --- 3619,3626 ---- a tzinfo subclass. The remaining arguments may be ints or longs.\n"); static PyNumberMethods time_as_number = { ! time_add, /* nb_add */ ! time_subtract, /* nb_subtract */ 0, /* nb_multiply */ 0, /* nb_divide */ 0, /* nb_remainder */