diff --git a/Misc/NEWS.d/next/Library/2025-03-08-17-07-00.gh-issue-88473.qg23g8.rst b/Misc/NEWS.d/next/Library/2025-03-08-17-07-00.gh-issue-88473.qg23g8.rst new file mode 100644 index 00000000000000..f38ec8ef810407 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-08-17-07-00.gh-issue-88473.qg23g8.rst @@ -0,0 +1,3 @@ +Implement a fast path for :class:`datetime.date` objects in :func:`datetime.date.today` +which results in a 5x performance gain while proper subclasses retain their +previous performance. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 07d7089be09d20..67c740f45a484a 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3259,21 +3259,37 @@ date_fromtimestamp(PyObject *cls, PyObject *obj) static PyObject * date_today(PyObject *cls, PyObject *Py_UNUSED(dummy)) { - PyObject *time; - PyObject *result; - time = time_time(); - if (time == NULL) - return NULL; + /* Use C implementation to boost performance for date type */ + if ((PyTypeObject *)cls == &PyDateTime_DateType) { + struct tm tm; + time_t t; + time(&t); - /* Note well: today() is a class method, so this may not call - * date.fromtimestamp. For example, it may call - * datetime.fromtimestamp. That's why we need all the accuracy - * time.time() delivers; if someone were gonzo about optimization, - * date.today() could get away with plain C time(). - */ - result = PyObject_CallMethodOneArg(cls, &_Py_ID(fromtimestamp), time); - Py_DECREF(time); - return result; + if (_PyTime_localtime(t, &tm) != 0) { + return NULL; + } + + return new_date_ex(tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + (PyTypeObject*)cls); + } + else { + PyObject *time; + PyObject *result; + time = time_time(); + if (time == NULL) { + return NULL; + } + + /* Note well: today() is a class method, so this may not call + * date.fromtimestamp. For example, it may call + * datetime.fromtimestamp. + */ + result = PyObject_CallMethodOneArg(cls, &_Py_ID(fromtimestamp), time); + Py_DECREF(time); + return result; + } } /*[clinic input]