@@ -96,6 +96,52 @@ fn print_header() {
9696 ) ;
9797}
9898
99+ /// Format a Unix timestamp (seconds since epoch) as `YYYY-MM-DD HH:MM:SS`
100+ /// using Howard Hinnant's civil_from_days algorithm — no external dependencies.
101+ fn format_unix_secs ( secs : u64 ) -> String {
102+ fn civil_from_days ( z : i64 ) -> ( i32 , u32 , u32 ) {
103+ let z = z + 719_468 ;
104+ let era = if z >= 0 { z } else { z - 146_096 } / 146_097 ;
105+ let doe = ( z - era * 146_097 ) as u64 ;
106+ let yoe = ( doe - doe / 1460 + doe / 36524 - doe / 146_096 ) / 365 ;
107+ let y = yoe as i64 + era * 400 ;
108+ let doy = doe - ( 365 * yoe + yoe / 4 - yoe / 100 ) ;
109+ let mp = ( 5 * doy + 2 ) / 153 ;
110+ let d = doy - ( 153 * mp + 2 ) / 5 + 1 ;
111+ let m = if mp < 10 { mp + 3 } else { mp - 9 } ;
112+ let y = if m <= 2 { y + 1 } else { y } ;
113+ ( y as i32 , m as u32 , d as u32 )
114+ }
115+
116+ let days = ( secs / 86_400 ) as i64 ;
117+ let tod = secs % 86_400 ;
118+ let ( year, month, day) = civil_from_days ( days) ;
119+ format ! (
120+ "{:04}-{:02}-{:02} {:02}:{:02}:{:02}" ,
121+ year,
122+ month,
123+ day,
124+ tod / 3600 ,
125+ ( tod % 3600 ) / 60 ,
126+ tod % 60
127+ )
128+ }
129+
130+ /// Reformat error messages that contain a raw `Time(Time(timestamp))` debug repr,
131+ /// replacing the opaque token with a human-readable UTC datetime.
132+ fn format_session_error ( msg : & str ) -> String {
133+ const PREFIX : & str = "Session expired at Time(Time(" ;
134+ const SUFFIX : & str = "))" ;
135+ if let Some ( rest) = msg. strip_prefix ( PREFIX ) {
136+ if let Some ( num_str) = rest. strip_suffix ( SUFFIX ) {
137+ if let Ok ( secs) = num_str. parse :: < u64 > ( ) {
138+ return format ! ( "Session expired at {} UTC" , format_unix_secs( secs) ) ;
139+ }
140+ }
141+ }
142+ msg. to_string ( )
143+ }
144+
99145enum Role {
100146 Sender ,
101147 Receiver ,
@@ -113,7 +159,7 @@ struct SessionHistoryRow<Status> {
113159 session_id : SessionId ,
114160 role : Role ,
115161 status : Status ,
116- completed_at : Option < u64 > ,
162+ completed_at : Option < String > ,
117163 error_message : Option < String > ,
118164}
119165
@@ -124,13 +170,7 @@ impl<Status: StatusText> fmt::Display for SessionHistoryRow<Status> {
124170 "{:<W_ID$} {:<W_ROLE$} {:<W_DONE$} {:<W_STATUS$}" ,
125171 self . session_id. to_string( ) ,
126172 self . role. as_str( ) ,
127- match self . completed_at {
128- None => "Not Completed" . to_string( ) ,
129- Some ( secs) => {
130- // TODO: human readable time
131- secs. to_string( )
132- }
133- } ,
173+ self . completed_at. as_deref( ) . unwrap_or( "Not Completed" ) ,
134174 self . error_message. as_deref( ) . unwrap_or( self . status. status_text( ) )
135175 )
136176 }
@@ -362,7 +402,7 @@ impl AppTrait for App {
362402 role : Role :: Sender ,
363403 status : SendSession :: Closed ( SenderSessionOutcome :: Failure ) ,
364404 completed_at : None ,
365- error_message : Some ( e. to_string ( ) ) ,
405+ error_message : Some ( format_session_error ( & e. to_string ( ) ) ) ,
366406 } ;
367407 send_rows. push ( row) ;
368408 }
@@ -388,7 +428,7 @@ impl AppTrait for App {
388428 role : Role :: Receiver ,
389429 status : ReceiveSession :: Closed ( ReceiverSessionOutcome :: Failure ) ,
390430 completed_at : None ,
391- error_message : Some ( e. to_string ( ) ) ,
431+ error_message : Some ( format_session_error ( & e. to_string ( ) ) ) ,
392432 } ;
393433 recv_rows. push ( row) ;
394434 }
@@ -415,7 +455,7 @@ impl AppTrait for App {
415455 role : Role :: Sender ,
416456 status : SendSession :: Closed ( SenderSessionOutcome :: Failure ) ,
417457 completed_at : Some ( completed_at) ,
418- error_message : Some ( e. to_string ( ) ) ,
458+ error_message : Some ( format_session_error ( & e. to_string ( ) ) ) ,
419459 } ;
420460 send_rows. push ( row) ;
421461 }
@@ -443,7 +483,7 @@ impl AppTrait for App {
443483 role : Role :: Receiver ,
444484 status : ReceiveSession :: Closed ( ReceiverSessionOutcome :: Failure ) ,
445485 completed_at : Some ( completed_at) ,
446- error_message : Some ( e. to_string ( ) ) ,
486+ error_message : Some ( format_session_error ( & e. to_string ( ) ) ) ,
447487 } ;
448488 recv_rows. push ( row) ;
449489 }
0 commit comments