From ade1e52cc7766114f98045a918ac01234e7998c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E8=B1=86?= Date: Mon, 5 Oct 2026 21:49:06 +0800 Subject: [PATCH] parse_time: handle 12 AM and 12 PM correctly on the 12-hour clock The period handling added a flat +12 offset whenever the input contained pm, which breaks both 12 o'clock cases: >>> parse_time('12:00 PM', locale='en_US') ValueError: hour must be in 0..23, not 24 >>> parse_time('12:30 AM', locale='en_US') datetime.time(12, 30) # midnight parsed as half past noon en_US's own medium time format is 'h:mm:ss a', so parsing noon in the most common locale crashes and midnight silently lands on the wrong side of the day. Convert the 12-hour clock properly: 12 AM is 00:00 and 12 PM is 12:00, only 1-11 AM/PM shift by twelve hours. --- babel/dates.py | 14 +++++++++----- tests/test_dates.py | 6 ++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/babel/dates.py b/babel/dates.py index 7b626aa11..c197df573 100644 --- a/babel/dates.py +++ b/babel/dates.py @@ -1375,14 +1375,18 @@ def parse_time( # TODO: support time zones # Check if the format specifies a period to be used; - # if it does, look for 'pm' to figure out an offset. - hour_offset = 0 - if 'a' in format_str and 'pm' in string.lower(): - hour_offset = 12 + # if it does, convert the hour from the 12-hour clock, on which + # 12 AM and 12 PM are 00:00 and 12:00 respectively. + hour = int(numbers[indexes['H']]) + if 'a' in format_str: + if 'pm' in string.lower(): + if hour != 12: + hour += 12 + elif 'am' in string.lower() and hour == 12: + hour = 0 # Parse up to three numbers from the string. minute = second = 0 - hour = int(numbers[indexes['H']]) + hour_offset if len(numbers) > 1: minute = int(numbers[indexes['M']]) if len(numbers) > 2: diff --git a/tests/test_dates.py b/tests/test_dates.py index 4f8c73907..06a3126c9 100644 --- a/tests/test_dates.py +++ b/tests/test_dates.py @@ -492,6 +492,12 @@ def test_parse_date_custom_format(): ('03:30 PM', time(15, 30)), # test hour-only parsing ('4 pm', time(16, 0)), + # test 12 o'clock am/pm conversion: noon and midnight + ('12:00 pm', time(12, 0)), + ('12:00 PM', time(12, 0)), + ('12:30 am', time(0, 30)), + ('12 AM', time(0, 0)), + ('12:00:15 pm', time(12, 0, 15)), ], ) def test_parse_time(input, expected):