diff --git a/tests/formatting.rs b/tests/formatting.rs index e54a9f618..6cb403b74 100644 --- a/tests/formatting.rs +++ b/tests/formatting.rs @@ -1,4 +1,5 @@ use std::io; +use std::num::NonZeroU8; use time::format_description::well_known::iso8601::{DateKind, OffsetPrecision, TimePrecision}; use time::format_description::well_known::{iso8601, Iso8601, Rfc2822, Rfc3339}; @@ -226,6 +227,26 @@ fn iso_8601() -> time::Result<()> { Ok(()) } +#[test] +fn iso_8601_issue_678() -> time::Result<()> { + macro_rules! assert_format_config { + ($formatted:literal $(, $($config:tt)+)?) => { + assert_eq!( + datetime!(2021-01-02 03:04:05.999_999_999 UTC).format( + &Iso8601::<{ iso8601::Config::DEFAULT$($($config)+)?.encode() }> + )?, + $formatted + ); + }; + } + + assert_format_config!("2021-01-02T03:04:05.999999999Z", .set_time_precision(TimePrecision::Second { decimal_digits: NonZeroU8::new(9) })); + assert_format_config!("2021-01-02T03:04:05.999999Z", .set_time_precision(TimePrecision::Second { decimal_digits: NonZeroU8::new(6) })); + assert_format_config!("2021-01-02T03:04:05.999Z", .set_time_precision(TimePrecision::Second { decimal_digits: NonZeroU8::new(3) })); + + Ok(()) +} + #[test] fn format_time() -> time::Result<()> { let format_output = [ diff --git a/time/src/formatting/mod.rs b/time/src/formatting/mod.rs index b57c15222..f5a6de58e 100644 --- a/time/src/formatting/mod.rs +++ b/time/src/formatting/mod.rs @@ -2,6 +2,7 @@ pub(crate) mod formattable; mod iso8601; + use core::num::NonZeroU8; use std::io; @@ -73,6 +74,10 @@ pub(crate) fn format_float( ) -> io::Result { match digits_after_decimal { Some(digits_after_decimal) => { + // Truncate the decimal points up to the precision + let trunc_num = 10_f64.powi(digits_after_decimal.get().cast_signed().extend()); + let value = f64::trunc(value * trunc_num) / trunc_num; + let digits_after_decimal = digits_after_decimal.get().extend(); let width = digits_before_decimal.extend::() + 1 + digits_after_decimal; write!(output, "{value:0>width$.digits_after_decimal$}")?;