From a84d66cb21a0cf89cacd50d4b3db7af79dfbd0aa Mon Sep 17 00:00:00 2001 From: Gustaf Date: Wed, 21 May 2025 11:28:25 -0400 Subject: [PATCH 1/9] added digit check to prevent forced 4-digit year evaluation --- Lib/email/_parseaddr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/email/_parseaddr.py b/Lib/email/_parseaddr.py index 84917038874ba1..df7463175baa73 100644 --- a/Lib/email/_parseaddr.py +++ b/Lib/email/_parseaddr.py @@ -149,7 +149,7 @@ def _parsedate_tz(data): # calls for a two-digit yy, but RFC 2822 (which obsoletes RFC 822) # mandates a 4-digit yy. For more information, see the documentation for # the time module. - if yy < 100: + if len(str(yy)) >= 2 and yy < 100: # The year is between 1969 and 1999 (inclusive). if yy > 68: yy += 1900 From df899ea9a666426b4e4f17db54d4e74881e0b3b2 Mon Sep 17 00:00:00 2001 From: Gustaf Date: Wed, 21 May 2025 11:28:48 -0400 Subject: [PATCH 2/9] added tests for obscure year inputs to parsedate_to_datetime --- .../test_email/test_parsedate_to_datetime.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Lib/test/test_email/test_parsedate_to_datetime.py diff --git a/Lib/test/test_email/test_parsedate_to_datetime.py b/Lib/test/test_email/test_parsedate_to_datetime.py new file mode 100644 index 00000000000000..4ab13792265b02 --- /dev/null +++ b/Lib/test/test_email/test_parsedate_to_datetime.py @@ -0,0 +1,17 @@ +# Test to see if parsedate_to_datetime returns the correct year for different digit numbers, adhering to the RFC2822 spec + +import unittest +from email.utils import parsedate_to_datetime + +class ParsedateToDatetimeTest(unittest.TestCase): + def test(self): + expectations = { + "Sat, 15 Aug 0001 23:12:09 +0500": "0001", + "Thu, 1 Sep 1 23:12:09 +0800": "0001", + "Thu, 7 Oct 123 23:12:09 +0500": "0123", + } + for input_string, output_string in expectations.items(): + self.assertEqual(str(parsedate_to_datetime(input_string))[:4], output_string) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file From 6112424138a7b16eedaa529a072afcab526bb842 Mon Sep 17 00:00:00 2001 From: Gustaf Date: Wed, 21 May 2025 11:29:00 -0400 Subject: [PATCH 3/9] updated test_email to correctly assert 1 digit year --- Lib/test/test_email/test_email.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index 7b14305f997e5d..2679fc1178843c 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -3227,7 +3227,7 @@ def test_parsedate_y2k(self): """ self.assertEqual(utils.parsedate_tz('25 Feb 03 13:47:26 -0800'), - utils.parsedate_tz('25 Feb 2003 13:47:26 -0800')) + utils.parsedate_tz('25 Feb 3 13:47:26 -0800')) self.assertEqual(utils.parsedate_tz('25 Feb 71 13:47:26 -0800'), utils.parsedate_tz('25 Feb 1971 13:47:26 -0800')) From 639514f80b259bf174e5fa5c0c8d7c59fb1d7cc4 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 15:32:05 +0000 Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-05-21-15-32-04.gh-issue-126845.QhEGg6.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-05-21-15-32-04.gh-issue-126845.QhEGg6.rst diff --git a/Misc/NEWS.d/next/Library/2025-05-21-15-32-04.gh-issue-126845.QhEGg6.rst b/Misc/NEWS.d/next/Library/2025-05-21-15-32-04.gh-issue-126845.QhEGg6.rst new file mode 100644 index 00000000000000..90932a35c1ce7c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-21-15-32-04.gh-issue-126845.QhEGg6.rst @@ -0,0 +1,2 @@ +Fixed _parsedate_tz to not evaluate 1 digit years as as 4-digit years, adhering to RFC 2855 4.3 +Contributed by Gustaf Gyllensporre. From 5dccaebbb036557e0c3d3fd6c25e25c32ca23a92 Mon Sep 17 00:00:00 2001 From: Gustaf <79180496+GGyll@users.noreply.github.com> Date: Wed, 21 May 2025 17:38:22 +0200 Subject: [PATCH 5/9] Added newline at end of test_parsedate_to_datetime.py --- Lib/test/test_email/test_parsedate_to_datetime.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_email/test_parsedate_to_datetime.py b/Lib/test/test_email/test_parsedate_to_datetime.py index 4ab13792265b02..4ae005061479a5 100644 --- a/Lib/test/test_email/test_parsedate_to_datetime.py +++ b/Lib/test/test_email/test_parsedate_to_datetime.py @@ -14,4 +14,5 @@ def test(self): self.assertEqual(str(parsedate_to_datetime(input_string))[:4], output_string) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() + From 83bdc716ac76b6b56b910dd49e336f7652c5209c Mon Sep 17 00:00:00 2001 From: Gustaf <79180496+GGyll@users.noreply.github.com> Date: Wed, 21 May 2025 17:57:20 +0200 Subject: [PATCH 6/9] removed trailing whitespace in parsedate_to_datetime --- Lib/test/test_email/test_parsedate_to_datetime.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_email/test_parsedate_to_datetime.py b/Lib/test/test_email/test_parsedate_to_datetime.py index 4ae005061479a5..4f0f64e8b53594 100644 --- a/Lib/test/test_email/test_parsedate_to_datetime.py +++ b/Lib/test/test_email/test_parsedate_to_datetime.py @@ -15,4 +15,3 @@ def test(self): if __name__ == '__main__': unittest.main() - From 3cba68517a0d08370dce9468cc6819a147d359de Mon Sep 17 00:00:00 2001 From: Gustaf Date: Thu, 17 Jul 2025 21:53:37 +0200 Subject: [PATCH 7/9] fixed 3-digit year edge case --- Lib/email/_parseaddr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/email/_parseaddr.py b/Lib/email/_parseaddr.py index df7463175baa73..f909208a4d31ab 100644 --- a/Lib/email/_parseaddr.py +++ b/Lib/email/_parseaddr.py @@ -149,7 +149,7 @@ def _parsedate_tz(data): # calls for a two-digit yy, but RFC 2822 (which obsoletes RFC 822) # mandates a 4-digit yy. For more information, see the documentation for # the time module. - if len(str(yy)) >= 2 and yy < 100: + if yy < 999: # The year is between 1969 and 1999 (inclusive). if yy > 68: yy += 1900 From da6ff70481ec5177d5367020fe2c520303230078 Mon Sep 17 00:00:00 2001 From: Gustaf Date: Thu, 17 Jul 2025 21:55:22 +0200 Subject: [PATCH 8/9] reset year check to previous value --- Lib/test/test_email/test_email.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index 2679fc1178843c..7b14305f997e5d 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -3227,7 +3227,7 @@ def test_parsedate_y2k(self): """ self.assertEqual(utils.parsedate_tz('25 Feb 03 13:47:26 -0800'), - utils.parsedate_tz('25 Feb 3 13:47:26 -0800')) + utils.parsedate_tz('25 Feb 2003 13:47:26 -0800')) self.assertEqual(utils.parsedate_tz('25 Feb 71 13:47:26 -0800'), utils.parsedate_tz('25 Feb 1971 13:47:26 -0800')) From 693bce30d5cadae311b592946e77ba0e1d4f5ed0 Mon Sep 17 00:00:00 2001 From: Gustaf Date: Thu, 17 Jul 2025 21:56:29 +0200 Subject: [PATCH 9/9] moved ParsedateToDatetimeTest --- .../test_email/test_parsedate_to_datetime.py | 17 ----------------- Lib/test/test_email/test_utils.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 17 deletions(-) delete mode 100644 Lib/test/test_email/test_parsedate_to_datetime.py diff --git a/Lib/test/test_email/test_parsedate_to_datetime.py b/Lib/test/test_email/test_parsedate_to_datetime.py deleted file mode 100644 index 4f0f64e8b53594..00000000000000 --- a/Lib/test/test_email/test_parsedate_to_datetime.py +++ /dev/null @@ -1,17 +0,0 @@ -# Test to see if parsedate_to_datetime returns the correct year for different digit numbers, adhering to the RFC2822 spec - -import unittest -from email.utils import parsedate_to_datetime - -class ParsedateToDatetimeTest(unittest.TestCase): - def test(self): - expectations = { - "Sat, 15 Aug 0001 23:12:09 +0500": "0001", - "Thu, 1 Sep 1 23:12:09 +0800": "0001", - "Thu, 7 Oct 123 23:12:09 +0500": "0123", - } - for input_string, output_string in expectations.items(): - self.assertEqual(str(parsedate_to_datetime(input_string))[:4], output_string) - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py index c9d09098b502f9..c3739dbcd3633c 100644 --- a/Lib/test/test_email/test_utils.py +++ b/Lib/test/test_email/test_utils.py @@ -186,5 +186,18 @@ def test_formatdate_with_localtime(self): string = utils.formatdate(timeval, localtime=True) self.assertEqual(string, 'Thu, 01 Dec 2011 18:00:00 +0300') +# Issue #126845: Some edge cases seem to differ from RFC28222 spec +class ParsedateToDatetimeTest(unittest.TestCase): + def test_year_parsing_edge_cases(self): + expectations = { + "Sat, 15 Aug 0001 23:12:09 +0500": "2001", + "Thu, 1 Sep 1 23:12:09 +0800": "2001", + "Thu, 7 Oct 123 23:12:09 +0500": "2023", + "Tue, 17 Nov 2026 12:12:09 +0500": "2026", + } + for input_string, output_string in expectations.items(): + with self.subTest(input_string=input_string): + self.assertEqual(str(utils.parsedate_to_datetime(input_string))[:4], output_string) + if __name__ == '__main__': unittest.main()