[Python-checkins] python/nondist/sandbox/datetime datetime.c,1.28,1.29 datetime.py,1.66,1.67 obj_date.c,1.10,1.11 obj_datetime.c,1.5,1.6 obj_delta.c,1.7,1.8 test_both.py,1.10,1.11 test_datetime.py,1.52,1.53 test_cdatetime.py,1.13,NONE

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Sun, 01 Dec 2002 11:37:31 -0800


Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv3635

Modified Files:
	datetime.c datetime.py obj_date.c obj_datetime.c obj_delta.c 
	test_both.py test_datetime.py 
Removed Files:
	test_cdatetime.py 
Log Message:
A huge # of changes, mostly implementing missing methods and getting the
arithmetic to work.  All test_both.py tests pass now, under both the C
and Python implementations.  No unique tests remained in test_cdatetime.py,
so that file was removed from the project.


Index: datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -C2 -d -r1.28 -r1.29
*** datetime.c	26 Nov 2002 23:02:52 -0000	1.28
--- datetime.c	1 Dec 2002 19:37:28 -0000	1.29
***************
*** 18,22 ****
  	PyObject_HEAD
  	long hashcode;
! 	long days;		/* this may be negative */
  	long seconds;		/* 0 <= seconds < 24*3600 is invariant */
  	long microseconds;	/* 0 <= microseconds < 1000000 is invariant */
--- 18,22 ----
  	PyObject_HEAD
  	long hashcode;
! 	long days;		/* in -TOOBIG_INPUT .. TOOBIG_INPUT */
  	long seconds;		/* 0 <= seconds < 24*3600 is invariant */
  	long microseconds;	/* 0 <= microseconds < 1000000 is invariant */
***************
*** 96,99 ****
--- 96,126 ----
  }
  
+ /* All input fields (year, month, day, hour, minute, second, millisecond,
+  * microsecond) are constrained to lie within -TOOBIG_INPUT .. TOOBIG_INPUT
+  * exclusive of endpoints.  You can't make this larger without studying the
+  * code very carefully, as various "can't overflow" assurances follow
+  * from the specific value used here.
+  */
+ #define TOOBIG_INPUT 1000000000  /* a billion; 1e9 */
+ 
+ /* Check that x is in the range given above.  If so, return 0.  If not,
+  * raise the given exception and return -1.
+  */
+ static int
+ check_range(long x, const char* tag, PyObject *exception)
+ {
+ 	char buf[200];
+ 
+ 	if (-TOOBIG_INPUT < x && x < TOOBIG_INPUT)
+ 		return 0;
+ 	/* PyErr_Format() ignores the "l" in "%ld", which isn't correct
+ 	 * on boxes where sizeof(long) > sizeof(int).  So roll our own.
+ 	 */
+ 	PyOS_snprintf(buf, sizeof(buf), "%s=%ld; must have magnitude < %ld",
+ 		      tag, x, TOOBIG_INPUT);
+ 	PyErr_SetString(exception, buf);
+ 	return -1;
+ }
+ 
  /* For each month ordinal in 1..12, the number of days in that month,
   * and the number of days before that month in the same year.  These
***************
*** 327,460 ****
  
  
! /* Create a date instance with no range checking. */
! static PyObject *
! new_date(int year, int month, int day)
  {
! 	PyDateTime_Date *self;
! 
! 	self = PyObject_New(PyDateTime_Date, &PyDateTime_DateType);
! 	if (self != NULL) {
! 		self->hashcode = -1;
! 		SET_YEAR(self, year);
! 		SET_MONTH(self, month);
! 		SET_DAY(self, day);
  	}
! 	return (PyObject *) self;
  }
  
! /* Create a datetime instance with no range checking. */
! static PyObject *
! new_datetime(int year, int month, int day, int hour, int minute,
!              int second, int usecond)
  {
! 	PyDateTime_DateTime *self;
  
- 	self = PyObject_New(PyDateTime_DateTime, &PyDateTime_DateTimeType);
- 	if (self != NULL) {
- 		self->hashcode = -1;
- 		SET_YEAR(self, year);
- 		SET_MONTH(self, month);
- 		SET_DAY(self, day);
- 		SET_HOUR(self, hour);
- 		SET_MINUTE(self, minute);
- 		SET_SECOND(self, second);
- 		SET_MICROSECOND(self, usecond);
  	}
! 	return (PyObject *) self;
  }
  
! /* An internal struct used for miserable normalization tasks. */
! typedef struct s_tmxxx {
! 	long year;	/* may be negative on output */
! 	long month; 	/* in 1..12 on output */
! 	long day;	/* in 1 .. days_in_month(year, month) on output */
! 	long hour;	/* in 0..23 on output */
! 	long minute;	/* in 0..59 on output */
! 	long second;	/* in 0 .. 59 on output */
! 	long microsecond;	/* in 0..999999 on output */
! } tmxxx;
! 
! #define TMXXX_CLEAR(PTR_TO_TMXXX) \
! 	memset(PTR_TO_TMXXX, 0, sizeof(struct s_tmxxx))
! 
! /* One step of mixed-radix conversion.  *lower is the lower unit and *higher
!  * the higher unit, such that 1 higher unit is equal to bound lower units.
!  * Normalize *lower to lie in range(bound), adding carries (if needed) to
!  * higher.
!  * If a carry is needed, adding into *higher may overflow.  In that case,
!  * retuns a non-zero value.  If everything is OK, returns 0.
   */
! static int
! norm1(long *higher, long *lower, long bound)
  {
! 	assert(bound > 0);
! 	if (*lower < 0 || *lower >= bound) {
! 		long carry;
! 		long new_higher;
  
- 		carry = divmod(*lower, bound, lower);
- 		assert(0 <= *lower && *lower < bound);
- 		new_higher = *higher + carry;
- 		if (SIGNED_ADD_OVERFLOWED(new_higher, *higher, carry))
- 			return 1;
- 		*higher = new_higher;
  	}
! 	return 0;
  }
  
! static int
! tmxxx_normalize(tmxxx *p)
  {
! 	int dim;	/* days in month */
! 	char *msg;
  
! 	if (norm1(&p->second, &p->microsecond, 1000000)) {
! 		msg = "second component too large";
! 		goto Overflow;
  	}
! 	assert(0 <= p->microsecond && p->microsecond < 1000000);
  
! 	if (norm1(&p->minute, &p->second, 60)) {
! 		msg = "minute component too large";
! 		goto Overflow;
  	}
! 	assert(0 <= p->second && p->second < 60);
  
! 	if (norm1(&p->hour, &p->minute, 60)) {
! 		msg = "hour component too large";
! 		goto Overflow;
  	}
! 	assert(0 <= p->minute && p->minute < 60);
  
! 	if (norm1(&p->day, &p->hour, 60)) {
! 		msg = "hour component too large";
! 		goto Overflow;
! 	}
! 	assert(0 <= p->hour && p->hour < 24);
  
! 	/* That was easy.  Now it gets muddy:  the proper range for day
! 	 * can't be determined without knowing the correct month and year,
! 	 * but if day is, e.g., plus or minus a million, the current month
! 	 * and year values make no sense (and may also be out of bounds
! 	 * themselves).
  	 * Saying 12 months == 1 year should be non-controversial.
  	 */
! 	if (p->month < 1 || p->month > 12) {
! 		--p->month;
! 		if (norm1(&p->year, &p->month, 12)) {
! 			msg = "year component too large";
! 			goto Overflow;
! 		}
! 		++p->month;
! 		assert (1 <= p->month && p->month <= 12);
  	}
  
- 	/* The other routines don't deal correctly with years < 0, so cut
- 	 * that off now.
- 	 */
- 	if (p->year < 0) {
- 		msg = "year component is negative";
- 		goto Overflow;
- 	}
  	/* Now only day can be out of bounds (year may also be out of bounds
  	 * for a datetime object, but we don't care about that here).
--- 354,519 ----
  
  
! /* One step of a mixed-radix conversion.  A "hi" unit is equivalent to
!  * factor "lo" units.  factor must be > 0.  If *lo is less than 0, or
!  * at least factor, enough of *lo is converted into "hi" units so that
!  * 0 <= *lo < factor.  The input values must be such that long overflow
!  * is impossible.
!  */
! static void
! normalize_pair(long *hi, long *lo, long factor)
  {
! 	assert(factor > 0);
! 	assert(lo != hi);
! 	if (*lo < 0 || *lo >= factor) {
! 		const long num_hi = divmod(*lo, factor, lo);
! 		const long new_hi = *hi + num_hi;
! 		assert(! SIGNED_ADD_OVERFLOWED(new_hi, *hi, num_hi));
! 		*hi = new_hi;
  	}
! 	assert(0 <= *lo && *lo < factor);
  }
  
! /* Fiddle days (d), hours (h), and minutes (m) so that
!  * 	0 <= *h < 24
!  * 	0 <= *m < 60
!  * The input values must be such that the internals don't overflow.
!  * The way this routine is used, we don't get close.
!  */
! static void
! normalize_d_h_m(long *d, long *h, long *m)
  {
! 	if (*m < 0 || *m >= 60) {
! 		normalize_pair(h, m, 60);
! 		/* |h| can't be bigger than about
! 		 * |original h| + |original m|/60 now.
! 		 */
  
  	}
! 	if (*h < 0 || *h >= 24) {
! 		normalize_pair(d, h, 24);
! 		/* |d| can't be bigger than about
! 		 * |original d| +
! 		 * (|original h| + |original m|/60) / 24 now.
! 		 */
! 	}
! 	assert(0 <= *h && *h < 24);
! 	assert(0 <= *m && *m < 60);
  }
  
! /* Fiddle days (d), seconds (s), and microseconds (us) so that
!  * 	0 <= *s < 24*3600
!  * 	0 <= *us < 1000000
!  * The input values must be such that the internals don't overflow.
!  * The way this routine is used, we don't get close.
   */
! static void
! normalize_d_s_us(long *d, long *s, long *us)
  {
! 	if (*us < 0 || *us >= 1000000) {
! 		normalize_pair(s, us, 1000000);
! 		/* |s| can't be bigger than about
! 		 * |original s| + |original us|/1000000 now.
! 		 */
  
  	}
! 	if (*s < 0 || *s >= 24*3600) {
! 		normalize_pair(d, s, 24*3600);
! 		/* |d| can't be bigger than about
! 		 * |original d| +
! 		 * (|original s| + |original us|/1000000) / (24*3600) now.
! 		 */
! 	}
! 	assert(0 <= *s && *s < 24*3600);
! 	assert(0 <= *us && *us < 1000000);
  }
  
! /* Fiddle days (d), seconds (s), and microseconds (us) so that the output
!  * duration is the same as the input duration, but with hours (h),
!  * minutes (m), and milliseconds (ms) all 0.
!  * The input values must be such that the internals don't overflow.  The
!  * way this routine is used, we don't get close.
!  * The output d, s, and us are intended to be passed to normalize_d_s_us
!  * to get them into their proper ranges.
!  */
! static void
! squash_h_m_ms_out_of_d_h_m_s_ms_us(long *d, long h, long m,
! 				   long *s, long ms, long *us)
  {
! 	if (h) {
! 		long new_minutes;
  
!        		normalize_pair(d, &h, 24);
! 		/* |d| can't be bigger than about
! 		 * |original d| + |original h|/24 now.
! 		 * h can't bigger than 23.
! 		 */
! 		new_minutes = m + h*60;
! 		assert(! SIGNED_ADD_OVERFLOWED(new_minutes, m, h*60));
! 		m = new_minutes;
! 		/* |m| can't be bigger than about
! 		 * |original m| + 23*60 now.
! 		 */
  	}
! 	if (m) {
! 		long new_seconds;
  
! 		normalize_pair(d, &m, 24*60);
! 		/* |d| can't be bigger than about
! 		 * |original d| + |original h|/24 +
! 		 * (|original m| + 23*60)/(24*60) now.
! 		 * m can't bigger than 24*60-1.
! 		 */
! 		new_seconds = *s + m*60;
! 		assert(! SIGNED_ADD_OVERFLOWED(new_seconds, *s, m*60));
! 		*s = new_seconds;
! 		/* |s| can't be bigger than about
! 		 * |original s| + (24*60-1) * 60 now.
! 		 */
  	}
! 	if (ms) {
! 		long new_us;
  
! 		normalize_pair(s, &ms, 1000);
! 		/* |s| can't be bigger than about
! 		 * |original s| + (24*60-1) * 60 + |original ms|/1000 now.
! 		 * ms can't be bigger than 999.
! 		 */
! 		new_us = *us + ms * 1000;
! 		assert(! SIGNED_ADD_OVERFLOWED(new_us, *us, ms*1000));
! 		*us = new_us;
! 		/* |us| can't be bigger than about
! 		 * |original us| + 999 * 1000.
! 		 */
  	}
! }
  
! /* Fiddle years (y), months (m), and days (d) so that
!  * 	1 <= *m <= 12
!  * 	1 <= *d <= days_in_month(*y, *m)
!  * The input values must be such that the internals don't overflow.
!  * The way this routine is used, we don't get close.
!  */
! static void
! normalize_y_m_d(long *y, long *m, long *d)
! {
! 	int dim;	/* # of days in month */
  
! 	/* This gets muddy:  the proper range for day can't be determined
! 	 * without knowing the correct month and year, but if day is, e.g.,
! 	 * plus or minus a million, the current month and year values make
! 	 * no sense (and may also be out of bounds themselves).
  	 * Saying 12 months == 1 year should be non-controversial.
  	 */
! 	if (*m < 1 || *m > 12) {
! 		--*m;
! 		normalize_pair(y, m, 12);
! 		++*m;
! 		/* |y| can't be bigger than about
! 		 * |original y| + |original m|/12 now.
! 		 */
  	}
+ 	assert(1 <= *m && *m <= 12);
+ 	assert(INT_MIN < *y && *y < INT_MAX);  /* so cast to int is safe */
  
  	/* Now only day can be out of bounds (year may also be out of bounds
  	 * for a datetime object, but we don't care about that here).
***************
*** 462,503 ****
  	 * method here is principled and explainable.
  	 */
! 	dim = days_in_month(p->year, p->month);
! 	if (p->day < 1 || p->day > dim) {
  		/* Move day-1 days from the first of the month.  First try to
  		 * get off cheap if we're only one day out of range
  		 * (adjustments for timezone alone can't be worse than that).
  		 */
! 		if (p->day == 0) {
! 			--p->month;
! 			if (p->month > 0)
! 				p->day = days_in_month(p->year, p->month);
  			else {
! 				--p->year;
! 				p->month = 12;
! 				p->day = 31;
  			}
  		}
! 		else if (p->day == dim + 1) {
  			/* move forward a day */
! 			++p->month;
! 			p->day = 1;
! 			if (p->month > 12) {
! 				p->month = 1;
! 				++p->year;
  			}
  		}
  		else {
! 			long ordinal = ymd_to_ord(p->year, p->month, 1) +
! 						  p->day - 1;
! 			ord_to_ymd(ordinal, &p->year, &p->month, &p->day);
  		}
  	}
! 	assert(p->month > 0);
! 	assert(p->day > 0);
! 	return 1;
  
! Overflow:
! 	PyErr_SetString(PyExc_OverflowError, msg);
! 	return 0;
  }
  
--- 521,603 ----
  	 * method here is principled and explainable.
  	 */
! 	dim = days_in_month((int)*y, (int)*m);
! 	if (*d < 1 || *d > dim) {
  		/* Move day-1 days from the first of the month.  First try to
  		 * get off cheap if we're only one day out of range
  		 * (adjustments for timezone alone can't be worse than that).
  		 */
! 		if (*d == 0) {
! 			--*m;
! 			if (*m > 0)
! 				*d = days_in_month((int)*y, (int)*m);
  			else {
! 				--*y;
! 				*m = 12;
! 				*d = 31;
  			}
  		}
! 		else if (*d == dim + 1) {
  			/* move forward a day */
! 			++*m;
! 			*d = 1;
! 			if (*m > 12) {
! 				*m = 1;
! 				++*y;
  			}
  		}
  		else {
! 			long ordinal = ymd_to_ord((int)*y, (int)*m, 1) +
! 						  *d - 1;
! 			ord_to_ymd(ordinal, y, m, d);
  		}
  	}
! 	assert(*m > 0);
! 	assert(*d > 0);
! }
  
! static PyObject *us_per_ms = NULL;
! static PyObject *us_per_second = NULL;
! static PyObject *us_per_minute = NULL;
! static PyObject *us_per_hour = NULL;
! static PyObject *us_per_day = NULL;
! static PyObject *us_per_week = NULL;
! 
! static PyObject *seconds_per_day = NULL;
! 
! /* Create a date instance with no range checking. */
! static PyObject *
! new_date(int year, int month, int day)
! {
! 	PyDateTime_Date *self;
! 
! 	self = PyObject_New(PyDateTime_Date, &PyDateTime_DateType);
! 	if (self != NULL) {
! 		self->hashcode = -1;
! 		SET_YEAR(self, year);
! 		SET_MONTH(self, month);
! 		SET_DAY(self, day);
! 	}
! 	return (PyObject *) self;
! }
! 
! /* Create a datetime instance with no range checking. */
! static PyObject *
! new_datetime(int year, int month, int day, int hour, int minute,
!              int second, int usecond)
! {
! 	PyDateTime_DateTime *self;
! 
! 	self = PyObject_New(PyDateTime_DateTime, &PyDateTime_DateTimeType);
! 	if (self != NULL) {
! 		self->hashcode = -1;
! 		SET_YEAR(self, year);
! 		SET_MONTH(self, month);
! 		SET_DAY(self, day);
! 		SET_HOUR(self, hour);
! 		SET_MINUTE(self, minute);
! 		SET_SECOND(self, second);
! 		SET_MICROSECOND(self, usecond);
! 	}
! 	return (PyObject *) self;
  }
  
***************
*** 505,539 ****
  new_delta(long days, long seconds, long microseconds)
  {
! 	PyDateTime_Delta *self = NULL;
  
! 	if (microseconds < 0 || microseconds >= 1000000) {
! 		long whole_seconds;
! 		long new_seconds;
  
! 		whole_seconds = divmod(microseconds, 1000000, &microseconds);
! 		assert(microseconds >= 0);
! 		new_seconds = seconds + whole_seconds;
! 		if (SIGNED_ADD_OVERFLOWED(new_seconds, seconds,
! 					  whole_seconds)) {
! 			PyErr_SetString(PyExc_OverflowError, "timedelta "
! 					"seconds component too large");
! 			goto done;
! 		}
! 		seconds = new_seconds;
! 	}
! 	if (seconds < 0 || seconds >= 24*3600) {
! 		long whole_days;
! 		long new_days;
  
- 		whole_days = divmod(seconds, 24*3600, &seconds);
- 		assert(seconds >= 0);
- 		new_days = days + whole_days;
- 		if (SIGNED_ADD_OVERFLOWED(new_days, days, whole_days)) {
- 			PyErr_SetString(PyExc_OverflowError, "timedelta "
- 					"days component too large");
- 			goto done;
- 		}
- 		days = new_days;
- 	}
  	self = PyObject_New(PyDateTime_Delta, &PyDateTime_DeltaType);
  	if (self != NULL) {
--- 605,615 ----
  new_delta(long days, long seconds, long microseconds)
  {
! 	PyDateTime_Delta *self;
  
! 	normalize_d_s_us(&days, &seconds, &microseconds);
  
!  	if (check_range(days, "timedelta days", PyExc_OverflowError) < 0)
!  		return NULL;
  
  	self = PyObject_New(PyDateTime_Delta, &PyDateTime_DeltaType);
  	if (self != NULL) {
***************
*** 543,547 ****
  		SET_TD_MICROSECONDS(self, microseconds);
  	}
- done:
  	return (PyObject *) self;
  }
--- 619,622 ----
***************
*** 627,630 ****
--- 702,717 ----
  	assert(DI100Y == 25 * DI4Y - 1);
  	assert(DI100Y == days_before_year(100+1));
+ 
+ 	us_per_ms = PyInt_FromLong(1000);
+ 	us_per_second = PyInt_FromLong(1000000);
+ 	us_per_minute = PyInt_FromLong(60000000);
+ 	seconds_per_day = PyInt_FromLong(24 * 3600);
+ 
+ 	/* The rest are too big for 32-bit ints, but even
+ 	 * us_per_week fits in 40 bits, so doubles should be exact.
+ 	 */
+ 	us_per_hour = PyLong_FromDouble(3600000000.0);
+ 	us_per_day = PyLong_FromDouble(86400000000.0);
+ 	us_per_week = PyLong_FromDouble(604800000000.0);
  
  }

Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.66
retrieving revision 1.67
diff -C2 -d -r1.66 -r1.67
*** datetime.py	26 Nov 2002 18:03:19 -0000	1.66
--- datetime.py	1 Dec 2002 19:37:28 -0000	1.67
***************
*** 466,469 ****
--- 466,471 ----
          return 1
  
+     def __hash__(self):
+         return hash((self.__days, self.__seconds, self.__microseconds))
  
  class date(object):

Index: obj_date.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_date.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -C2 -d -r1.10 -r1.11
*** obj_date.c	26 Nov 2002 22:51:04 -0000	1.10
--- obj_date.c	1 Dec 2002 19:37:28 -0000	1.11
***************
*** 5,34 ****
  
  /* Fiddle out-of-bounds months and days so that the result makes some kind
!  * of sense.  The parameters are both inputs and outputs.  Returns 0 on
!  * failure and > 0 for success.  Failure means the adjusted year is out of
!  * bounds.
   */
  static int
  normalize_date(long *year, long *month, long *day)
  {
- 	tmxxx t;
  	int result;
  
! 	TMXXX_CLEAR(&t);
! 	t.year = *year;
! 	t.month = *month;
! 	t.day = *day;
! 	result = tmxxx_normalize(&t);
! 	if (result > 0) {
! 		/* looks good */
! 		*year = t.year;
! 		*month = t.month;
! 		*day = t.day;
! 
! 		if (*year < MINYEAR || *year > MAXYEAR) {
! 			PyErr_SetString(PyExc_OverflowError,
! 					"date value out of range");
! 			result = 0;
! 		}
  	}
  	return result;
--- 5,23 ----
  
  /* Fiddle out-of-bounds months and days so that the result makes some kind
!  * of sense.  The parameters are both inputs and outputs.  Returns < 0 on
!  * failure, where failure means the adjusted year is out of bounds.
   */
  static int
  normalize_date(long *year, long *month, long *day)
  {
  	int result;
  
! 	normalize_y_m_d(year, month, day);
! 	if (MINYEAR <= *year && *year <= MAXYEAR)
! 		result = 0;
! 	else {
! 		PyErr_SetString(PyExc_OverflowError,
! 				"date value out of range");
! 		result = -1;
  	}
  	return result;
***************
*** 64,71 ****
  		long int month = GET_MONTH(date);
  		long int day = GET_DAY(date) + GET_TD_DAYS(delta);
! 		if (normalize_date(&year, &month, &day))
! 			result = new_date(year, month, day);
! 		else
  			result = NULL;
  	}
  	else {
--- 53,60 ----
  		long int month = GET_MONTH(date);
  		long int day = GET_DAY(date) + GET_TD_DAYS(delta);
! 		if (normalize_date(&year, &month, &day) < 0)
  			result = NULL;
+ 		else
+ 			result = new_date(year, month, day);
  	}
  	else {
***************
*** 145,149 ****
  }
  
! static int
  date_hash(PyDateTime_Date *self)
  {
--- 134,138 ----
  }
  
! static long
  date_hash(PyDateTime_Date *self)
  {

Index: obj_datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_datetime.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** obj_datetime.c	21 Nov 2002 19:47:34 -0000	1.5
--- obj_datetime.c	1 Dec 2002 19:37:28 -0000	1.6
***************
*** 4,26 ****
   */
  
- static void
- normalize_pair(long int *parent, long int *child, int size)
- {
- 	if (*child < 0) {
- 		long int borrow = (*child / size) + 1;
- 		*parent -= borrow;
- 		*child += (borrow * size);
- 	}
- 	else if (*child >= size) {
- 		long int carry = *child / size;
- 		*parent += carry;
- 		*child -= (carry * size);
- 	}
- }
- 
  static int
! normalize_datetime(long int *year, long int *month, long int *day,
!                    long int *hour, long int *minute, long int *second,
!                    long int *microsecond)
  {
  	normalize_pair(second, microsecond, 1000000);
--- 4,11 ----
   */
  
  static int
! normalize_datetime(long *year, long *month, long *day,
!                    long *hour, long *minute, long *second,
!                    long *microsecond)
  {
  	normalize_pair(second, microsecond, 1000000);
***************
*** 28,32 ****
  	normalize_pair(hour, minute, 60);
  	normalize_pair(day, hour, 24);
- 
  	return normalize_date(year, month, day);
  }
--- 13,16 ----
***************
*** 35,52 ****
  add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta)
  {
! 	long int year = GET_YEAR(date);
! 	long int month = GET_MONTH(date);
! 	long int day = GET_DAY(date) + GET_TD_DAYS(delta);
! 	long int hour = GET_HOUR(date);
! 	long int minute = GET_MINUTE(date);
! 	long int second = GET_SECOND(date) + GET_TD_SECONDS(delta);
! 	long int microsecond = GET_MICROSECOND(date) + GET_TD_MICROSECONDS(delta);
  
  	if (normalize_datetime(&year, &month, &day,
! 			       &hour, &minute, &second, &microsecond))
  		return new_datetime(year, month, day,
  				    hour, minute, second, microsecond);
! 	else
  		return NULL;
  }
  
--- 19,78 ----
  add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta)
  {
! 	long year = GET_YEAR(date);
! 	long month = GET_MONTH(date);
! 	long day = GET_DAY(date) + GET_TD_DAYS(delta);
! 	long hour = GET_HOUR(date);
! 	long minute = GET_MINUTE(date);
! 	long second = GET_SECOND(date) + GET_TD_SECONDS(delta);
! 	long microsecond = 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_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta)
! {
! 	long year = GET_YEAR(date);
! 	long month = GET_MONTH(date);
! 	long day = GET_DAY(date) - GET_TD_DAYS(delta);
! 	long hour = GET_HOUR(date);
! 	long minute = GET_MINUTE(date);
! 	long second = GET_SECOND(date) - GET_TD_SECONDS(delta);
! 	long microsecond = 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_datetime_datetime(PyDateTime_DateTime *left, PyDateTime_DateTime *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 seconds1 = (GET_HOUR(left) * 60 + GET_MINUTE(left)) * 60 +
+ 			GET_SECOND(left);
+ 	long seconds2 = (GET_HOUR(right) * 60 + GET_MINUTE(right)) * 60 +
+ 			GET_SECOND(right);
+ 
+ 	long delta_us = GET_MICROSECOND(left) - GET_MICROSECOND(right);
+ 
+ 	return new_delta(days1 - days2, seconds1 - seconds2, delta_us);
  }
  
***************
*** 72,75 ****
--- 98,129 ----
  }
  
+ static PyObject *
+ datetime_subtract(PyObject *left, PyObject *right)
+ {
+ 	PyTypeObject *left_type = left->ob_type;
+ 	PyTypeObject *right_type = right->ob_type;
+ 	PyObject *result = Py_NotImplemented;
+ 
+ 	if (PyType_IsSubtype(left_type, &PyDateTime_DateTimeType)) {
+ 		/* datetime - ??? */
+ 		if (PyType_IsSubtype(right_type, &PyDateTime_DateTimeType)) {
+ 			/* datetime - datetime */
+ 			result = sub_datetime_datetime(
+ 					(PyDateTime_DateTime *)left,
+ 					(PyDateTime_DateTime *)right);
+ 		}
+ 		else if (PyType_IsSubtype(right_type, &PyDateTime_DeltaType)) {
+ 			/* datetime - timedelta */
+ 			result = sub_datetime_timedelta(
+ 					(PyDateTime_DateTime *)left,
+ 					(PyDateTime_Delta *)right);
+ 		}
+ 	}
+ 
+ 	if (result == Py_NotImplemented)
+ 		Py_INCREF(result);
+ 	return result;
+ }
+ 
  static int
  datetime_compare(PyDateTime_DateTime *self, PyObject *other)
***************
*** 91,120 ****
  }
  
! static int
  datetime_hash(PyDateTime_DateTime *self)
  {
  	if (self->hashcode == -1) {
  		PyObject *temp;
! 		if (GET_MICROSECOND(self) != 0)
! 			temp = Py_BuildValue("lllllll", GET_YEAR(self),
! 					     GET_MONTH(self), GET_DAY(self),
! 					     GET_HOUR(self), GET_MINUTE(self),
! 					     GET_SECOND(self), GET_MICROSECOND(self));
! 		else if (GET_SECOND(self) != 0)
! 			temp = Py_BuildValue("llllll", GET_YEAR(self),
! 					     GET_MONTH(self), GET_DAY(self),
! 					     GET_HOUR(self), GET_MINUTE(self),
! 					     GET_SECOND(self));
! 		else if (GET_MINUTE(self) != 0)
! 			temp = Py_BuildValue("lllll", GET_YEAR(self),
! 					     GET_MONTH(self), GET_DAY(self),
! 					     GET_HOUR(self), GET_MINUTE(self));
! 		else if (GET_HOUR(self) != 0)
! 			temp = Py_BuildValue("llll", GET_YEAR(self),
! 					     GET_MONTH(self), GET_DAY(self),
! 					     GET_HOUR(self));
! 		else
! 			temp = Py_BuildValue("lll", GET_YEAR(self),
! 					     GET_MONTH(self), GET_DAY(self));
  		if (temp != NULL) {
  			self->hashcode = PyObject_Hash(temp);
--- 145,157 ----
  }
  
! static long
  datetime_hash(PyDateTime_DateTime *self)
  {
  	if (self->hashcode == -1) {
  		PyObject *temp;
! 		temp = Py_BuildValue("lllllll", GET_YEAR(self),
! 				     GET_MONTH(self), GET_DAY(self),
! 				     GET_HOUR(self), GET_MINUTE(self),
! 				     GET_SECOND(self), GET_MICROSECOND(self));
  		if (temp != NULL) {
  			self->hashcode = PyObject_Hash(temp);
***************
*** 213,224 ****
  	return PyString_FromString(buffer);
  }
- 
- static PyObject *
- datetime_subtract(PyObject *left, PyObject *right)
- {
- 	Py_INCREF(Py_NotImplemented);
- 	return Py_NotImplemented;
- }
- 
  
  static PyObject *
--- 250,253 ----

Index: obj_delta.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_delta.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -d -r1.7 -r1.8
*** obj_delta.c	26 Nov 2002 05:37:09 -0000	1.7
--- obj_delta.c	1 Dec 2002 19:37:28 -0000	1.8
***************
*** 1,7 ****
! /* imp_delta.c
   *
   * PyDateTime_Delta implementation.
   */
  
  
  static PyObject *
--- 1,168 ----
! /* obj_delta.c
   *
   * PyDateTime_Delta implementation.
   */
  
+ /* Convert a timedelta to a number of us,
+  * 	(24*3600*self.days + self.seconds)*1000000 + self.microseconds
+  * as a Python int or long.
+  * Doing mixed-radix arithmetic by hand instead is excruciating in C,
+  * due to ubiquitous overflow possibilities.
+  */
+ static PyObject *
+ delta_to_microseconds(PyDateTime_Delta *self)
+ {
+ 	PyObject *x1 = NULL;
+ 	PyObject *x2 = NULL;
+ 	PyObject *x3 = NULL;
+ 	PyObject *result = NULL;
+ 
+ 	x1 = PyInt_FromLong(GET_TD_DAYS(self));
+ 	if (x1 == NULL)
+ 		goto Done;
+ 	x2 = PyNumber_Multiply(x1, seconds_per_day);	/* days in seconds */
+ 	if (x2 == NULL)
+ 		goto Done;
+ 	Py_DECREF(x1);
+ 	x1 = NULL;
+ 
+ 	/* x2 has days in seconds */
+ 	x1 = PyInt_FromLong(GET_TD_SECONDS(self));	/* seconds */
+ 	if (x1 == NULL)
+ 		goto Done;
+ 	x3 = PyNumber_Add(x1, x2);	/* days and seconds in seconds */
+ 	if (x3 == NULL)
+ 		goto Done;
+ 	Py_DECREF(x1);
+ 	Py_DECREF(x2);
+ 	x1 = x2 = NULL;
+ 
+ 	/* x3 has days+seconds in seconds */
+ 	x1 = PyNumber_Multiply(x3, us_per_second);	/* us */
+ 	if (x1 == NULL)
+ 		goto Done;
+ 	Py_DECREF(x3);
+ 	x3 = NULL;
+ 
+ 	/* x1 has days+seconds in us */
+ 	x2 = PyInt_FromLong(GET_TD_MICROSECONDS(self));
+ 	if (x2 == NULL)
+ 		goto Done;
+ 	result = PyNumber_Add(x1, x2);
+ 
+ Done:
+ 	Py_XDECREF(x1);
+ 	Py_XDECREF(x2);
+ 	Py_XDECREF(x3);
+ 	return result;
+ }
+ 
+ /* Convert a number of us (as a Python int or long) to a timedelta.
+  */
+ static PyObject *
+ microseconds_to_delta(PyObject *pyus)
+ {
+ 	long us;
+ 	long s;
+ 	long d;
+ 
+ 	PyObject *tuple = NULL;
+ 	PyObject *num = NULL;
+ 	PyObject *result = NULL;
+ 
+ 	tuple = PyNumber_Divmod(pyus, us_per_second);
+ 	if (tuple == NULL)
+ 		goto Done;
+ 
+ 	num = PyTuple_GetItem(tuple, 1);	/* us */
+ 	if (num == NULL)
+ 		goto Done;
+ 	us = PyLong_AsLong(num);
+ 	num = NULL;
+ 	if (us < 0) {
+ 		/* The divisor was positive, so this must be an error. */
+ 		assert(PyErr_Occurred());
+ 		goto Done;
+ 	}
+ 
+ 	num = PyTuple_GetItem(tuple, 0);	/* leftover seconds */
+ 	if (num == NULL)
+ 		goto Done;
+ 	Py_INCREF(num);
+ 	Py_DECREF(tuple);
+ 
+ 	tuple = PyNumber_Divmod(num, seconds_per_day);
+ 	if (tuple == NULL)
+ 		goto Done;
+ 	Py_DECREF(num);
+ 
+ 	num = PyTuple_GetItem(tuple, 1); 	/* seconds */
+ 	if (num == NULL)
+ 		goto Done;
+ 	s = PyLong_AsLong(num);
+ 	num = NULL;
+ 	if (s < 0) {
+ 		/* The divisor was positive, so this must be an error. */
+ 		assert(PyErr_Occurred());
+ 		goto Done;
+ 	}
+ 
+ 	num = PyTuple_GetItem(tuple, 0);	/* leftover days */
+ 	if (num == NULL)
+ 		goto Done;
+ 	Py_INCREF(num);
+ 
+ 	d = PyLong_AsLong(num);
+ 	if (d == -1 && PyErr_Occurred())
+ 		goto Done;
+ 	result = new_delta(d, s, us);
+ 
+ Done:
+ 	Py_XDECREF(tuple);
+ 	Py_XDECREF(num);
+ 	return result;
+ }
+ 
+ static PyObject *
+ multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta)
+ {
+ 	PyObject *pyus_in;
+ 	PyObject *pyus_out;
+ 	PyObject *result;
+ 
+ 	pyus_in = delta_to_microseconds(delta);
+ 	if (pyus_in == NULL)
+ 		return NULL;
+ 
+ 	pyus_out = PyNumber_Multiply(pyus_in, intobj);
+ 	Py_DECREF(pyus_in);
+ 	if (pyus_out == NULL)
+ 		return NULL;
+ 
+ 	result = microseconds_to_delta(pyus_out);
+ 	Py_DECREF(pyus_out);
+ 	return result;
+ }
+ 
+ static PyObject *
+ divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj)
+ {
+ 	PyObject *pyus_in;
+ 	PyObject *pyus_out;
+ 	PyObject *result;
+ 
+ 	pyus_in = delta_to_microseconds(delta);
+ 	if (pyus_in == NULL)
+ 		return NULL;
+ 
+ 	pyus_out = PyNumber_FloorDivide(pyus_in, intobj);
+ 	Py_DECREF(pyus_in);
+ 	if (pyus_out == NULL)
+ 		return NULL;
+ 
+ 	result = microseconds_to_delta(pyus_out);
+ 	Py_DECREF(pyus_out);
+ 	return result;
+ }
  
  static PyObject *
***************
*** 10,50 ****
  	PyTypeObject *left_type = left->ob_type;
  	PyTypeObject *right_type = right->ob_type;
- 	PyDateTime_Delta *delta;
- 	PyObject *other;
- 	PyTypeObject *other_type;
  
! 	if (PyType_IsSubtype(left_type, &PyDateTime_DeltaType)) {
! 		/* delta + ??? */
! 		delta = (PyDateTime_Delta *) left;
! 		if (PyType_IsSubtype(right_type, &PyDateTime_DeltaType)) {
! 			/* delta + delta */
! 			/* seconds and microseconds can't overflow, due to
! 			 * the invariant bounds on them.
! 			 */
! 			const long seconds = GET_TD_SECONDS(delta) +
! 					     GET_TD_SECONDS(right);
! 			const long microseconds = GET_TD_MICROSECONDS(delta) +
! 						  GET_TD_MICROSECONDS(right);
! 			/* But days can overflow. */
! 			const long days1 = GET_TD_DAYS(delta);
! 			const long days2 = GET_TD_DAYS(right);
! 			const long days = days1 + days2;
! 			if (SIGNED_ADD_OVERFLOWED(days, days1, days2)) {
! 				PyErr_SetString(PyExc_OverflowError,
! 						"timedelta addition");
! 				return NULL;
! 			}
! 			return new_delta(days, seconds, microseconds);
! 		}
! 		/* XXX This code is unused. */
! 		other = right;
! 		other_type = right_type;
! 	}
! 	else {
! 		/* !delta + delta */
! 		/* XXX This code is unused. */
! 		delta = (PyDateTime_Delta *) right;
! 		other = left;
! 		other_type = left_type;
  	}
  	Py_INCREF(Py_NotImplemented);
--- 171,186 ----
  	PyTypeObject *left_type = left->ob_type;
  	PyTypeObject *right_type = right->ob_type;
  
! 	if (PyType_IsSubtype(left_type, &PyDateTime_DeltaType) &&
! 	    PyType_IsSubtype(right_type, &PyDateTime_DeltaType)) {
! 		/* delta + delta */
! 		/* The C-level additions can't overflow because of the
! 		 * invariant bounds.
! 		 */
! 		long days = GET_TD_DAYS(left) + GET_TD_DAYS(right);
! 		long seconds = GET_TD_SECONDS(left) + GET_TD_SECONDS(right);
! 		long microseconds = GET_TD_MICROSECONDS(left) +
! 				    GET_TD_MICROSECONDS(right);
! 		return new_delta(days, seconds, microseconds);
  	}
  	Py_INCREF(Py_NotImplemented);
***************
*** 113,116 ****
--- 249,253 ----
  {
  	int result = -1;
+ 
  	if (!PyObject_TypeCheck(other, &PyDateTime_DeltaType))
  		PyErr_Format(PyExc_TypeError,
***************
*** 133,149 ****
  }
  
! static int
  delta_hash(PyDateTime_Delta *self)
  {
! 	return -2;
! }
! 
! static PyObject *
! multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta)
! {
! 	long i = PyInt_AS_LONG(intobj);
! 	return new_delta(GET_TD_DAYS(delta) * i,
! 			 GET_TD_SECONDS(delta) * i,
! 			 GET_TD_MICROSECONDS(delta) * i);
  }
  
--- 270,287 ----
  }
  
! static long
  delta_hash(PyDateTime_Delta *self)
  {
! 	if (self->hashcode == -1) {
! 		PyObject *temp = Py_BuildValue("lll",
! 						self->days,
! 						self->seconds,
! 						self->microseconds);
! 		if (temp != NULL) {
! 			self->hashcode = PyObject_Hash(temp);
! 			Py_DECREF(temp);
! 		}
! 	}
! 	return self->hashcode;
  }
  
***************
*** 151,192 ****
  delta_multiply(PyObject *left, PyObject *right)
  {
! 	PyObject *result = NULL;
  	if (PyType_IsSubtype(left->ob_type, &PyDateTime_DeltaType)) {
  		/* delta * ??? */
! 		if (PyInt_Check(right))
  			result = multiply_int_timedelta(right,
  					(PyDateTime_Delta *) left);
- 		else {
- 			Py_INCREF(Py_NotImplemented);
- 			return Py_NotImplemented;
- 		}
  	}
! 	else if (PyInt_Check(left))
  		result = multiply_int_timedelta(left,
  						(PyDateTime_Delta *) right);
! 	else {
! 		/* !(delta | int) * delta */
! 		Py_INCREF(Py_NotImplemented);
! 		return Py_NotImplemented;
  	}
  	return result;
  }
  
  static PyObject *
  delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
  {
  	PyObject *self = NULL;
- 	long int days, seconds = 0, microseconds = 0;
  
! 	/* XXX We're missing 4 keyword args from the Python version. */
! 	/* XXX The Python version doesn't require a days argument. */
  	static char *keywords[] = {
! 		"days", "seconds", "microseconds", NULL
  	};
  
! 	if (PyArg_ParseTupleAndKeywords(args, kw, "l|ll:__new__", keywords,
! 					&days, &seconds, &microseconds)) {
! 		self = new_delta(days, seconds, microseconds);
  	}
  	return self;
  }
--- 289,526 ----
  delta_multiply(PyObject *left, PyObject *right)
  {
! 	PyObject *result = Py_NotImplemented;
! 
  	if (PyType_IsSubtype(left->ob_type, &PyDateTime_DeltaType)) {
  		/* delta * ??? */
! 		if (PyInt_Check(right) || PyLong_Check(right))
  			result = multiply_int_timedelta(right,
  					(PyDateTime_Delta *) left);
  	}
! 	else if (PyInt_Check(left) || PyLong_Check(left))
  		result = multiply_int_timedelta(left,
  						(PyDateTime_Delta *) right);
! 
! 	if (result == Py_NotImplemented)
! 		Py_INCREF(result);
! 	return result;
! }
! 
! static PyObject *
! delta_divide(PyObject *left, PyObject *right)
! {
! 	PyObject *result = Py_NotImplemented;
! 
! 	if (PyType_IsSubtype(left->ob_type, &PyDateTime_DeltaType)) {
! 		/* delta * ??? */
! 		if (PyInt_Check(right) || PyLong_Check(right))
! 			result = divide_timedelta_int(
! 					(PyDateTime_Delta *)left,
! 					right);
  	}
+ 
+ 	if (result == Py_NotImplemented)
+ 		Py_INCREF(result);
  	return result;
  }
  
+ /* Fold in the value of the tag ("seconds", "weeks", etc) component of a
+  * a timedelta constructor.  sofar is the # of microseconds accounted for
+  * so far, and there are factor microseconds per current unit, the number
+  * of which is given by num.  num * factor is added to sofar in a
+  * numerically careful way, and that's the result.  Any fractional
+  * microseconds left over (this can happen if num is a float type) are
+  * added into *leftover.
+  * If num is NULL, no computation is done, and sofar is returned (after
+  * incremented its refcount).
+  * Note that there are many ways this can give an error (NULL) return.
+  */
+ static PyObject *
+ accum(const char* tag, PyObject *sofar, PyObject *num, PyObject *factor,
+       double *leftover)
+ {
+ 	PyObject *prod;
+ 	PyObject *sum;
+ 
+ 	if (num == NULL) {
+ 		Py_INCREF(sofar);
+ 		return sofar;
+ 	}
+ 
+ 	if (PyInt_Check(num) || PyLong_Check(num)) {
+ 		prod = PyNumber_Multiply(num, factor);
+ 		if (prod == NULL)
+ 			return NULL;
+ 		sum = PyNumber_Add(sofar, prod);
+ 		Py_DECREF(prod);
+ 		return sum;
+ 	}
+ 
+ 	if (PyFloat_Check(num)) {
+ 		double dnum;
+ 		double fracpart;
+ 		double intpart;
+ 		PyObject *x;
+ 		PyObject *y;
+ 
+ 		/* The Plan:  decompose num into an integer part and a
+ 		 * fractional part, num = intpart + fracpart.
+ 		 * Then num * factor ==
+ 		 *      intpart * factor + fracpart * factor
+ 		 * and the LHS can be computed exactly in long arithmetic.
+ 		 * The RHS is again broken into an int part and frac part.
+ 		 * and the frac part is added into *leftover.
+ 		 */
+ 		dnum = PyFloat_AsDouble(num);
+ 		if (dnum == -1.0 && PyErr_Occurred())
+ 			return NULL;
+ 		fracpart = modf(dnum, &intpart);
+ 		x = PyLong_FromDouble(intpart);
+ 		if (x == NULL)
+ 			return NULL;
+ 
+ 		prod = PyNumber_Multiply(x, factor);
+ 		Py_DECREF(x);
+ 		if (prod == NULL)
+ 			return NULL;
+ 
+ 		sum = PyNumber_Add(sofar, prod);
+ 		Py_DECREF(prod);
+ 		if (sum == NULL)
+ 			return NULL;
+ 
+ 		/* So far we've lost no information.  Dealing with the
+ 		 * fractional part requires float arithmetic, and may
+ 		 * lose a little info.
+ 		 */
+ 		assert(PyInt_Check(factor) || PyLong_Check(factor));
+ 		if (PyInt_Check(factor))
+ 			dnum = (double)PyInt_AsLong(factor);
+ 		else
+ 			dnum = PyLong_AsDouble(factor);
+ 
+ 		dnum *= fracpart;
+ 		fracpart = modf(dnum, &intpart);
+ 		x = PyLong_FromDouble(intpart);
+ 		if (x == NULL) {
+ 			Py_DECREF(sum);
+ 			return NULL;
+ 		}
+ 
+ 		y = PyNumber_Add(sum, x);
+ 		Py_DECREF(sum);
+ 		Py_DECREF(x);
+ 		*leftover += fracpart;
+ 		return y;
+ 	}
+ 
+ 	PyErr_Format(PyExc_TypeError,
+ 		     "unsupported type for timedelta %s component: %s",
+ 		     tag, num->ob_type->tp_name);
+ 	return NULL;
+ }
+ 
  static PyObject *
  delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
  {
  	PyObject *self = NULL;
  
! 	/* Argument objects. */
! 	PyObject *day = NULL;
! 	PyObject *second = NULL;
! 	PyObject *us = NULL;
! 	PyObject *ms = NULL;
! 	PyObject *minute = NULL;
! 	PyObject *hour = NULL;
! 	PyObject *week = NULL;
! 
! 	PyObject *x = NULL;
! 	PyObject *y = NULL;
! 	double leftover_us = 0.0;
! 
! 	PyObject *one;
! 
  	static char *keywords[] = {
! 		"days", "seconds", "microseconds", "milliseconds",
! 		"minutes", "hours", "weeks", NULL
  	};
  
! 	if (PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOO:__new__",
! 					keywords,
! 					&day, &second, &us,
! 					&ms, &minute, &hour, &week) == 0)
! 		goto Done;
! 
! 	x = PyInt_FromLong(0);
! 	if (x == NULL)
! 		goto Done;
! 
! 	one = PyInt_FromLong(1);
! 	if (one == NULL)
! 		goto Done;
! 	y = accum("microseconds", x, us, one, &leftover_us);
! 	Py_DECREF(one);
! 	Py_DECREF(x);
! 	x = y;
! 	if (x == NULL)
! 		goto Done;
! 
! 	y = accum("milliseconds", x, ms, us_per_ms, &leftover_us);
! 	Py_DECREF(x);
! 	x = y;
! 	if (x == NULL)
! 		goto Done;
! 
! 	y = accum("seconds", x, second, us_per_second, &leftover_us);
! 	Py_DECREF(x);
! 	x = y;
! 	if (x == NULL)
! 		goto Done;
! 
! 	y = accum("minutes", x, minute, us_per_minute, &leftover_us);
! 	Py_DECREF(x);
! 	x = y;
! 	if (x == NULL)
! 		goto Done;
! 
! 	y = accum("hours", x, hour, us_per_hour, &leftover_us);
! 	Py_DECREF(x);
! 	x = y;
! 	if (x == NULL)
! 		goto Done;
! 
! 	y = accum("days", x, day, us_per_day, &leftover_us);
! 	Py_DECREF(x);
! 	x = y;
! 	if (x == NULL)
! 		goto Done;
! 
! 	y = accum("weeks", x, week, us_per_week, &leftover_us);
! 	Py_DECREF(x);
! 	x = y;
! 	if (x == NULL)
! 		goto Done;
! 
! 	if (leftover_us) {
! 		PyObject *temp;
! 		if (leftover_us >= 0.0)
! 			leftover_us = floor(leftover_us + 0.5);
! 		else
! 			leftover_us = ceil(leftover_us - 0.5);
! 		temp = PyLong_FromDouble(leftover_us);
! 		if (temp == NULL) {
! 			Py_DECREF(x);
! 			goto Done;
! 		}
! 		y = PyNumber_Add(x, temp);
! 		Py_DECREF(temp);
! 		Py_DECREF(x);
! 		x = y;
! 		if (x == NULL)
! 			goto Done;
  	}
+ 
+ 	self = microseconds_to_delta(x);
+ 	Py_DECREF(x);
+ Done:
  	return self;
  }
***************
*** 236,252 ****
  
  static PyNumberMethods delta_as_number = {
! 	delta_add,					/* nb_add */
! 	delta_subtract,					/* nb_subtract */
! 	delta_multiply,					/* nb_multiply */
! 	0,						/* nb_divide */
! 	0,						/* nb_remainder */
! 	0,						/* nb_divmod */
! 	0,						/* nb_power */
! 	(unaryfunc)delta_negative,			/* nb_negative */
! 	(unaryfunc)delta_positive,			/* nb_positive */
! 	(unaryfunc)delta_abs,				/* nb_absolute */
! 	(inquiry)delta_nonzero,				/* nb_nonzero */
  };
- 
  static PyTypeObject PyDateTime_DeltaType = {
  	PyObject_HEAD_INIT(NULL)
--- 570,612 ----
  
  static PyNumberMethods delta_as_number = {
! 	delta_add,				/* nb_add */
! 	delta_subtract,				/* nb_subtract */
! 	delta_multiply,				/* nb_multiply */
! 	delta_divide,				/* nb_divide */
! 	0,					/* nb_remainder */
! 	0,					/* nb_divmod */
! 	0,					/* nb_power */
! 	(unaryfunc)delta_negative,		/* nb_negative */
! 	(unaryfunc)delta_positive,		/* nb_positive */
! 	(unaryfunc)delta_abs,			/* nb_absolute */
! 	(inquiry)delta_nonzero,			/* nb_nonzero */
! 	0,					/*nb_invert*/
! 	0,					/*nb_lshift*/
! 	0,					/*nb_rshift*/
! 	0,					/*nb_and*/
! 	0,					/*nb_xor*/
! 	0,					/*nb_or*/
! 	0,					/*nb_coerce*/
! 	0,					/*nb_int*/
! 	0,					/*nb_long*/
! 	0,					/*nb_float*/
! 	0,					/*nb_oct*/
! 	0, 					/*nb_hex*/
! 	0,					/*nb_inplace_add*/
! 	0,					/*nb_inplace_subtract*/
! 	0,					/*nb_inplace_multiply*/
! 	0,					/*nb_inplace_divide*/
! 	0,					/*nb_inplace_remainder*/
! 	0,					/*nb_inplace_power*/
! 	0,					/*nb_inplace_lshift*/
! 	0,					/*nb_inplace_rshift*/
! 	0,					/*nb_inplace_and*/
! 	0,					/*nb_inplace_xor*/
! 	0,					/*nb_inplace_or*/
! 	delta_divide,				/* nb_floor_divide */
! 	0,					/* nb_true_divide */
! 	0,					/* nb_inplace_floor_divide */
! 	0,					/* nb_inplace_true_divide */
  };
  static PyTypeObject PyDateTime_DeltaType = {
  	PyObject_HEAD_INIT(NULL)

Index: test_both.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_both.py,v
retrieving revision 1.10
retrieving revision 1.11
diff -C2 -d -r1.10 -r1.11
*** test_both.py	26 Nov 2002 21:22:38 -0000	1.10
--- test_both.py	1 Dec 2002 19:37:28 -0000	1.11
***************
*** 55,59 ****
          self.assertEqual(a*10, timedelta(70))
          self.assertEqual(a*10, 10*a)
-         # XXX Next one fails in the C implementation.
          self.assertEqual(a*10L, 10*a)
          self.assertEqual(b*10, timedelta(0, 600))
--- 55,58 ----
***************
*** 101,104 ****
--- 100,132 ----
          eq(td(milliseconds=0.001), td(microseconds=1))
  
+     def test_carries(self):
+         t1 = timedelta(days=100,
+                        weeks=-7,
+                        hours=-24*(100-49),
+                        minutes=-3,
+                        seconds=12,
+                        microseconds=(3*60 - 12) * 1000000)
+         t2 = timedelta()
+         self.assertEqual(t1, t2)
+ 
+     def test_hash_equality(self):
+         t1 = timedelta(days=100,
+                    weeks=-7,
+                    hours=-24*(100-49),
+                    minutes=-3,
+                    seconds=12,
+                    microseconds=(3*60 - 12) * 1000000)
+         t2 = timedelta()
+         self.assertEqual(hash(t1), hash(t2))
+ 
+         t1 += timedelta(weeks=7)
+         t2 += timedelta(days=7*7)
+         self.assertEqual(t1, t2)
+         self.assertEqual(hash(t1), hash(t2))
+ 
+         d = {t1: 1}
+         d[t2] = 2
+         self.assertEqual(len(d), 1)
+ 
  #############################################################################
  # date tests
***************
*** 334,338 ****
          n = (big.days*24*3600 + big.seconds)*1000000 + big.microseconds
          # n == 315537897599999999 ~= 2**58.13
-         # XXX Next line fails in the C implementation.
          justasbig = timedelta(0, 0, n)
          self.assertEqual(big, justasbig)
--- 362,365 ----
***************
*** 359,367 ****
  # datetime tests
  
! # XXX The Python version of this test class inherits from TestDate.  And
! # XXX it should.  Trying it here, though, causes 4 new errors when the
! # XXX C implementation is getting tested.
! 
! class TestDateTime(unittest.TestCase):
  
      theclass = datetime.datetime
--- 386,390 ----
  # datetime tests
  
! class TestDateTime(TestDate):
  
      theclass = datetime.datetime
***************
*** 415,419 ****
--- 438,580 ----
          self.assertEqual(t.ctime(), "Sat Mar  2 18:03:05 2002")
  
+     def test_tz_independent_comparing(self):
+         dt1 = self.theclass(2002, 3, 1, 9, 0, 0)
+         dt2 = self.theclass(2002, 3, 1, 10, 0, 0)
+         dt3 = self.theclass(2002, 3, 1, 9, 0, 0)
+         self.assertEqual(dt1, dt3)
+         self.assert_(dt2 > dt3)
+ 
+         # Make sure comparison doesn't forget microseconds, and isn't done
+         # via comparing a float timestamp (an IEEE double doesn't have enough
+         # precision to span microsecond resolution across years 1 thru 9999,
+         # so comparing via timestamp necessarily calls some distinct values
+         # equal).
+         dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998)
+         us = timedelta(microseconds=1)
+         dt2 = dt1 + us
+         self.assertEqual(dt2 - dt1, us)
+         self.assert_(dt1 < dt2)
  
+     def test_bad_constructor_arguments(self):
+         # bad years
+         self.theclass(MINYEAR, 1, 1)  # no exception
+         self.theclass(MAXYEAR, 1, 1)  # no exception
+         self.assertRaises(ValueError, self.theclass, MINYEAR-1, 1, 1)
+         self.assertRaises(ValueError, self.theclass, MAXYEAR+1, 1, 1)
+         # bad months
+         self.theclass(2000, 1, 1)    # no exception
+         self.theclass(2000, 12, 1)   # no exception
+         self.assertRaises(ValueError, self.theclass, 2000, 0, 1)
+         self.assertRaises(ValueError, self.theclass, 2000, 13, 1)
+         # bad days
+         self.theclass(2000, 2, 29)   # no exception
+         self.theclass(2004, 2, 29)   # no exception
+         self.theclass(2400, 2, 29)   # no exception
+         self.assertRaises(ValueError, self.theclass, 2000, 2, 30)
+         self.assertRaises(ValueError, self.theclass, 2001, 2, 29)
+         self.assertRaises(ValueError, self.theclass, 2100, 2, 29)
+         self.assertRaises(ValueError, self.theclass, 1900, 2, 29)
+         self.assertRaises(ValueError, self.theclass, 2000, 1, 0)
+         self.assertRaises(ValueError, self.theclass, 2000, 1, 32)
+         # bad hours
+         self.theclass(2000, 1, 31, 0)    # no exception
+         self.theclass(2000, 1, 31, 23)   # no exception
+         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, -1)
+         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 24)
+         # bad minutes
+         self.theclass(2000, 1, 31, 23, 0)    # no exception
+         self.theclass(2000, 1, 31, 23, 59)   # no exception
+         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, -1)
+         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 60)
+         # bad seconds
+         self.theclass(2000, 1, 31, 23, 59, 0)    # no exception
+         self.theclass(2000, 1, 31, 23, 59, 59)   # no exception
+         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, -1)
+         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, 60)
+         # bad microseconds
+         self.theclass(2000, 1, 31, 23, 59, 59, 0)    # no exception
+         self.theclass(2000, 1, 31, 23, 59, 59, 999999)   # no exception
+         self.assertRaises(ValueError, self.theclass,
+                           2000, 1, 31, 23, 59, 59, -1)
+         self.assertRaises(ValueError, self.theclass,
+                           2000, 1, 31, 23, 59, 59,
+                           1000000)
+ 
+     def test_hash_equality(self):
+         d = self.theclass(2000, 12, 31, 23, 30, 17)
+         e = self.theclass(2000, 12, 31, 23, 30, 17)
+         self.assertEqual(d, e)
+         self.assertEqual(hash(d), hash(e))
+ 
+         dic = {d: 1}
+         dic[e] = 2
+         self.assertEqual(len(dic), 1)
+         self.assertEqual(dic[d], 2)
+         self.assertEqual(dic[e], 2)
+ 
+         d = self.theclass(2001,  1,  1,  0,  5, 17)
+         e = self.theclass(2001,  1,  1,  0,  5, 17)
+         self.assertEqual(d, e)
+         self.assertEqual(hash(d), hash(e))
+ 
+         dic = {d: 1}
+         dic[e] = 2
+         self.assertEqual(len(dic), 1)
+         self.assertEqual(dic[d], 2)
+         self.assertEqual(dic[e], 2)
+ 
+     def test_computations(self):
+         a = self.theclass(2002, 1, 31)
+         b = self.theclass(1956, 1, 31)
+         diff = a-b
+         self.assertEqual(diff.days, 46*365 + len(range(1956, 2002, 4)))
+         self.assertEqual(diff.seconds, 0)
+         self.assertEqual(diff.microseconds, 0)
+         a = self.theclass(2002, 3, 2, 17, 6)
+         millisec = timedelta(0, 0, 1000)
+         hour = timedelta(0, 3600)
+         day = timedelta(1)
+         week = timedelta(7)
+         self.assertEqual(a + hour, self.theclass(2002, 3, 2, 18, 6))
+         self.assertEqual(a + 10*hour, self.theclass(2002, 3, 3, 3, 6))
+         self.assertEqual(a - hour, self.theclass(2002, 3, 2, 16, 6))
+         self.assertEqual(a - hour, a + -hour)
+         self.assertEqual(a - 20*hour, self.theclass(2002, 3, 1, 21, 6))
+         self.assertEqual(a + day, self.theclass(2002, 3, 3, 17, 6))
+         self.assertEqual(a - day, self.theclass(2002, 3, 1, 17, 6))
+         self.assertEqual(a + week, self.theclass(2002, 3, 9, 17, 6))
+         self.assertEqual(a - week, self.theclass(2002, 2, 23, 17, 6))
+         self.assertEqual(a + 52*week, self.theclass(2003, 3, 1, 17, 6))
+         self.assertEqual(a - 52*week, self.theclass(2001, 3, 3, 17, 6))
+         self.assertEqual((a + week) - a, week)
+         self.assertEqual((a + day) - a, day)
+         self.assertEqual((a + hour) - a, hour)
+         self.assertEqual((a + millisec) - a, millisec)
+         self.assertEqual((a - week) - a, -week)
+         self.assertEqual((a - day) - a, -day)
+         self.assertEqual((a - hour) - a, -hour)
+         self.assertEqual((a - millisec) - a, -millisec)
+         self.assertEqual(a - (a + week), -week)
+         self.assertEqual(a - (a + day), -day)
+         self.assertEqual(a - (a + hour), -hour)
+         self.assertEqual(a - (a + millisec), -millisec)
+         self.assertEqual(a - (a - week), week)
+         self.assertEqual(a - (a - day), day)
+         self.assertEqual(a - (a - hour), hour)
+         self.assertEqual(a - (a - millisec), millisec)
+         self.assertEqual(a + (week + day + hour + millisec),
+                          self.theclass(2002, 3, 10, 18, 6, 0, 1000))
+         self.assertEqual(a + (week + day + hour + millisec),
+                          (((a + week) + day) + hour) + millisec)
+         self.assertEqual(a - (week + day + hour + millisec),
+                          self.theclass(2002, 2, 22, 16, 5, 59, 999000))
+         self.assertEqual(a - (week + day + hour + millisec),
+                          (((a - week) - day) - hour) - millisec)
+         # Add/sub ints, longs, floats should be illegal
+         for i in 1, 1L, 1.0:
+             self.assertRaises(TypeError, lambda: a+i)
+             self.assertRaises(TypeError, lambda: a-i)
+             self.assertRaises(TypeError, lambda: i+a)
+             self.assertRaises(TypeError, lambda: i-a)
  
  def test_suite():

Index: test_datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_datetime.py,v
retrieving revision 1.52
retrieving revision 1.53
diff -C2 -d -r1.52 -r1.53
*** test_datetime.py	26 Nov 2002 21:22:38 -0000	1.52
--- test_datetime.py	1 Dec 2002 19:37:28 -0000	1.53
***************
*** 215,358 ****
      theclass = datetime
  
-     def test_tz_independent_comparing(self):
-         dt1 = self.theclass(2002, 3, 1, 9, 0, 0)
-         dt2 = self.theclass(2002, 3, 1, 10, 0, 0)
-         dt3 = self.theclass(2002, 3, 1, 9, 0, 0)
-         self.assertEqual(dt1, dt3)
-         self.assert_(dt2 > dt3)
- 
-         # Make sure comparison doesn't forget microseconds, and isn't done
-         # via comparing a float timestamp (an IEEE double doesn't have enough
-         # precision to span microsecond resolution across years 1 thru 9999,
-         # so comparing via timestamp necessarily calls some distinct values
-         # equal).
-         dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998)
-         us = timedelta(microseconds=1)
-         dt2 = dt1 + us
-         self.assertEqual(dt2 - dt1, us)
-         self.assert_(dt1 < dt2)
- 
-     def test_bad_constructor_arguments(self):
-         # bad years
-         self.theclass(MINYEAR, 1, 1)  # no exception
-         self.theclass(MAXYEAR, 1, 1)  # no exception
-         self.assertRaises(ValueError, self.theclass, MINYEAR-1, 1, 1)
-         self.assertRaises(ValueError, self.theclass, MAXYEAR+1, 1, 1)
-         # bad months
-         self.theclass(2000, 1, 1)    # no exception
-         self.theclass(2000, 12, 1)   # no exception
-         self.assertRaises(ValueError, self.theclass, 2000, 0, 1)
-         self.assertRaises(ValueError, self.theclass, 2000, 13, 1)
-         # bad days
-         self.theclass(2000, 2, 29)   # no exception
-         self.theclass(2004, 2, 29)   # no exception
-         self.theclass(2400, 2, 29)   # no exception
-         self.assertRaises(ValueError, self.theclass, 2000, 2, 30)
-         self.assertRaises(ValueError, self.theclass, 2001, 2, 29)
-         self.assertRaises(ValueError, self.theclass, 2100, 2, 29)
-         self.assertRaises(ValueError, self.theclass, 1900, 2, 29)
-         self.assertRaises(ValueError, self.theclass, 2000, 1, 0)
-         self.assertRaises(ValueError, self.theclass, 2000, 1, 32)
-         # bad hours
-         self.theclass(2000, 1, 31, 0)    # no exception
-         self.theclass(2000, 1, 31, 23)   # no exception
-         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, -1)
-         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 24)
-         # bad minutes
-         self.theclass(2000, 1, 31, 23, 0)    # no exception
-         self.theclass(2000, 1, 31, 23, 59)   # no exception
-         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, -1)
-         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 60)
-         # bad seconds
-         self.theclass(2000, 1, 31, 23, 59, 0)    # no exception
-         self.theclass(2000, 1, 31, 23, 59, 59)   # no exception
-         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, -1)
-         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, 60)
-         # bad microseconds
-         self.theclass(2000, 1, 31, 23, 59, 59, 0)    # no exception
-         self.theclass(2000, 1, 31, 23, 59, 59, 999999)   # no exception
-         self.assertRaises(ValueError, self.theclass,
-                           2000, 1, 31, 23, 59, 59, -1)
-         self.assertRaises(ValueError, self.theclass,
-                           2000, 1, 31, 23, 59, 59,
-                           1000000)
- 
-     def test_hash_equality(self):
-         d = self.theclass(2000, 12, 31, 23, 30, 17)
-         e = self.theclass(2000, 12, 31, 23, 30, 17)
-         self.assertEqual(d, e)
-         self.assertEqual(hash(d), hash(e))
- 
-         dic = {d: 1}
-         dic[e] = 2
-         self.assertEqual(len(dic), 1)
-         self.assertEqual(dic[d], 2)
-         self.assertEqual(dic[e], 2)
- 
-         d = self.theclass(2001,  1,  1,  0,  5, 17)
-         e = self.theclass(2001,  1,  1,  0,  5, 17)
-         self.assertEqual(d, e)
-         self.assertEqual(hash(d), hash(e))
- 
-         dic = {d: 1}
-         dic[e] = 2
-         self.assertEqual(len(dic), 1)
-         self.assertEqual(dic[d], 2)
-         self.assertEqual(dic[e], 2)
- 
-     def test_computations(self):
-         a = self.theclass(2002, 1, 31)
-         b = self.theclass(1956, 1, 31)
-         diff = a-b
-         self.assertEqual(diff.days, 46*365 + len(range(1956, 2002, 4)))
-         self.assertEqual(diff.seconds, 0)
-         self.assertEqual(diff.microseconds, 0)
-         a = self.theclass(2002, 3, 2, 17, 6)
-         millisec = timedelta(0, 0, 1000)
-         hour = timedelta(0, 3600)
-         day = timedelta(1)
-         week = timedelta(7)
-         self.assertEqual(a + hour, self.theclass(2002, 3, 2, 18, 6))
-         self.assertEqual(a + 10*hour, self.theclass(2002, 3, 3, 3, 6))
-         self.assertEqual(a - hour, self.theclass(2002, 3, 2, 16, 6))
-         self.assertEqual(a - hour, a + -hour)
-         self.assertEqual(a - 20*hour, self.theclass(2002, 3, 1, 21, 6))
-         self.assertEqual(a + day, self.theclass(2002, 3, 3, 17, 6))
-         self.assertEqual(a - day, self.theclass(2002, 3, 1, 17, 6))
-         self.assertEqual(a + week, self.theclass(2002, 3, 9, 17, 6))
-         self.assertEqual(a - week, self.theclass(2002, 2, 23, 17, 6))
-         self.assertEqual(a + 52*week, self.theclass(2003, 3, 1, 17, 6))
-         self.assertEqual(a - 52*week, self.theclass(2001, 3, 3, 17, 6))
-         self.assertEqual((a + week) - a, week)
-         self.assertEqual((a + day) - a, day)
-         self.assertEqual((a + hour) - a, hour)
-         self.assertEqual((a + millisec) - a, millisec)
-         self.assertEqual((a - week) - a, -week)
-         self.assertEqual((a - day) - a, -day)
-         self.assertEqual((a - hour) - a, -hour)
-         self.assertEqual((a - millisec) - a, -millisec)
-         self.assertEqual(a - (a + week), -week)
-         self.assertEqual(a - (a + day), -day)
-         self.assertEqual(a - (a + hour), -hour)
-         self.assertEqual(a - (a + millisec), -millisec)
-         self.assertEqual(a - (a - week), week)
-         self.assertEqual(a - (a - day), day)
-         self.assertEqual(a - (a - hour), hour)
-         self.assertEqual(a - (a - millisec), millisec)
-         self.assertEqual(a + (week + day + hour + millisec),
-                          self.theclass(2002, 3, 10, 18, 6, 0, 1000))
-         self.assertEqual(a + (week + day + hour + millisec),
-                          (((a + week) + day) + hour) + millisec)
-         self.assertEqual(a - (week + day + hour + millisec),
-                          self.theclass(2002, 2, 22, 16, 5, 59, 999000))
-         self.assertEqual(a - (week + day + hour + millisec),
-                          (((a - week) - day) - hour) - millisec)
-         # Add/sub ints, longs, floats should be illegal
-         for i in 1, 1L, 1.0:
-             self.assertRaises(TypeError, lambda: a+i)
-             self.assertRaises(TypeError, lambda: a-i)
-             self.assertRaises(TypeError, lambda: i+a)
-             self.assertRaises(TypeError, lambda: i-a)
- 
      def test_tmxxx(self):
          from datetime import tmxxx
--- 215,218 ----

--- test_cdatetime.py DELETED ---