[Python-checkins] python/dist/src/Modules timemodule.c,2.140,2.141

bcannon at users.sourceforge.net bcannon at users.sourceforge.net
Sat Jun 19 16:48:46 EDT 2004


Update of /cvsroot/python/python/dist/src/Modules
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18933/Modules

Modified Files:
	timemodule.c 
Log Message:
Raise ValueError when value being stored in a time_t variable will result in
more than a second of precision.  Primarily affects ctime, localtime, and
gmtime.

Closes bug #919012 thanks to Tim Peters' code.

Tim suggests that the new funciton being introduced, _PyTime_DoubletoTimet(),
should be added to the internal C API and then used in datetime where
appropriate.  Not being done now for lack of time.


Index: timemodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/timemodule.c,v
retrieving revision 2.140
retrieving revision 2.141
diff -C2 -d -r2.140 -r2.141
*** timemodule.c	2 Mar 2004 04:38:10 -0000	2.140
--- timemodule.c	19 Jun 2004 20:48:43 -0000	2.141
***************
*** 85,88 ****
--- 85,117 ----
  static PyObject *moddict;
  
+ /* Cast double x to time_t, but raise ValueError if x is too large
+  * to fit in a time_t.  ValueError is set on return iff the return
+  * value is (time_t)-1 and PyErr_Occurred().
+  */
+ static time_t
+ _PyTime_DoubleToTimet(double x)
+ {
+ 	time_t result;
+ 	double diff;
+ 
+ 	result = (time_t)x;
+ 	/* How much info did we lose?  time_t may be an integral or
+ 	 * floating type, and we don't know which.  If it's integral,
+ 	 * we don't know whether C truncates, rounds, returns the floor,
+ 	 * etc.  If we lost a second or more, the C rounding is
+ 	 * unreasonable, or the input just doesn't fit in a time_t;
+ 	 * call it an error regardless.  Note that the original cast to
+ 	 * time_t can cause a C error too, but nothing we can do to
+ 	 * worm around that.
+ 	 */
+ 	diff = x - (double)result;
+ 	if (diff <= -1.0 || diff >= 1.0) {
+ 		PyErr_SetString(PyExc_ValueError,
+ 		                "timestamp out of range for platform time_t");
+ 		result = (time_t)-1;
+ 	}
+ 	return result;
+ }
+ 
  static PyObject *
  time_time(PyObject *self, PyObject *args)
***************
*** 232,240 ****
  
  static PyObject *
! time_convert(time_t when, struct tm * (*function)(const time_t *))
  {
  	struct tm *p;
  	errno = 0;
! 	p = function(&when);
  	if (p == NULL) {
  #ifdef EINVAL
--- 261,273 ----
  
  static PyObject *
! time_convert(double when, struct tm * (*function)(const time_t *))
  {
  	struct tm *p;
+ 	time_t whent = _PyTime_DoubleToTimet(when);
+ 
+ 	if (whent == (time_t)-1 && PyErr_Occurred())
+ 		return NULL;
  	errno = 0;
! 	p = function(&whent);
  	if (p == NULL) {
  #ifdef EINVAL
***************
*** 255,259 ****
  	if (!PyArg_ParseTuple(args, "|d:gmtime", &when))
  		return NULL;
! 	return time_convert((time_t)when, gmtime);
  }
  
--- 288,292 ----
  	if (!PyArg_ParseTuple(args, "|d:gmtime", &when))
  		return NULL;
! 	return time_convert(when, gmtime);
  }
  
***************
*** 273,277 ****
  	if (!PyArg_ParseTuple(args, "|d:localtime", &when))
  		return NULL;
! 	return time_convert((time_t)when, localtime);
  }
  
--- 306,310 ----
  	if (!PyArg_ParseTuple(args, "|d:localtime", &when))
  		return NULL;
! 	return time_convert(when, localtime);
  }
  
***************
*** 481,485 ****
  		if (!PyArg_ParseTuple(args, "|d:ctime", &dt))
  			return NULL;
! 		tt = (time_t)dt;
  	}
  	p = ctime(&tt);
--- 514,520 ----
  		if (!PyArg_ParseTuple(args, "|d:ctime", &dt))
  			return NULL;
! 		tt = _PyTime_DoubleToTimet(dt);
! 		if (tt == (time_t)-1 && PyErr_Occurred())
! 			return NULL;
  	}
  	p = ctime(&tt);




More information about the Python-checkins mailing list