@@ -48,6 +48,7 @@ pub mod secp256k1;
4848pub mod securechip;
4949pub mod ui;
5050
51+ use :: util:: c_types:: c_int;
5152use core:: time:: Duration ;
5253
5354pub use bitbox02_sys:: buffer_t;
@@ -116,19 +117,73 @@ pub fn reset(status: bool) {
116117 unsafe { bitbox02_sys:: reset_reset ( status) }
117118}
118119
119- pub fn strftime ( timestamp : u32 , format : & str ) -> String {
120- let mut out = [ 0u8 ; 100 ] ;
121- unsafe {
122- bitbox02_sys:: strftime (
123- out. as_mut_ptr ( ) ,
124- out. len ( ) as _ ,
125- crate :: util:: str_to_cstr_vec ( format) . unwrap ( ) . as_ptr ( ) ,
126- bitbox02_sys:: localtime ( & ( timestamp as bitbox02_sys:: time_t ) ) ,
127- ) ;
120+ pub struct Tm {
121+ tm : bitbox02_sys:: tm ,
122+ }
123+
124+ fn range ( low : c_int , item : c_int , high : c_int ) -> c_int {
125+ core:: cmp:: max ( low, core:: cmp:: min ( item, high) )
126+ }
127+
128+ impl Tm {
129+ /// Returns the weekday, one of "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
130+ pub fn weekday ( & self ) -> String {
131+ // Same as '%a' in strftime:
132+ // https://github.com/arnoldrobbins/strftime/blob/2011b7e82365d25220b8949e252eb5f28c0994cd/strftime.c#435
133+ let wday = self . tm . tm_wday ;
134+ if !( 0 ..=6 ) . contains ( & wday) {
135+ return "?" . into ( ) ;
136+ }
137+ [ "Sun" , "Mon" , "Tue" , "Wed" , "Thu" , "Fri" , "Sat" ] [ wday as usize ] . into ( )
138+ }
139+
140+ /// Returns 'year-month-day', e.g. 2024-07-16, equivalent of '%Y-%m-%d' in strftime.
141+ pub fn date ( & self ) -> String {
142+ // Same as strftime:
143+ // %Y - https://github.com/arnoldrobbins/strftime/blob/2011b7e82365d25220b8949e252eb5f28c0994cd/strftime.c#L712
144+ // %m - https://github.com/arnoldrobbins/strftime/blob/2011b7e82365d25220b8949e252eb5f28c0994cd/strftime.c#L600
145+ // %d - https://github.com/arnoldrobbins/strftime/blob/2011b7e82365d25220b8949e252eb5f28c0994cd/strftime.c#L498
146+ format ! (
147+ "{}-{:02}-{:02}" ,
148+ 1900 + self . tm. tm_year,
149+ range( 0 , self . tm. tm_mon, 11 ) + 1 ,
150+ range( 1 , self . tm. tm_mday, 31 )
151+ )
152+ }
153+
154+ /// Returns the zero-padded hour from 00-23, e.g. "07".
155+ pub fn hour ( & self ) -> String {
156+ // Same as '%H' in strftime:
157+ // https://github.com/arnoldrobbins/strftime/blob/2011b7e82365d25220b8949e252eb5f28c0994cd/strftime.c#582
158+ format ! ( "{:02}" , range( 0 , self . tm. tm_hour, 23 ) )
159+ }
160+
161+ /// Returns the zero-padded minute from 00-59, e.g. "07".
162+ pub fn minute ( & self ) -> String {
163+ // Same as '%M' in strftime:
164+ // https://github.com/arnoldrobbins/strftime/blob/2011b7e82365d25220b8949e252eb5f28c0994cd/strftime.c#L605
165+ format ! ( "{:02}" , range( 0 , self . tm. tm_min, 59 ) )
128166 }
129- crate :: util:: str_from_null_terminated ( & out[ ..] )
130- . unwrap ( )
131- . into ( )
167+
168+ /// Returns the zero-padded second from 00-60, e.g. "07".
169+ pub fn second ( & self ) -> String {
170+ // Same as '%S' in strftime:
171+ // https://github.com/arnoldrobbins/strftime/blob/2011b7e82365d25220b8949e252eb5f28c0994cd/strftime.c#L645
172+ format ! ( "{:02}" , range( 0 , self . tm. tm_sec, 60 ) )
173+ }
174+ }
175+
176+ pub fn get_datetime ( timestamp : u32 ) -> Result < Tm , ( ) > {
177+ Ok ( Tm {
178+ tm : unsafe {
179+ let localtime = bitbox02_sys:: localtime ( & ( timestamp as bitbox02_sys:: time_t ) ) ;
180+ if localtime. is_null ( ) {
181+ return Err ( ( ) ) ;
182+ }
183+
184+ * localtime
185+ } ,
186+ } )
132187}
133188
134189/// Formats the timestamp in the local timezone.
@@ -146,15 +201,19 @@ pub fn format_datetime(
146201 if !( MAX_WEST_UTC_OFFSET ..=MAX_EAST_UTC_OFFSET ) . contains ( & timezone_offset) {
147202 return Err ( ( ) ) ;
148203 }
149-
150- Ok ( strftime (
151- ( ( timestamp as i64 ) + ( timezone_offset as i64 ) ) as u32 ,
152- if date_only {
153- "%a %Y-%m-%d"
154- } else {
155- "%a %Y-%m-%d\n %H:%M"
156- } ,
157- ) )
204+ let ts = ( ( timestamp as i64 ) + ( timezone_offset as i64 ) ) as u32 ;
205+ let tm = get_datetime ( ts) ?;
206+ Ok ( if date_only {
207+ format ! ( "{} {}" , tm. weekday( ) , tm. date( ) )
208+ } else {
209+ format ! (
210+ "{} {}\n {}:{}" ,
211+ tm. weekday( ) ,
212+ tm. date( ) ,
213+ tm. hour( ) ,
214+ tm. minute( )
215+ )
216+ } )
158217}
159218
160219#[ cfg( not( feature = "testing" ) ) ]
@@ -200,14 +259,6 @@ pub fn println_stdout(msg: &str) {
200259mod tests {
201260 use super :: * ;
202261
203- #[ test]
204- fn test_strftime ( ) {
205- assert_eq ! (
206- strftime( 1601281809 , "%a %Y-%m-%d\n %H:%M" ) . as_str( ) ,
207- "Mon 2020-09-28\n 08:30" ,
208- ) ;
209- }
210-
211262 #[ test]
212263 fn test_format_datetime ( ) {
213264 assert_eq ! (
0 commit comments