[Python-checkins] python/nondist/sandbox/datetime obj_time.c,NONE,1.1 datetime.c,1.45,1.46 datetime.h,1.10,1.11 obj_datetime.c,1.30,1.31

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Sat, 07 Dec 2002 08:36:19 -0800


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

Modified Files:
	datetime.c datetime.h obj_datetime.c 
Added Files:
	obj_time.c 
Log Message:
Prepare to implement the time type.  This is mostly massive macro
renaming, since e.g. the old GET_HOUR will become too ambiguous to
tolerate.  That in turn triggered another round of long-line folding.

The new obj_time.c is just a copy of obj_datetime.c, and isn't yet
compiled.  Added a struct decl and macros for the time type, so far
unreferenced.

Moved the struct decl for timedelta into the .h file, since it didn't
make sense that it was the only one unexposed.


--- NEW FILE: obj_time.c ---
/*
 * PyDateTime_Time implementation.
 * XXX This is currently a copy of obj_datetime.c, and unused.
 */

/* Accessor properties. */

static PyObject *
datetime_hour(PyDateTime_DateTime *self, void *unused)
{
	return PyInt_FromLong(DATE_GET_HOUR(self));
}

static PyObject *
datetime_minute(PyDateTime_DateTime *self, void *unused)
{
	return PyInt_FromLong(DATE_GET_MINUTE(self));
}

static PyObject *
datetime_second(PyDateTime_DateTime *self, void *unused)
{
	return PyInt_FromLong(DATE_GET_SECOND(self));
}

static PyObject *
datetime_microsecond(PyDateTime_DateTime *self, void *unused)
{
	return PyInt_FromLong(DATE_GET_MICROSECOND(self));
}

static PyGetSetDef datetime_getset[] = {
	{"hour",        (getter)datetime_hour},
	{"minute",      (getter)datetime_minute},
	{"second",      (getter)datetime_second},
	{"microsecond", (getter)datetime_microsecond},
	{NULL}
};

/* Constructors. */

static PyObject *
datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
	PyObject *self = NULL;
	long year;
	long month;
	long day;
	long hour = 0;
	long minute = 0;
	long second = 0;
	long usecond = 0;

	static char *keywords[] = {
		"year", "month", "day", "hour", "minute", "second",
		"microsecond", NULL
	};

	if (PyArg_ParseTupleAndKeywords(args, kw, "lll|llll", keywords,
					&year, &month, &day, &hour, &minute,
					&second, &usecond)) {
		if (year < MINYEAR || year > MAXYEAR) {
			PyErr_SetString(PyExc_ValueError,
					"year is out of range");
			return NULL;
		}
		if (month < 1 || month > 12) {
			PyErr_SetString(PyExc_ValueError,
					"month must be in 1..12");
			return NULL;
		}
		if (day < 1 || day > days_in_month(year, month)) {
			PyErr_SetString(PyExc_ValueError,
					"day is out of range for month");
			return NULL;
		}
		if (hour < 0 || hour > 23) {
			PyErr_SetString(PyExc_ValueError,
					"hour must be in 0..23");
			return NULL;
		}
		if (minute < 0 || minute > 59) {
			PyErr_SetString(PyExc_ValueError,
					"minute must be in 0..59");
			return NULL;
		}
		if (second < 0 || second > 59) {
			PyErr_SetString(PyExc_ValueError,
					"second must be in 0..59");
			return NULL;
		}
		if (usecond < 0 || usecond > 999999) {
			PyErr_SetString(PyExc_ValueError,
					"microsecond must be in 0..999999");
			return NULL;
		}
		self = new_datetime(year, month, day, hour, minute, second,
				     usecond);
	}
	return self;
}


/* TM_FUNC is the shared type of localtime() and gmtime(). */
typedef struct tm *(*TM_FUNC)(const time_t *timer);

static PyObject *
datetime_from_timestamp(PyObject *cls, TM_FUNC f, double timestamp)
{
	struct tm *tm;
	time_t timet = (time_t)timestamp;
	long us = (long)((timestamp - (double)timet) * 1e6);
	PyObject *result = NULL;

	tm = f(&timet);
	if (tm)
		result = PyObject_CallFunction(cls, "lllllll",
					       tm->tm_year + 1900,
					       tm->tm_mon + 1,
					       tm->tm_mday,
					       tm->tm_hour,
					       tm->tm_min,
					       tm->tm_sec,
					       us);
	else
		PyErr_SetString(PyExc_ValueError,
				"timestamp out of range for "
				"platform localtime()/gmtime() function");
	return result;
}

/* Return new local datetime from timestamp (Python timestamp -- a double). */
static PyObject *
datetime_fromtimestamp(PyObject *self, PyObject *args)
{
	PyObject *cls;
	double timestamp;
	PyObject *result = NULL;

	if (PyArg_ParseTuple(args, "Od:fromtimestamp", &cls, &timestamp))
		result = datetime_from_timestamp(cls, localtime, timestamp);
	return result;
}

/* Return new UTC datetime from timestamp (Python timestamp -- a double). */
static PyObject *
datetime_utcfromtimestamp(PyObject *self, PyObject *args)
{
	PyObject *cls;
	double timestamp;
	PyObject *result = NULL;

	if (PyArg_ParseTuple(args, "Od:utcfromtimestamp", &cls, &timestamp))
		result = datetime_from_timestamp(cls, gmtime, timestamp);
	return result;
}

static PyObject *
datetime_now(PyObject *self, PyObject *cls)
{
	/* XXX MAJOR:  This needs to get some notion of current time
	 * XXX to better than 1-second resolution.  Doing this in a x-
	 * XXX platform way is mondo painful.  Maybe floattime() from
	 * XXX timemodule.c is good enough?  We're running out of bits
	 * XXX in a typical time_t, though, and gettimeofday() should do
	 * XXX better than floattime() -- but gettimeofday isn't portable.
	 */
#if 0
	/* XXX need to create the instance by calling cls(y,mon,d,h,min,s,u) */
	struct timeval t;
	struct tm *tm;
	time_t timet;

#ifdef GETTIMEOFDAY_NO_TZ
	gettimeofday(&t);
#else /* !GETTIMEOFDAY_NO_TZ */
	gettimeofday(&t, (struct timezone *)NULL);
#endif /* !GETTIMEOFDAY_NO_TZ */
	timet = t.tv_sec;
	tm = localtime(&timet);

	return PyObject_CallFunction(cls, "iiiiiil",
				     tm->tm_year + 1900, tm->tm_mon + 1,
				     tm->tm_mday, tm->tm_hour, tm->tm_min,
				     tm->tm_sec, t.tv_usec);
#else
	/* XXX need to create the instance by calling cls(y,mon,d,h,min,s,u) */
	struct tm *tm;
	time_t timet;

 	time(&timet);
	tm = localtime(&timet);

	return PyObject_CallFunction(cls, "llllll",
				     tm->tm_year + 1900, tm->tm_mon + 1,
				     tm->tm_mday, tm->tm_hour, tm->tm_min,
				     tm->tm_sec);
#endif
}

static PyObject *
datetime_utcnow(PyObject *self, PyObject *cls)
{
	/* XXX Like datetime_now, this would like to do better than
	 * XXX 1-second resolution.
	 */
	struct tm *tm;
	time_t timet;

 	time(&timet);
	tm = gmtime(&timet);

	return PyObject_CallFunction(cls, "llllll",
				     tm->tm_year + 1900, tm->tm_mon + 1,
				     tm->tm_mday, tm->tm_hour, tm->tm_min,
				     tm->tm_sec);
}

/* datetime arithmetic. */

/* Force all the datetime fields into range.  The parameters are both
 * inputs and outputs.  Returns < 0 on error.
 */
static int
normalize_datetime(long *year, long *month, long *day,
                   long *hour, long *minute, long *second,
                   long *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);
}

static PyObject *
add_datetime_timedelta(PyDateTime_DateTime *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_datetime_timedelta(PyDateTime_DateTime *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_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 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);
}

static PyObject *
datetime_add(PyObject *left, PyObject *right)
{
	PyTypeObject *left_type = left->ob_type;
	PyTypeObject *right_type = right->ob_type;

	if (PyType_IsSubtype(left_type, &PyDateTime_DateTimeType)) {
		/* datetime + ??? */
		if (PyType_IsSubtype(right_type, &PyDateTime_DeltaType))
			/* datetime + delta */
			return add_datetime_timedelta(
					(PyDateTime_DateTime *)left,
					(PyDateTime_Delta *)right);
	}
	else if (PyType_IsSubtype(left_type, &PyDateTime_DeltaType)) {
		/* delta + datetime */
		return add_datetime_timedelta((PyDateTime_DateTime *) right,
					      (PyDateTime_Delta *) left);
	}
	Py_INCREF(Py_NotImplemented);
	return Py_NotImplemented;
}

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 - delta */
			result = sub_datetime_timedelta(
					(PyDateTime_DateTime *)left,
					(PyDateTime_Delta *)right);
		}
	}

	if (result == Py_NotImplemented)
		Py_INCREF(result);
	return result;
}

/* Various ways to turn a datetime into a string. */

static PyObject *
datetime_repr(PyDateTime_DateTime *self)
{
	char buffer[1000];
	char *typename = self->ob_type->tp_name;

	if (DATE_GET_MICROSECOND(self)) {
		PyOS_snprintf(buffer, sizeof(buffer),
			      "%s(%d, %d, %d, %d, %d, %d, %d)",
			      typename,
			      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
			      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
			      DATE_GET_SECOND(self),
			      DATE_GET_MICROSECOND(self));
	}
	else if (DATE_GET_SECOND(self)) {
		PyOS_snprintf(buffer, sizeof(buffer),
			      "%s(%d, %d, %d, %d, %d, %d)",
			      typename,
			      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
			      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
			      DATE_GET_SECOND(self));
	}
	else {
		PyOS_snprintf(buffer, sizeof(buffer),
			      "%s(%d, %d, %d, %d, %d)",
			      typename,
			      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
			      DATE_GET_HOUR(self), DATE_GET_MINUTE(self));
	}
	return PyString_FromString(buffer);
}

static PyObject *
datetime_isoformat_helper(PyDateTime_DateTime *self, char sep)
{
	char buffer[100];
	char *cp;

	cp = isoformat_date((PyDateTime_Date *)self, buffer, sizeof(buffer));
	assert(cp != NULL);
	*cp++ = sep;
	isoformat_time(self, cp, sizeof(buffer) - (cp - buffer));

	return PyString_FromString(buffer);
}

static PyObject *
datetime_str(PyDateTime_DateTime *self)
{
	return datetime_isoformat_helper(self, ' ');
}

static PyObject *
datetime_isoformat(PyDateTime_DateTime *self,
                   PyObject *args, PyObject *kw)
{
	char sep = 'T';
	static char *keywords[] = {"sep", NULL};

	if (!PyArg_ParseTupleAndKeywords(args, kw, "|c:isoformat", keywords,
					 &sep))
		return NULL;
	return datetime_isoformat_helper(self, sep);
}

static PyObject *
datetime_ctime(PyDateTime_DateTime *self)
{
	return format_ctime((PyDateTime_Date *)self,
			    DATE_GET_HOUR(self),
			    DATE_GET_MINUTE(self),
			    DATE_GET_SECOND(self));
}

/* Miscellaneous methods. */

/* This is more natural as a tp_compare, but doesn't work then:  for whatever
 * reason, Python's try_3way_compare ignores tp_compare unless
 * PyInstance_Check returns true, but these aren't old-style classes.
 */
static PyObject *
datetime_richcompare(PyDateTime_DateTime *self, PyObject *other, int op)
{
	long diff;

	if (!PyType_IsSubtype(other->ob_type, &PyDateTime_DateTimeType)) {
		PyErr_Format(PyExc_TypeError,
			     "can't compare datetime to %s instance",
			     other->ob_type->tp_name);
		return NULL;
	}
	diff = memcmp(self->data, ((PyDateTime_DateTime *)other)->data,
		      _PyDateTime_DATETIME_DATA_SIZE);
	return diff_to_bool(diff, op);
}

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),
				      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
				      DATE_GET_SECOND(self),
				      DATE_GET_MICROSECOND(self));
		if (temp != NULL) {
			self->hashcode = PyObject_Hash(temp);
			Py_DECREF(temp);
		}
	}
	return self->hashcode;
}

static PyObject *
datetime_timetuple(PyDateTime_DateTime *self)
{
	const int year = GET_YEAR(self);
	const int month = GET_MONTH(self);
	const int day = GET_DAY(self);

	return Py_BuildValue("iiiiiiiii",
			     year, month, day,
			     DATE_GET_HOUR(self),
			     DATE_GET_MINUTE(self),
			     DATE_GET_SECOND(self),
			     weekday(year, month, day),
			     days_before_month(year, month) + day,
			     -1);
}

static PyObject *
datetime_getdate(PyDateTime_DateTime *self)
{
	return new_date((int)GET_YEAR(self),
			(int)GET_MONTH(self),
			(int)GET_DAY(self));
}

/* Pickle support.  Quite a maze! */

static PyObject *
datetime_getstate(PyDateTime_DateTime *self)
{
	return PyString_FromStringAndSize(self->data,
					  _PyDateTime_DATETIME_DATA_SIZE);
}

static PyObject *
datetime_setstate(PyDateTime_DateTime *self, PyObject *state)
{
	const int len = PyString_Size(state);
	unsigned char *pdata = (unsigned char*)PyString_AsString(state);

	if (! PyString_Check(state) ||
	    len != _PyDateTime_DATETIME_DATA_SIZE) {
		PyErr_SetString(PyExc_TypeError,
				"bad argument to datetime.__setstate__");
		return NULL;
	}
	memcpy(self->data, pdata, _PyDateTime_DATETIME_DATA_SIZE);
	self->hashcode = -1;

	Py_INCREF(Py_None);
	return Py_None;
}

/* XXX This seems a ridiculously inefficient way to pickle a short string. */
static PyObject *
datetime_pickler(PyObject *module, PyDateTime_DateTime *datetime)
{
	PyObject *state;
	PyObject *result = NULL;

	if (datetime->ob_type != &PyDateTime_DateTimeType) {
		PyErr_Format(PyExc_TypeError,
			     "bad type passed to datetime pickler: %s",
			     datetime->ob_type->tp_name);
		return NULL;
	}
	state = datetime_getstate(datetime);
	if (state) {
		result = Py_BuildValue("O(O)",
				       datetime_unpickler_object,
				       state);
		Py_DECREF(state);
	}
	return result;
}

static PyObject *
datetime_unpickler(PyObject *module, PyObject *arg)
{
	PyDateTime_DateTime *self;

	if (! PyString_CheckExact(arg)) {
		PyErr_Format(PyExc_TypeError,
			     "bad type passed to datetime unpickler: %s",
			     arg->ob_type->tp_name);
		return NULL;
	}
	self = PyObject_New(PyDateTime_DateTime, &PyDateTime_DateTimeType);
	if (self != NULL) {
		PyObject *res = datetime_setstate(self, arg);
		Py_XDECREF(res);
	}
	return (PyObject *)self;
}

static PyMethodDef datetime_methods[] = {
	/* Class methods: */
	/* XXX METH_CLASS is implemented incorrectly:
	 * XXX http://www.python.org/sf/548651
	 * XXX The signatures of these methods will need to change (for
	 * XXX the better) when that's fixed.
	 */
	{"now",         (PyCFunction)datetime_now,
	 METH_O | METH_CLASS,
	 "Return a new datetime representing local day and time."},

	{"utcnow",         (PyCFunction)datetime_utcnow,
	 METH_O | METH_CLASS,
	 "Return a new datetime representing UTC day and time."},

	{"fromtimestamp", (PyCFunction)datetime_fromtimestamp,
	 METH_VARARGS | METH_CLASS,
	 "timestamp -> local datetime from a POSIX timestamp "
	 "(like time.time())."},

	{"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp,
	 METH_VARARGS | METH_CLASS,
	 "timestamp -> UTC datetime from a POSIX timestamp "
	 "(like time.time())."},

	/* Instance methods: */
	{"timetuple",   (PyCFunction)datetime_timetuple, METH_NOARGS,
         "Return time tuple, compatible with time.localtime()."},

	{"date",   (PyCFunction)datetime_getdate, METH_NOARGS,
         "Return date object with same year, month and day."},

	{"ctime",       (PyCFunction)datetime_ctime,	METH_NOARGS,
	 "Return ctime() style string."},

	{"isoformat",   (PyCFunction)datetime_isoformat, METH_KEYWORDS,
	 "[sep] -> string in ISO 8601 format, YYYY-MM-DDTHH:MM:SS.mmmmmm.\n\n"
	 "sep is used to separate the year from the time, and defaults\n"
	 "to 'T'."},

	{"__setstate__", (PyCFunction)datetime_setstate, METH_O,
	 	PyDoc_STR("__setstate__(state)")},

	{"__getstate__", (PyCFunction)datetime_getstate, METH_NOARGS,
	 	PyDoc_STR("__getstate__() -> state")},
	{NULL,	NULL}
};

static char datetime_doc[] =
"Basic date/time type.";

static PyNumberMethods datetime_as_number = {
	datetime_add,				/* nb_add */
	datetime_subtract,			/* nb_subtract */
	0,					/* nb_multiply */
	0,					/* nb_divide */
	0,					/* nb_remainder */
	0,					/* nb_divmod */
	0,					/* nb_power */
	0,					/* nb_negative */
	0,					/* nb_positive */
	0,					/* nb_absolute */
	(inquiry)date_nonzero,			/* nb_nonzero */
};

statichere PyTypeObject PyDateTime_DateTimeType = {
	PyObject_HEAD_INIT(NULL)
	0,					/* ob_size */
	/* XXX When this module is renamed to datetime, change tp_name. */
	"_datetime.datetime",			/* tp_name */
	sizeof(PyDateTime_DateTime),		/* tp_basicsize */
	0,					/* tp_itemsize */
	(destructor)PyObject_Del,		/* tp_dealloc */
	0,					/* tp_print */
	0,					/* tp_getattr */
	0,					/* tp_setattr */
	0,					/* tp_compare */
	(reprfunc)datetime_repr,		/* tp_repr */
	&datetime_as_number,			/* tp_as_number */
	0,					/* tp_as_sequence */
	0,					/* tp_as_mapping */
	(hashfunc)datetime_hash,		/* tp_hash */
	0,              			/* tp_call */
	(reprfunc)datetime_str,			/* tp_str */
	PyObject_GenericGetAttr,		/* tp_getattro */
	0,					/* tp_setattro */
	0,					/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
        Py_TPFLAGS_BASETYPE,			/* tp_flags */
	datetime_doc,				/* tp_doc */
	0,					/* tp_traverse */
	0,					/* tp_clear */
	(richcmpfunc)datetime_richcompare,	/* tp_richcompare */
	0,					/* tp_weaklistoffset */
	0,					/* tp_iter */
	0,					/* tp_iternext */
	datetime_methods,			/* tp_methods */
	0,					/* tp_members */
	datetime_getset,			/* tp_getset */
	&PyDateTime_DateType,			/* tp_base */
	0,					/* tp_dict */
	0,					/* tp_descr_get */
	0,					/* tp_descr_set */
	0,					/* tp_dictoffset */
	0,					/* tp_init */
	0,					/* tp_alloc */
	datetime_new,				/* tp_new */
	_PyObject_Del,				/* tp_free */
};


Index: datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.c,v
retrieving revision 1.45
retrieving revision 1.46
diff -C2 -d -r1.45 -r1.46
*** datetime.c	7 Dec 2002 02:23:08 -0000	1.45
--- datetime.c	7 Dec 2002 16:36:16 -0000	1.46
***************
*** 21,43 ****
  #define MAX_DELTA_DAYS 999999999
  
- typedef struct
- {
- 	PyObject_HEAD
- 	long hashcode;		/* -1 when unknown */
- 	long days;		/* -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS */
- 	long seconds;		/* 0 <= seconds < 24*3600 is invariant */
- 	long microseconds;	/* 0 <= microseconds < 1000000 is invariant */
- } PyDateTime_Delta;
- 
  /* Rename the long macros in datetime.h to more reasonable short names. */
  #define GET_YEAR		PyDateTime_GET_YEAR
  #define GET_MONTH		PyDateTime_GET_MONTH
  #define GET_DAY			PyDateTime_GET_DAY
! #define GET_HOUR		PyDateTime_GET_HOUR
! #define GET_MINUTE		PyDateTime_GET_MINUTE
! #define GET_SECOND		PyDateTime_GET_SECOND
! #define GET_MICROSECOND		PyDateTime_GET_MICROSECOND
  
! /* Date accessors. */
  #define SET_YEAR(o, v)		(((o)->data[0] = ((v) & 0xff00) >> 8), \
                                   ((o)->data[1] = ((v) & 0x00ff)))
--- 21,34 ----
  #define MAX_DELTA_DAYS 999999999
  
  /* Rename the long macros in datetime.h to more reasonable short names. */
  #define GET_YEAR		PyDateTime_GET_YEAR
  #define GET_MONTH		PyDateTime_GET_MONTH
  #define GET_DAY			PyDateTime_GET_DAY
! #define DATE_GET_HOUR		PyDateTime_DATE_GET_HOUR
! #define DATE_GET_MINUTE		PyDateTime_DATE_GET_MINUTE
! #define DATE_GET_SECOND		PyDateTime_DATE_GET_SECOND
! #define DATE_GET_MICROSECOND	PyDateTime_DATE_GET_MICROSECOND
  
! /* Date accessors for date and datetime. */
  #define SET_YEAR(o, v)		(((o)->data[0] = ((v) & 0xff00) >> 8), \
                                   ((o)->data[1] = ((v) & 0x00ff)))
***************
*** 45,57 ****
  #define SET_DAY(o, v)		(PyDateTime_GET_DAY(o) = (v))
  
! /* Date/Time accessors. */
! #define SET_HOUR(o, v)		(PyDateTime_GET_HOUR(o) = (v))
! #define SET_MINUTE(o, v)	(PyDateTime_GET_MINUTE(o) = (v))
! #define SET_SECOND(o, v)	(PyDateTime_GET_SECOND(o) = (v))
! #define SET_MICROSECOND(o, v)	(((o)->data[7] = ((v) & 0xff0000) >> 16), \
!                                  ((o)->data[8] = ((v) & 0x00ff00) >> 8), \
!                                  ((o)->data[9] = ((v) & 0x0000ff)))
  
! /* Delta accessors. */
  #define GET_TD_DAYS(o)		(((PyDateTime_Delta *)(o))->days)
  #define GET_TD_SECONDS(o)	(((PyDateTime_Delta *)(o))->seconds)
--- 36,58 ----
  #define SET_DAY(o, v)		(PyDateTime_GET_DAY(o) = (v))
  
! /* Date/Time accessors for datetime. */
! #define DATE_SET_HOUR(o, v)	(PyDateTime_DATE_GET_HOUR(o) = (v))
! #define DATE_SET_MINUTE(o, v)	(PyDateTime_DATE_GET_MINUTE(o) = (v))
! #define DATE_SET_SECOND(o, v)	(PyDateTime_DATE_GET_SECOND(o) = (v))
! #define DATE_SET_MICROSECOND(o, v)	\
! 	(((o)->data[7] = ((v) & 0xff0000) >> 16), \
!          ((o)->data[8] = ((v) & 0x00ff00) >> 8), \
!          ((o)->data[9] = ((v) & 0x0000ff)))
  
! /* Time accessors for time. */
! #define TIME_SET_HOUR(o, v)	(PyDateTime_TIME_GET_HOUR(o) = (v))
! #define TIME_SET_MINUTE(o, v)	(PyDateTime_TIME_GET_MINUTE(o) = (v))
! #define TIME_SET_SECOND(o, v)	(PyDateTime_TIME_GET_SECOND(o) = (v))
! #define TIME_SET_MICROSECOND(o, v)	\
! 	(((o)->data[7] = ((v) & 0xff0000) >> 16), \
!          ((o)->data[8] = ((v) & 0x00ff00) >> 8), \
!          ((o)->data[9] = ((v) & 0x0000ff)))
! 
! /* Delta accessors for timedelta. */
  #define GET_TD_DAYS(o)		(((PyDateTime_Delta *)(o))->days)
  #define GET_TD_SECONDS(o)	(((PyDateTime_Delta *)(o))->seconds)
***************
*** 368,373 ****
  	PyOS_snprintf(buffer, bufflen,
  		      "%02d:%02d:%02d.%06d",
! 		      GET_HOUR(dt), GET_MINUTE(dt), GET_SECOND(dt),
! 		      GET_MICROSECOND(dt));
  }
  
--- 369,376 ----
  	PyOS_snprintf(buffer, bufflen,
  		      "%02d:%02d:%02d.%06d",
! 		      DATE_GET_HOUR(dt),
! 		      DATE_GET_MINUTE(dt),
! 		      DATE_GET_SECOND(dt),
! 		      DATE_GET_MICROSECOND(dt));
  }
  
***************
*** 527,534 ****
  		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;
--- 530,537 ----
  		SET_MONTH(self, month);
  		SET_DAY(self, day);
! 		DATE_SET_HOUR(self, hour);
! 		DATE_SET_MINUTE(self, minute);
! 		DATE_SET_SECOND(self, second);
! 		DATE_SET_MICROSECOND(self, usecond);
  	}
  	return (PyObject *) self;

Index: datetime.h
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -C2 -d -r1.10 -r1.11
*** datetime.h	22 Nov 2002 03:34:42 -0000	1.10
--- datetime.h	7 Dec 2002 16:36:16 -0000	1.11
***************
*** 26,29 ****
--- 26,32 ----
  #define _PyDateTime_DATETIME_DATA_SIZE 10
  
+ /* # of bytes for hour, minute, second, and usecond. */
+ #define _PyDateTime_TIME_DATA_SIZE 6
+ 
  typedef struct
  {
***************
*** 40,57 ****
  }  PyDateTime_DateTime;
  
  /* Apply for date instances. */
! #define PyDateTime_GET_YEAR(o)     (((PyDateTime_Date*)o)->data[0] << 8 \
!                                     | ((PyDateTime_Date*)o)->data[1])
  #define PyDateTime_GET_MONTH(o)    (((PyDateTime_Date*)o)->data[2])
  #define PyDateTime_GET_DAY(o)      (((PyDateTime_Date*)o)->data[3])
  
! /* Apply for datetime instances. */
! #define PyDateTime_GET_HOUR(o)        (((PyDateTime_DateTime*)o)->data[4])
! #define PyDateTime_GET_MINUTE(o)      (((PyDateTime_DateTime*)o)->data[5])
! #define PyDateTime_GET_SECOND(o)      (((PyDateTime_DateTime*)o)->data[6])
! #define PyDateTime_GET_MICROSECOND(o) \
  	((((PyDateTime_DateTime*)o)->data[7] << 16) |	\
           (((PyDateTime_DateTime*)o)->data[8] << 8)  |	\
!          ((PyDateTime_DateTime*)o)->data[9])
  
  #endif
--- 43,85 ----
  }  PyDateTime_DateTime;
  
+ typedef struct
+ {
+ 	PyObject_HEAD
+ 	long hashcode;
+ 	unsigned char data[_PyDateTime_TIME_DATA_SIZE];
+ }  PyDateTime_Time;
+ 
+ typedef struct
+ {
+ 	PyObject_HEAD
+ 	long hashcode;		/* -1 when unknown */
+ 	long days;		/* -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS */
+ 	long seconds;		/* 0 <= seconds < 24*3600 is invariant */
+ 	long microseconds;	/* 0 <= microseconds < 1000000 is invariant */
+ } PyDateTime_Delta;
+ 
  /* Apply for date instances. */
! #define PyDateTime_GET_YEAR(o)     ((((PyDateTime_Date*)o)->data[0] << 8) | \
!                                      ((PyDateTime_Date*)o)->data[1])
  #define PyDateTime_GET_MONTH(o)    (((PyDateTime_Date*)o)->data[2])
  #define PyDateTime_GET_DAY(o)      (((PyDateTime_Date*)o)->data[3])
  
! /* Apply for datetime and date instances. */
! #define PyDateTime_DATE_GET_HOUR(o)        (((PyDateTime_DateTime*)o)->data[4])
! #define PyDateTime_DATE_GET_MINUTE(o)      (((PyDateTime_DateTime*)o)->data[5])
! #define PyDateTime_DATE_GET_SECOND(o)      (((PyDateTime_DateTime*)o)->data[6])
! #define PyDateTime_DATE_GET_MICROSECOND(o) 		\
  	((((PyDateTime_DateTime*)o)->data[7] << 16) |	\
           (((PyDateTime_DateTime*)o)->data[8] << 8)  |	\
!           ((PyDateTime_DateTime*)o)->data[9])
! 
! /* Apply for time instances. */
! #define PyDateTime_TIME_GET_HOUR(o)        (((PyDateTime_Time*)o)->data[0])
! #define PyDateTime_TIME_GET_MINUTE(o)      (((PyDateTime_Time*)o)->data[1])
! #define PyDateTime_TIME_GET_SECOND(o)      (((PyDateTime_Time*)o)->data[2])
! #define PyDateTime_TIME_GET_MICROSECOND(o) 		\
! 	((((PyDateTime_Time*)o)->data[3] << 16) |	\
!          (((PyDateTime_Time*)o)->data[4] << 8)  |	\
!           ((PyDateTime_Time*)o)->data[5])
  
  #endif

Index: obj_datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_datetime.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -C2 -d -r1.30 -r1.31
*** obj_datetime.c	7 Dec 2002 05:33:45 -0000	1.30
--- obj_datetime.c	7 Dec 2002 16:36:16 -0000	1.31
***************
*** 8,12 ****
  datetime_hour(PyDateTime_DateTime *self, void *unused)
  {
! 	return PyInt_FromLong(GET_HOUR(self));
  }
  
--- 8,12 ----
  datetime_hour(PyDateTime_DateTime *self, void *unused)
  {
! 	return PyInt_FromLong(DATE_GET_HOUR(self));
  }
  
***************
*** 14,18 ****
  datetime_minute(PyDateTime_DateTime *self, void *unused)
  {
! 	return PyInt_FromLong(GET_MINUTE(self));
  }
  
--- 14,18 ----
  datetime_minute(PyDateTime_DateTime *self, void *unused)
  {
! 	return PyInt_FromLong(DATE_GET_MINUTE(self));
  }
  
***************
*** 20,24 ****
  datetime_second(PyDateTime_DateTime *self, void *unused)
  {
! 	return PyInt_FromLong(GET_SECOND(self));
  }
  
--- 20,24 ----
  datetime_second(PyDateTime_DateTime *self, void *unused)
  {
! 	return PyInt_FromLong(DATE_GET_SECOND(self));
  }
  
***************
*** 26,30 ****
  datetime_microsecond(PyDateTime_DateTime *self, void *unused)
  {
! 	return PyInt_FromLong(GET_MICROSECOND(self));
  }
  
--- 26,30 ----
  datetime_microsecond(PyDateTime_DateTime *self, void *unused)
  {
! 	return PyInt_FromLong(DATE_GET_MICROSECOND(self));
  }
  
***************
*** 242,249 ****
  	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,
--- 242,250 ----
  	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,
***************
*** 264,271 ****
  	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,
--- 265,273 ----
  	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,
***************
*** 286,300 ****
  				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, 1);
  }
  
--- 288,301 ----
  				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);
  }
  
***************
*** 358,376 ****
  	char *typename = self->ob_type->tp_name;
  
! 	if (GET_MICROSECOND(self)) {
  		PyOS_snprintf(buffer, sizeof(buffer),
  			      "%s(%d, %d, %d, %d, %d, %d, %d)",
  			      typename,
  			      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)) {
  		PyOS_snprintf(buffer, sizeof(buffer),
  			      "%s(%d, %d, %d, %d, %d, %d)",
  			      typename,
  			      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
! 			      GET_HOUR(self), GET_MINUTE(self),
! 			      GET_SECOND(self));
  	}
  	else {
--- 359,378 ----
  	char *typename = self->ob_type->tp_name;
  
! 	if (DATE_GET_MICROSECOND(self)) {
  		PyOS_snprintf(buffer, sizeof(buffer),
  			      "%s(%d, %d, %d, %d, %d, %d, %d)",
  			      typename,
  			      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
! 			      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
! 			      DATE_GET_SECOND(self), 
! 			      DATE_GET_MICROSECOND(self));
  	}
! 	else if (DATE_GET_SECOND(self)) {
  		PyOS_snprintf(buffer, sizeof(buffer),
  			      "%s(%d, %d, %d, %d, %d, %d)",
  			      typename,
  			      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
! 			      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
! 			      DATE_GET_SECOND(self));
  	}
  	else {
***************
*** 379,383 ****
  			      typename,
  			      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
! 			      GET_HOUR(self), GET_MINUTE(self));
  	}
  	return PyString_FromString(buffer);
--- 381,385 ----
  			      typename,
  			      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
! 			      DATE_GET_HOUR(self), DATE_GET_MINUTE(self));
  	}
  	return PyString_FromString(buffer);
***************
*** 421,427 ****
  {
  	return format_ctime((PyDateTime_Date *)self,
! 			    GET_HOUR(self),
! 			    GET_MINUTE(self),
! 			    GET_SECOND(self));
  }
  
--- 423,429 ----
  {
  	return format_ctime((PyDateTime_Date *)self,
! 			    DATE_GET_HOUR(self),
! 			    DATE_GET_MINUTE(self),
! 			    DATE_GET_SECOND(self));
  }
  
***************
*** 455,460 ****
  		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);
--- 457,463 ----
  		temp = Py_BuildValue("lllllll", GET_YEAR(self),
  				      GET_MONTH(self), GET_DAY(self),
! 				      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
! 				      DATE_GET_SECOND(self), 
! 				      DATE_GET_MICROSECOND(self));
  		if (temp != NULL) {
  			self->hashcode = PyObject_Hash(temp);
***************
*** 474,480 ****
  	return Py_BuildValue("iiiiiiiii",
  			     year, month, day,
! 			     GET_HOUR(self),
! 			     GET_MINUTE(self),
! 			     GET_SECOND(self),
  			     weekday(year, month, day),
  			     days_before_month(year, month) + day,
--- 477,483 ----
  	return Py_BuildValue("iiiiiiiii",
  			     year, month, day,
! 			     DATE_GET_HOUR(self),
! 			     DATE_GET_MINUTE(self),
! 			     DATE_GET_SECOND(self),
  			     weekday(year, month, day),
  			     days_before_month(year, month) + day,