vtcode_commons/
message_timestamp.rs1use chrono::{DateTime, Local};
10
11pub fn format_message_time(now: DateTime<Local>) -> String {
16 now.format("%-I:%M %p").to_string()
17}
18
19pub fn message_timestamp_footer(now: DateTime<Local>) -> String {
24 format!("· {}", format_message_time(now))
25}
26
27pub fn current_message_timestamp_footer() -> String {
29 message_timestamp_footer(Local::now())
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35 use chrono::TimeZone;
36
37 fn local_at(hour: u32, minute: u32) -> DateTime<Local> {
38 Local
39 .with_ymd_and_hms(2026, 11, 2, hour, minute, 0)
40 .single()
41 .expect("fixture timestamp must be unambiguous")
42 }
43
44 #[test]
45 fn formats_afternoon_without_leading_zero() {
46 assert_eq!(format_message_time(local_at(15, 12)), "3:12 PM");
47 }
48
49 #[test]
50 fn formats_single_digit_morning_hour() {
51 assert_eq!(format_message_time(local_at(9, 5)), "9:05 AM");
52 }
53
54 #[test]
55 fn formats_double_digit_morning_hour() {
56 assert_eq!(format_message_time(local_at(11, 55)), "11:55 AM");
57 }
58
59 #[test]
60 fn midnight_is_twelve_am_not_zero() {
61 assert_eq!(format_message_time(local_at(0, 5)), "12:05 AM");
62 }
63
64 #[test]
65 fn noon_is_twelve_pm_not_zero() {
66 assert_eq!(format_message_time(local_at(12, 0)), "12:00 PM");
67 }
68
69 #[test]
70 fn footer_prefixes_time_with_middot() {
71 assert_eq!(message_timestamp_footer(local_at(15, 12)), "· 3:12 PM");
72 }
73
74 #[test]
75 fn current_footer_has_footer_shape() {
76 let footer = current_message_timestamp_footer();
77 let time = footer.strip_prefix("· ").expect("current footer must carry the middot");
78 assert!(time.contains(':'), "current footer must show clock time: {footer:?}");
79 assert!(time.ends_with("AM") || time.ends_with("PM"), "current footer must show meridiem: {footer:?}");
80 }
81}