From 7eae3c042a5066893a32636867b9e2c650c65cf8 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Wed, 24 Jun 2026 22:11:40 +0200 Subject: [PATCH 1/3] Fix parse_date and parse_time to raise ParseError instead of ValueError When parse_date or parse_time receives an input string whose numbers produce an out-of-range date or time (e.g. month 13, hour 25), the final datetime.date / datetime.time constructor raises a raw ValueError. Callers that catch ParseError (the documented error type for this module) never see the exception. Wrap both constructors in try/except and re-raise as ParseError with a message that includes the input string and the expected format pattern. Fixes #1178. --- babel/dates.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/babel/dates.py b/babel/dates.py index a5e2dd996..c8b888a9b 100644 --- a/babel/dates.py +++ b/babel/dates.py @@ -1423,7 +1423,10 @@ def parse_date( day = int(numbers[indexes['D']]) if month > 12: month, day = day, month - return datetime.date(year, month, day) + try: + return datetime.date(year, month, day) + except ValueError as e: + raise ParseError(f"String '{string}' does not match format '{fmt.pattern}' ({e})") from None def parse_time( @@ -1492,7 +1495,10 @@ def parse_time( minute = int(numbers[indexes['M']]) if len(numbers) > 2: second = int(numbers[indexes['S']]) - return datetime.time(hour, minute, second) + try: + return datetime.time(hour, minute, second) + except ValueError as e: + raise ParseError(f"String '{string}' does not match format '{fmt.pattern}' ({e})") from None class DateTimePattern: From af9656f008c2e6dbf7790e0520b32ecfd03228fe Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Fri, 31 Jul 2026 21:06:35 +0200 Subject: [PATCH 2/3] Address review: chain ValueError, reword message, add out-of-range tests --- babel/dates.py | 8 ++++++-- tests/test_dates.py | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/babel/dates.py b/babel/dates.py index c8b888a9b..6c251a7f7 100644 --- a/babel/dates.py +++ b/babel/dates.py @@ -1426,7 +1426,9 @@ def parse_date( try: return datetime.date(year, month, day) except ValueError as e: - raise ParseError(f"String '{string}' does not match format '{fmt.pattern}' ({e})") from None + raise ParseError( + f"'{string}' does not represent a valid date for format '{fmt.pattern}'" + ) from e def parse_time( @@ -1498,7 +1500,9 @@ def parse_time( try: return datetime.time(hour, minute, second) except ValueError as e: - raise ParseError(f"String '{string}' does not match format '{fmt.pattern}' ({e})") from None + raise ParseError( + f"'{string}' does not represent a valid time for format '{fmt.pattern}'" + ) from e class DateTimePattern: diff --git a/tests/test_dates.py b/tests/test_dates.py index 08e367c66..c75a3e16e 100644 --- a/tests/test_dates.py +++ b/tests/test_dates.py @@ -741,6 +741,20 @@ def test_parse_errors(case, func): func(case, locale='en_US') +def test_parse_date_out_of_range(): + with pytest.raises(dates.ParseError) as excinfo: + dates.parse_date('2005-02-30', format='yyyy-MM-dd') + assert 'does not represent a valid date' in str(excinfo.value) + assert isinstance(excinfo.value.__cause__, ValueError) + + +def test_parse_time_out_of_range(): + with pytest.raises(dates.ParseError) as excinfo: + dates.parse_time('25:00', format='HH:mm') + assert 'does not represent a valid time' in str(excinfo.value) + assert isinstance(excinfo.value.__cause__, ValueError) + + def test_datetime_format_get_week_number(): format = dates.DateTimeFormat(date(2006, 1, 8), Locale.parse('de_DE')) assert format.get_week_number(6) == 1 From 54a67f38c49488313f465b8bcf94df8b11326cba Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 4 Nov 2026 11:12:16 +0200 Subject: [PATCH 3/3] Fix lint --- babel/dates.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/babel/dates.py b/babel/dates.py index 6c251a7f7..c6d5a9e85 100644 --- a/babel/dates.py +++ b/babel/dates.py @@ -1427,7 +1427,7 @@ def parse_date( return datetime.date(year, month, day) except ValueError as e: raise ParseError( - f"'{string}' does not represent a valid date for format '{fmt.pattern}'" + f"'{string}' does not represent a valid date for format '{fmt.pattern}'", ) from e @@ -1501,7 +1501,7 @@ def parse_time( return datetime.time(hour, minute, second) except ValueError as e: raise ParseError( - f"'{string}' does not represent a valid time for format '{fmt.pattern}'" + f"'{string}' does not represent a valid time for format '{fmt.pattern}'", ) from e