https://github.com/python/cpython/commit/e0fda794fadb09f08a5d1a04aa6a7e0b42a99666
commit: e0fda794fadb09f08a5d1a04aa6a7e0b42a99666
branch: main
author: Stan Ulbrych <[email protected]>
committer: gpshead <[email protected]>
date: 2025-03-20T20:47:09-07:00
summary:
gh-70647: Raise a more informative error for when date is out of range
(GH-131335)
More informative error messages mean less debugging what went wrong.
files:
A Misc/NEWS.d/next/Library/2025-03-16-18-30-00.gh-issue-70647.1qq2r3.rst
M Lib/_pydatetime.py
M Lib/test/datetimetester.py
M Modules/_datetimemodule.c
diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py
index 26bcd1e491d78c..50e21a12335611 100644
--- a/Lib/_pydatetime.py
+++ b/Lib/_pydatetime.py
@@ -576,7 +576,7 @@ def _check_date_fields(year, month, day):
raise ValueError(f"month must be in 1..12, not {month}")
dim = _days_in_month(year, month)
if not 1 <= day <= dim:
- raise ValueError(f"day must be in 1..{dim}, not {day}")
+ raise ValueError(f"day {day} must be in range 1..{dim} for month
{month} in year {year}")
return year, month, day
def _check_time_fields(hour, minute, second, microsecond, fold):
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index 84eb872f964ba1..f9d20ef9c626a9 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -1988,8 +1988,6 @@ def test_valuerror_messages(self):
r"(year|month|day) must be in \d+\.\.\d+, not \d+"
)
test_cases = [
- (2009, 1, 32), # Day out of range
- (2009, 2, 31), # Day out of range
(2009, 13, 1), # Month out of range
(2009, 0, 1), # Month out of range
(10000, 12, 31), # Year out of range
@@ -2000,6 +1998,11 @@ def test_valuerror_messages(self):
with self.assertRaisesRegex(ValueError, pattern):
self.theclass(*case)
+ # days out of range have their own error message, see issue 70647
+ with self.assertRaises(ValueError) as msg:
+ self.theclass(2009, 1, 32)
+ self.assertIn(f"day 32 must be in range 1..31 for month 1 in year
2009", str(msg.exception))
+
def test_fromisoformat(self):
# Test that isoformat() is reversible
base_dates = [
@@ -3259,7 +3262,6 @@ def test_valuerror_messages(self):
(2009, 4, 1, 12, 30, 90), # Second out of range
(2009, 4, 1, 12, 90, 45), # Minute out of range
(2009, 4, 1, 25, 30, 45), # Hour out of range
- (2009, 4, 32, 24, 0, 0), # Day out of range
(2009, 13, 1, 24, 0, 0), # Month out of range
(9999, 12, 31, 24, 0, 0), # Year out of range
]
@@ -3268,6 +3270,11 @@ def test_valuerror_messages(self):
with self.assertRaisesRegex(ValueError, pattern):
self.theclass(*case)
+ # days out of range have their own error message, see issue 70647
+ with self.assertRaises(ValueError) as msg:
+ self.theclass(2009, 4, 32, 24, 0, 0)
+ self.assertIn(f"day 32 must be in range 1..30 for month 4 in year
2009", str(msg.exception))
+
def test_fromisoformat_datetime(self):
# Test that isoformat() is reversible
base_dates = [
@@ -3575,7 +3582,6 @@ def test_fromisoformat_fails_datetime_valueerror(self):
"2009-04-01T12:30:90", # Second out of range
"2009-04-01T12:90:45", # Minute out of range
"2009-04-01T25:30:45", # Hour out of range
- "2009-04-32T24:00:00", # Day out of range
"2009-13-01T24:00:00", # Month out of range
"9999-12-31T24:00:00", # Year out of range
]
@@ -3585,6 +3591,11 @@ def test_fromisoformat_fails_datetime_valueerror(self):
with self.assertRaisesRegex(ValueError, pattern):
self.theclass.fromisoformat(bad_str)
+ # days out of range have their own error message, see issue 70647
+ with self.assertRaises(ValueError) as msg:
+ self.theclass.fromisoformat("2009-04-32T24:00:00")
+ self.assertIn(f"day 32 must be in range 1..30 for month 4 in year
2009", str(msg.exception))
+
def test_fromisoformat_fails_surrogate(self):
# Test that when fromisoformat() fails with a surrogate character as
# the separator, the error message contains the original string
diff --git
a/Misc/NEWS.d/next/Library/2025-03-16-18-30-00.gh-issue-70647.1qq2r3.rst
b/Misc/NEWS.d/next/Library/2025-03-16-18-30-00.gh-issue-70647.1qq2r3.rst
new file mode 100644
index 00000000000000..33fb244cd563ba
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-03-16-18-30-00.gh-issue-70647.1qq2r3.rst
@@ -0,0 +1,2 @@
+When creating a :mod:`datetime` object with an out of range date a more
informative
+error is raised.
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index 70b59d67f56bda..9bba0e3354b26b 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -664,7 +664,8 @@ check_date_args(int year, int month, int day)
int dim = days_in_month(year, month);
if (day < 1 || day > dim) {
PyErr_Format(PyExc_ValueError,
- "day must be in 1..%d, not %d", dim, day);
+ "day %i must be in range 1..%d for month %i in year %i",
+ day, dim, month, year);
return -1;
}
return 0;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]