This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: date.today() is half as fast as datetime.now().date()
Type: performance Stage:
Components: Extension Modules Versions: Python 3.11
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Anthony Sottile, corona10, p-ganssle, rkm
Priority: normal Keywords:

Created on 2021-06-04 01:50 by Anthony Sottile, last changed 2022-04-11 14:59 by admin.

Messages (4)
msg395061 - (view) Author: Anthony Sottile (Anthony Sottile) * Date: 2021-06-04 01:50
```console
$ python3.10 -m timeit -s 'from datetime import datetime' 'datetime.now().date()'
500000 loops, best of 5: 708 nsec per loop
$ python3.10 -m timeit -s 'from datetime import date' 'date.today()'
200000 loops, best of 5: 1.4 usec per loop
```

this surprised me so I dug into it -- it appears a fast path can be added to `date.today()` to make it faster than `datetime.date.now()` -- though I'm rather unfamiliar with the functions involved here

here is my ~sloppy patch attempting to add a fast path, I would need some guidance to improve it and get it accepted:

```diff
$ git diff -w
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index 8ef2dad37a..7eaa5d1740 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -2875,6 +2875,17 @@ date_fromtimestamp(PyObject *cls, PyObject *obj)
 static PyObject *
 date_today(PyObject *cls, PyObject *dummy)
 {
+    /* fast path, don't call fromtimestamp */
+    if ((PyTypeObject *)cls == &PyDateTime_DateType) {
+        struct tm tm;
+        time_t t;
+        time(&t);
+        localtime_r(&t, &tm);
+        return new_date_ex(tm.tm_year + 1900,
+                           tm.tm_mon + 1,
+                           tm.tm_mday,
+                           (PyTypeObject*)cls);
+    } else {
         PyObject *time;
         PyObject *result;
         _Py_IDENTIFIER(fromtimestamp);
@@ -2893,6 +2904,7 @@ date_today(PyObject *cls, PyObject *dummy)
         Py_DECREF(time);
         return result;
     }
+}
 
 /*[clinic input]
 @classmethod
```

after this, `date.today()` is faster!

```console
$ ./python -m timeit -s 'from datetime import datetime' 'datetime.now().date()'
500000 loops, best of 5: 764 nsec per loop
$ ./python -m timeit -s 'from datetime import date' 'date.today()'
500000 loops, best of 5: 407 nsec per loop
```

\o/
msg395116 - (view) Author: Paul Ganssle (p-ganssle) * (Python committer) Date: 2021-06-04 19:55
Yeah, I knew this was slower and it's been on my long list to look at it (tied to this is the fact that `datetime.today()` is basically just a slow version of `datetime.now()`, in defiance of user expectations).

My inclination is that we shouldn't re-implement `fromtimestamp` in `date.today`, but rather call `date_fromtimestamp` in the fast path. I believe that incurs the overhead of creating one additional Python object (an integer), but if it's a sufficiently significant speedup, we could possibly refactor `date_fromtimestamp` to a version that accepts a C integer and a version that accepts a Python integer, then call the version accepting a C integer.

I think this won't give any speedup to `datetime.today`, since `datetime.today` will still take the slow path. If we care about this, we *may* be able to implement `datetime.today` as an alias for `datetime.now(None)`, assuming there are no behavioral differences between the two.
msg395123 - (view) Author: Anthony Sottile (Anthony Sottile) * Date: 2021-06-04 21:21
@terry.reddy -- I believe your title change makes this more difficult to understand
msg395124 - (view) Author: Anthony Sottile (Anthony Sottile) * Date: 2021-06-04 21:22
*terry.reedy oops typo!
History
Date User Action Args
2022-04-11 14:59:46adminsetgithub: 88473
2021-06-04 21:22:03Anthony Sottilesetmessages: + msg395124
2021-06-04 21:21:53Anthony Sottilesetmessages: + msg395123
2021-06-04 21:14:57terry.reedysettitle: date.today() is 2x slower than datetime.now().date() -> date.today() is half as fast as datetime.now().date()
2021-06-04 19:55:33p-gansslesetmessages: + msg395116
2021-06-04 19:27:01rkmsetnosy: + rkm
2021-06-04 03:10:23corona10setnosy: + corona10
2021-06-04 03:09:36corona10setnosy: + p-ganssle
2021-06-04 01:50:33Anthony Sottilecreate