Index: Doc/library/datetime.rst =================================================================== --- Doc/library/datetime.rst (revision 73532) +++ Doc/library/datetime.rst (working copy) @@ -338,6 +338,17 @@ date.max.toordinal()``. For any date *d*, ``date.fromordinal(d.toordinal()) == d``. +.. method:: date.strptime(date_string, format) + + Return a :class:`date` corresponding to *date_string, parsed according to + *format*. This is equivalent to ``date(*(time.strptime(date_string, + format)[0:3]))``. :exc:`ValueError` is raised if the date string and + format can't be parsed by `time.strptime`, if it returns a value which + isn't a time tuple, or if the time part is nonzero. + + .. versionadded:: 2.7 + + Class attributes: @@ -1118,9 +1129,22 @@ If an argument outside those ranges is given, :exc:`ValueError` is raised. All default to ``0`` except *tzinfo*, which defaults to :const:`None`. + +Other constructors, all class methods: + +.. method:: time.strptime(date_string, format) + + Return a :class:`time` corresponding to *date_string, parsed according to + *format*. This is equivalent to ``time(*(time.strptime(date_string, + format)[4:6]))``. :exc:`ValueError` is raised if the date string and + format can't be parsed by `time.strptime`, if it returns a value which + isn't a time tuple, or if the time part is nonzero. + + .. versionadded:: 2.7 + + Class attributes: - .. attribute:: time.min The earliest representable :class:`time`, ``time(0, 0, 0, 0)``. Index: Lib/test/test_datetime.py =================================================================== --- Lib/test/test_datetime.py (revision 73532) +++ Lib/test/test_datetime.py (working copy) @@ -510,6 +510,20 @@ dt2 = dt - delta self.assertEqual(dt2, dt - days) + def test_strptime(self): + import _strptime + + string = '2004-12-01 13:02:47.197' + format = '%Y-%m-%d %H:%M:%S.%f' + self.assertRaises(ValueError, date.strptime, string, format) + + string = '2004-12-01' + format = '%Y-%m-%d' + result, frac = _strptime._strptime(string, format) + expected = date(*(result[0:3])) + got = date.strptime(string, format) + self.assertEqual(expected, got) + class SubclassDate(date): sub_var = 1 @@ -1841,6 +1855,20 @@ # A naive object replaces %z and %Z with empty strings. self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''") + def test_strptime(self): + import _strptime + + string = '2004-12-01 13:02:47.197' + format = '%Y-%m-%d %H:%M:%S.%f' + self.assertRaises(ValueError, self.theclass.strptime, string, format) + + string = '13:02:47.197' + format = '%H:%M:%S.%f' + result, frac = _strptime._strptime(string, format) + expected = self.theclass(*(result[3:6] + (frac,))) + got = self.theclass.strptime(string, format) + self.assertEqual(expected, got) + def test_format(self): t = self.theclass(1, 2, 3, 4) self.assertEqual(t.__format__(''), str(t)) Index: Modules/datetimemodule.c =================================================================== --- Modules/datetimemodule.c (revision 73532) +++ Modules/datetimemodule.c (working copy) @@ -103,6 +103,9 @@ static PyTypeObject PyDateTime_DeltaType; static PyTypeObject PyDateTime_TimeType; static PyTypeObject PyDateTime_TZInfoType; +static PyObject *datetime_strptime(PyObject *cls, PyObject *args); +static PyObject *datetime_getdate(PyDateTime_DateTime *self); +static PyObject *datetime_gettime(PyDateTime_DateTime *self); /* --------------------------------------------------------------------------- * Math utilities. @@ -2361,6 +2364,32 @@ return result; } +/* Return new date from time.strptime(). */ +static PyObject * +date_strptime(PyObject *cls, PyObject *args) +{ + PyObject *date = NULL; + PyObject *datetime; + + datetime = datetime_strptime((PyObject *)&PyDateTime_DateTimeType, args); + + if (datetime == NULL) + return NULL; + + if (DATE_GET_HOUR(datetime) + || DATE_GET_MINUTE(datetime) + || DATE_GET_SECOND(datetime) + || DATE_GET_MICROSECOND(datetime)) + PyErr_SetString(PyExc_ValueError, + "date.strptime value cannot have a time part"); + else + date = datetime_getdate((PyDateTime_DateTime *)datetime); + + Py_DECREF(datetime); + + return date; +} + /* * Date arithmetic. */ @@ -2688,6 +2717,10 @@ PyDoc_STR("Current date or datetime: same as " "self.__class__.fromtimestamp(time.time()).")}, + {"strptime", (PyCFunction)date_strptime, METH_VARARGS | METH_CLASS, + PyDoc_STR("string, format -> new date parsed from a string " + "(like time.strptime()).")}, + /* Instance methods: */ {"ctime", (PyCFunction)date_ctime, METH_NOARGS, @@ -3160,6 +3193,50 @@ return self; } +/* Return new time from time.strptime(). */ +static PyObject * +time_strptime(PyObject *cls, PyObject *args) +{ + PyObject *time = NULL; + PyObject *datetime; + + static PyObject *emptyDatetime = NULL; + + /* To ensure that the given string does not contain a date, + * compare with the result of an empty date string. + */ + if (emptyDatetime == NULL) { + PyObject *emptyStringPair = Py_BuildValue("ss", "", ""); + if (emptyStringPair == NULL) + return NULL; + emptyDatetime = datetime_strptime( + (PyObject *)&PyDateTime_DateTimeType, + emptyStringPair); + Py_DECREF(emptyStringPair); + if (emptyDatetime == NULL) + return NULL; + } + + datetime = datetime_strptime( + (PyObject *)&PyDateTime_DateTimeType, + args); + + if (datetime == NULL) + return NULL; + + if (GET_YEAR(datetime) != GET_YEAR(emptyDatetime) + || GET_MONTH(datetime) != GET_MONTH(emptyDatetime) + || GET_DAY(datetime) != GET_DAY(emptyDatetime)) + PyErr_SetString(PyExc_ValueError, + "time.strptime value cannot have a date part"); + else + time = datetime_gettime((PyDateTime_DateTime *)datetime); + + Py_DECREF(datetime); + + return time; +} + /* * Destructor. */ @@ -3479,6 +3556,14 @@ static PyMethodDef time_methods[] = { + /* Class methods: */ + + {"strptime", (PyCFunction)time_strptime, METH_VARARGS | METH_CLASS, + PyDoc_STR("string, format -> new time parsed from a string " + "(like time.strptime()).")}, + + /* Instance methods: */ + {"isoformat", (PyCFunction)time_isoformat, METH_NOARGS, PyDoc_STR("Return string in ISO 8601 format, HH:MM:SS[.mmmmmm]" "[+HH:MM].")},