diff -r 3fbfa61634de Doc/library/datetime.rst --- a/Doc/library/datetime.rst Thu Jul 19 00:14:35 2012 -0500 +++ b/Doc/library/datetime.rst Thu Jul 19 18:52:40 2012 -0300 @@ -426,6 +426,17 @@ 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`, or if it returns a value where + the time part is nonzero. + + .. versionadded:: 3.3 + + Class attributes: .. attribute:: date.min @@ -597,6 +608,17 @@ section :ref:`strftime-strptime-behavior`. +.. method:: time.strptime(time_string, format) + + Return a :class:`time` corresponding to *time_string*, parsed according to + *format*. This is equivalent to ``time(*(time.strptime(time_string, + format)[4:7]))``. :exc:`ValueError` is raised if the time string and + format cannot be parsed by `time.strptime`, or if it returns a value with + non-default values for the date part. + + .. versionadded:: 3.3 + + Example of counting days to an event:: >>> import time @@ -783,7 +805,7 @@ Return a :class:`.datetime` corresponding to *date_string*, parsed according to *format*. This is equivalent to ``datetime(*(time.strptime(date_string, format)[0:6]))``. :exc:`ValueError` is raised if the date_string and format - can't be parsed by :func:`time.strptime` or if it returns a value which isn't a + cannot be parsed by :func:`time.strptime` or if it returns a value which isn't a time tuple. See section :ref:`strftime-strptime-behavior`. @@ -1278,6 +1300,20 @@ 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:: 3.3 + + Class attributes: diff -r 3fbfa61634de Lib/_strptime.py --- a/Lib/_strptime.py Thu Jul 19 00:14:35 2012 -0500 +++ b/Lib/_strptime.py Thu Jul 19 18:52:40 2012 -0300 @@ -17,6 +17,7 @@ from re import IGNORECASE, ASCII from re import escape as re_escape from datetime import (date as datetime_date, + datetime as datetime_datetime, timedelta as datetime_timedelta, timezone as datetime_timezone) try: @@ -509,3 +510,9 @@ args += (tz,) return cls(*args) + +def _strptime_date(data_string, format="%a %b %d %Y"): + dt = _strptime_datetime(datetime_datetime, data_string, format) + if dt.hour or dt.minute or dt.second or dt.microsecond: + raise ValueError("date.strptime value cannot have a time part") + return dt.date() diff -r 3fbfa61634de Lib/datetime.py --- a/Lib/datetime.py Thu Jul 19 00:14:35 2012 -0500 +++ b/Lib/datetime.py Thu Jul 19 18:52:40 2012 -0300 @@ -648,6 +648,7 @@ isoweekday(), isocalendar(), isoformat() ctime() strftime() + strptime() Properties (readonly): year, month, day @@ -698,6 +699,12 @@ y, m, d = _ord2ymd(n) return cls(y, m, d) + @classmethod + def strptime(cls, date_string, fmt="%a %b %d"): + 'string, format -> new datetime parsed from a string (like time.strptime()).' + import _strptime + return _strptime._strptime_date(date_string, fmt) + # Conversions to string def __repr__(self): diff -r 3fbfa61634de Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py Thu Jul 19 00:14:35 2012 -0500 +++ b/Lib/test/datetimetester.py Thu Jul 19 18:52:40 2012 -0300 @@ -748,6 +748,19 @@ dt2 = dt - delta self.assertEqual(dt2, dt - days) + def test_strptime(self): + 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 @@ -1113,6 +1126,19 @@ #check that this standard extension works t.strftime("%f") + def test_strptime(self): + 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 = '2004-12-01' + format = '%Y-%m-%d' + result, frac = _strptime._strptime(string, format) + + expected = self.theclass(*(result[0:3])) + got = self.theclass.strptime(string, format) + self.assertEqual(expected, got) def test_format(self): dt = self.theclass(2007, 9, 10) diff -r 3fbfa61634de Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c Thu Jul 19 00:14:35 2012 -0500 +++ b/Modules/_datetimemodule.c Thu Jul 19 18:52:40 2012 -0300 @@ -103,6 +103,9 @@ static PyTypeObject PyDateTime_TimeType; static PyTypeObject PyDateTime_TZInfoType; static PyTypeObject PyDateTime_TimeZoneType; +static PyObject *datetime_strptime(PyObject *cls, PyObject *args); +static PyObject *datetime_getdate(PyDateTime_DateTime *self); +static PyObject *datetime_gettime(PyDateTime_DateTime *self); /* --------------------------------------------------------------------------- * Math utilities. @@ -2533,6 +2536,31 @@ 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. */ @@ -2830,6 +2858,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, @@ -3520,6 +3552,51 @@ 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. */ @@ -3849,6 +3926,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].")}, @@ -5006,6 +5091,10 @@ PyDoc_STR("string, format -> new datetime parsed from a string " "(like time.strptime()).")}, + {"strptime", (PyCFunction)time_strptime, METH_VARARGS | METH_CLASS, + PyDoc_STR("string, format -> new time 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")},