@@ -31,7 +31,10 @@ fn get_timezone_abbreviation(dt: &DateTime<Local>) -> String {
3131 // Try to parse it as a chrono-tz timezone
3232 if let Ok ( tz) = tz_str. parse :: < Tz > ( ) {
3333 // Convert the local datetime to the specified timezone
34- if let Some ( dt_tz) = tz. from_local_datetime ( & dt. naive_local ( ) ) . single ( ) {
34+ // Use earliest() to handle DST transitions consistently
35+ let dt_tz = tz. from_local_datetime ( & dt. naive_local ( ) ) . earliest ( )
36+ . or_else ( || tz. from_local_datetime ( & dt. naive_local ( ) ) . latest ( ) ) ;
37+ if let Some ( dt_tz) = dt_tz {
3538 return dt_tz. format ( "%Z" ) . to_string ( ) ;
3639 }
3740 }
@@ -49,15 +52,69 @@ fn get_timezone_abbreviation(dt: &DateTime<Local>) -> String {
4952}
5053
5154/// Format a datetime string, replacing %Z with proper timezone abbreviation
52- fn format_with_timezone ( formatstr : & str , dt : & DateTime < Local > ) -> String {
55+ fn format_with_timezone_local ( formatstr : & str , dt : & DateTime < Local > ) -> String {
5356 if formatstr. contains ( "%Z" ) {
5457 let tz_abbr = get_timezone_abbreviation ( dt) ;
55- let formatted = dt. format ( formatstr) . to_string ( ) ;
56- // Replace the offset (like +01:00) with the timezone abbreviation
57- // chrono uses %Z for offset, so we need to replace it
58- // The offset format from chrono with %Z is like "+01:00" or "+00:00"
59- let offset_pattern = dt. format ( "%Z" ) . to_string ( ) ;
60- formatted. replace ( & offset_pattern, & tz_abbr)
58+ // Process the format string character by character to handle %Z properly
59+ let mut result = String :: new ( ) ;
60+ let mut chars = formatstr. chars ( ) . peekable ( ) ;
61+
62+ while let Some ( ch) = chars. next ( ) {
63+ if ch == '%' {
64+ if let Some ( & next_ch) = chars. peek ( ) {
65+ if next_ch == '%' {
66+ // %% should become % in the output - let chrono handle this
67+ result. push ( '%' ) ;
68+ result. push ( '%' ) ;
69+ chars. next ( ) ; // consume the second %
70+ continue ;
71+ } else if next_ch == 'Z' {
72+ // Replace %Z with the timezone abbreviation
73+ result. push_str ( & tz_abbr) ;
74+ chars. next ( ) ; // consume 'Z'
75+ continue ;
76+ }
77+ }
78+ }
79+ result. push ( ch) ;
80+ }
81+
82+ // Format the modified format string
83+ dt. format ( & result) . to_string ( )
84+ } else {
85+ dt. format ( formatstr) . to_string ( )
86+ }
87+ }
88+
89+ /// Format a datetime string for UTC, replacing %Z with "UTC"
90+ fn format_with_timezone_utc ( formatstr : & str , dt : & DateTime < Utc > ) -> String {
91+ if formatstr. contains ( "%Z" ) {
92+ // Process the format string character by character to handle %Z properly
93+ let mut result = String :: new ( ) ;
94+ let mut chars = formatstr. chars ( ) . peekable ( ) ;
95+
96+ while let Some ( ch) = chars. next ( ) {
97+ if ch == '%' {
98+ if let Some ( & next_ch) = chars. peek ( ) {
99+ if next_ch == '%' {
100+ // %% should become % in the output - let chrono handle this
101+ result. push ( '%' ) ;
102+ result. push ( '%' ) ;
103+ chars. next ( ) ; // consume the second %
104+ continue ;
105+ } else if next_ch == 'Z' {
106+ // Replace %Z with "UTC"
107+ result. push_str ( "UTC" ) ;
108+ chars. next ( ) ; // consume 'Z'
109+ continue ;
110+ }
111+ }
112+ }
113+ result. push ( ch) ;
114+ }
115+
116+ // Format the modified format string
117+ dt. format ( & result) . to_string ( )
61118 } else {
62119 dt. format ( formatstr) . to_string ( )
63120 }
@@ -86,19 +143,12 @@ struct Args {
86143
87144fn show_time_local ( formatstr : & str ) -> String {
88145 let now = chrono:: Local :: now ( ) ;
89- format_with_timezone ( formatstr, & now)
146+ format_with_timezone_local ( formatstr, & now)
90147}
91148
92149fn show_time_utc ( formatstr : & str ) -> String {
93150 let now = chrono:: Utc :: now ( ) ;
94- // For UTC, %Z should always be "UTC"
95- if formatstr. contains ( "%Z" ) {
96- let formatted = now. format ( formatstr) . to_string ( ) ;
97- let offset_pattern = now. format ( "%Z" ) . to_string ( ) ;
98- formatted. replace ( & offset_pattern, "UTC" )
99- } else {
100- now. format ( formatstr) . to_string ( )
101- }
151+ format_with_timezone_utc ( formatstr, & now)
102152}
103153
104154fn show_time ( utc : bool , formatstr : & str ) {
0 commit comments