From 74156a84e4ac8d0a9723602bba3341a8f278123d Mon Sep 17 00:00:00 2001 From: Josh Kaplan Date: Wed, 8 Oct 2025 17:53:52 -0400 Subject: [PATCH] Implement round-ties-to-even for Duration Debug for consistency with f64 --- library/core/src/time.rs | 28 +++++++++++++++++++++++++++- library/coretests/tests/time.rs | 10 +++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/library/core/src/time.rs b/library/core/src/time.rs index f721fcd6156cf..ae8f91392247c 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1318,7 +1318,33 @@ impl fmt::Debug for Duration { // normal floating point numbers. However, we only need to do work // when rounding up. This happens if the first digit of the // remaining ones is >= 5. - let integer_part = if fractional_part > 0 && fractional_part >= divisor * 5 { + let integer_part = if fractional_part > 0 && fractional_part == divisor * 5 { + let last_digit_is_odd = if pos > 0 { + (buf[pos - 1] - b'0') % 2 == 1 + } else { + // No fractional digits - check the integer part + (integer_part % 2) == 1 + }; + + if last_digit_is_odd { + let mut rev_pos = pos; + let mut carry = true; + while carry && rev_pos > 0 { + rev_pos -= 1; + + if buf[rev_pos] < b'9' { + buf[rev_pos] += 1; + carry = false; + } else { + buf[rev_pos] = b'0'; + } + } + + if carry { integer_part.checked_add(1) } else { Some(integer_part) } + } else { + Some(integer_part) + } + } else if fractional_part > 0 && fractional_part > divisor * 5 { // Round up the number contained in the buffer. We go through // the buffer backwards and keep track of the carry. let mut rev_pos = pos; diff --git a/library/coretests/tests/time.rs b/library/coretests/tests/time.rs index fb3c50f9bde98..ff80ff680943f 100644 --- a/library/coretests/tests/time.rs +++ b/library/coretests/tests/time.rs @@ -439,7 +439,6 @@ fn debug_formatting_precision_two() { assert_eq!(format!("{:.2?}", Duration::new(4, 001_000_000)), "4.00s"); assert_eq!(format!("{:.2?}", Duration::new(2, 100_000_000)), "2.10s"); assert_eq!(format!("{:.2?}", Duration::new(2, 104_990_000)), "2.10s"); - assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.11s"); assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s"); } @@ -480,6 +479,15 @@ fn debug_formatting_precision_high() { assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s"); } +#[test] +fn debug_formatting_round_to_even() { + assert_eq!(format!("{:.0?}", Duration::new(1, 500_000_000)), "2s"); + assert_eq!(format!("{:.0?}", Duration::new(2, 500_000_000)), "2s"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_500_000)), "2ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 2_500_000)), "2ms"); + assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.10s"); +} + #[test] fn duration_const() { // test that the methods of `Duration` are usable in a const context