diff --git a/babel/dates.py b/babel/dates.py index 69610a7f0..3727b8d19 100644 --- a/babel/dates.py +++ b/babel/dates.py @@ -1646,7 +1646,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_dates.py b/tests/test_dates.py index 12bb23433..b217deab9 100644 --- a/tests/test_dates.py +++ b/tests/test_dates.py @@ -177,6 +177,14 @@ def test_fractional_seconds_zero(self): t = time(15, 30, 0) assert dates.DateTimeFormat(t, locale='en_US')['SSSS'] == '0000' + def test_fractional_seconds_rounding_does_not_overflow_field(self): + t = time(1, 2, 3, 990000) + assert dates.DateTimeFormat(t, locale='en_US')['S'] == '9' + t = time(1, 2, 3, 999500) + assert dates.DateTimeFormat(t, locale='en_US')['SS'] == '99' + t = time(1, 2, 3, 999999) + assert dates.DateTimeFormat(t, locale='en_US')['SSSS'] == '9999' + def test_milliseconds_in_day(self): t = time(15, 30, 12, 345000) assert dates.DateTimeFormat(t, locale='en_US')['AAAA'] == '55812345'