Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some edge cases in email.utils.parsedate_to_datetime seem to differ from RFC2822 spec #126845

Open
ariebovenberg opened this issue Nov 14, 2024 · 2 comments
Labels
stdlib Python modules in the Lib dir topic-email type-bug An unexpected behavior, bug, or error

Comments

@ariebovenberg
Copy link
Contributor

ariebovenberg commented Nov 14, 2024

Bug report

Bug description:

While tinkering around with email.utils.parsedate_to_datetime, I found some behavior that may be worth adjusting.

1. low-number years aren't handled according to spec:

The year is any numeric year 1900 or later. [section 3.3]

[section 4.3] The syntax for the obsolete date format allows a 2 digit year.
[..]
Where a two or three digit year occurs in a date, the year is to be
interpreted as follows: If a two digit year is encountered whose
value is between 00 and 49, the year is interpreted by adding 2000,
ending up with a value between 2000 and 2049. If a two digit year is
encountered with a value between 50 and 99, or any three digit year
is encountered, the year is interpreted by adding 1900.

>>> parsedate_to_datetime("Sat, 15 Aug 0001 23:12:09 +0500")
datetime.datetime(2001, 8, 15, 23, 12, 9, ...)

expected: either year 1, or a parsing failure. Neither the new or old format interpret 4-digit years this way.

2. offset minutes larger than 59 don't lead to parsing failure

>>> parsedate_to_datetime('Sat, 15 Aug 0001 23:12:09 +0590')
datetime.datetime(2001, 8, 15, 23, 12, 9, tzinfo=datetime.timezone(datetime.timedelta(seconds=23400)))

expected: parse failure. Instead, the "90 minutes" component is parsed without issue (0590 being equal to 0630). The spec is actually not explicit about this, although "A date-time specification MUST be semantically valid". Note that a "90" value as minute in the time component does give the appropriate parsing failure.

Note: datetime.fromisoformat() has the same behavior. Also in this case, I can't determine whether ISO8601 explicitly disallows it. RFC3339 is clear on disallowing this.

3. Invalid day-of-week doesn't lead to parsing failure

>>> parsedate_to_datetime('Sun, 15 Aug 0001 23:12:09 +0520')  # actually a saturday

expected: parsing failure

A date-time specification MUST be semantically valid. That is, the
day-of-the-week (if included) MUST be the day implied by the date,

4. Non-ASCII digits don't lead to parsing failure

If I'm reading the RFC correctly, only ASCII characters are valid.

>>> parsedate_to_datetime('Sat, 15 Aug 01 𝟚𝟛:𝟝𝟛:𝟛𝟛 +0500')  # note the fancy numbers
datetime.datetime(2001, 8, 15, 23, 53, 33, ...)

expected: parsing failure

5. Handling of the -0000 case may be inconsistent with drive to eliminate the practice of "naive UTC" datetimes.

Lately, the datetime module appears to discourage the usage of naive datetimes to mean UTC, as evidenced by the deprecation of utcnow() and other methods.

However, parsedate_to_datetime will return a naive datetime in the -0000 case.

>>> parsedate_to_datetime("Sat, 15 Aug 01 23:53:33 -0000")
datetime.datetime(2001, 8, 15, 23, 53, 33)

expected: tzinfo=UTC

The spec says:

"-0000" also indicates Universal Time, it is
used to indicate that the time was generated on a system that may be
in a local time zone other than Universal Time and therefore
indicates that the date-time contains no information about the local
time zone.

The spec again is a bit fuzzy, but my reading here is that -0000 means "UTC, with no offset known". In contrast, +0000 means "UTC offset known to be 0". My impression would be that only omission of the offset should result in a naive datetime. What do you think?

CPython versions tested on:

3.13

Operating systems tested on:

macOS

edit: typo

@ariebovenberg ariebovenberg added the type-bug An unexpected behavior, bug, or error label Nov 14, 2024
@picnixz picnixz added the extension-modules C modules in the Modules dir label Nov 14, 2024
@picnixz picnixz added stdlib Python modules in the Lib dir and removed extension-modules C modules in the Modules dir labels Nov 14, 2024
@encukou
Copy link
Member

encukou commented Nov 15, 2024

Thanks for the report!

parsedate_to_datetime docs refer to parsedate(), whose docs say:

some mailers don’t follow that format as specified, so parsedate() tries to guess correctly in such cases.

That is, these functions parse but do not validate their input. Full validation is left for a third-party library. (Python could add it, taking a standard as an argument and validating based on that, but I don't think anyone's interested in maintaining it in stdlib.)

With that, IMO:

  1. is a bug, that should be year 1. Do you want to send a PR?
  2. is fine
  3. is fine
  4. is fine
  5. is fine -- the docs cover this case explicitly. (AFAICS, RFC 2822 does not allow omitting the zone, so -0000 is the way to indicate a naive datetime.)

@ariebovenberg
Copy link
Contributor Author

@encukou thanks—sorry I missed that context. I'm happy to submit a PR for the year issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir topic-email type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants