kernel32: Conditional variable tests.
[wine] / dlls / kernel32 / tests / time.c
1 /*
2  * Unit test suite for time functions
3  *
4  * Copyright 2004 Uwe Bonnes
5  * Copyright 2007 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "wine/test.h"
23 #include "winbase.h"
24 #include "winnls.h"
25
26 static BOOL (WINAPI *pTzSpecificLocalTimeToSystemTime)(LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME);
27 static BOOL (WINAPI *pSystemTimeToTzSpecificLocalTime)(LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME);
28 static int (WINAPI *pGetCalendarInfoA)(LCID,CALID,CALTYPE,LPSTR,int,LPDWORD);
29 static int (WINAPI *pGetCalendarInfoW)(LCID,CALID,CALTYPE,LPWSTR,int,LPDWORD);
30
31 #define SECSPERMIN         60
32 #define SECSPERDAY        86400
33 /* 1601 to 1970 is 369 years plus 89 leap days */
34 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
35 #define TICKSPERSEC       10000000
36 #define TICKSPERMSEC      10000
37 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
38
39
40 #define NEWYEAR_1980_HI 0x01a8e79f
41 #define NEWYEAR_1980_LO 0xe1d58000
42
43 #define MAYDAY_2002_HI 0x01c1f107
44 #define MAYDAY_2002_LO 0xb82b6000
45
46 #define ATIME_HI  0x1c2349b
47 #define ATIME_LOW 0x580716b0
48
49 #define LOCAL_ATIME_HI  0x01c23471
50 #define LOCAL_ATIME_LOW 0x6f310eb0
51
52 #define DOS_DATE(y,m,d) ( (((y)-1980)<<9) | ((m)<<5) | (d) )
53 #define DOS_TIME(h,m,s) ( ((h)<<11) | ((m)<<5) | ((s)>>1) )
54
55
56 #define SETUP_1980(st) \
57     (st).wYear = 1980; \
58     (st).wMonth = 1; \
59     (st).wDay = 1; \
60     (st).wHour = 0; \
61     (st).wMinute = 0; \
62     (st).wSecond = 0; \
63     (st).wMilliseconds = 0;
64
65 #define SETUP_2002(st) \
66     (st).wYear = 2002; \
67     (st).wMonth = 5; \
68     (st).wDay = 1; \
69     (st).wHour = 12; \
70     (st).wMinute = 0; \
71     (st).wSecond = 0; \
72     (st).wMilliseconds = 0;
73
74 #define SETUP_ATIME(st) \
75     (st).wYear = 2002; \
76     (st).wMonth = 7; \
77     (st).wDay = 26; \
78     (st).wHour = 11; \
79     (st).wMinute = 55; \
80     (st).wSecond = 32; \
81     (st).wMilliseconds = 123;
82
83 #define SETUP_ZEROTIME(st) \
84     (st).wYear = 1601; \
85     (st).wMonth = 1; \
86     (st).wDay = 1; \
87     (st).wHour = 0; \
88     (st).wMinute = 0; \
89     (st).wSecond = 0; \
90     (st).wMilliseconds = 0;
91
92 #define SETUP_EARLY(st) \
93     (st).wYear = 1600; \
94     (st).wMonth = 12; \
95     (st).wDay = 31; \
96     (st).wHour = 23; \
97     (st).wMinute = 59; \
98     (st).wSecond = 59; \
99     (st).wMilliseconds = 999;
100
101
102 static void test_conversions(void)
103 {
104     FILETIME ft;
105     SYSTEMTIME st;
106
107     memset(&ft,0,sizeof ft);
108
109     SetLastError(0xdeadbeef);
110     SETUP_EARLY(st)
111     ok (!SystemTimeToFileTime(&st, &ft), "Conversion succeeded EARLY\n");
112     ok (GetLastError() == ERROR_INVALID_PARAMETER ||
113         GetLastError() == 0xdeadbeef, /* win9x */
114         "EARLY should be INVALID\n");
115
116     SETUP_ZEROTIME(st)
117     ok (SystemTimeToFileTime(&st, &ft), "Conversion failed ZERO_TIME\n");
118     ok( (!((ft.dwHighDateTime != 0) || (ft.dwLowDateTime != 0))),
119         "Wrong time for ATIME: %08x %08x (correct %08x %08x)\n",
120         ft.dwLowDateTime, ft.dwHighDateTime, 0, 0);
121
122
123     SETUP_ATIME(st)
124     ok (SystemTimeToFileTime(&st,&ft), "Conversion Failed ATIME\n");
125     ok( (!((ft.dwHighDateTime != ATIME_HI) || (ft.dwLowDateTime!=ATIME_LOW))),
126         "Wrong time for ATIME: %08x %08x (correct %08x %08x)\n",
127         ft.dwLowDateTime, ft.dwHighDateTime, ATIME_LOW, ATIME_HI);
128
129
130     SETUP_2002(st)
131     ok (SystemTimeToFileTime(&st, &ft), "Conversion failed 2002\n");
132
133     ok( (!((ft.dwHighDateTime != MAYDAY_2002_HI) ||
134          (ft.dwLowDateTime!=MAYDAY_2002_LO))),
135         "Wrong time for 2002 %08x %08x (correct %08x %08x)\n", ft.dwLowDateTime,
136         ft.dwHighDateTime, MAYDAY_2002_LO, MAYDAY_2002_HI);
137
138
139     SETUP_1980(st)
140     ok((SystemTimeToFileTime(&st, &ft)), "Conversion failed 1980\n");
141
142     ok( (!((ft.dwHighDateTime!=NEWYEAR_1980_HI) ||
143         (ft.dwLowDateTime!=NEWYEAR_1980_LO))) ,
144         "Wrong time for 1980 %08x %08x (correct %08x %08x)\n", ft.dwLowDateTime,
145          ft.dwHighDateTime, NEWYEAR_1980_LO,NEWYEAR_1980_HI  );
146
147     ok(DosDateTimeToFileTime(DOS_DATE(1980,1,1),DOS_TIME(0,0,0),&ft),
148         "DosDateTimeToFileTime() failed\n");
149
150     ok( (!((ft.dwHighDateTime!=NEWYEAR_1980_HI) ||
151          (ft.dwLowDateTime!=NEWYEAR_1980_LO))),
152         "Wrong time DosDateTimeToFileTime %08x %08x (correct %08x %08x)\n",
153         ft.dwHighDateTime, ft.dwLowDateTime, NEWYEAR_1980_HI, NEWYEAR_1980_LO);
154
155 }
156
157 static void test_invalid_arg(void)
158 {
159     FILETIME ft;
160     SYSTEMTIME st;
161
162
163     /* Invalid argument checks */
164
165     memset(&ft,0,sizeof ft);
166     ok( DosDateTimeToFileTime(DOS_DATE(1980,1,1),DOS_TIME(0,0,0),&ft), /* this is 1 Jan 1980 00:00:00 */
167         "DosDateTimeToFileTime() failed\n");
168
169     ok( (ft.dwHighDateTime==NEWYEAR_1980_HI) && (ft.dwLowDateTime==NEWYEAR_1980_LO),
170         "filetime for 1/1/80 00:00:00 was %08x %08x\n", ft.dwHighDateTime, ft.dwLowDateTime);
171
172     /* now check SystemTimeToFileTime */
173     memset(&ft,0,sizeof ft);
174
175
176     /* try with a bad month */
177     SETUP_1980(st)
178     st.wMonth = 0;
179
180     ok( !SystemTimeToFileTime(&st, &ft), "bad month\n");
181
182     /* with a bad hour */
183     SETUP_1980(st)
184     st.wHour = 24;
185
186     ok( !SystemTimeToFileTime(&st, &ft), "bad hour\n");
187
188     /* with a bad minute */
189     SETUP_1980(st)
190     st.wMinute = 60;
191
192     ok( !SystemTimeToFileTime(&st, &ft), "bad minute\n");
193 }
194
195 static LONGLONG system_time_to_minutes(const SYSTEMTIME *st)
196 {
197     BOOL ret;
198     FILETIME ft;
199     LONGLONG minutes;
200
201     SetLastError(0xdeadbeef);
202     ret = SystemTimeToFileTime(st, &ft);
203     ok(ret, "SystemTimeToFileTime error %u\n", GetLastError());
204
205     minutes = ((LONGLONG)ft.dwHighDateTime << 32) + ft.dwLowDateTime;
206     minutes /= (LONGLONG)600000000; /* convert to minutes */
207     return minutes;
208 }
209
210 static LONG get_tz_bias(const TIME_ZONE_INFORMATION *tzinfo, DWORD tz_id)
211 {
212     switch (tz_id)
213     {
214     case TIME_ZONE_ID_DAYLIGHT:
215         if (memcmp(&tzinfo->StandardDate, &tzinfo->DaylightDate, sizeof(tzinfo->DaylightDate)) != 0)
216             return tzinfo->DaylightBias;
217         /* fall through */
218
219     case TIME_ZONE_ID_STANDARD:
220         return tzinfo->StandardBias;
221
222     default:
223         trace("unknown time zone id %d\n", tz_id);
224         /* fall through */
225     case TIME_ZONE_ID_UNKNOWN:
226         return 0;
227     }
228 }
229  
230 static void test_GetTimeZoneInformation(void)
231 {
232     char std_name[32], dlt_name[32];
233     TIME_ZONE_INFORMATION tzinfo, tzinfo1;
234     BOOL res;
235     DWORD tz_id;
236     SYSTEMTIME st, current, utc, local;
237     FILETIME l_ft, s_ft;
238     LONGLONG l_time, s_time;
239     LONG diff;
240
241     GetSystemTime(&st);
242     s_time = system_time_to_minutes(&st);
243
244     SetLastError(0xdeadbeef);
245     res = SystemTimeToFileTime(&st, &s_ft);
246     ok(res, "SystemTimeToFileTime error %u\n", GetLastError());
247     SetLastError(0xdeadbeef);
248     res = FileTimeToLocalFileTime(&s_ft, &l_ft);
249     ok(res, "FileTimeToLocalFileTime error %u\n", GetLastError());
250     SetLastError(0xdeadbeef);
251     res = FileTimeToSystemTime(&l_ft, &local);
252     ok(res, "FileTimeToSystemTime error %u\n", GetLastError());
253     l_time = system_time_to_minutes(&local);
254
255     tz_id = GetTimeZoneInformation(&tzinfo);
256     ok(tz_id != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
257
258     trace("tz_id %u (%s)\n", tz_id,
259           tz_id == TIME_ZONE_ID_DAYLIGHT ? "TIME_ZONE_ID_DAYLIGHT" :
260           (tz_id == TIME_ZONE_ID_STANDARD ? "TIME_ZONE_ID_STANDARD" :
261           (tz_id == TIME_ZONE_ID_UNKNOWN ? "TIME_ZONE_ID_UNKNOWN" :
262           "TIME_ZONE_ID_INVALID")));
263
264     WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1, std_name, sizeof(std_name), NULL, NULL);
265     WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1, dlt_name, sizeof(dlt_name), NULL, NULL);
266     trace("bias %d, %s - %s\n", tzinfo.Bias, std_name, dlt_name);
267     trace("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
268         tzinfo.StandardDate.wDay, tzinfo.StandardDate.wMonth,
269         tzinfo.StandardDate.wYear, tzinfo.StandardDate.wDayOfWeek,
270         tzinfo.StandardDate.wHour, tzinfo.StandardDate.wMinute,
271         tzinfo.StandardDate.wSecond, tzinfo.StandardDate.wMilliseconds,
272         tzinfo.StandardBias);
273     trace("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
274         tzinfo.DaylightDate.wDay, tzinfo.DaylightDate.wMonth,
275         tzinfo.DaylightDate.wYear, tzinfo.DaylightDate.wDayOfWeek,
276         tzinfo.DaylightDate.wHour, tzinfo.DaylightDate.wMinute,
277         tzinfo.DaylightDate.wSecond, tzinfo.DaylightDate.wMilliseconds,
278         tzinfo.DaylightBias);
279
280     diff = (LONG)(s_time - l_time);
281     ok(diff == tzinfo.Bias + get_tz_bias(&tzinfo, tz_id),
282        "system/local diff %d != tz bias %d\n",
283        diff, tzinfo.Bias + get_tz_bias(&tzinfo, tz_id));
284
285     ok(SetEnvironmentVariableA("TZ","GMT0") != 0,
286        "SetEnvironmentVariableA failed\n");
287     res =  GetTimeZoneInformation(&tzinfo1);
288     ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
289
290     ok(((tzinfo.Bias == tzinfo1.Bias) && 
291         (tzinfo.StandardBias == tzinfo1.StandardBias) &&
292         (tzinfo.DaylightBias == tzinfo1.DaylightBias)),
293        "Bias influenced by TZ variable\n"); 
294     ok(SetEnvironmentVariableA("TZ",NULL) != 0,
295        "SetEnvironmentVariableA failed\n");
296
297     if (!pSystemTimeToTzSpecificLocalTime)
298     {
299         win_skip("SystemTimeToTzSpecificLocalTime not available\n");
300         return;
301     }
302
303     diff = get_tz_bias(&tzinfo, tz_id);
304
305     utc = st;
306     SetLastError(0xdeadbeef);
307     res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &current);
308     if (!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
309     {
310         win_skip("SystemTimeToTzSpecificLocalTime is not implemented\n");
311         return;
312     }
313
314     ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError());
315     s_time = system_time_to_minutes(&current);
316
317     tzinfo.StandardBias -= 123;
318     tzinfo.DaylightBias += 456;
319
320     res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &local);
321     ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError());
322     l_time = system_time_to_minutes(&local);
323     ok(l_time - s_time == diff - get_tz_bias(&tzinfo, tz_id), "got %d, expected %d\n",
324        (LONG)(l_time - s_time), diff - get_tz_bias(&tzinfo, tz_id));
325
326     /* pretend that there is no transition dates */
327     tzinfo.DaylightDate.wDay = 0;
328     tzinfo.DaylightDate.wMonth = 0;
329     tzinfo.DaylightDate.wYear = 0;
330     tzinfo.StandardDate.wDay = 0;
331     tzinfo.StandardDate.wMonth = 0;
332     tzinfo.StandardDate.wYear = 0;
333
334     res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &local);
335     ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError());
336     l_time = system_time_to_minutes(&local);
337     ok(l_time - s_time == diff, "got %d, expected %d\n",
338        (LONG)(l_time - s_time), diff);
339
340     /* test 23:01, 31st of December date */
341     memset(&tzinfo, 0, sizeof(tzinfo));
342     tzinfo.StandardDate.wMonth = 10;
343     tzinfo.StandardDate.wDay = 5;
344     tzinfo.StandardDate.wHour = 2;
345     tzinfo.StandardDate.wMinute = 0;
346     tzinfo.DaylightDate.wMonth = 4;
347     tzinfo.DaylightDate.wDay = 1;
348     tzinfo.DaylightDate.wHour = 2;
349     tzinfo.Bias = 0;
350     tzinfo.StandardBias = 0;
351     tzinfo.DaylightBias = -60;
352     utc.wYear = 2012;
353     utc.wMonth = 12;
354     utc.wDay = 31;
355     utc.wHour = 23;
356     utc.wMinute = 1;
357     res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &local);
358     ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError());
359     ok(local.wYear==2012 && local.wMonth==12 && local.wDay==31 && local.wHour==23 && local.wMinute==1,
360             "got (%d-%d-%d %02d:%02d), expected (2012-12-31 23:01)\n",
361             local.wYear, local.wMonth, local.wDay, local.wHour, local.wMinute);
362 }
363
364 static void test_FileTimeToSystemTime(void)
365 {
366     FILETIME ft;
367     SYSTEMTIME st;
368     ULONGLONG time = (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
369     BOOL ret;
370
371     ft.dwHighDateTime = 0;
372     ft.dwLowDateTime  = 0;
373     ret = FileTimeToSystemTime(&ft, &st);
374     ok( ret,
375        "FileTimeToSystemTime() failed with Error %d\n",GetLastError());
376     ok(((st.wYear == 1601) && (st.wMonth  == 1) && (st.wDay    == 1) &&
377         (st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 0) &&
378         (st.wMilliseconds == 0)),
379         "Got Year %4d Month %2d Day %2d\n",  st.wYear, st.wMonth, st.wDay);
380
381     ft.dwHighDateTime = (UINT)(time >> 32);
382     ft.dwLowDateTime  = (UINT)time;
383     ret = FileTimeToSystemTime(&ft, &st);
384     ok( ret,
385        "FileTimeToSystemTime() failed with Error %d\n",GetLastError());
386     ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
387         (st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 1) &&
388         (st.wMilliseconds == 0)),
389        "Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
390        st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
391        st.wMilliseconds);
392 }
393
394 static void test_FileTimeToLocalFileTime(void)
395 {
396     FILETIME ft, lft;
397     SYSTEMTIME st;
398     TIME_ZONE_INFORMATION tzinfo;
399     DWORD res =  GetTimeZoneInformation(&tzinfo);
400     ULONGLONG time = (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970 +
401         (LONGLONG)(tzinfo.Bias + 
402             ( res == TIME_ZONE_ID_STANDARD ? tzinfo.StandardBias :
403             ( res == TIME_ZONE_ID_DAYLIGHT ? tzinfo.DaylightBias : 0 ))) *
404              SECSPERMIN *TICKSPERSEC;
405     BOOL ret;
406
407     ok( res != TIME_ZONE_ID_INVALID , "GetTimeZoneInformation failed\n");
408     ft.dwHighDateTime = (UINT)(time >> 32);
409     ft.dwLowDateTime  = (UINT)time;
410     ret = FileTimeToLocalFileTime(&ft, &lft);
411     ok( ret,
412        "FileTimeToLocalFileTime() failed with Error %d\n",GetLastError());
413     FileTimeToSystemTime(&lft, &st);
414     ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
415         (st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 1) &&
416         (st.wMilliseconds == 0)),
417        "Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
418        st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
419        st.wMilliseconds);
420
421     ok(SetEnvironmentVariableA("TZ","GMT") != 0,
422        "SetEnvironmentVariableA failed\n");
423     ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
424     ret = FileTimeToLocalFileTime(&ft, &lft);
425     ok( ret,
426        "FileTimeToLocalFileTime() failed with Error %d\n",GetLastError());
427     FileTimeToSystemTime(&lft, &st);
428     ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
429         (st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 1) &&
430         (st.wMilliseconds == 0)),
431        "Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
432        st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
433        st.wMilliseconds);
434     ok(SetEnvironmentVariableA("TZ",NULL) != 0,
435        "SetEnvironmentVariableA failed\n");
436 }
437
438 typedef struct {
439     int nr;             /* test case number for easier lookup */
440     TIME_ZONE_INFORMATION *ptz; /* ptr to timezone */
441     SYSTEMTIME slt;     /* system/local time to convert */
442     WORD ehour;        /* expected hour */
443 } TZLT2ST_case;
444
445 static void test_TzSpecificLocalTimeToSystemTime(void)
446 {    
447     TIME_ZONE_INFORMATION tzE, tzW, tzS;
448     SYSTEMTIME result;
449     int i, j, year;
450
451     if (!pTzSpecificLocalTimeToSystemTime || !pSystemTimeToTzSpecificLocalTime)
452     {
453         win_skip("TzSpecificLocalTimeToSystemTime or SystemTimeToTzSpecificLocalTime not available\n");
454         return;
455     }
456
457     ZeroMemory( &tzE, sizeof(tzE));
458     ZeroMemory( &tzW, sizeof(tzW));
459     ZeroMemory( &tzS, sizeof(tzS));
460     /* timezone Eastern hemisphere */
461     tzE.Bias=-600;
462     tzE.StandardBias=0;
463     tzE.DaylightBias=-60;
464     tzE.StandardDate.wMonth=10;
465     tzE.StandardDate.wDayOfWeek=0; /* Sunday */
466     tzE.StandardDate.wDay=5;       /* last (Sunday) of the month */
467     tzE.StandardDate.wHour=3;
468     tzE.DaylightDate.wMonth=3;
469     tzE.DaylightDate.wDay=5;
470     tzE.DaylightDate.wHour=2;
471     /* timezone Western hemisphere */
472     tzW.Bias=240;
473     tzW.StandardBias=0;
474     tzW.DaylightBias=-60;
475     tzW.StandardDate.wMonth=10;
476     tzW.StandardDate.wDayOfWeek=0; /* Sunday */
477     tzW.StandardDate.wDay=4;       /* 4th (Sunday) of the month */
478     tzW.StandardDate.wHour=2;
479     tzW.DaylightDate.wMonth=4;
480     tzW.DaylightDate.wDay=1;
481     tzW.DaylightDate.wHour=2;
482     /* timezone Southern hemisphere */
483     tzS.Bias=240;
484     tzS.StandardBias=0;
485     tzS.DaylightBias=-60;
486     tzS.StandardDate.wMonth=4;
487     tzS.StandardDate.wDayOfWeek=0; /*Sunday */
488     tzS.StandardDate.wDay=1;       /* 1st (Sunday) of the month */
489     tzS.StandardDate.wHour=2;
490     tzS.DaylightDate.wMonth=10;
491     tzS.DaylightDate.wDay=4;
492     tzS.DaylightDate.wHour=2;
493     /*tests*/
494         /* TzSpecificLocalTimeToSystemTime */
495     {   TZLT2ST_case cases[] = {
496             /* standard->daylight transition */
497             { 1, &tzE, {2004,3,-1,28,1,0,0,0}, 15 },
498             { 2, &tzE, {2004,3,-1,28,1,59,59,999}, 15},
499             { 3, &tzE, {2004,3,-1,28,2,0,0,0}, 15},
500             /* daylight->standard transition */
501             { 4, &tzE, {2004,10,-1,31,2,0,0,0} , 15 },
502             { 5, &tzE, {2004,10,-1,31,2,59,59,999}, 15 },
503             { 6, &tzE, {2004,10,-1,31,3,0,0,0}, 17 },
504             /* West and with fixed weekday of the month */
505             { 7, &tzW, {2004,4,-1,4,1,0,0,0}, 5},
506             { 8, &tzW, {2004,4,-1,4,1,59,59,999}, 5},
507             { 9, &tzW, {2004,4,-1,4,2,0,0,0}, 5},
508             { 10, &tzW, {2004,10,-1,24,1,0,0,0}, 4},
509             { 11, &tzW, {2004,10,-1,24,1,59,59,999}, 4},
510             { 12, &tzW, {2004,10,-1,24,2,0,0,0 }, 6},
511             /* and now South */
512             { 13, &tzS, {2004,4,-1,4,1,0,0,0}, 4},
513             { 14, &tzS, {2004,4,-1,4,1,59,59,999}, 4},
514             { 15, &tzS, {2004,4,-1,4,2,0,0,0}, 6},
515             { 16, &tzS, {2004,10,-1,24,1,0,0,0}, 5},
516             { 17, &tzS, {2004,10,-1,24,1,59,59,999}, 5},
517             { 18, &tzS, {2004,10,-1,24,2,0,0,0}, 5},
518             {0}
519         };
520     /*  days of transitions to put into the cases array */
521         int yeardays[][6]=
522         {
523               {28,31,4,24,4,24}  /* 1999 */
524             , {26,29,2,22,2,22}  /* 2000 */
525             , {25,28,1,28,1,28}  /* 2001 */
526             , {31,27,7,27,7,27}  /* 2002 */
527             , {30,26,6,26,6,26}  /* 2003 */
528             , {28,31,4,24,4,24}  /* 2004 */
529             , {27,30,3,23,3,23}  /* 2005 */
530             , {26,29,2,22,2,22}  /* 2006 */
531             , {25,28,1,28,1,28}  /* 2007 */
532             , {30,26,6,26,6,26}  /* 2008 */
533             , {29,25,5,25,5,25}  /* 2009 */
534             , {28,31,4,24,4,24}  /* 2010 */
535             , {27,30,3,23,3,23}  /* 2011 */
536             , {25,28,1,28,1,28}  /* 2012 */
537             , {31,27,7,27,7,27}  /* 2013 */
538             , {30,26,6,26,6,26}  /* 2014 */
539             , {29,25,5,25,5,25}  /* 2015 */
540             , {27,30,3,23,3,23}  /* 2016 */
541             , {26,29,2,22,2,22}  /* 2017 */
542             , {25,28,1,28,1,28}  /* 2018 */
543             , {31,27,7,27,7,27}  /* 2019 */
544             ,{0}
545         };
546         for( j=0 , year = 1999; yeardays[j][0] ; j++, year++) {
547             for (i=0; cases[i].nr; i++) {
548                 if(i) cases[i].nr += 18;
549                 cases[i].slt.wYear = year;
550                 cases[i].slt.wDay = yeardays[j][i/3];
551                 pTzSpecificLocalTimeToSystemTime( cases[i].ptz, &(cases[i].slt), &result);
552                 ok( result.wHour == cases[i].ehour,
553                         "Test TzSpecificLocalTimeToSystemTime #%d. Got %4d-%02d-%02d %02d:%02d. Expect hour =  %02d\n", 
554                         cases[i].nr, result.wYear, result.wMonth, result.wDay,
555                         result.wHour, result.wMinute, cases[i].ehour);
556             }
557         }
558     }
559         /* SystemTimeToTzSpecificLocalTime */
560     {   TZLT2ST_case cases[] = {
561             /* standard->daylight transition */
562             { 1, &tzE, {2004,3,-1,27,15,0,0,0}, 1 },
563             { 2, &tzE, {2004,3,-1,27,15,59,59,999}, 1},
564             { 3, &tzE, {2004,3,-1,27,16,0,0,0}, 3},
565             /* daylight->standard transition */
566             { 4,  &tzE, {2004,10,-1,30,15,0,0,0}, 2 },
567             { 5, &tzE, {2004,10,-1,30,15,59,59,999}, 2 },
568             { 6, &tzE, {2004,10,-1,30,16,0,0,0}, 2 },
569             /* West and with fixed weekday of the month */
570             { 7, &tzW, {2004,4,-1,4,5,0,0,0}, 1},
571             { 8, &tzW, {2004,4,-1,4,5,59,59,999}, 1},
572             { 9, &tzW, {2004,4,-1,4,6,0,0,0}, 3},
573             { 10, &tzW, {2004,10,-1,24,4,0,0,0}, 1},
574             { 11, &tzW, {2004,10,-1,24,4,59,59,999}, 1},
575             { 12, &tzW, {2004,10,-1,24,5,0,0,0 }, 1},
576             /* and now South */
577             { 13, &tzS, {2004,4,-1,4,4,0,0,0}, 1},
578             { 14, &tzS, {2004,4,-1,4,4,59,59,999}, 1},
579             { 15, &tzS, {2004,4,-1,4,5,0,0,0}, 1},
580             { 16, &tzS, {2004,10,-1,24,5,0,0,0}, 1},
581             { 17, &tzS, {2004,10,-1,24,5,59,59,999}, 1},
582             { 18, &tzS, {2004,10,-1,24,6,0,0,0}, 3},
583
584             {0}
585         }; 
586     /*  days of transitions to put into the cases array */
587         int yeardays[][6]=
588         {
589               {27,30,4,24,4,24}  /* 1999 */
590             , {25,28,2,22,2,22}  /* 2000 */
591             , {24,27,1,28,1,28}  /* 2001 */
592             , {30,26,7,27,7,27}  /* 2002 */
593             , {29,25,6,26,6,26}  /* 2003 */
594             , {27,30,4,24,4,24}  /* 2004 */
595             , {26,29,3,23,3,23}  /* 2005 */
596             , {25,28,2,22,2,22}  /* 2006 */
597             , {24,27,1,28,1,28}  /* 2007 */
598             , {29,25,6,26,6,26}  /* 2008 */
599             , {28,24,5,25,5,25}  /* 2009 */
600             , {27,30,4,24,4,24}  /* 2010 */
601             , {26,29,3,23,3,23}  /* 2011 */
602             , {24,27,1,28,1,28}  /* 2012 */
603             , {30,26,7,27,7,27}  /* 2013 */
604             , {29,25,6,26,6,26}  /* 2014 */
605             , {28,24,5,25,5,25}  /* 2015 */
606             , {26,29,3,23,3,23}  /* 2016 */
607             , {25,28,2,22,2,22}  /* 2017 */
608             , {24,27,1,28,1,28}  /* 2018 */
609             , {30,26,7,27,7,27}  /* 2019 */
610             , {0}
611         };
612         for( j=0 , year = 1999; yeardays[j][0] ; j++, year++) {
613             for (i=0; cases[i].nr; i++) {
614                 if(i) cases[i].nr += 18;
615                 cases[i].slt.wYear = year;
616                 cases[i].slt.wDay = yeardays[j][i/3];
617                 pSystemTimeToTzSpecificLocalTime( cases[i].ptz, &(cases[i].slt), &result);
618                 ok( result.wHour == cases[i].ehour,
619                         "Test SystemTimeToTzSpecificLocalTime #%d. Got %4d-%02d-%02d %02d:%02d. Expect hour = %02d\n", 
620                         cases[i].nr, result.wYear, result.wMonth, result.wDay,
621                         result.wHour, result.wMinute, cases[i].ehour);
622             }
623         }
624
625     }        
626 }
627
628 static void test_FileTimeToDosDateTime(void)
629 {
630     FILETIME ft = { 0 };
631     WORD fatdate, fattime;
632     BOOL ret;
633
634     if (0)
635     {
636         /* Crashes */
637         FileTimeToDosDateTime(NULL, NULL, NULL);
638     }
639     /* Parameter checking */
640     SetLastError(0xdeadbeef);
641     ret = FileTimeToDosDateTime(&ft, NULL, NULL);
642     ok(!ret, "expected failure\n");
643     ok(GetLastError() == ERROR_INVALID_PARAMETER,
644        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
645
646     SetLastError(0xdeadbeef);
647     ret = FileTimeToDosDateTime(&ft, &fatdate, NULL);
648     ok(!ret, "expected failure\n");
649     ok(GetLastError() == ERROR_INVALID_PARAMETER,
650        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
651
652     SetLastError(0xdeadbeef);
653     ret = FileTimeToDosDateTime(&ft, NULL, &fattime);
654     ok(!ret, "expected failure\n");
655     ok(GetLastError() == ERROR_INVALID_PARAMETER,
656        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
657
658     SetLastError(0xdeadbeef);
659     ret = FileTimeToDosDateTime(&ft, &fatdate, &fattime);
660     ok(!ret, "expected failure\n");
661     ok(GetLastError() == ERROR_INVALID_PARAMETER,
662        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
663 }
664
665 static void test_GetCalendarInfo(void)
666 {
667     char bufferA[20];
668     WCHAR bufferW[20];
669     DWORD val1, val2;
670     int ret;
671
672     if (!pGetCalendarInfoA || !pGetCalendarInfoW)
673     {
674         trace( "GetCalendarInfo missing\n" );
675         return;
676     }
677
678     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
679                              NULL, 0, &val1 );
680     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
681     ok( ret == sizeof(val1), "wrong size %u\n", ret );
682     ok( val1 >= 2000 && val1 < 2100, "wrong value %u\n", val1 );
683
684     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
685                              NULL, 0, &val2 );
686     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
687     ok( ret == sizeof(val2)/sizeof(WCHAR), "wrong size %u\n", ret );
688     ok( val1 == val2, "A/W mismatch %u/%u\n", val1, val2 );
689
690     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, bufferA, sizeof(bufferA), NULL );
691     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
692     ok( ret == 5, "wrong size %u\n", ret );
693     ok( atoi( bufferA ) == val1, "wrong value %s/%u\n", bufferA, val1 );
694
695     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, bufferW, sizeof(bufferW), NULL );
696     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
697     ok( ret == 5, "wrong size %u\n", ret );
698     memset( bufferA, 0x55, sizeof(bufferA) );
699     WideCharToMultiByte( CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL );
700     ok( atoi( bufferA ) == val1, "wrong value %s/%u\n", bufferA, val1 );
701
702     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
703                              NULL, 0, NULL );
704     ok( !ret, "GetCalendarInfoA succeeded\n" );
705     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
706
707     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, NULL, 0, NULL );
708     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
709     ok( ret == 5, "wrong size %u\n", ret );
710
711     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
712                              NULL, 0, NULL );
713     ok( !ret, "GetCalendarInfoW succeeded\n" );
714     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
715
716     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, NULL, 0, NULL );
717     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
718     ok( ret == 5, "wrong size %u\n", ret );
719 }
720
721 START_TEST(time)
722 {
723     HMODULE hKernel = GetModuleHandle("kernel32");
724     pTzSpecificLocalTimeToSystemTime = (void *)GetProcAddress(hKernel, "TzSpecificLocalTimeToSystemTime");
725     pSystemTimeToTzSpecificLocalTime = (void *)GetProcAddress( hKernel, "SystemTimeToTzSpecificLocalTime");
726     pGetCalendarInfoA = (void *)GetProcAddress(hKernel, "GetCalendarInfoA");
727     pGetCalendarInfoW = (void *)GetProcAddress(hKernel, "GetCalendarInfoW");
728
729     test_conversions();
730     test_invalid_arg();
731     test_GetTimeZoneInformation();
732     test_FileTimeToSystemTime();
733     test_FileTimeToLocalFileTime();
734     test_TzSpecificLocalTimeToSystemTime();
735     test_FileTimeToDosDateTime();
736     test_GetCalendarInfo();
737 }