bpo-32403: Faster date and datetime constructors by pganssle · Pull Request #4993 · python/cpython

This fixes bpo-32403 and bpo-32404. The first one is a performance enhancement, the second is a bugfix.

Using this script to benchmark the alternate constructors, I see significant improvements in speed across the board (note that since the subclasses don't take the fast path, they are a reasonable proxy for the speed from before this patch). You can see the results on my laptop (using the debug build, not the profiling optimized build) below:

Running with N = 10000, k=20
                   |           datetime           |       DateTimeSubclass       
=================================================================================
constructor        |  1416.5  [1463.9 (±71) ns]   |  1494.8  [1569.2 (±119) ns]  
fromordinal        |  1081.5  [1117.2 (±24) ns]   |  2180.7  [2357.3 (±279) ns]  
fromisoformat      |   928.8   [962.5 (±34) ns]   |  2834.8  [3179.7 (±281) ns]  
fromtimestamp      |  1504.3  [1600.9 (±63) ns]   |  3625.1  [3869.6 (±280) ns]  
utcfromtimestamp   |  1178.6  [1281.2 (±172) ns]  |  3242.6  [3445.0 (±205) ns]  
combine            |  1060.1  [1111.0 (±73) ns]   |  2808.7  [3013.0 (±236) ns]  
now                |  1219.3  [1325.0 (±216) ns]  |  3625.5  [3892.7 (±300) ns]  
today              |  4868.5  [5261.0 (±565) ns]  |  7189.5  [7663.0 (±436) ns]  
=================================================================================
                   |             date             |         DateSubclass         
=================================================================================
constructor        |  974.5   [1010.1 (±39) ns]   |  1114.7  [1298.8 (±229) ns]  
fromordinal        |  1059.7  [1109.4 (±59) ns]   |  1923.1  [2258.8 (±375) ns]  
fromisoformat      |  817.5   [905.1 (±123) ns]   |  1734.1  [2160.8 (±542) ns]  
fromtimestamp      |  1285.4  [1484.7 (±378) ns]  |  2363.6  [3038.6 (±783) ns]  
today              |  4551.7  [4976.6 (±584) ns]  |  5828.9  [6883.9 (±934) ns]  
=================================================================================

For comparision, here is the same script run against master:

Running with N = 10000, k=20
                   |           datetime           |       DateTimeSubclass       
=================================================================================
constructor        |  1335.9  [1350.3 (±24) ns]   |  1406.0  [1426.9 (±15) ns]   
fromordinal        |  1905.0  [1948.3 (±42) ns]   |  2011.5  [2055.4 (±32) ns]   
fromisoformat      |   918.1   [929.3 (±6) ns]    |  2660.8  [2707.7 (±25) ns]   
fromtimestamp      |  1570.1  [1611.8 (±28) ns]   |  1732.1  [1766.3 (±30) ns]   
utcfromtimestamp   |  1202.7  [1234.5 (±18) ns]   |  1334.9  [1371.7 (±26) ns]   
combine            |  2584.9  [2626.3 (±22) ns]   |  2722.8  [2759.8 (±25) ns]   
now                |   1317.2  [1338.2 (±9) ns]   |  1509.7  [1563.7 (±24) ns]   
today              |  5027.1  [5096.9 (±71) ns]   |  5237.6  [5334.9 (±73) ns]   
=================================================================================
                   |             date             |         DateSubclass         
=================================================================================
constructor        |   912.8   [928.8 (±15) ns]   |   996.4   [1003.9 (±7) ns]   
fromordinal        |  1662.9  [1706.4 (±40) ns]   |  1773.6  [1820.7 (±41) ns]   
fromisoformat      |   818.5   [829.0 (±9) ns]    |  1630.0  [1743.3 (±289) ns]  
fromtimestamp      |  2155.2  [2213.4 (±41) ns]   |  2321.9  [2486.9 (±590) ns]  
today              |  5502.0  [5624.6 (±76) ns]   |  5679.8  [5845.4 (±445) ns]  
=================================================================================

https://bugs.python.org/issue32403