Repository navigation
Conversation
Documentation build overview
21 files changed ·
|
Read ASCII names from the current locale without caching them across setlocale calls. Preserve explicitly supplied weekdays in time.strptime, including numeric weekdays and weekdays that disagree with the date. Non-ASCII names and mixed spellings of a field retain the Python parser.
Use the current locale for AM/PM indicators and preserve the default without an indicator. Include the equivalent %k, %l and %P directives. Locales with empty or non-ASCII indicators retain the Python parser.
Allow nonterminal offsets, offset seconds and fractions, and %:z. Preserve fractional offsets for datetime and time objects, and preserve terminal UTC/GMT names and DST metadata for time.strptime. Local timezone names and nonterminal %Z still use the Python parser.
Expand %F, %D, %T and %R through the same field parser without allocating a temporary format string. Include %e and the optional whitespace directives %n and %t.
Calculate dates for %j, %U/%W and %G/%V using the shared Gregorian calendar helpers. Preserve explicit weekdays and time.strptime yday values when a week or ordinal date crosses a year boundary.
Use the same whitespace predicate as Python for %n, %t, and trimming AM/PM indicators. Cover ASCII separators before adjacent numeric fields in the alias formats.
da4922b to
5cc3575
Compare
Common numeric directives were passing through alias and locale-name checks before parsing their digits. Look up equivalent fields directly in the directive table and dispatch once to select the parsing rules. Compute missing weekdays in time.strptime, so the datetime methods avoid work they don't use. Keep weekdays supplied by the input or calculated from ordinal dates intact. Add coverage for mixed directive spellings and inferred weekdays.
|
I reran the public benchmarks for the dispatch revision. Several common formats improved, though the results are noisy and don't establish that all regressions are gone. The repeated ISO-week measurement still shows a slowdown. The parser now selects handlers directly for common numeric formats. In an isolated native probe, it executes 19–21% fewer instructions for For
Six of the twelve common-case comparisons improved significantly versus the previous child revision; the other six didn't differ significantly. The Other entry points and representative formats
‡ These cases use the fallback parser. The ISO-week result is worth calling out: an ABBA repeat measured 143 ns before and 153 ns after, an 8% slowdown. The isolated native parser executes 7.5% fewer instructions and uses about 19% fewer cycles for that format, but that doesn't explain or negate the public result. The common-format run used pyperf with four workers, five values and two warmups; the extended run used three workers, four values and two warmups. Both used the same 32 inputs per format and the C time locale. The first public run had severe variance and was stopped; the replacement run still had substantial variance, so absolute times and small differences shouldn't be treated as precise estimates. The build used GCC 16.2.1 with The compared revisions were upstream The correctness checks passed: 1,358 tests run (137 skipped), 3,840 benchmark smoke results and 96,000 differential comparisons across C, French, German and Japanese locales. I used AI assistance to prepare this benchmark update. |
Separate locale name normalization from matching and AM/PM support checks. Share the month table and leap-year calculation, and document the cases where parsed metadata deliberately differs from the calendar date. Check that representative formats use the C parser through all four public entry points. Add generated comparisons with the Python parser, retaining explicit examples for runs without Hypothesis.
Follows #158253, now merged.
This extends the shared C parser used by
datetime.datetime.strptime,datetime.date.strptime,datetime.time.strptime, andtime.strptime.The format groups are separate commits, ordered by the usage survey:
%b,%B,%a,%A, plus numeric weekdays%wand%u.%Iand%p, plus%k,%l, and%P.%z, offset seconds and fractions,%:z, and terminalUTC/GMTnames with%Z.%F,%D,%T,%R,%e,%n, and%t.%j,%U,%W,%G, and%V.Locale names are read on each call, so there is no cache to invalidate after
setlocale(). Explicit weekdays and timezone names are preserved intime.strptimeresults.Non-ASCII input and name sets, empty AM/PM indicators, locale composites such as
%c, local timezone names, and nonterminal%Zretain the Python parser. Parser mismatches, mixed spellings of a field, and matches requiring backtracking also fall back. The one-argument form oftime.strptimeis unchanged.After rebasing onto upstream main,
test_strptime,test_time, andtest_datetimepass, along with 3,840 benchmark correctness checks. Before this rebase, 96,000 comparisons against the Python parser across C, French, German, and Japanese locales passed, as did the documentation build. Free-threaded debug tests and repeated leak checks passed before the earlier rebase.The benchmarks below were collected before the rebase, comparing
510c6226ec6with071bc0bd031. They have not been rerun against the current base and head. Both builds used GCC 16.2.1 andCFLAGS="-O3 -g -fno-omit-frame-pointer", without PGO or LTO. Each case uses the same 32 inputs for all four APIs. Two runs per revision alternate before/after/after/before, with three worker processes and three measured values per run. The numeric-date and Unicode-fallback rows use longer repeats with six workers, five values, and a 50 ms minimum sample time, after the initial measurements showed substantial variation. Most rows are still short runs; small differences need more measurement.These earlier measurements show speedups for the added formats and overhead for some existing numeric formats. The table includes two of those slower cases; the complete results are below.
—means the difference was not statistically significant, and‡marks cases that still use the Python parser.Selected
datetime.datetime.strptimeresults:%Y-%m-%d%Y-%m-%d %H:%M:%S%b %d, %Y%d %B %Y %H:%M:%S%a, %d %b %Y %H:%M:%S GMT%Y-%m-%d %I:%M:%S %p%Y-%m-%d %H:%M:%S %Z(UTC)%Y-%m-%dT%H:%M:%S%z(+053012.345678)%Y-%m-%d %z %H:%M:%S(+0530)%F%F %T%Y-%j%G-W%V-%u%Y-%W-%wComplete benchmarks for all four entry points
datetime.datetime.strptime%Y-%m-%d%Y%m%d%Y/%m/%d%m/%d/%Y%d/%m/%Y%Y-%m-%d %H:%M:%S%Y-%m-%d %H:%M:%S.%f%Y%m%d%H%M%S%Y-%m-%dT%H:%M:%S%z(UTC)%Y-%m-%dT%H:%M:%SZ%Y-%m-%dT%H:%M:%S.%fZ%Y-%m-%dT%H:%M:%S.%f%z(+0530)%H:%M:%S%H:%M:%S.%f%z(+0530)%d %B %Y %H:%M:%S%b %d, %Y%a, %d %b %Y %H:%M:%S GMT%Y-%m-%d %I:%M:%S %p%Y-%m-%dT%H:%M:%S%z(+053012.345678)%Y-%m-%d %z %H:%M:%S(+0530)%Y-%m-%d %H:%M:%S %Z(UTC)%F%F %T%Y-%j%G-W%V-%u%Y-%W-%w%Y-%m-%d %H:%M:%S+ rotating suffix%d %B %Y %H:%M:%S+ rotating suffix%c‡%Y年%m月%d日‡datetime.date.strptime%Y-%m-%d%Y%m%d%Y/%m/%d%m/%d/%Y%d/%m/%Y%Y-%m-%d %H:%M:%S%Y-%m-%d %H:%M:%S.%f%Y%m%d%H%M%S%Y-%m-%dT%H:%M:%S%z(UTC)%Y-%m-%dT%H:%M:%SZ%Y-%m-%dT%H:%M:%S.%fZ%Y-%m-%dT%H:%M:%S.%f%z(+0530)%H:%M:%S%H:%M:%S.%f%z(+0530)%d %B %Y %H:%M:%S%b %d, %Y%a, %d %b %Y %H:%M:%S GMT%Y-%m-%d %I:%M:%S %p%Y-%m-%dT%H:%M:%S%z(+053012.345678)%Y-%m-%d %z %H:%M:%S(+0530)%Y-%m-%d %H:%M:%S %Z(UTC)%F%F %T%Y-%j%G-W%V-%u%Y-%W-%w%Y-%m-%d %H:%M:%S+ rotating suffix%d %B %Y %H:%M:%S+ rotating suffix%c‡%Y年%m月%d日‡datetime.time.strptime%Y-%m-%d%Y%m%d%Y/%m/%d%m/%d/%Y%d/%m/%Y%Y-%m-%d %H:%M:%S%Y-%m-%d %H:%M:%S.%f%Y%m%d%H%M%S%Y-%m-%dT%H:%M:%S%z(UTC)%Y-%m-%dT%H:%M:%SZ%Y-%m-%dT%H:%M:%S.%fZ%Y-%m-%dT%H:%M:%S.%f%z(+0530)%H:%M:%S%H:%M:%S.%f%z(+0530)%d %B %Y %H:%M:%S%b %d, %Y%a, %d %b %Y %H:%M:%S GMT%Y-%m-%d %I:%M:%S %p%Y-%m-%dT%H:%M:%S%z(+053012.345678)%Y-%m-%d %z %H:%M:%S(+0530)%Y-%m-%d %H:%M:%S %Z(UTC)%F%F %T%Y-%j%G-W%V-%u%Y-%W-%w%Y-%m-%d %H:%M:%S+ rotating suffix%d %B %Y %H:%M:%S+ rotating suffix%c‡%Y年%m月%d日‡time.strptime%Y-%m-%d%Y%m%d%Y/%m/%d%m/%d/%Y%d/%m/%Y%Y-%m-%d %H:%M:%S%Y-%m-%d %H:%M:%S.%f%Y%m%d%H%M%S%Y-%m-%dT%H:%M:%S%z(UTC)%Y-%m-%dT%H:%M:%SZ%Y-%m-%dT%H:%M:%S.%fZ%Y-%m-%dT%H:%M:%S.%f%z(+0530)%H:%M:%S%H:%M:%S.%f%z(+0530)%d %B %Y %H:%M:%S%b %d, %Y%a, %d %b %Y %H:%M:%S GMT%Y-%m-%d %I:%M:%S %p%Y-%m-%dT%H:%M:%S%z(+053012.345678)%Y-%m-%d %z %H:%M:%S(+0530)%Y-%m-%d %H:%M:%S %Z(UTC)%F%F %T%Y-%j%G-W%V-%u%Y-%W-%w%Y-%m-%d %H:%M:%S+ rotating suffix%d %B %Y %H:%M:%S+ rotating suffix%c‡%Y年%m月%d日‡Benchmark reproducer
Build both revisions with the configure options above and
--without-ensurepip, installpyperf==2.9.0into a shared dependency directory, and save the script below asbenchmark.py. For each interpreter:PYTHONPATH=/path/to/deps /path/to/python benchmark.py --smoke PYTHONPATH=/path/to/deps /path/to/python benchmark.py \ --inherit-environ=PYTHONPATH --affinity=2 \ -p 3 -n 3 -w 1 --min-time=0.01 -o run.jsonChoose an available CPU for
--affinity, and use a different output file for each run. The comparison uses two runs per revision in before/after/after/before order.For the longer repeats, add
--case numeric_dateor--case unicode_dateand--method datetime,date,datetime_time, ortime, and replace the timing options with-p 6 -n 5 -w 2 --min-time=0.05.