[Python-checkins] python/nondist/sandbox/datetime obj_datetime.c,1.53,1.54 obj_datetimetz.c,1.10,1.11

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Fri, 13 Dec 2002 22:32:00 -0800


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

Modified Files:
	obj_datetime.c obj_datetimetz.c 
Log Message:
Made datetime_combine smart enough to deal with datetimetz.combine() too.
The design of this function looks flaky:  the Python implementation allows
date, datetime, or datetimetz for the date argument, and time or timetz
for the time argument.  datetime.combine(datetimetz, timetz) ignores the
tzinfo from both arguments.  datetimetz.combine(datetimetz, timetz)
ignores timetz from the datetimetz argument.  All of that is none of
documented, tested, or even mentioned, and *feels* out of control.

Also restored non-functional code for the 4 other datetimetz class
methods -- I overlooked that these aren't really the datetime methods
of the same names, because the datetimetz flavors accept optional
tzinfo arguments.


Index: obj_datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_datetime.c,v
retrieving revision 1.53
retrieving revision 1.54
diff -C2 -d -r1.53 -r1.54
*** obj_datetime.c	14 Dec 2002 01:33:57 -0000	1.53
--- obj_datetime.c	14 Dec 2002 06:31:58 -0000	1.54
***************
*** 197,201 ****
  }
  
! /* Return new datetime from date and time arguments. */
  static PyObject *
  datetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
--- 197,208 ----
  }
  
! /* Return new datetime or datetimetz from date/datetime/datetimetz and
!  * time/timetz arguments.
!  * XXX If the date is a datetime, the time part is ignored.  If the
!  * XXX date is a datetimetz, the tzinfo part is also ignored.  It's not
!  * XXX clear that this was intentional.  If cls is datetime (not datetimetz),
!  * XXX the tzinfo of the time part is also ignored.  Again the intent is
!  * XXX unclear.
!  */
  static PyObject *
  datetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
***************
*** 217,220 ****
--- 224,234 ----
  				    		TIME_GET_SECOND(time),
  				    		TIME_GET_MICROSECOND(time));
+ 	if (result && PyTimeTZ_Check(time) && PyDateTimeTZ_Check(result)) {
+ 		/* Copy the tzinfo field. */
+ 		PyObject *tzinfo = ((PyDateTime_TimeTZ *)time)->tzinfo;
+ 		Py_INCREF(tzinfo);
+ 		Py_DECREF(((PyDateTime_DateTimeTZ *)result)->tzinfo);
+ 		((PyDateTime_DateTimeTZ *)result)->tzinfo = tzinfo;
+ 	}
  	return result;
  }

Index: obj_datetimetz.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_datetimetz.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -C2 -d -r1.10 -r1.11
*** obj_datetimetz.c	14 Dec 2002 06:03:17 -0000	1.10
--- obj_datetimetz.c	14 Dec 2002 06:31:58 -0000	1.11
***************
*** 60,86 ****
  }
  
! /* Return new datetime from date and time arguments. */
  static PyObject *
! datetimetz_combine(PyObject *cls, PyObject *args, PyObject *kw)
  {
!  	static char *keywords[] = {"date", "time", NULL};
! 	PyObject *date;
  	PyObject *time;
  	PyObject *result = NULL;
  
! 	if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!:combine", keywords,
! 					&PyDateTime_DateType, &date,
! 					&PyDateTime_TimeType, &time))
! 		result = PyObject_CallFunction(cls, "iiiiiii",
! 						GET_YEAR(date),
! 				    		GET_MONTH(date),
! 						GET_DAY(date),
! 				    		TIME_GET_HOUR(time),
! 				    		TIME_GET_MINUTE(time),
! 				    		TIME_GET_SECOND(time),
! 				    		TIME_GET_MICROSECOND(time));
  	return result;
  }
  
  /*
   * Destructor.
--- 60,190 ----
  }
  
! /* TM_FUNC is the shared type of localtime() and gmtime(). */
! typedef struct tm *(*TM_FUNC)(const time_t *timer);
! 
! /* Internal helper.
!  * Build datetime from a time_t and a distinct count of microseconds.
!  * Pass localtime or gmtime for f, to control the interpretation of timet.
!  */
  static PyObject *
! datetimetz_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, long us)
  {
! 	struct tm *tm;
! 	PyObject *result = NULL;
! 
! 	tm = f(&timet);
! 	if (tm)
! 		result = PyObject_CallFunction(cls, "iiiiiil",
! 					       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;
! }
! 
! /* Internal helper.
!  * Build datetime from a Python timestamp.  Pass localtime or gmtime for f,
!  * to control the interpretation of the timestamp.  Since a double doesn't
!  * have enough bits to cover a datetime's full range of precision, it's
!  * better to call datetimetz_from_timet_and_us provided you have a way
!  * to get that much precision (e.g., C time() isn't good enough).
!  */
! static PyObject *
! datetimetz_from_timestamp(PyObject *cls, TM_FUNC f, double timestamp)
! {
! 	time_t timet = (time_t)timestamp;
! 	long us = (long)((timestamp - (double)timet) * 1e6);
! 
! 	return datetimetz_from_timet_and_us(cls, f, timet, us);
! }
! 
! /* Internal helper.
!  * Build most accurate possible datetime for current time.  Pass localtime or
!  * gmtime for f as appropriate.
!  */
! static PyObject *
! datetimetz_best_possible(PyObject *cls, TM_FUNC f)
! {
! #ifdef HAVE_GETTIMEOFDAY
! 	struct timeval t;
! 
! #ifdef GETTIMEOFDAY_NO_TZ
! 	gettimeofday(&t);
! #else
! 	gettimeofday(&t, (struct timezone *)NULL);
! #endif
! 	return datetimetz_from_timet_and_us(cls, f, t.tv_sec, t.tv_usec);
! 
! #else	/* ! HAVE_GETTIMEOFDAY */
! 	/* No flavor of gettimeofday exists on this platform.  Python's
! 	 * time.time() does a lot of other platform tricks to get the
! 	 * best time it can on the platform, and we're not going to do
! 	 * better than that (if we could, the better code would belong
! 	 * in time.time()!)  We're limited by the precision of a double,
! 	 * though.
! 	 */
  	PyObject *time;
+ 	double dtime;
+ 
+ 	time = time_time();
+     	if (time == NULL)
+     		return NULL;
+ 	dtime = PyFloat_AsDouble(time);
+ 	Py_DECREF(time);
+ 	if (dtime == -1.0 && PyErr_Occurred())
+ 		return NULL;
+ 	return datetimetz_from_timestamp(cls, f, dtime);
+ #endif	/* ! HAVE_GETTIMEOFDAY */
+ }
+ 
+ /* Return new local datetime from timestamp (Python timestamp -- a double). */
+ static PyObject *
+ datetimetz_fromtimestamp(PyObject *cls, PyObject *args)
+ {
+ 	double timestamp;
  	PyObject *result = NULL;
  
! 	if (PyArg_ParseTuple(args, "d:fromtimestamp", &timestamp))
! 		result = datetimetz_from_timestamp(cls, localtime, timestamp);
! 	return result;
! }
! 
! /* Return new UTC datetime from timestamp (Python timestamp -- a double). */
! static PyObject *
! datetimetz_utcfromtimestamp(PyObject *cls, PyObject *args)
! {
! 	double timestamp;
! 	PyObject *result = NULL;
! 
! 	if (PyArg_ParseTuple(args, "d:utcfromtimestamp", &timestamp))
! 		result = datetimetz_from_timestamp(cls, gmtime, timestamp);
  	return result;
  }
  
+ /* Return best possible local time -- this isn't constrained by the
+  * precision of a timestamp.
+  */
+ static PyObject *
+ datetimetz_now(PyObject *cls, PyObject *dummy)
+ {
+ 	return datetimetz_best_possible(cls, localtime);
+ }
+ 
+ /* Return best possible UTC time -- this isn't constrained by the
+  * precision of a timestamp.
+  */
+ static PyObject *
+ datetimetz_utcnow(PyObject *cls, PyObject *dummy)
+ {
+ 	return datetimetz_best_possible(cls, gmtime);
+ }
+ 
  /*
   * Destructor.
***************
*** 415,423 ****
  static PyMethodDef datetimetz_methods[] = {
  	/* Class methods: */
! 	/* Inherited: now(), utcnow(), fromtimestamp(), utcfromtimestamp(). */
  
! 	{"combine", (PyCFunction)datetimetz_combine,
! 	 METH_VARARGS | METH_KEYWORDS | METH_CLASS,
! 	 PyDoc_STR("date, time -> datetime with same date and time fields")},
  
  	/* Instance methods: */
--- 519,546 ----
  static PyMethodDef datetimetz_methods[] = {
  	/* Class methods: */
! 	/* Inherited: combine(). */
  
! 	/* XXX Inherited: now(), utcnow(), fromtimestamp(), utcfromtimestamp().
! 	   XXX But they shouldn't be:  these take a frickin' optional tzinfo
! 	   XXX argument in the datetimetz flavors.
! 
! 	{"now",         (PyCFunction)datetimetz_now,
! 	 METH_NOARGS | METH_CLASS,
! 	 PyDoc_STR("Return a new datetime representing local day and time.")},
! 
! 	{"utcnow",         (PyCFunction)datetimetz_utcnow,
! 	 METH_NOARGS | METH_CLASS,
! 	 PyDoc_STR("Return a new datetime representing UTC day and time.")},
! 
! 	{"fromtimestamp", (PyCFunction)datetimetz_fromtimestamp,
! 	 METH_VARARGS | METH_CLASS,
! 	 PyDoc_STR("timestamp -> local datetime from a POSIX timestamp "
! 	 	   "(like time.time()).")},
! 
! 	{"utcfromtimestamp", (PyCFunction)datetimetz_utcfromtimestamp,
! 	 METH_VARARGS | METH_CLASS,
! 	 PyDoc_STR("timestamp -> UTC datetime from a POSIX timestamp "
! 	 	   "(like time.time()).")},
! 	*/
  
  	/* Instance methods: */