Skip to content

Fix decimal comma, Roman numeral year and zh search regressions - #1554

Merged
AdrianAtZyte merged 8 commits into
scrapinghub:masterfrom
AdrianAtZyte:fix-1.5.0-regressions
Nov 4, 2026
Merged

AdrianAtZyte merged 8 commits into
scrapinghub:masterfrom
AdrianAtZyte:fix-1.5.0-regressions

Conversation

@AdrianAtZyte

Copy link
Copy Markdown
Member

No description provided.

@AdrianAtZyte AdrianAtZyte mentioned this pull request Oct 27, 2026
2 tasks done
@codspeed

codspeed Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 10 untouched benchmarks


Comparing AdrianAtZyte:fix-1.5.0-regressions (39bbd7c) with master (2d93cdc)

Open in CodSpeed

@codecov

codecov Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.20%. Comparing base (b1a87f9) to head (39bbd7c).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1554   +/-   ##
=======================================
  Coverage   99.19%   99.20%           
=======================================
  Files         239      239           
  Lines        4098     4137   +39     
=======================================
+ Hits         4065     4104   +39     
  Misses         33       33           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@serhii73

Copy link
Copy Markdown
Collaborator

I reviewed this and ran it against v1.4.3 and current master. I am not approving yet, because one issue should be fixed before 1.5.0.

Blocking: new quadratic time in sanitize_date(). _decimal_comma_to_point() calls re.search(r"\d{4}", match.string, endpos=match.start()) for every hh:mm:ss,dddd match, so each match rescans everything before it. sanitize_date() runs on every parse() input.

sanitize_date("a" * 200000 + " 2021 " + "10:00:00,1234 " * 8000)

This takes 3.6 s on this branch, against 0.016 s on master and 0.013 s on v1.4.3, and the time doubles with the number of matches. It is the same class of problem as the pending security advisories, and 1.4.3 does not have it.

Finding the first run of four digits once avoids it. With the change below the case above takes 0.02 s, the results are unchanged and the full suite passes (25083):

Patch
+RE_FOUR_DIGITS = re.compile(r"\d{4}")
...
-    date_string = RE_SANITIZE_DECIMAL_COMMA.sub(_decimal_comma_to_point, date_string)
+    first_four_digits = RE_FOUR_DIGITS.search(date_string)
+    year_end = first_four_digits.end() if first_four_digits else None
+    date_string = RE_SANITIZE_DECIMAL_COMMA.sub(
+        lambda match: _decimal_comma_to_point(match, year_end), date_string
+    )
...
-def _decimal_comma_to_point(match: re.Match[str]) -> str:
+def _decimal_comma_to_point(match: re.Match[str], year_end: int | None) -> str:
...
-        and not re.search(r"\d{4}", match.string, endpos=match.start())
+        and not (year_end is not None and year_end <= match.start())

Non-blocking differences from current master (not from v1.4.3), in case you want to look:

  • parse("Posted on Jan 5 MMX", settings={"IGNORE_SURROUNDING_TEXT": True}) now returns 2026-01-05 instead of 2010-01-05, with no error. The retry never calls _parse_with_short_roman_year.
  • With _MAX_EXPRESSION_LENGTH = 50, search_dates("and " * 11 + "in 2 days 2020-09-01", languages=["en"]) loses the 2020-09-01 result. 10 repetitions still find it.
  • Thu, 30 May 2024 10:13:10 -0500 CDT (CDT) and strings with three equivalent timezone tokens parse on master but return None now, because only one extra token is popped. They also returned None in 1.4.3.

AdrianAtZyte and others added 4 commits October 30, 2026 09:59
These tests compare the elapsed wall-clock time with 0.5 s or 1.0 s, and two of
them have only about four times of margin on an idle machine (0.26 s and 0.13 s
against limits of 1.0 s and 0.5 s). When the machine is busy, the wall-clock
time grows without any change in the code: one of them took 1.75 s once in a
full-suite run on a loaded machine, and with the CPU oversubscribed four times
17 of 110 executions of these 11 tests failed (9 of 10 for
test_search_dates_long_punctuation_run_between_dates and 8 of 10 for
test_sanitize_date_long_roman_numeral_run).

Use process_time() instead of monotonic(): the same 110 executions under the
same load pass, and on the sources of the main branch, which do not have the
fixes, the same 8 of the 11 tests still fail with 3 to 9 s against the 1.0 s
limit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Russian handling of compound ordinals, such as "двадцать" and "первое", must
not combine two numbers that are written next to each other in a numeric date.
Before the main branch changed it, "20 03 2021" was read as the 23rd of the
current month in 2021 and "30 01 2020" was not parsed at all. They are the 20th
of March 2021 and the 30th of January 2020. Cover that, and that "20 3 мая" is
still combined.

The two numeric dates fail on the sources of the main branch (2021-11-23 and
None) and pass with the changes of this pull request.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@AdrianAtZyte
AdrianAtZyte merged commit 474b15e into scrapinghub:master Nov 4, 2026
19 checks passed
serhii73 added a commit to AdrianAtZyte/dateparser that referenced this pull request Nov 4, 2026
Bring the draft in line with master after "Deprecate instead of remove"
(scrapinghub#1556): what it turned back into deprecations moves from "Breaking changes"
to "Deprecations", and the removal of the public parse() return tuples is
dropped because it no longer happens.

Check every other entry against the code and 1.4.3: replace examples that
behave the same on 1.4.3 or only under explicit languages with ones that
show the change, add the caveats a user would trip over (the ngram strategy
of the date_formats argument, the locales of the Levantine month names, the
default PREFER_MONTH_OF_YEAR for quarters), drop the English label-and-colon
example of scrapinghub#1496 because scrapinghub#1482 undid that change, and add the fixes that had
no entry: the region argument (scrapinghub#1423), Russian numeric dates (scrapinghub#1554) and the
IndexError of search_dates() for zh-Hans, zh-Hant and yue (scrapinghub#1401, scrapinghub#1407).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
serhii73 added a commit that referenced this pull request Nov 4, 2026
* Add release notes for 1.5.0

* Update the 1.5.0 release notes

Bring the draft in line with master after "Deprecate instead of remove"
(#1556): what it turned back into deprecations moves from "Breaking changes"
to "Deprecations", and the removal of the public parse() return tuples is
dropped because it no longer happens.

Check every other entry against the code and 1.4.3: replace examples that
behave the same on 1.4.3 or only under explicit languages with ones that
show the change, add the caveats a user would trip over (the ngram strategy
of the date_formats argument, the locales of the Levantine month names, the
default PREFER_MONTH_OF_YEAR for quarters), drop the English label-and-colon
example of #1496 because #1482 undid that change, and add the fixes that had
no entry: the region argument (#1423), Russian numeric dates (#1554) and the
IndexError of search_dates() for zh-Hans, zh-Hant and yue (#1401, #1407).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Serhii A <24910277+serhii73@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants