[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, &microsecond) < 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, &microsecond) < 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 ----

AltStyle によって変換されたページ (->オリジナル) /