@@ -540,6 +540,14 @@ fn write_row_name(mut out: impl Write, s: &str, prefix_len: usize) -> Result<()>
540540 Ok ( ( ) )
541541}
542542
543+ /// Format a timestamp for human display, without nanoseconds.
544+ ///
545+ /// Nanoseconds are irrelevant noise for container build timestamps;
546+ /// this produces the same format as RFC3339 but truncated to seconds.
547+ fn format_timestamp ( t : & chrono:: DateTime < chrono:: Utc > ) -> impl std:: fmt:: Display {
548+ t. format ( "%Y-%m-%dT%H:%M:%SZ" )
549+ }
550+
543551/// Helper function to render verbose ostree information
544552fn render_verbose_ostree_info (
545553 mut out : impl Write ,
@@ -636,13 +644,7 @@ fn human_render_slot(
636644 writeln ! ( out, "{}" , composefs. verity) ?;
637645 }
638646
639- // Format the timestamp without nanoseconds since those are just irrelevant noise for human
640- // consumption - that time scale should basically never matter for container builds.
641- let timestamp = image
642- . timestamp
643- . as_ref ( )
644- // This format is the same as RFC3339, just without nanos.
645- . map ( |t| t. to_utc ( ) . format ( "%Y-%m-%dT%H:%M:%SZ" ) ) ;
647+ let timestamp = image. timestamp . as_ref ( ) . map ( format_timestamp) ;
646648 // If we have a version, combine with timestamp
647649 if let Some ( version) = image. version . as_deref ( ) {
648650 write_row_name ( & mut out, "Version" , prefix_len) ?;
@@ -939,6 +941,42 @@ pub(crate) fn container_inspect(
939941mod tests {
940942 use super :: * ;
941943
944+ #[ test]
945+ fn test_format_timestamp ( ) {
946+ use chrono:: TimeZone ;
947+ let cases = [
948+ // Standard case
949+ (
950+ chrono:: Utc . with_ymd_and_hms ( 2024 , 8 , 7 , 12 , 0 , 0 ) . unwrap ( ) ,
951+ "2024-08-07T12:00:00Z" ,
952+ ) ,
953+ // Midnight
954+ (
955+ chrono:: Utc . with_ymd_and_hms ( 2023 , 1 , 1 , 0 , 0 , 0 ) . unwrap ( ) ,
956+ "2023-01-01T00:00:00Z" ,
957+ ) ,
958+ // End of day
959+ (
960+ chrono:: Utc
961+ . with_ymd_and_hms ( 2025 , 12 , 31 , 23 , 59 , 59 )
962+ . unwrap ( ) ,
963+ "2025-12-31T23:59:59Z" ,
964+ ) ,
965+ // Subsecond precision should be dropped
966+ (
967+ chrono:: Utc
968+ . with_ymd_and_hms ( 2024 , 6 , 15 , 10 , 30 , 45 )
969+ . unwrap ( )
970+ + chrono:: Duration :: nanoseconds ( 123_456_789 ) ,
971+ "2024-06-15T10:30:45Z" ,
972+ ) ,
973+ ] ;
974+ for ( input, expected) in cases {
975+ let result = format_timestamp ( & input) . to_string ( ) ;
976+ assert_eq ! ( result, expected, "Failed for input {input:?}" ) ;
977+ }
978+ }
979+
942980 fn human_status_from_spec_fixture ( spec_fixture : & str ) -> Result < String > {
943981 let host: Host = serde_yaml:: from_str ( spec_fixture) . unwrap ( ) ;
944982 let mut w = Vec :: new ( ) ;
0 commit comments