why not datetime.strptime() ?

josh at yucs.org josh at yucs.org
Tue Jan 11 12:33:35 EST 2005


On Tue, Jan 11, 2005 at 08:56:33AM -0600, Skip Montanaro wrote:
>     * The seventh item returned from time.strptime() is the day of the week.
>       You're passing it into the microsecond arg of the datetime constructor

Thanks!

>       and ignoring the timezone info (ninth item returned from
>       time.strptime(), eighth arg to the datetime constructor).
> 

This is intentional. time.strptime() doesn't expose the timezone (only
the daylight savings flag), so i'd have to duplicate its logic in order
to distinguish between local time and utc. Since it's easy to explicitly
call somedatetime.replace(tzinfo=sometzinfo), having strptime() always
create "naive" datetimes seemed most sensible.

>     * It would be nice if the import happened only once and was cached:
> 
>       static PyObject *time_module;
>       ...
>       if (time_module == NULL &&
>           (time_module = PyImport_ImportModule("time")) == NULL)
>                 return NULL;
>       obj = PyObject_CallMethod(time_module, ...);

The datetime is full of these calls. Would it make sense to make this a
separate patch? (Or maybe the PyImport_ImportModule could implement such
a cache :) ?)
-------------- next part --------------
*** Modules/datetimemodule.c.orig	2003-10-20 10:34:46.000000000 -0400
--- Modules/datetimemodule.c	2005-01-11 12:19:36.839337336 -0500
***************
*** 3774,3779 ****
--- 3774,3819 ----
  	return result;
  }
  
+ /* Return new datetime from time.strptime(). */
+ static PyObject *
+ datetime_strptime(PyObject *cls, PyObject *args)
+ {
+ 	PyObject *result = NULL, *obj, *module;
+ 	const char *string, *format;
+ 
+ 	if (!PyArg_ParseTuple(args, "ss:strptime", &string, &format))
+ 		return NULL;
+ 
+ 	if ((module = PyImport_ImportModule("time")) == NULL)
+ 		return NULL;
+ 	obj = PyObject_CallMethod(module, "strptime", "ss", string, format);
+ 	Py_DECREF(module);
+ 
+ 	if (obj != NULL) {
+ 		int i, good_timetuple = 1;
+ 		long int ia[6];
+ 		if (PySequence_Check(obj) && PySequence_Size(obj) >= 6)
+ 			for (i=0; i < 6; i++) {
+ 				PyObject *p = PySequence_GetItem(obj, i);
+ 				if (PyInt_Check(p))
+ 					ia[i] = PyInt_AsLong(p);
+ 				else
+ 					good_timetuple = 0;
+ 				Py_DECREF(p);
+ 			}
+ 		else
+ 			good_timetuple = 0;
+ 		if (good_timetuple)
+ 			result = PyObject_CallFunction(cls, "iiiiii",
+ 				ia[0], ia[1], ia[2], ia[3], ia[4], ia[5]);
+ 		else
+ 			PyErr_SetString(PyExc_ValueError,
+ 				"unexpected value from time.strptime");
+ 		Py_DECREF(obj);
+ 	}
+ 	return result;
+ }
+ 
  /* Return new datetime from date/datetime and time arguments. */
  static PyObject *
  datetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
***************
*** 4385,4390 ****
--- 4425,4435 ----
  	 PyDoc_STR("timestamp -> UTC datetime from a POSIX timestamp "
  	 	   "(like time.time()).")},
  
+ 	{"strptime", (PyCFunction)datetime_strptime,
+ 	 METH_VARARGS | METH_CLASS,
+ 	 PyDoc_STR("strptime -> new datetime parsed from a string"
+ 	 	   "(like time.strptime()).")},
+ 
  	{"combine", (PyCFunction)datetime_combine,
  	 METH_VARARGS | METH_KEYWORDS | METH_CLASS,
  	 PyDoc_STR("date, time -> datetime with same date and time fields")},
*** Doc/lib/libdatetime.tex.orig	2003-09-06 01:36:56.000000000 -0400
--- Doc/lib/libdatetime.tex	2005-01-11 12:02:30.000000000 -0500
***************
*** 624,629 ****
--- 624,636 ----
    ignored.
    \end{methoddesc}
  
+ \begin{methoddesc}{strptime}{date_string, format}
+   Return the date corresponding to date_string, parsed according
+   to format. This is equivalent to \code{datetime(*(time.strptime(
+   date_string, format)[0:6]))}. \exception{ValueError} is raised if
+   \code{time.strptime()} returns a value which isn't a timetuple.
+ \end{methoddesc}
+ 
  Class attributes:
  
  \begin{memberdesc}{min}
*** Lib/test/test_datetime.py.orig	2005-01-11 11:56:36.000000000 -0500
--- Lib/test/test_datetime.py	2005-01-11 12:28:30.268243816 -0500
***************
*** 1351,1356 ****
--- 1351,1365 ----
              # Else try again a few times.
          self.failUnless(abs(from_timestamp - from_now) <= tolerance)
  
+     def test_strptime(self):
+         import time
+ 
+         string = '2004-12-01'
+         format = '%Y-%m-%d'
+         expected = self.theclass(*(time.strptime(string, format)[0:6]))
+         got = self.theclass.strptime(string, format)
+         self.assertEqual(expected, got)
+ 
      def test_more_timetuple(self):
          # This tests fields beyond those tested by the TestDate.test_timetuple.
          t = self.theclass(2004, 12, 31, 6, 22, 33)


More information about the Python-list mailing list