msvcrt: Keep FILE critical section initialized after closing file.
[wine] / dlls / msvcrt / tests / time.c
1 /*
2  * Unit test suite for time functions.
3  *
4  * Copyright 2004 Uwe Bonnes
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "wine/test.h"
22 #include "winbase.h"
23 #include "winnls.h"
24 #include "time.h"
25
26 #include <stdlib.h> /*setenv*/
27 #include <stdio.h> /*printf*/
28 #include <errno.h>
29
30 #define _MAX__TIME64_T     (((__time64_t)0x00000007 << 32) | 0x93406FFF)
31
32 #define SECSPERDAY         86400
33 #define SECSPERHOUR        3600
34 #define SECSPERMIN         60
35 #define MINSPERHOUR        60
36 #define HOURSPERDAY        24
37
38 static __time32_t (__cdecl *p_mkgmtime32)(struct tm*);
39 static struct tm* (__cdecl *p_gmtime32)(__time32_t*);
40 static errno_t    (__cdecl *p_gmtime32_s)(struct tm*, __time32_t*);
41 static errno_t    (__cdecl *p_strtime_s)(char*,size_t);
42 static errno_t    (__cdecl *p_strdate_s)(char*,size_t);
43 static errno_t    (__cdecl *p_localtime32_s)(struct tm*, __time32_t*);
44 static errno_t    (__cdecl *p_localtime64_s)(struct tm*, __time64_t*);
45 static int*       (__cdecl *p__daylight)(void);
46 static int*       (__cdecl *p___p__daylight)(void);
47
48 static void init(void)
49 {
50     HMODULE hmod = GetModuleHandleA("msvcrt.dll");
51
52     p_gmtime32 = (void*)GetProcAddress(hmod, "_gmtime32");
53     p_gmtime32_s = (void*)GetProcAddress(hmod, "_gmtime32_s");
54     p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32");
55     p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s");
56     p_strdate_s = (void*)GetProcAddress(hmod, "_strdate_s");
57     p_localtime32_s = (void*)GetProcAddress(hmod, "_localtime32_s");
58     p_localtime64_s = (void*)GetProcAddress(hmod, "_localtime64_s");
59     p__daylight = (void*)GetProcAddress(hmod, "__daylight");
60     p___p__daylight = (void*)GetProcAddress(hmod, "__p__daylight");
61 }
62
63 static int get_test_year(time_t *start)
64 {
65     time_t now = time(NULL);
66     struct tm *tm = localtime(&now);
67
68     /* compute start of year in seconds */
69     *start = SECSPERDAY * ((tm->tm_year - 70) * 365 +
70                            (tm->tm_year - 69) / 4 -
71                            (tm->tm_year - 1) / 100 +
72                            (tm->tm_year + 299) / 400);
73     return tm->tm_year;
74 }
75
76 static void test_ctime(void)
77 {
78     time_t badtime = -1;
79     char* ret;
80     ret = ctime(&badtime);
81     ok(ret == NULL, "expected ctime to return NULL, got %s\n", ret);
82 }
83 static void test_gmtime(void)
84 {
85     __time32_t valid, gmt;
86     struct tm* gmt_tm, gmt_tm_s;
87     errno_t err;
88
89     if(!p_gmtime32) {
90         win_skip("Skipping _gmtime32 tests\n");
91         return;
92     }
93
94     gmt_tm = p_gmtime32(NULL);
95     ok(gmt_tm == NULL, "gmt_tm != NULL\n");
96
97     gmt = -1;
98     gmt_tm = p_gmtime32(&gmt);
99     ok(gmt_tm == NULL, "gmt_tm != NULL\n");
100
101     gmt = valid = 0;
102     gmt_tm = p_gmtime32(&gmt);
103     if(!gmt_tm) {
104         ok(0, "_gmtime32() failed\n");
105         return;
106     }
107
108     ok(((gmt_tm->tm_year == 70) && (gmt_tm->tm_mon  == 0) && (gmt_tm->tm_yday  == 0) &&
109                 (gmt_tm->tm_mday ==  1) && (gmt_tm->tm_wday == 4) && (gmt_tm->tm_hour  == 0) &&
110                 (gmt_tm->tm_min  ==  0) && (gmt_tm->tm_sec  == 0) && (gmt_tm->tm_isdst == 0)),
111             "Wrong date:Year %4d mon %2d yday %3d mday %2d wday %1d hour%2d min %2d sec %2d dst %2d\n",
112             gmt_tm->tm_year, gmt_tm->tm_mon, gmt_tm->tm_yday, gmt_tm->tm_mday, gmt_tm->tm_wday,
113             gmt_tm->tm_hour, gmt_tm->tm_min, gmt_tm->tm_sec, gmt_tm->tm_isdst);
114
115     if(!p_mkgmtime32) {
116         win_skip("Skipping _mkgmtime32 tests\n");
117         return;
118     }
119
120     gmt_tm->tm_wday = gmt_tm->tm_yday = 0;
121     gmt = p_mkgmtime32(gmt_tm);
122     ok(gmt == valid, "gmt = %u\n", gmt);
123     ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday);
124     ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday);
125
126     gmt_tm->tm_wday = gmt_tm->tm_yday = 0;
127     gmt_tm->tm_isdst = -1;
128     gmt = p_mkgmtime32(gmt_tm);
129     ok(gmt == valid, "gmt = %u\n", gmt);
130     ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday);
131     ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday);
132
133     gmt_tm->tm_wday = gmt_tm->tm_yday = 0;
134     gmt_tm->tm_isdst = 1;
135     gmt = p_mkgmtime32(gmt_tm);
136     ok(gmt == valid, "gmt = %u\n", gmt);
137     ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday);
138     ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday);
139
140     gmt = valid = 173921;
141     gmt_tm = p_gmtime32(&gmt);
142     if(!gmt_tm) {
143         ok(0, "_gmtime32() failed\n");
144         return;
145     }
146
147     gmt_tm->tm_isdst = -1;
148     gmt = p_mkgmtime32(gmt_tm);
149     ok(gmt == valid, "gmt = %u\n", gmt);
150     ok(gmt_tm->tm_wday == 6, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday);
151     ok(gmt_tm->tm_yday == 2, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday);
152
153     gmt_tm->tm_isdst = 1;
154     gmt = p_mkgmtime32(gmt_tm);
155     ok(gmt == valid, "gmt = %u\n", gmt);
156
157     if(!p_gmtime32_s) {
158         win_skip("Skipping _gmtime32_s tests\n");
159         return;
160     }
161
162     errno = 0;
163     gmt = 0;
164     err = p_gmtime32_s(NULL, &gmt);
165     ok(err == EINVAL, "err = %d\n", err);
166     ok(errno == EINVAL, "errno = %d\n", errno);
167
168     errno = 0;
169     gmt = -1;
170     err = p_gmtime32_s(&gmt_tm_s, &gmt);
171     ok(err == EINVAL, "err = %d\n", err);
172     ok(errno == EINVAL, "errno = %d\n", errno);
173     ok(gmt_tm_s.tm_year == -1, "tm_year = %d\n", gmt_tm_s.tm_year);
174 }
175
176 static void test_mktime(void)
177 {
178     TIME_ZONE_INFORMATION tzinfo;
179     DWORD res =  GetTimeZoneInformation(&tzinfo);
180     struct tm my_tm, sav_tm;
181     time_t nulltime, local_time;
182     char TZ_env[256];
183     char buffer[64];
184     int year;
185     time_t ref, secs;
186
187     year = get_test_year( &ref );
188     ref += SECSPERDAY;
189
190     ok (res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
191     WideCharToMultiByte( CP_ACP, 0, tzinfo.StandardName, -1, buffer, sizeof(buffer), NULL, NULL );
192     trace( "bias %d std %d dst %d zone %s\n",
193            tzinfo.Bias, tzinfo.StandardBias, tzinfo.DaylightBias, buffer );
194     /* Bias may be positive or negative, to use offset of one day */
195     my_tm = *localtime(&ref);  /* retrieve current dst flag */
196     secs = SECSPERDAY - tzinfo.Bias * SECSPERMIN;
197     secs -= (my_tm.tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN;
198     my_tm.tm_mday = 1 + secs/SECSPERDAY;
199     secs = secs % SECSPERDAY;
200     my_tm.tm_hour = secs / SECSPERHOUR;
201     secs = secs % SECSPERHOUR;
202     my_tm.tm_min = secs / SECSPERMIN;
203     secs = secs % SECSPERMIN;
204     my_tm.tm_sec = secs;
205
206     my_tm.tm_year = year;
207     my_tm.tm_mon  =  0;
208
209     sav_tm = my_tm;
210
211     local_time = mktime(&my_tm);
212     ok(local_time == ref, "mktime returned %u, expected %u\n",
213        (DWORD)local_time, (DWORD)ref);
214     /* now test some unnormalized struct tm's */
215     my_tm = sav_tm;
216     my_tm.tm_sec += 60;
217     my_tm.tm_min -= 1;
218     local_time = mktime(&my_tm);
219     ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n",
220         (DWORD)local_time, (DWORD)ref);
221     ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
222         my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
223         my_tm.tm_sec == sav_tm.tm_sec,
224             "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n",
225             my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
226             my_tm.tm_hour,my_tm.tm_sec,
227             sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
228             sav_tm.tm_hour,sav_tm.tm_sec);
229     my_tm = sav_tm;
230     my_tm.tm_min -= 60;
231     my_tm.tm_hour += 1;
232     local_time = mktime(&my_tm);
233     ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n",
234        (DWORD)local_time, (DWORD)ref);
235     ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
236         my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
237         my_tm.tm_sec == sav_tm.tm_sec,
238             "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n",
239             my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
240             my_tm.tm_hour,my_tm.tm_sec,
241             sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
242             sav_tm.tm_hour,sav_tm.tm_sec);
243     my_tm = sav_tm;
244     my_tm.tm_mon -= 12;
245     my_tm.tm_year += 1;
246     local_time = mktime(&my_tm);
247     ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n",
248        (DWORD)local_time, (DWORD)ref);
249     ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
250         my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
251         my_tm.tm_sec == sav_tm.tm_sec,
252             "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n",
253             my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
254             my_tm.tm_hour,my_tm.tm_sec,
255             sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
256             sav_tm.tm_hour,sav_tm.tm_sec);
257     my_tm = sav_tm;
258     my_tm.tm_mon += 12;
259     my_tm.tm_year -= 1;
260     local_time = mktime(&my_tm);
261     ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n",
262        (DWORD)local_time, (DWORD)ref);
263     ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
264         my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
265         my_tm.tm_sec == sav_tm.tm_sec,
266             "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n",
267             my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
268             my_tm.tm_hour,my_tm.tm_sec,
269             sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
270             sav_tm.tm_hour,sav_tm.tm_sec);
271     /* now a bad time example */
272     my_tm = sav_tm;
273     my_tm.tm_year = 69;
274     local_time = mktime(&my_tm);
275     ok((local_time == -1), "(bad time) mktime returned %d, expected -1\n", (int)local_time);
276
277     my_tm = sav_tm;
278     /* TEST that we are independent from the TZ variable */
279     /*Argh, msvcrt doesn't have setenv() */
280     _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):""));
281     putenv("TZ=GMT");
282     nulltime = mktime(&my_tm);
283     ok(nulltime == ref,"mktime returned 0x%08x\n",(DWORD)nulltime);
284     putenv(TZ_env);
285 }
286
287 static void test_localtime(void)
288 {
289     TIME_ZONE_INFORMATION tzinfo;
290     DWORD res =  GetTimeZoneInformation(&tzinfo);
291     time_t gmt, ref;
292
293     char TZ_env[256];
294     struct tm* lt;
295     int year = get_test_year( &ref );
296     int is_leap = !(year % 4) && ((year % 100) || !((year + 300) % 400));
297
298     gmt = ref + SECSPERDAY + tzinfo.Bias * SECSPERMIN;
299     ok (res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
300     lt = localtime(&gmt);
301     gmt += (lt->tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN;
302     lt = localtime(&gmt);
303     ok(((lt->tm_year == year) && (lt->tm_mon  == 0) && (lt->tm_yday  == 1) &&
304         (lt->tm_mday ==  2) && (lt->tm_hour  == 0) &&
305         (lt->tm_min  ==  0) && (lt->tm_sec  == 0)),
306        "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n",
307        lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, 
308        lt->tm_min, lt->tm_sec, lt->tm_isdst); 
309
310     _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):""));
311     putenv("TZ=GMT");
312     lt = localtime(&gmt);
313     ok(((lt->tm_year == year) && (lt->tm_mon  == 0) && (lt->tm_yday  == 1) &&
314         (lt->tm_mday ==  2) && (lt->tm_hour  == 0) &&
315         (lt->tm_min  ==  0) && (lt->tm_sec  == 0)),
316        "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n",
317        lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, 
318        lt->tm_min, lt->tm_sec, lt->tm_isdst); 
319     putenv(TZ_env);
320
321     /* June 22 */
322     gmt = ref + 202 * SECSPERDAY + tzinfo.Bias * SECSPERMIN;
323     lt = localtime(&gmt);
324     gmt += (lt->tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN;
325     lt = localtime(&gmt);
326     ok(((lt->tm_year == year) && (lt->tm_mon  == 6) && (lt->tm_yday  == 202) &&
327         (lt->tm_mday == 22 - is_leap) && (lt->tm_hour  == 0) &&
328         (lt->tm_min  ==  0) && (lt->tm_sec  == 0)),
329        "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n",
330        lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, 
331        lt->tm_min, lt->tm_sec, lt->tm_isdst); 
332 }
333
334 static void test_strdate(void)
335 {
336     char date[16], * result;
337     int month, day, year, count, len;
338     errno_t err;
339
340     result = _strdate(date);
341     ok(result == date, "Wrong return value\n");
342     len = strlen(date);
343     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
344     count = sscanf(date, "%02d/%02d/%02d", &month, &day, &year);
345     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
346
347     if(!p_strdate_s) {
348         win_skip("Skipping _strdate_s tests\n");
349         return;
350     }
351
352     errno = 0;
353     err = p_strdate_s(NULL, 1);
354     ok(err == EINVAL, "err = %d\n", err);
355     ok(errno == EINVAL, "errno = %d\n", errno);
356
357     date[0] = 'x';
358     date[1] = 'x';
359     err = p_strdate_s(date, 8);
360     ok(err == ERANGE, "err = %d\n", err);
361     ok(errno == ERANGE, "errno = %d\n", errno);
362     ok(date[0] == '\0', "date[0] != '\\0'\n");
363     ok(date[1] == 'x', "date[1] != 'x'\n");
364
365     err = p_strdate_s(date, 9);
366     ok(err == 0, "err = %x\n", err);
367 }
368
369 static void test_strtime(void)
370 {
371     char time[16], * result;
372     int hour, minute, second, count, len;
373     errno_t err;
374
375     result = _strtime(time);
376     ok(result == time, "Wrong return value\n");
377     len = strlen(time);
378     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
379     count = sscanf(time, "%02d:%02d:%02d", &hour, &minute, &second);
380     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
381
382     if(!p_strtime_s) {
383         win_skip("Skipping _strtime_s tests\n");
384         return;
385     }
386
387     errno = 0;
388     err = p_strtime_s(NULL, 0);
389     ok(err == EINVAL, "err = %d\n", err);
390     ok(errno == EINVAL, "errno = %d\n", errno);
391
392     err = p_strtime_s(NULL, 1);
393     ok(err == EINVAL, "err = %d\n", err);
394     ok(errno == EINVAL, "errno = %d\n", errno);
395
396     time[0] = 'x';
397     err = p_strtime_s(time, 8);
398     ok(err == ERANGE, "err = %d\n", err);
399     ok(errno == ERANGE, "errno = %d\n", errno);
400     ok(time[0] == '\0', "time[0] != '\\0'\n");
401
402     err = p_strtime_s(time, 9);
403     ok(err == 0, "err = %x\n", err);
404 }
405
406 static void test_wstrdate(void)
407 {
408     wchar_t date[16], * result;
409     int month, day, year, count, len;
410     wchar_t format[] = { '%','0','2','d','/','%','0','2','d','/','%','0','2','d',0 };
411
412     result = _wstrdate(date);
413     ok(result == date, "Wrong return value\n");
414     len = wcslen(date);
415     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
416     count = swscanf(date, format, &month, &day, &year);
417     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
418 }
419
420 static void test_wstrtime(void)
421 {
422     wchar_t time[16], * result;
423     int hour, minute, second, count, len;
424     wchar_t format[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',0 };
425
426     result = _wstrtime(time);
427     ok(result == time, "Wrong return value\n");
428     len = wcslen(time);
429     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
430     count = swscanf(time, format, &hour, &minute, &second);
431     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
432 }
433
434 static void test_localtime32_s(void)
435 {
436     struct tm tm;
437     __time32_t time;
438     errno_t err;
439
440     if (!p_localtime32_s)
441     {
442         win_skip("Skipping _localtime32_s tests\n");
443         return;
444     }
445
446     errno = EBADF;
447     err = p_localtime32_s(NULL, NULL);
448     ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
449     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
450
451     errno = EBADF;
452     time = 0x12345678;
453     err = p_localtime32_s(NULL, &time);
454     ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
455     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
456
457     memset(&tm, 0, sizeof(tm));
458     errno = EBADF;
459     err = p_localtime32_s(&tm, NULL);
460     ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
461     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
462     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
463        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
464        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
465        "Expected tm structure members to be initialized to -1, got "
466        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
467        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
468        tm.tm_isdst);
469
470     memset(&tm, 0, sizeof(tm));
471     time = -1;
472     errno = EBADF;
473     err = p_localtime32_s(&tm, &time);
474     ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
475     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
476     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
477        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
478        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
479        "Expected tm structure members to be initialized to -1, got "
480        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
481        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
482        tm.tm_isdst);
483 }
484
485 static void test_localtime64_s(void)
486 {
487     struct tm tm;
488     __time64_t time;
489     errno_t err;
490
491     if (!p_localtime64_s)
492     {
493         win_skip("Skipping _localtime64_s tests\n");
494         return;
495     }
496
497     errno = EBADF;
498     err = p_localtime64_s(NULL, NULL);
499     ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
500     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
501
502     errno = EBADF;
503     time = 0xdeadbeef;
504     err = p_localtime64_s(NULL, &time);
505     ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
506     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
507
508     memset(&tm, 0, sizeof(tm));
509     errno = EBADF;
510     err = p_localtime64_s(&tm, NULL);
511     ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
512     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
513     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
514        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
515        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
516        "Expected tm structure members to be initialized to -1, got "
517        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
518        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
519        tm.tm_isdst);
520
521     memset(&tm, 0, sizeof(tm));
522     time = -1;
523     errno = EBADF;
524     err = p_localtime64_s(&tm, &time);
525     ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
526     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
527     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
528        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
529        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
530        "Expected tm structure members to be initialized to -1, got "
531        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
532        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
533        tm.tm_isdst);
534
535     memset(&tm, 0, sizeof(tm));
536     time = _MAX__TIME64_T + 1;
537     errno = EBADF;
538     err = p_localtime64_s(&tm, &time);
539     ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
540     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
541     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
542        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
543        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
544        "Expected tm structure members to be initialized to -1, got "
545        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
546        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
547        tm.tm_isdst);
548 }
549
550 static void test_daylight(void)
551 {
552     int *ret1, *ret2;
553
554     if (!p__daylight)
555     {
556         win_skip("__daylight() not available\n");
557         return;
558     }
559
560     if (!p___p__daylight)
561     {
562         win_skip("__p__daylight not available\n");
563         return;
564     }
565
566     ret1 = p__daylight();
567     ret2 = p___p__daylight();
568     ok(ret1 && ret1 == ret2, "got %p\n", ret1);
569 }
570
571 START_TEST(time)
572 {
573     init();
574
575     test_ctime();
576     test_gmtime();
577     test_mktime();
578     test_localtime();
579     test_strdate();
580     test_strtime();
581     test_wstrdate();
582     test_wstrtime();
583     test_localtime32_s();
584     test_localtime64_s();
585     test_daylight();
586 }