@@ -106,9 +106,15 @@ impl TransactionRecord {
106106 }
107107
108108 /// Get a short version of the tx hash
109+ ///
110+ /// Returns a truncated hash in the format "prefix...suffix".
111+ /// Assumes the hash is an ASCII hex string.
109112 pub fn short_hash ( & self ) -> String {
110- if self . tx_hash . len ( ) > 16 {
111- format ! ( "{}...{}" , & self . tx_hash[ ..8 ] , & self . tx_hash[ self . tx_hash. len( ) -8 ..] )
113+ let chars: Vec < char > = self . tx_hash . chars ( ) . collect ( ) ;
114+ if chars. len ( ) > 16 {
115+ let prefix: String = chars[ ..8 ] . iter ( ) . collect ( ) ;
116+ let suffix: String = chars[ chars. len ( ) -8 ..] . iter ( ) . collect ( ) ;
117+ format ! ( "{}...{}" , prefix, suffix)
112118 } else {
113119 self . tx_hash . clone ( )
114120 }
@@ -137,15 +143,76 @@ impl TransactionRecord {
137143 }
138144
139145 /// Format date for display
146+ ///
147+ /// Returns a human-readable date string in the format "YYYY-MM-DD HH:MM:SS UTC".
140148 pub fn format_date ( & self ) -> String {
141- // Simple date formatting (YYYY-MM-DD HH:MM)
142- use std:: time:: { Duration , UNIX_EPOCH } ;
143- let datetime = UNIX_EPOCH + Duration :: from_secs ( self . timestamp ) ;
144- format ! ( "{:?}" , datetime) // Simplified; in production use chrono
149+ // Convert Unix timestamp to date components
150+ const SECONDS_PER_MINUTE : u64 = 60 ;
151+ const SECONDS_PER_HOUR : u64 = 3600 ;
152+ const SECONDS_PER_DAY : u64 = 86400 ;
153+
154+ let mut remaining = self . timestamp ;
155+
156+ // Calculate days since epoch
157+ let days = remaining / SECONDS_PER_DAY ;
158+ remaining %= SECONDS_PER_DAY ;
159+
160+ // Calculate time components
161+ let hours = remaining / SECONDS_PER_HOUR ;
162+ remaining %= SECONDS_PER_HOUR ;
163+ let minutes = remaining / SECONDS_PER_MINUTE ;
164+ let seconds = remaining % SECONDS_PER_MINUTE ;
165+
166+ // Calculate year, month, day from days since epoch (1970-01-01)
167+ let ( year, month, day) = days_to_ymd ( days) ;
168+
169+ format ! ( "{:04}-{:02}-{:02} {:02}:{:02}:{:02} UTC" , year, month, day, hours, minutes, seconds)
170+ }
171+ }
172+
173+ /// Convert days since epoch to year, month, day
174+ fn days_to_ymd ( days : u64 ) -> ( u64 , u64 , u64 ) {
175+ // Simplified calculation - handles dates from 1970 onwards
176+ let mut remaining_days = days;
177+ let mut year = 1970u64 ;
178+
179+ loop {
180+ let days_in_year = if is_leap_year ( year) { 366 } else { 365 } ;
181+ if remaining_days < days_in_year {
182+ break ;
183+ }
184+ remaining_days -= days_in_year;
185+ year += 1 ;
186+ }
187+
188+ let days_in_months: [ u64 ; 12 ] = if is_leap_year ( year) {
189+ [ 31 , 29 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ]
190+ } else {
191+ [ 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ]
192+ } ;
193+
194+ let mut month = 1u64 ;
195+ for days_in_month in days_in_months. iter ( ) {
196+ if remaining_days < * days_in_month {
197+ break ;
198+ }
199+ remaining_days -= * days_in_month;
200+ month += 1 ;
145201 }
202+
203+ let day = remaining_days + 1 ;
204+ ( year, month, day)
205+ }
206+
207+ /// Check if a year is a leap year
208+ fn is_leap_year ( year : u64 ) -> bool {
209+ ( year % 4 == 0 && year % 100 != 0 ) || ( year % 400 == 0 )
146210}
147211
148212/// Transaction history manager
213+ ///
214+ /// Note: When deserializing, call `rebuild_index()` to ensure
215+ /// the hash index is correctly populated for lookups.
149216#[ derive( Debug , Clone , Default , Serialize , Deserialize ) ]
150217pub struct TransactionHistory {
151218 /// All transactions
@@ -164,6 +231,16 @@ impl TransactionHistory {
164231 }
165232 }
166233
234+ /// Rebuild the hash index after deserialization
235+ ///
236+ /// Call this method after deserializing a TransactionHistory to ensure
237+ /// lookups via get() and get_mut() work correctly.
238+ pub fn ensure_indexed ( & mut self ) {
239+ if self . hash_index . is_empty ( ) && !self . transactions . is_empty ( ) {
240+ self . rebuild_index ( ) ;
241+ }
242+ }
243+
167244 /// Add a transaction to history
168245 pub fn add ( & mut self , record : TransactionRecord ) {
169246 let hash = record. tx_hash . clone ( ) ;
0 commit comments