[Python-checkins] python/nondist/sandbox/datetime datetime.py,1.103,1.104 obj_datetimetz.c,1.12,1.13 test_both.py,1.79,1.80
tim_one@users.sourceforge.net
tim_one@users.sourceforge.net
2002年12月14日 00:03:17 -0800
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv16734
Modified Files:
datetime.py obj_datetimetz.c test_both.py
Log Message:
Implemented datetimetz arithmetic.
TestDateTimeTZ inherits from TestDateTime now, and all tests pass.
However, there are no tests of datetimetz arithmetic that exercise any of
the new C code, or any of the relevant Python code.
Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.103
retrieving revision 1.104
diff -C2 -d -r1.103 -r1.104
*** datetime.py 14 Dec 2002 01:33:57 -0000 1.103
--- datetime.py 14 Dec 2002 08:03:14 -0000 1.104
***************
*** 1500,1504 ****
return supersub(other)
if myoff is None or otoff is None:
! raise ValueError, "cannot mix naive and timezone-aware time"
return supersub(other) + timedelta(minutes=otoff-myoff)
--- 1500,1504 ----
return supersub(other)
if myoff is None or otoff is None:
! raise TypeError, "cannot mix naive and timezone-aware time"
return supersub(other) + timedelta(minutes=otoff-myoff)
Index: obj_datetimetz.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_datetimetz.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** obj_datetimetz.c 14 Dec 2002 06:38:09 -0000 1.12
--- obj_datetimetz.c 14 Dec 2002 08:03:14 -0000 1.13
***************
*** 236,304 ****
*/
static PyObject *
! add_datetimetz_timedelta(PyDateTime_DateTimeTZ *date, PyDateTime_Delta *delta)
! {
! /* Note that the C-level additions can't overflow, because of
! * invariant bounds on the member values.
! */
! long year = GET_YEAR(date);
! long month = GET_MONTH(date);
! long day = GET_DAY(date) + GET_TD_DAYS(delta);
! long hour = DATE_GET_HOUR(date);
! long minute = DATE_GET_MINUTE(date);
! long second = DATE_GET_SECOND(date) + GET_TD_SECONDS(delta);
! long microsecond = DATE_GET_MICROSECOND(date) +
! GET_TD_MICROSECONDS(delta);
!
! if (normalize_datetime(&year, &month, &day,
! &hour, &minute, &second, µsecond) < 0)
! return NULL;
! else
! return new_datetime(year, month, day,
! hour, minute, second, microsecond);
! }
!
! static PyObject *
! sub_datetimetz_timedelta(PyDateTime_DateTimeTZ *date, PyDateTime_Delta *delta)
{
! /* Note that the C-level subtractions can't overflow, because of
! * invariant bounds on the member values.
! */
! long year = GET_YEAR(date);
! long month = GET_MONTH(date);
! long day = GET_DAY(date) - GET_TD_DAYS(delta);
! long hour = DATE_GET_HOUR(date);
! long minute = DATE_GET_MINUTE(date);
! long second = DATE_GET_SECOND(date) - GET_TD_SECONDS(delta);
! long microsecond = DATE_GET_MICROSECOND(date) -
! GET_TD_MICROSECONDS(delta);
! if (normalize_datetime(&year, &month, &day,
! &hour, &minute, &second, µsecond) < 0)
! return NULL;
! else
! return new_datetime(year, month, day,
! hour, minute, second, microsecond);
! }
! static PyObject *
! sub_datetimetz_datetime(PyDateTime_DateTimeTZ *left, PyDateTime_DateTimeTZ *right)
! {
! long days1 = ymd_to_ord(GET_YEAR(left),
! GET_MONTH(left),
! GET_DAY(left));
! long days2 = ymd_to_ord(GET_YEAR(right),
! GET_MONTH(right),
! GET_DAY(right));
! /* These can't overflow, since the values are normalized. At most
! * this gives the number of seconds in one day.
! */
! long delta_s = (DATE_GET_HOUR(left) - DATE_GET_HOUR(right)) * 3600 +
! (DATE_GET_MINUTE(left) - DATE_GET_MINUTE(right)) * 60 +
! DATE_GET_SECOND(left) - DATE_GET_SECOND(right);
! long delta_us = DATE_GET_MICROSECOND(left) -
! DATE_GET_MICROSECOND(right);
! return new_delta(days1 - days2, delta_s, delta_us, 1);
}
--- 236,275 ----
*/
+ /* If base is Py_NotImplemented or NULL, just return it.
+ * Else base is a datetime, exactly one of {left, right} is a datetimetz,
+ * and we want to create a datetimetz with the same date and time fields
+ * as base, and with the tzinfo field from left or right. Do that,
+ * return it, and decref base. This is used to transform the result of
+ * a binary datetime operation (base) into a datetimetz result.
+ */
static PyObject *
! attach_tzinfo(PyObject *base, PyObject *left, PyObject *right)
{
! PyDateTime_DateTimeTZ *self;
! PyDateTime_DateTimeTZ *result;
! if (base == NULL || base == Py_NotImplemented)
! return base;
! assert(PyDateTime_CheckExact(base));
! if (PyDateTimeTZ_Check(left)) {
! assert(! PyDateTimeTZ_Check(right));
! self = (PyDateTime_DateTimeTZ *)left;
! }
! else {
! assert(PyDateTimeTZ_Check(right));
! self = (PyDateTime_DateTimeTZ *)right;
! }
! result = PyObject_New(PyDateTime_DateTimeTZ,
! &PyDateTime_DateTimeTZType);
! if (result != NULL) {
! memcpy(result->data, ((PyDateTime_DateTime *)base)->data,
! _PyDateTime_DATETIME_DATASIZE);
! Py_INCREF(self->tzinfo);
! result->tzinfo = self->tzinfo;
! }
! Py_DECREF(base);
! return (PyObject *)result;
}
***************
*** 306,324 ****
datetimetz_add(PyObject *left, PyObject *right)
{
! if (PyDateTime_Check(left)) {
! /* datetime + ??? */
! if (PyDelta_Check(right))
! /* datetime + delta */
! return add_datetimetz_timedelta(
! (PyDateTime_DateTimeTZ *)left,
! (PyDateTime_Delta *)right);
! }
! else if (PyDelta_Check(left)) {
! /* delta + datetime */
! return add_datetimetz_timedelta((PyDateTime_DateTimeTZ *) right,
! (PyDateTime_Delta *) left);
! }
! Py_INCREF(Py_NotImplemented);
! return Py_NotImplemented;
}
--- 277,281 ----
datetimetz_add(PyObject *left, PyObject *right)
{
! return attach_tzinfo(datetime_add(left, right), left, right);
}
***************
*** 330,344 ****
if (PyDateTime_Check(left)) {
/* datetime - ??? */
! if (PyDelta_Check(right)) {
/* datetime - datetime */
! result = sub_datetimetz_datetime(
! (PyDateTime_DateTimeTZ *)left,
! (PyDateTime_DateTimeTZ *)right);
}
else if (PyDelta_Check(right)) {
! /* datetime - delta */
! result = sub_datetimetz_timedelta(
! (PyDateTime_DateTimeTZ *)left,
(PyDateTime_Delta *)right);
}
}
--- 287,333 ----
if (PyDateTime_Check(left)) {
/* datetime - ??? */
! if (PyDateTime_Check(right)) {
/* datetime - datetime */
! naivety n1, n2;
! long offset1, offset2;
! PyDateTime_Delta *delta;
!
! n1 = classify_object(left, &offset1);
! assert(n1 != OFFSET_UNKNOWN);
! if (n1 == OFFSET_ERROR)
! return NULL;
!
! n2 = classify_object(right, &offset2);
! assert(n2 != OFFSET_UNKNOWN);
! if (n2 == OFFSET_ERROR)
! return NULL;
!
! if (n1 != n2) {
! PyErr_SetString(PyExc_TypeError,
! "can't subtract offset-naive and "
! "offset-aware datetimes");
! return NULL;
! }
! delta = (PyDateTime_Delta *)sub_datetime_datetime(
! (PyDateTime_DateTime *)left,
! (PyDateTime_DateTime *)right);
! if (delta == NULL || offset1 == offset2)
! return (PyObject *)delta;
! /* (left - offset1) - (right - offset2) =
! * (left - right) + (offset2 - offset1)
! */
! result = new_delta(delta->days,
! delta->seconds +
! (offset2 - offset1) * 60,
! delta->microseconds,
! 1);
! Py_DECREF(delta);
}
else if (PyDelta_Check(right)) {
! /* datetimetz - delta */
! result = sub_datetime_timedelta(
! (PyDateTime_DateTime *)left,
(PyDateTime_Delta *)right);
+ result = attach_tzinfo(result, left, right);
}
}
Index: test_both.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_both.py,v
retrieving revision 1.79
retrieving revision 1.80
diff -C2 -d -r1.79 -r1.80
*** test_both.py 14 Dec 2002 06:38:09 -0000 1.79
--- test_both.py 14 Dec 2002 08:03:14 -0000 1.80
***************
*** 1666,1671 ****
self.assertRaises(ValueError, lambda: bool(t))
! # XXX Derive this from TestDateTime.
! class TestDateTimeTZ(unittest.TestCase):
theclass = datetimetz
--- 1666,1670 ----
self.assertRaises(ValueError, lambda: bool(t))
! class TestDateTimeTZ(TestDateTime):
theclass = datetimetz
***************
*** 1681,1766 ****
self.assertEqual(dt.microsecond, 7)
self.assertEqual(dt.tzinfo, None)
-
- # XXX This is a copy of TestDate's routine. We'll eventually inherit
- # XXX it.
- def test_compare(self):
- t1 = self.theclass(2, 3, 4)
- t2 = self.theclass(2, 3, 4)
- self.failUnless(t1 == t2)
- self.failUnless(t1 <= t2)
- self.failUnless(t1 >= t2)
- self.failUnless(not t1 != t2)
- self.failUnless(not t1 < t2)
- self.failUnless(not t1 > t2)
- self.assertEqual(cmp(t1, t2), 0)
- self.assertEqual(cmp(t2, t1), 0)
-
- for args in (3, 3, 3), (2, 4, 4), (2, 3, 5):
- t2 = self.theclass(*args) # this is larger than t1
- self.failUnless(t1 < t2)
- self.failUnless(t2 > t1)
- self.failUnless(t1 <= t2)
- self.failUnless(t2 >= t1)
- self.failUnless(t1 != t2)
- self.failUnless(t2 != t1)
- self.failUnless(not t1 == t2)
- self.failUnless(not t2 == t1)
- self.failUnless(not t1 > t2)
- self.failUnless(not t2 < t1)
- self.failUnless(not t1 >= t2)
- self.failUnless(not t2 <= t1)
- self.assertEqual(cmp(t1, t2), -1)
- self.assertEqual(cmp(t2, t1), 1)
-
- for badarg in 10, 10L, 34.5, "abc", {}, [], ():
- self.assertRaises(TypeError, lambda: t1 == badarg)
- self.assertRaises(TypeError, lambda: t1 != badarg)
- self.assertRaises(TypeError, lambda: t1 <= badarg)
- self.assertRaises(TypeError, lambda: t1 < badarg)
- self.assertRaises(TypeError, lambda: t1 > badarg)
- self.assertRaises(TypeError, lambda: t1 >= badarg)
- self.assertRaises(TypeError, lambda: badarg == t1)
- self.assertRaises(TypeError, lambda: badarg != t1)
- self.assertRaises(TypeError, lambda: badarg <= t1)
- self.assertRaises(TypeError, lambda: badarg < t1)
- self.assertRaises(TypeError, lambda: badarg > t1)
- self.assertRaises(TypeError, lambda: badarg >= t1)
-
- # XXX This is a copy of TestDateTime's routine. We'll eventually inherit
- # XXX it.
- def test_more_compare(self):
- # The test_compare() inherited from TestDate covers the error cases.
- # We just want to test lexicographic ordering on the members datetime
- # has that date lacks.
- args = [2000, 11, 29, 20, 58, 16, 999998]
- t1 = self.theclass(*args)
- t2 = self.theclass(*args)
- self.failUnless(t1 == t2)
- self.failUnless(t1 <= t2)
- self.failUnless(t1 >= t2)
- self.failUnless(not t1 != t2)
- self.failUnless(not t1 < t2)
- self.failUnless(not t1 > t2)
- self.assertEqual(cmp(t1, t2), 0)
- self.assertEqual(cmp(t2, t1), 0)
-
- for i in range(len(args)):
- newargs = args[:]
- newargs[i] = args[i] + 1
- t2 = self.theclass(*newargs) # this is larger than t1
- self.failUnless(t1 < t2)
- self.failUnless(t2 > t1)
- self.failUnless(t1 <= t2)
- self.failUnless(t2 >= t1)
- self.failUnless(t1 != t2)
- self.failUnless(t2 != t1)
- self.failUnless(not t1 == t2)
- self.failUnless(not t2 == t1)
- self.failUnless(not t1 > t2)
- self.failUnless(not t2 < t1)
- self.failUnless(not t1 >= t2)
- self.failUnless(not t2 <= t1)
- self.assertEqual(cmp(t1, t2), -1)
- self.assertEqual(cmp(t2, t1), 1)
def test_even_more_compare(self):
--- 1680,1683 ----