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 8f1ddf330f3940..897dd06e5b4574 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3291,19 +3291,31 @@ static PyObject * datetime_date_today_impl(PyTypeObject *type) /*[clinic end generated code: output=d5474697df6b251c input=21688afa289c0a06]*/ { - PyObject *time; - PyObject *result; - time = time_time(); - if (time == NULL) + /* Use C implementation to boost performance for date type */ + if (type == &PyDateTime_DateType) { + struct tm tm; + time_t t; + time(&t); + + if (_PyTime_localtime(t, &tm) != 0) { + return NULL; + } + + return new_date_ex(tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + type); + } + + PyObject *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. 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(). + /* Note well: since today() is a class method, it may not call + * date.fromtimestamp, e.g., it may call datetime.fromtimestamp. */ - result = PyObject_CallMethodOneArg((PyObject*)type, &_Py_ID(fromtimestamp), time); + PyObject *result = PyObject_CallMethodOneArg((PyObject*)type, &_Py_ID(fromtimestamp), time); Py_DECREF(time); return result; }