From dbd44a55f0388b925796479e04694fddc026ec54 Mon Sep 17 00:00:00 2001 From: Vineeth Sai Date: Thu, 27 Aug 2026 10:15:37 -0700 Subject: [PATCH] Clamp rounded fractional seconds to the field width DateTimeFormat rounds the fraction to the requested number of digits, so a microsecond value close enough to a whole second rounds up to a value one digit too wide: time(1, 2, 3, 990000) formatted as 'S' gave '10' rather than '9', and 999999 as 'SSSS' gave '10000'. Clamp the rounded value to the largest the field can hold. Rebased onto current master, where the DateTimeFormat tests were moved out of tests/test_dates.py into tests/test_date_time_format.py and flattened from methods into module-level functions; the regression test follows them. Signed-off-by: Vineeth Sai --- babel/dates.py | 5 ++++- tests/test_date_time_format.py | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/babel/dates.py b/babel/dates.py index 7b626aa11..37c48235e 100644 --- a/babel/dates.py +++ b/babel/dates.py @@ -1638,7 +1638,10 @@ def format_frac_seconds(self, num: int) -> str: of digits passed in. """ value = self.value.microsecond / 1000000 - return self.format(round(value, num) * 10**num, num) + # Rounding can carry the value up to a whole second (for example 0.999 + # rounds to 1.0), which would add a digit; clamp to the field width. + frac = min(int(round(value, num) * 10**num), 10**num - 1) + return self.format(frac, num) def format_milliseconds_in_day(self, num): msecs = ( diff --git a/tests/test_date_time_format.py b/tests/test_date_time_format.py index 5ca620879..a60dc2242 100644 --- a/tests/test_date_time_format.py +++ b/tests/test_date_time_format.py @@ -175,6 +175,15 @@ def test_fractional_seconds(): assert DateTimeFormat(t, locale='en_US')['SSSSS'] == '00080' +def test_fractional_seconds_rounding_does_not_overflow_field(): + t = time(1, 2, 3, 990000) + assert DateTimeFormat(t, locale='en_US')['S'] == '9' + t = time(1, 2, 3, 999500) + assert DateTimeFormat(t, locale='en_US')['SS'] == '99' + t = time(1, 2, 3, 999999) + assert DateTimeFormat(t, locale='en_US')['SSSS'] == '9999' + + def test_fractional_seconds_zero(): t = time(15, 30, 0) assert DateTimeFormat(t, locale='en_US')['SSSS'] == '0000'