@@ -5,7 +5,10 @@ use std::{env, mem, ptr};
55fn main ( ) {
66 test_clocks ( ) ;
77 test_posix_gettimeofday ( ) ;
8- test_localtime_r ( ) ;
8+ test_localtime_r_gmt ( ) ;
9+ test_localtime_r_pst ( ) ;
10+ test_localtime_r_epoch ( ) ;
11+ test_localtime_r_future ( ) ;
912}
1013
1114/// Tests whether clock support exists at all
@@ -46,14 +49,9 @@ fn test_posix_gettimeofday() {
4649 assert_eq ! ( is_error, -1 ) ;
4750}
4851
49- fn test_localtime_r ( ) {
50- // Set timezone to GMT.
51- let key = "TZ" ;
52- env:: set_var ( key, "GMT" ) ;
53-
54- const TIME_SINCE_EPOCH : libc:: time_t = 1712475836 ;
55- let custom_time_ptr = & TIME_SINCE_EPOCH ;
56- let mut tm = libc:: tm {
52+ // Helper function to create an empty tm struct
53+ fn create_empty_tm ( ) -> libc:: tm {
54+ libc:: tm {
5755 tm_sec : 0 ,
5856 tm_min : 0 ,
5957 tm_hour : 0 ,
@@ -77,7 +75,17 @@ fn test_localtime_r() {
7775 target_os = "android"
7876 ) ) ]
7977 tm_zone : std:: ptr:: null_mut :: < libc:: c_char > ( ) ,
80- } ;
78+ }
79+ }
80+
81+ // Original GMT test
82+ fn test_localtime_r_gmt ( ) {
83+ // Set timezone to GMT.
84+ let key = "TZ" ;
85+ env:: set_var ( key, "GMT" ) ;
86+ const TIME_SINCE_EPOCH : libc:: time_t = 1712475836 ; // 2024-04-07 07:43:56 GMT
87+ let custom_time_ptr = & TIME_SINCE_EPOCH ;
88+ let mut tm = create_empty_tm ( ) ;
8189 let res = unsafe { libc:: localtime_r ( custom_time_ptr, & mut tm) } ;
8290
8391 assert_eq ! ( tm. tm_sec, 56 ) ;
@@ -95,20 +103,127 @@ fn test_localtime_r() {
95103 target_os = "freebsd" ,
96104 target_os = "android"
97105 ) ) ]
98- assert_eq ! ( tm. tm_gmtoff, 0 ) ;
106+ {
107+ assert_eq ! ( tm. tm_gmtoff, 0 ) ;
108+ unsafe {
109+ assert_eq ! ( std:: ffi:: CStr :: from_ptr( tm. tm_zone) . to_str( ) . unwrap( ) , "+00" ) ;
110+ }
111+ }
112+
113+ // The returned value is the pointer passed in.
114+ assert ! ( ptr:: eq( res, & mut tm) ) ;
115+
116+ // Remove timezone setting.
117+ env:: remove_var ( key) ;
118+ }
119+
120+ // PST timezone test (testing different timezone handling)
121+ fn test_localtime_r_pst ( ) {
122+ let key = "TZ" ;
123+ env:: set_var ( key, "PST8PDT" ) ;
124+ const TIME_SINCE_EPOCH : libc:: time_t = 1712475836 ;
125+ let custom_time_ptr = & TIME_SINCE_EPOCH ;
126+ let mut tm = create_empty_tm ( ) ;
127+
128+ let res = unsafe { libc:: localtime_r ( custom_time_ptr, & mut tm) } ;
129+
130+ assert_eq ! ( tm. tm_sec, 56 ) ;
131+ assert_eq ! ( tm. tm_min, 43 ) ;
132+ assert_eq ! ( tm. tm_hour, 0 ) ; // 7 - 7 = 0 (PDT offset)
133+ assert_eq ! ( tm. tm_mday, 7 ) ;
134+ assert_eq ! ( tm. tm_mon, 3 ) ;
135+ assert_eq ! ( tm. tm_year, 124 ) ;
136+ assert_eq ! ( tm. tm_wday, 0 ) ;
137+ assert_eq ! ( tm. tm_yday, 97 ) ;
138+ assert_eq ! ( tm. tm_isdst, -1 ) ; // DST information unavailable
139+
99140 #[ cfg( any(
100141 target_os = "linux" ,
101142 target_os = "macos" ,
102143 target_os = "freebsd" ,
103144 target_os = "android"
104145 ) ) ]
105- unsafe {
106- assert_eq ! ( std:: ffi:: CStr :: from_ptr( tm. tm_zone) . to_str( ) . unwrap( ) , "+00" )
107- } ;
146+ {
147+ assert_eq ! ( tm. tm_gmtoff, -25200 ) ; // -7 hours in seconds
148+ unsafe {
149+ assert_eq ! ( std:: ffi:: CStr :: from_ptr( tm. tm_zone) . to_str( ) . unwrap( ) , "-07" ) ;
150+ }
151+ }
152+
153+ assert ! ( ptr:: eq( res, & mut tm) ) ;
154+ env:: remove_var ( key) ;
155+ }
156+
157+ // Unix epoch test (edge case testing)
158+ fn test_localtime_r_epoch ( ) {
159+ let key = "TZ" ;
160+ env:: set_var ( key, "GMT" ) ;
161+ const TIME_SINCE_EPOCH : libc:: time_t = 0 ; // 1970-01-01 00:00:00
162+ let custom_time_ptr = & TIME_SINCE_EPOCH ;
163+ let mut tm = create_empty_tm ( ) ;
164+
165+ let res = unsafe { libc:: localtime_r ( custom_time_ptr, & mut tm) } ;
166+
167+ assert_eq ! ( tm. tm_sec, 0 ) ;
168+ assert_eq ! ( tm. tm_min, 0 ) ;
169+ assert_eq ! ( tm. tm_hour, 0 ) ;
170+ assert_eq ! ( tm. tm_mday, 1 ) ;
171+ assert_eq ! ( tm. tm_mon, 0 ) ;
172+ assert_eq ! ( tm. tm_year, 70 ) ;
173+ assert_eq ! ( tm. tm_wday, 4 ) ; // Thursday
174+ assert_eq ! ( tm. tm_yday, 0 ) ;
175+ assert_eq ! ( tm. tm_isdst, -1 ) ;
176+
177+ #[ cfg( any(
178+ target_os = "linux" ,
179+ target_os = "macos" ,
180+ target_os = "freebsd" ,
181+ target_os = "android"
182+ ) ) ]
183+ {
184+ assert_eq ! ( tm. tm_gmtoff, 0 ) ;
185+ unsafe {
186+ assert_eq ! ( std:: ffi:: CStr :: from_ptr( tm. tm_zone) . to_str( ) . unwrap( ) , "+00" ) ;
187+ }
188+ }
108189
109- // The returned value is the pointer passed in.
110190 assert ! ( ptr:: eq( res, & mut tm) ) ;
191+ env:: remove_var ( key) ;
192+ }
111193
112- // Remove timezone setting.
194+ // Future date test (testing large values)
195+ fn test_localtime_r_future ( ) {
196+ let key = "TZ" ;
197+ env:: set_var ( key, "GMT" ) ;
198+ const TIME_SINCE_EPOCH : libc:: time_t = 2524608000 ; // 2050-01-01 00:00:00
199+ let custom_time_ptr = & TIME_SINCE_EPOCH ;
200+ let mut tm = create_empty_tm ( ) ;
201+
202+ let res = unsafe { libc:: localtime_r ( custom_time_ptr, & mut tm) } ;
203+
204+ assert_eq ! ( tm. tm_sec, 0 ) ;
205+ assert_eq ! ( tm. tm_min, 0 ) ;
206+ assert_eq ! ( tm. tm_hour, 0 ) ;
207+ assert_eq ! ( tm. tm_mday, 1 ) ;
208+ assert_eq ! ( tm. tm_mon, 0 ) ;
209+ assert_eq ! ( tm. tm_year, 150 ) ;
210+ assert_eq ! ( tm. tm_wday, 6 ) ; // Saturday
211+ assert_eq ! ( tm. tm_yday, 0 ) ;
212+ assert_eq ! ( tm. tm_isdst, -1 ) ;
213+
214+ #[ cfg( any(
215+ target_os = "linux" ,
216+ target_os = "macos" ,
217+ target_os = "freebsd" ,
218+ target_os = "android"
219+ ) ) ]
220+ {
221+ assert_eq ! ( tm. tm_gmtoff, 0 ) ;
222+ unsafe {
223+ assert_eq ! ( std:: ffi:: CStr :: from_ptr( tm. tm_zone) . to_str( ) . unwrap( ) , "+00" ) ;
224+ }
225+ }
226+
227+ assert ! ( ptr:: eq( res, & mut tm) ) ;
113228 env:: remove_var ( key) ;
114229}
0 commit comments