Skip to content

Given a month with 32 days, dateparser fails with some years but parses with others #868

Closed

Description

@Asa-Nisi-Masa

System

Ubuntu 18.04
Python 3.6.9

Description

Compare the following two snippets

from dateparser import parse

# None
parse("32 DEC 95", date_formats=["%d %b %y"])

and

from dateparser import parse

# 2032-12-10 00:00:00
parse("32 DEC 10", date_formats=["%d %b %y"])

In both cases December with 32 days is given. In the first case, suddenly the 32 becomes the year, even though date_formats specifies a different format.

Expected behavior

I would expect both of the parsed dates to be None

Activity

  1. noviluni commented on Jan 19, 2021

    @noviluni
    Contributor

    It seems a bug. I even tried with "DATE_ORDER" but it gives a result too 😮 🤔

    >>> parse("32 DEC 10", date_formats=["%d %b %y"], settings={'DATE_ORDER': 'DMY'})
    datetime.datetime(2032, 12, 10, 0, 0)

    I will check it.

  2. self-assigned this
    on Sep 24, 2026
  3. Alox1d commented on Oct 15, 2026

    @Alox1d

    For the remaining date_formats part, separate from the DATE_ORDER work in #1443, the current source treats supplied formats as attempts rather than an exclusive allowlist: after those attempts fail, get_date_data() continues through the enabled parsers.

    A regression for an exclusive-format contract can restrict that second stage:

    parse(
        "32 DEC 10", date_formats=["%d %b %y"], languages=["en"],
        settings={"PARSERS": ["custom-formats"]},
    )

    The expected result is None; add 32 DEC 95 as the same invalid-day case and 31 DEC 10 / 31 DEC 95 as positive controls. This tests calendar validity without allowing a failed day token to become the year. It also gives the documentation a concrete distinction between preferred formats and permitted formats.

    I maintain DateParser Kotlin; its MIT invalid-calendar regression fixtures illustrate that rejection boundary. They are a source/test reference, not interchangeable Python APIs. I haven't run this example against dateparser.

  4. serhii73 commented on Oct 16, 2026

    @serhii73
    Collaborator

    Thanks again for the review of #1443. This is where I ended up on the date_formats half that we left for this issue (checked on current master, ac088237).

    Where the wrong dates come from. Not from the formats: when no format matches, the string goes on to the other parsers, which read the numbers in a locale's order. That is how parse("32 DEC 10", date_formats=["%d %b %y"]) becomes 2032-12-10, and, without languages, "31 FEB 10" becomes 2031-02-10 (read by sv, which is year-first). The fallback is old and intended (formats first, then everything else), but it was never documented. The docstring change in #1440 now says it.

    What exists today.

    • STRICT_DATE_ORDER with a DATE_ORDER that matches the format: the issue's example gives None with {"DATE_ORDER": "DMY", "STRICT_DATE_ORDER": "year"}, and "all" also stops the day/month swap. It requires DATE_ORDER (it raises without), so it does not help when there is no single order, and date_formats alone is not covered.
    • PARSERS=["custom-formats"] also gives None (for 32 DEC 10 and 32 DEC 95, as @Alox1d suggested in the last comment), but it switches off every other parser: timestamps, relative dates, free-form dates.

    What remains. In a grid of 12 formats and 4,136 strings, 744 of the 2,828 invalid ones (26%) still return a date with date_formats alone.

    Proposal I tried. The idea from the #1443 thread: skip the fallback when the string has the shape of one of the formats (strptime with every digit replaced by 1). It is small (34 lines, no new setting) and returns None for the issue's examples. As a default it is too broad, though. In a differential run of 812,514 calls it only turned dates into None (never a date into another date, no new exceptions), but that is 13% of the dates master returns. Some of those are valid day/month swaps ("12/31/2020" with %d/%m/%Y is 2020-12-31 today), and in my first version plain years and Unix timestamps with digit-only formats too. A narrower rule (not when swapping day and month would parse, never for digit-only strings) removes most of that and keeps nearly all the out-of-range cases.

    Question. Given the opt-in rule from #1443, which would you prefer?

    I can send a PR for (b) or (c). I would keep this issue open until we decide.

  5. Alox1d commented on Oct 17, 2026

    @Alox1d

    Thanks for the detailed check. I'd go with (a) for the docs now and (b) for a behavior change, keeping the current default. The compatibility cases you found, together with the opt-in direction in #1443, make (c) hard to justify.

    For (b), I'd document the exact rejection boundary, including the day/month-swap and digit-only exceptions. The tests should include 32 DEC 10 / 32 DEC 95, their valid 31 DEC counterparts, and automatic language detection as well as explicit languages. Your 31 FEB 10 example shows why the locale fallback matters here.

    A PR with the narrower rule and its remaining counterexamples would make it easier to review. Agreed on keeping this issue open.

  6. serhii73 commented on Oct 19, 2026

    @serhii73
    Collaborator

    The opt-in rule (a STRICT_DATE_FORMATS setting, default unchanged), with the docs, the 32 DEC 10 / 32 DEC 95 / 31 DEC tests and its remaining counterexamples, is in #1547; the docstring text is still #1440.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions