Skip to content

Commit 05a798d

Browse files
committed
status: Extract format_timestamp helper
Deduplicate the timestamp formatting code used in human-readable status output. The format string was inlined with a multi-line comment explaining it; extract it into a named function. Assisted-by: OpenCode (Claude claude-opus-4-6) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent fb37239 commit 05a798d

1 file changed

Lines changed: 45 additions & 7 deletions

File tree

crates/lib/src/status.rs

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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
544552
fn 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(
939941
mod 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

Comments
 (0)