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