wined3d: Recognize Nvidia GT520 cards.
[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 long*      (__cdecl *p___p__dstbias)(void);
50 static long*      (__cdecl *p___p__timezone)(void);
51 static size_t     (__cdecl *p_strftime)(char *, size_t, const char *, const struct tm *);
52 static size_t     (__cdecl *p_wcsftime)(wchar_t *, size_t, const wchar_t *, const struct tm *);
53 static char*      (__cdecl *p_asctime)(const struct tm *);
54
55 static void init(void)
56 {
57     HMODULE hmod = LoadLibrary("msvcrt.dll");
58
59     p_gmtime32 = (void*)GetProcAddress(hmod, "_gmtime32");
60     p_gmtime = (void*)GetProcAddress(hmod, "gmtime");
61     p_gmtime32_s = (void*)GetProcAddress(hmod, "_gmtime32_s");
62     p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32");
63     p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s");
64     p_strdate_s = (void*)GetProcAddress(hmod, "_strdate_s");
65     p_localtime32_s = (void*)GetProcAddress(hmod, "_localtime32_s");
66     p_localtime64_s = (void*)GetProcAddress(hmod, "_localtime64_s");
67     p__daylight = (void*)GetProcAddress(hmod, "__daylight");
68     p___p__daylight = (void*)GetProcAddress(hmod, "__p__daylight");
69     p___p__dstbias = (void*)GetProcAddress(hmod, "__p__dstbias");
70     p___p__timezone = (void*)GetProcAddress(hmod, "__p__timezone");
71     p_strftime = (void*)GetProcAddress(hmod, "strftime");
72     p_wcsftime = (void*)GetProcAddress(hmod, "wcsftime");
73     p_asctime = (void*)GetProcAddress(hmod, "asctime");
74 }
75
76 static int get_test_year(time_t *start)
77 {
78     time_t now = time(NULL);
79     struct tm *tm = localtime(&now);
80
81     /* compute start of year in seconds */
82     *start = SECSPERDAY * ((tm->tm_year - 70) * 365 +
83                            (tm->tm_year - 69) / 4 -
84                            (tm->tm_year - 1) / 100 +
85                            (tm->tm_year + 299) / 400);
86     return tm->tm_year;
87 }
88
89 static void test_ctime(void)
90 {
91     time_t badtime = -1;
92     char* ret;
93     ret = ctime(&badtime);
94     ok(ret == NULL, "expected ctime to return NULL, got %s\n", ret);
95 }
96 static void test_gmtime(void)
97 {
98     __time32_t valid, gmt;
99     struct tm* gmt_tm, gmt_tm_s;
100     errno_t err;
101
102     if(!p_gmtime32) {
103         win_skip("Skipping _gmtime32 tests\n");
104         return;
105     }
106
107     gmt_tm = p_gmtime32(NULL);
108     ok(gmt_tm == NULL, "gmt_tm != NULL\n");
109
110     gmt = -1;
111     gmt_tm = p_gmtime32(&gmt);
112     ok(gmt_tm == NULL, "gmt_tm != NULL\n");
113
114     gmt = valid = 0;
115     gmt_tm = p_gmtime32(&gmt);
116     if(!gmt_tm) {
117         ok(0, "_gmtime32() failed\n");
118         return;
119     }
120
121     ok(((gmt_tm->tm_year == 70) && (gmt_tm->tm_mon  == 0) && (gmt_tm->tm_yday  == 0) &&
122                 (gmt_tm->tm_mday ==  1) && (gmt_tm->tm_wday == 4) && (gmt_tm->tm_hour  == 0) &&
123                 (gmt_tm->tm_min  ==  0) && (gmt_tm->tm_sec  == 0) && (gmt_tm->tm_isdst == 0)),
124             "Wrong date:Year %4d mon %2d yday %3d mday %2d wday %1d hour%2d min %2d sec %2d dst %2d\n",
125             gmt_tm->tm_year, gmt_tm->tm_mon, gmt_tm->tm_yday, gmt_tm->tm_mday, gmt_tm->tm_wday,
126             gmt_tm->tm_hour, gmt_tm->tm_min, gmt_tm->tm_sec, gmt_tm->tm_isdst);
127
128     if(!p_mkgmtime32) {
129         win_skip("Skipping _mkgmtime32 tests\n");
130         return;
131     }
132
133     gmt_tm->tm_wday = gmt_tm->tm_yday = 0;
134     gmt = p_mkgmtime32(gmt_tm);
135     ok(gmt == valid, "gmt = %u\n", gmt);
136     ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday);
137     ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday);
138
139     gmt_tm->tm_wday = gmt_tm->tm_yday = 0;
140     gmt_tm->tm_isdst = -1;
141     gmt = p_mkgmtime32(gmt_tm);
142     ok(gmt == valid, "gmt = %u\n", gmt);
143     ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday);
144     ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday);
145
146     gmt_tm->tm_wday = gmt_tm->tm_yday = 0;
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 == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday);
151     ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday);
152
153     gmt = valid = 173921;
154     gmt_tm = p_gmtime32(&gmt);
155     if(!gmt_tm) {
156         ok(0, "_gmtime32() failed\n");
157         return;
158     }
159
160     gmt_tm->tm_isdst = -1;
161     gmt = p_mkgmtime32(gmt_tm);
162     ok(gmt == valid, "gmt = %u\n", gmt);
163     ok(gmt_tm->tm_wday == 6, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday);
164     ok(gmt_tm->tm_yday == 2, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday);
165
166     gmt_tm->tm_isdst = 1;
167     gmt = p_mkgmtime32(gmt_tm);
168     ok(gmt == valid, "gmt = %u\n", gmt);
169
170     if(!p_gmtime32_s) {
171         win_skip("Skipping _gmtime32_s tests\n");
172         return;
173     }
174
175     errno = 0;
176     gmt = 0;
177     err = p_gmtime32_s(NULL, &gmt);
178     ok(err == EINVAL, "err = %d\n", err);
179     ok(errno == EINVAL, "errno = %d\n", errno);
180
181     errno = 0;
182     gmt = -1;
183     err = p_gmtime32_s(&gmt_tm_s, &gmt);
184     ok(err == EINVAL, "err = %d\n", err);
185     ok(errno == EINVAL, "errno = %d\n", errno);
186     ok(gmt_tm_s.tm_year == -1, "tm_year = %d\n", gmt_tm_s.tm_year);
187 }
188
189 static void test_mktime(void)
190 {
191     TIME_ZONE_INFORMATION tzinfo;
192     DWORD res =  GetTimeZoneInformation(&tzinfo);
193     struct tm my_tm, sav_tm;
194     time_t nulltime, local_time;
195     char TZ_env[256];
196     char buffer[64];
197     int year;
198     time_t ref, secs;
199
200     year = get_test_year( &ref );
201     ref += SECSPERDAY;
202
203     ok (res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
204     WideCharToMultiByte( CP_ACP, 0, tzinfo.StandardName, -1, buffer, sizeof(buffer), NULL, NULL );
205     trace( "bias %d std %d dst %d zone %s\n",
206            tzinfo.Bias, tzinfo.StandardBias, tzinfo.DaylightBias, buffer );
207     /* Bias may be positive or negative, to use offset of one day */
208     my_tm = *localtime(&ref);  /* retrieve current dst flag */
209     secs = SECSPERDAY - tzinfo.Bias * SECSPERMIN;
210     secs -= (my_tm.tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN;
211     my_tm.tm_mday = 1 + secs/SECSPERDAY;
212     secs = secs % SECSPERDAY;
213     my_tm.tm_hour = secs / SECSPERHOUR;
214     secs = secs % SECSPERHOUR;
215     my_tm.tm_min = secs / SECSPERMIN;
216     secs = secs % SECSPERMIN;
217     my_tm.tm_sec = secs;
218
219     my_tm.tm_year = year;
220     my_tm.tm_mon  =  0;
221
222     sav_tm = my_tm;
223
224     local_time = mktime(&my_tm);
225     ok(local_time == ref, "mktime returned %u, expected %u\n",
226        (DWORD)local_time, (DWORD)ref);
227     /* now test some unnormalized struct tm's */
228     my_tm = sav_tm;
229     my_tm.tm_sec += 60;
230     my_tm.tm_min -= 1;
231     local_time = mktime(&my_tm);
232     ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n",
233         (DWORD)local_time, (DWORD)ref);
234     ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
235         my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
236         my_tm.tm_sec == sav_tm.tm_sec,
237             "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n",
238             my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
239             my_tm.tm_hour,my_tm.tm_sec,
240             sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
241             sav_tm.tm_hour,sav_tm.tm_sec);
242     my_tm = sav_tm;
243     my_tm.tm_min -= 60;
244     my_tm.tm_hour += 1;
245     local_time = mktime(&my_tm);
246     ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n",
247        (DWORD)local_time, (DWORD)ref);
248     ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
249         my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
250         my_tm.tm_sec == sav_tm.tm_sec,
251             "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n",
252             my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
253             my_tm.tm_hour,my_tm.tm_sec,
254             sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
255             sav_tm.tm_hour,sav_tm.tm_sec);
256     my_tm = sav_tm;
257     my_tm.tm_mon -= 12;
258     my_tm.tm_year += 1;
259     local_time = mktime(&my_tm);
260     ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n",
261        (DWORD)local_time, (DWORD)ref);
262     ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
263         my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
264         my_tm.tm_sec == sav_tm.tm_sec,
265             "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n",
266             my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
267             my_tm.tm_hour,my_tm.tm_sec,
268             sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
269             sav_tm.tm_hour,sav_tm.tm_sec);
270     my_tm = sav_tm;
271     my_tm.tm_mon += 12;
272     my_tm.tm_year -= 1;
273     local_time = mktime(&my_tm);
274     ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n",
275        (DWORD)local_time, (DWORD)ref);
276     ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
277         my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
278         my_tm.tm_sec == sav_tm.tm_sec,
279             "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n",
280             my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
281             my_tm.tm_hour,my_tm.tm_sec,
282             sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
283             sav_tm.tm_hour,sav_tm.tm_sec);
284     /* now a bad time example */
285     my_tm = sav_tm;
286     my_tm.tm_year = 69;
287     local_time = mktime(&my_tm);
288     ok((local_time == -1), "(bad time) mktime returned %d, expected -1\n", (int)local_time);
289
290     my_tm = sav_tm;
291     /* TEST that we are independent from the TZ variable */
292     /*Argh, msvcrt doesn't have setenv() */
293     _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):""));
294     putenv("TZ=GMT");
295     nulltime = mktime(&my_tm);
296     ok(nulltime == ref,"mktime returned 0x%08x\n",(DWORD)nulltime);
297     putenv(TZ_env);
298 }
299
300 static void test_localtime(void)
301 {
302     TIME_ZONE_INFORMATION tzinfo;
303     DWORD res =  GetTimeZoneInformation(&tzinfo);
304     time_t gmt, ref;
305
306     char TZ_env[256];
307     struct tm* lt;
308     int year = get_test_year( &ref );
309     int is_leap = !(year % 4) && ((year % 100) || !((year + 300) % 400));
310
311     gmt = ref + SECSPERDAY + tzinfo.Bias * SECSPERMIN;
312     ok (res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
313     lt = localtime(&gmt);
314     gmt += (lt->tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN;
315     lt = localtime(&gmt);
316     ok(((lt->tm_year == year) && (lt->tm_mon  == 0) && (lt->tm_yday  == 1) &&
317         (lt->tm_mday ==  2) && (lt->tm_hour  == 0) &&
318         (lt->tm_min  ==  0) && (lt->tm_sec  == 0)),
319        "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n",
320        lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, 
321        lt->tm_min, lt->tm_sec, lt->tm_isdst); 
322
323     _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):""));
324     putenv("TZ=GMT");
325     lt = localtime(&gmt);
326     ok(((lt->tm_year == year) && (lt->tm_mon  == 0) && (lt->tm_yday  == 1) &&
327         (lt->tm_mday ==  2) && (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     putenv(TZ_env);
333
334     /* June 22 */
335     gmt = ref + 202 * SECSPERDAY + tzinfo.Bias * SECSPERMIN;
336     lt = localtime(&gmt);
337     gmt += (lt->tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN;
338     lt = localtime(&gmt);
339     ok(((lt->tm_year == year) && (lt->tm_mon  == 6) && (lt->tm_yday  == 202) &&
340         (lt->tm_mday == 22 - is_leap) && (lt->tm_hour  == 0) &&
341         (lt->tm_min  ==  0) && (lt->tm_sec  == 0)),
342        "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n",
343        lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, 
344        lt->tm_min, lt->tm_sec, lt->tm_isdst); 
345 }
346
347 static void test_strdate(void)
348 {
349     char date[16], * result;
350     int month, day, year, count, len;
351     errno_t err;
352
353     result = _strdate(date);
354     ok(result == date, "Wrong return value\n");
355     len = strlen(date);
356     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
357     count = sscanf(date, "%02d/%02d/%02d", &month, &day, &year);
358     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
359
360     if(!p_strdate_s) {
361         win_skip("Skipping _strdate_s tests\n");
362         return;
363     }
364
365     errno = 0;
366     err = p_strdate_s(NULL, 1);
367     ok(err == EINVAL, "err = %d\n", err);
368     ok(errno == EINVAL, "errno = %d\n", errno);
369
370     date[0] = 'x';
371     date[1] = 'x';
372     err = p_strdate_s(date, 8);
373     ok(err == ERANGE, "err = %d\n", err);
374     ok(errno == ERANGE, "errno = %d\n", errno);
375     ok(date[0] == '\0', "date[0] != '\\0'\n");
376     ok(date[1] == 'x', "date[1] != 'x'\n");
377
378     err = p_strdate_s(date, 9);
379     ok(err == 0, "err = %x\n", err);
380 }
381
382 static void test_strtime(void)
383 {
384     char time[16], * result;
385     int hour, minute, second, count, len;
386     errno_t err;
387
388     result = _strtime(time);
389     ok(result == time, "Wrong return value\n");
390     len = strlen(time);
391     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
392     count = sscanf(time, "%02d:%02d:%02d", &hour, &minute, &second);
393     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
394
395     if(!p_strtime_s) {
396         win_skip("Skipping _strtime_s tests\n");
397         return;
398     }
399
400     errno = 0;
401     err = p_strtime_s(NULL, 0);
402     ok(err == EINVAL, "err = %d\n", err);
403     ok(errno == EINVAL, "errno = %d\n", errno);
404
405     err = p_strtime_s(NULL, 1);
406     ok(err == EINVAL, "err = %d\n", err);
407     ok(errno == EINVAL, "errno = %d\n", errno);
408
409     time[0] = 'x';
410     err = p_strtime_s(time, 8);
411     ok(err == ERANGE, "err = %d\n", err);
412     ok(errno == ERANGE, "errno = %d\n", errno);
413     ok(time[0] == '\0', "time[0] != '\\0'\n");
414
415     err = p_strtime_s(time, 9);
416     ok(err == 0, "err = %x\n", err);
417 }
418
419 static void test_wstrdate(void)
420 {
421     wchar_t date[16], * result;
422     int month, day, year, count, len;
423     wchar_t format[] = { '%','0','2','d','/','%','0','2','d','/','%','0','2','d',0 };
424
425     result = _wstrdate(date);
426     ok(result == date, "Wrong return value\n");
427     len = wcslen(date);
428     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
429     count = swscanf(date, format, &month, &day, &year);
430     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
431 }
432
433 static void test_wstrtime(void)
434 {
435     wchar_t time[16], * result;
436     int hour, minute, second, count, len;
437     wchar_t format[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',0 };
438
439     result = _wstrtime(time);
440     ok(result == time, "Wrong return value\n");
441     len = wcslen(time);
442     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
443     count = swscanf(time, format, &hour, &minute, &second);
444     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
445 }
446
447 static void test_localtime32_s(void)
448 {
449     struct tm tm;
450     __time32_t time;
451     errno_t err;
452
453     if (!p_localtime32_s)
454     {
455         win_skip("Skipping _localtime32_s tests\n");
456         return;
457     }
458
459     errno = EBADF;
460     err = p_localtime32_s(NULL, NULL);
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     errno = EBADF;
465     time = 0x12345678;
466     err = p_localtime32_s(NULL, &time);
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
470     memset(&tm, 0, sizeof(tm));
471     errno = EBADF;
472     err = p_localtime32_s(&tm, NULL);
473     ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
474     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
475     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
476        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
477        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
478        "Expected tm structure members to be initialized to -1, got "
479        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
480        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
481        tm.tm_isdst);
482
483     memset(&tm, 0, sizeof(tm));
484     time = -1;
485     errno = EBADF;
486     err = p_localtime32_s(&tm, &time);
487     ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
488     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
489     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
490        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
491        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
492        "Expected tm structure members to be initialized to -1, got "
493        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
494        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
495        tm.tm_isdst);
496 }
497
498 static void test_localtime64_s(void)
499 {
500     struct tm tm;
501     __time64_t time;
502     errno_t err;
503
504     if (!p_localtime64_s)
505     {
506         win_skip("Skipping _localtime64_s tests\n");
507         return;
508     }
509
510     errno = EBADF;
511     err = p_localtime64_s(NULL, NULL);
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     errno = EBADF;
516     time = 0xdeadbeef;
517     err = p_localtime64_s(NULL, &time);
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
521     memset(&tm, 0, sizeof(tm));
522     errno = EBADF;
523     err = p_localtime64_s(&tm, NULL);
524     ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
525     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
526     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
527        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
528        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
529        "Expected tm structure members to be initialized to -1, got "
530        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
531        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
532        tm.tm_isdst);
533
534     memset(&tm, 0, sizeof(tm));
535     time = -1;
536     errno = EBADF;
537     err = p_localtime64_s(&tm, &time);
538     ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
539     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
540     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
541        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
542        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
543        "Expected tm structure members to be initialized to -1, got "
544        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
545        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
546        tm.tm_isdst);
547
548     memset(&tm, 0, sizeof(tm));
549     time = _MAX__TIME64_T + 1;
550     errno = EBADF;
551     err = p_localtime64_s(&tm, &time);
552     ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
553     ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
554     ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
555        tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
556        tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
557        "Expected tm structure members to be initialized to -1, got "
558        "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
559        tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
560        tm.tm_isdst);
561 }
562
563 static void test_daylight(void)
564 {
565     int *ret1, *ret2;
566
567     if (!p__daylight)
568     {
569         win_skip("__daylight() not available\n");
570         return;
571     }
572
573     if (!p___p__daylight)
574     {
575         win_skip("__p__daylight not available\n");
576         return;
577     }
578
579     ret1 = p__daylight();
580     ret2 = p___p__daylight();
581     ok(ret1 && ret1 == ret2, "got %p\n", ret1);
582 }
583
584 static void test_strftime(void)
585 {
586     static const wchar_t cW[] = { '%','c',0 };
587     static const char expected[] = "01/01/70 00:00:00";
588     time_t gmt;
589     struct tm* gmt_tm;
590     char buf[256], bufA[256];
591     WCHAR bufW[256];
592     long retA, retW;
593
594     if (!p_strftime || !p_wcsftime || !p_gmtime)
595     {
596         win_skip("strftime, wcsftime or gmtime is not available\n");
597         return;
598     }
599
600     setlocale(LC_TIME, "C");
601
602     gmt = 0;
603     gmt_tm = p_gmtime(&gmt);
604     ok(gmt_tm != NULL, "gmtime failed\n");
605
606     errno = 0xdeadbeef;
607     retA = strftime(NULL, 0, "copy", gmt_tm);
608     ok(retA == 0, "expected 0, got %ld\n", retA);
609     ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno);
610
611     retA = strftime(bufA, 256, "copy", NULL);
612     ok(retA == 4, "expected 4, got %ld\n", retA);
613     ok(!strcmp(bufA, "copy"), "got %s\n", bufA);
614
615     retA = strftime(bufA, 256, "copy it", gmt_tm);
616     ok(retA == 7, "expected 7, got %ld\n", retA);
617     ok(!strcmp(bufA, "copy it"), "got %s\n", bufA);
618
619     errno = 0xdeadbeef;
620     retA = strftime(bufA, 2, "copy", gmt_tm);
621     ok(retA == 0, "expected 0, got %ld\n", retA);
622     ok(!strcmp(bufA, "") || broken(!strcmp(bufA, "copy it")), "got %s\n", bufA);
623     ok(errno==ERANGE || errno==0xdeadbeef, "errno = %d\n", errno);
624
625     errno = 0xdeadbeef;
626     retA = strftime(bufA, 256, "a%e", gmt_tm);
627     ok(retA==0 || broken(retA==1), "expected 0, got %ld\n", retA);
628     ok(!strcmp(bufA, "") || broken(!strcmp(bufA, "a")), "got %s\n", bufA);
629     ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno);
630
631     if(0) { /* crashes on Win2k */
632         errno = 0xdeadbeef;
633         retA = strftime(bufA, 256, "%c", NULL);
634         ok(retA == 0, "expected 0, got %ld\n", retA);
635         ok(!strcmp(bufA, ""), "got %s\n", bufA);
636         ok(errno == EINVAL, "errno = %d\n", errno);
637     }
638
639     retA = strftime(bufA, 256, "e%#%e", gmt_tm);
640     ok(retA == 3, "expected 3, got %ld\n", retA);
641     ok(!strcmp(bufA, "e%e"), "got %s\n", bufA);
642
643     retA = strftime(bufA, 256, "%c", gmt_tm);
644     ok(retA == 17, "expected 17, got %ld\n", retA);
645     ok(strcmp(bufA, expected) == 0, "expected %s, got %s\n", expected, bufA);
646
647     retW = wcsftime(bufW, 256, cW, gmt_tm);
648     ok(retW == 17, "expected 17, got %ld\n", retW);
649     ok(retA == retW, "expected %ld, got %ld\n", retA, retW);
650     buf[0] = 0;
651     retA = WideCharToMultiByte(CP_ACP, 0, bufW, retW, buf, 256, NULL, NULL);
652     buf[retA] = 0;
653     ok(strcmp(bufA, buf) == 0, "expected %s, got %s\n", bufA, buf);
654
655     retA = strftime(bufA, 256, "%x", gmt_tm);
656     ok(retA == 8, "expected 8, got %ld\n", retA);
657     ok(!strcmp(bufA, "01/01/70"), "got %s\n", bufA);
658
659     retA = strftime(bufA, 256, "%X", gmt_tm);
660     ok(retA == 8, "expected 8, got %ld\n", retA);
661     ok(!strcmp(bufA, "00:00:00"), "got %s\n", bufA);
662
663     retA = strftime(bufA, 256, "%a", gmt_tm);
664     ok(retA == 3, "expected 3, got %ld\n", retA);
665     ok(!strcmp(bufA, "Thu"), "got %s\n", bufA);
666
667     retA = strftime(bufA, 256, "%A", gmt_tm);
668     ok(retA == 8, "expected 8, got %ld\n", retA);
669     ok(!strcmp(bufA, "Thursday"), "got %s\n", bufA);
670
671     retA = strftime(bufA, 256, "%b", gmt_tm);
672     ok(retA == 3, "expected 3, got %ld\n", retA);
673     ok(!strcmp(bufA, "Jan"), "got %s\n", bufA);
674
675     retA = strftime(bufA, 256, "%B", gmt_tm);
676     ok(retA == 7, "expected 7, got %ld\n", retA);
677     ok(!strcmp(bufA, "January"), "got %s\n", bufA);
678
679     retA = strftime(bufA, 256, "%d", gmt_tm);
680     ok(retA == 2, "expected 2, got %ld\n", retA);
681     ok(!strcmp(bufA, "01"), "got %s\n", bufA);
682
683     retA = strftime(bufA, 256, "%#d", gmt_tm);
684     ok(retA == 1, "expected 1, got %ld\n", retA);
685     ok(!strcmp(bufA, "1"), "got %s\n", bufA);
686
687     retA = strftime(bufA, 256, "%H", gmt_tm);
688     ok(retA == 2, "expected 2, got %ld\n", retA);
689     ok(!strcmp(bufA, "00"), "got %s\n", bufA);
690
691     retA = strftime(bufA, 256, "%I", gmt_tm);
692     ok(retA == 2, "expected 2, got %ld\n", retA);
693     ok(!strcmp(bufA, "12"), "got %s\n", bufA);
694
695     retA = strftime(bufA, 256, "%j", gmt_tm);
696     ok(retA == 3, "expected 3, got %ld\n", retA);
697     ok(!strcmp(bufA, "001"), "got %s\n", bufA);
698
699     retA = strftime(bufA, 256, "%m", gmt_tm);
700     ok(retA == 2, "expected 2, got %ld\n", retA);
701     ok(!strcmp(bufA, "01"), "got %s\n", bufA);
702
703     retA = strftime(bufA, 256, "%#M", gmt_tm);
704     ok(retA == 1, "expected 1, got %ld\n", retA);
705     ok(!strcmp(bufA, "0"), "got %s\n", bufA);
706
707     retA = strftime(bufA, 256, "%p", gmt_tm);
708     ok(retA == 2, "expected 2, got %ld\n", retA);
709     ok(!strcmp(bufA, "AM"), "got %s\n", bufA);
710
711     retA = strftime(bufA, 256, "%U", gmt_tm);
712     ok(retA == 2, "expected 2, got %ld\n", retA);
713     ok(!strcmp(bufA, "00"), "got %s\n", bufA);
714
715     retA = strftime(bufA, 256, "%W", gmt_tm);
716     ok(retA == 2, "expected 2, got %ld\n", retA);
717     ok(!strcmp(bufA, "00"), "got %s\n", bufA);
718
719     gmt_tm->tm_wday = 0;
720     retA = strftime(bufA, 256, "%U", gmt_tm);
721     ok(retA == 2, "expected 2, got %ld\n", retA);
722     ok(!strcmp(bufA, "01"), "got %s\n", bufA);
723
724     retA = strftime(bufA, 256, "%W", gmt_tm);
725     ok(retA == 2, "expected 2, got %ld\n", retA);
726     ok(!strcmp(bufA, "00"), "got %s\n", bufA);
727
728     gmt_tm->tm_yday = 365;
729     retA = strftime(bufA, 256, "%U", gmt_tm);
730     ok(retA == 2, "expected 2, got %ld\n", retA);
731     ok(!strcmp(bufA, "53"), "got %s\n", bufA);
732
733     retA = strftime(bufA, 256, "%W", gmt_tm);
734     ok(retA == 2, "expected 2, got %ld\n", retA);
735     ok(!strcmp(bufA, "52"), "got %s\n", bufA);
736
737     gmt_tm->tm_mon = 1;
738     gmt_tm->tm_mday = 30;
739     retA = strftime(bufA, 256, "%c", gmt_tm);
740     todo_wine {
741         ok(retA == 17, "expected 17, got %ld\n", retA);
742         ok(!strcmp(bufA, "02/30/70 00:00:00"), "got %s\n", bufA);
743     }
744 }
745
746 static void test_asctime(void)
747 {
748     struct tm* gmt_tm;
749     time_t gmt;
750     char *ret;
751
752     if(!p_asctime || !p_gmtime)
753     {
754         win_skip("asctime or gmtime is not available\n");
755         return;
756     }
757
758     gmt = 0;
759     gmt_tm = p_gmtime(&gmt);
760     ret = p_asctime(gmt_tm);
761     ok(!strcmp(ret, "Thu Jan 01 00:00:00 1970\n"), "asctime retunred %s\n", ret);
762
763     gmt = 312433121;
764     gmt_tm = p_gmtime(&gmt);
765     ret = p_asctime(gmt_tm);
766     ok(!strcmp(ret, "Mon Nov 26 02:58:41 1979\n"), "asctime retunred %s\n", ret);
767
768     /* Week day is only checked if it's in 0..6 range */
769     gmt_tm->tm_wday = 3;
770     ret = p_asctime(gmt_tm);
771     ok(!strcmp(ret, "Wed Nov 26 02:58:41 1979\n"), "asctime returned %s\n", ret);
772
773     errno = 0xdeadbeef;
774     gmt_tm->tm_wday = 7;
775     ret = p_asctime(gmt_tm);
776     ok(!ret || broken(!ret[0]), "asctime returned %s\n", ret);
777     ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno);
778
779     /* Year day is ignored */
780     gmt_tm->tm_wday = 3;
781     gmt_tm->tm_yday = 1300;
782     ret = p_asctime(gmt_tm);
783     ok(!strcmp(ret, "Wed Nov 26 02:58:41 1979\n"), "asctime returned %s\n", ret);
784
785     /* Dates that can't be displayed using 26 characters are broken */
786     gmt_tm->tm_mday = 28;
787     gmt_tm->tm_year = 8100;
788     ret = p_asctime(gmt_tm);
789     ok(!strcmp(ret, "Wed Nov 28 02:58:41 :000\n"), "asctime returned %s\n", ret);
790
791     gmt_tm->tm_year = 264100;
792     ret = p_asctime(gmt_tm);
793     ok(!strcmp(ret, "Wed Nov 28 02:58:41 :000\n"), "asctime returned %s\n", ret);
794
795     /* asctime works from year 1900 */
796     errno = 0xdeadbeef;
797     gmt_tm->tm_year = -1;
798     ret = p_asctime(gmt_tm);
799     ok(!ret || broken(!strcmp(ret, "Wed Nov 28 02:58:41 190/\n")), "asctime returned %s\n", ret);
800     ok(errno==EINVAL || broken(errno == 0xdeadbeef), "errno = %d\n", errno);
801
802     errno = 0xdeadbeef;
803     gmt_tm->tm_mon = 1;
804     gmt_tm->tm_mday = 30;
805     gmt_tm->tm_year = 79;
806     ret = p_asctime(gmt_tm);
807     ok(!ret || broken(!strcmp(ret, "Wed Feb 30 02:58:41 1979\n")), "asctime returned %s\n", ret);
808     ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno);
809 }
810
811 static void test__tzset(void)
812 {
813     char TZ_env[256];
814     int ret;
815
816     if(!p___p__daylight || !p___p__timezone || !p___p__dstbias) {
817         win_skip("__p__daylight, __p__timezone or __p__dstbias is not available\n");
818         return;
819     }
820
821     _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):""));
822
823     ret = *p___p__daylight();
824     ok(ret == 1, "*__p__daylight() = %d\n", ret);
825     ret = *p___p__timezone();
826     ok(ret == 28800, "*__p__timezone() = %d\n", ret);
827     ret = *p___p__dstbias();
828     ok(ret == -3600, "*__p__dstbias() = %d\n", ret);
829
830     _putenv("TZ=xxx+1yyy");
831     _tzset();
832     ret = *p___p__daylight();
833     ok(ret == 121, "*__p__daylight() = %d\n", ret);
834     ret = *p___p__timezone();
835     ok(ret == 3600, "*__p__timezone() = %d\n", ret);
836     ret = *p___p__dstbias();
837     ok(ret == -3600, "*__p__dstbias() = %d\n", ret);
838
839     *p___p__dstbias() = 0;
840     _putenv("TZ=xxx+1:3:5zzz");
841     _tzset();
842     ret = *p___p__daylight();
843     ok(ret == 122, "*__p__daylight() = %d\n", ret);
844     ret = *p___p__timezone();
845     ok(ret == 3785, "*__p__timezone() = %d\n", ret);
846     ret = *p___p__dstbias();
847     ok(ret == 0, "*__p__dstbias() = %d\n", ret);
848
849     _putenv(TZ_env);
850 }
851
852 START_TEST(time)
853 {
854     init();
855
856     test__tzset();
857     test_strftime();
858     test_ctime();
859     test_gmtime();
860     test_mktime();
861     test_localtime();
862     test_strdate();
863     test_strtime();
864     test_wstrdate();
865     test_wstrtime();
866     test_localtime32_s();
867     test_localtime64_s();
868     test_daylight();
869     test_asctime();
870 }