kernel32: There is no need to zero-fill the FormatMessage() temporary buffer.
[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
341 static void test_FileTimeToSystemTime(void)
342 {
343     FILETIME ft;
344     SYSTEMTIME st;
345     ULONGLONG time = (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
346     BOOL ret;
347
348     ft.dwHighDateTime = 0;
349     ft.dwLowDateTime  = 0;
350     ret = FileTimeToSystemTime(&ft, &st);
351     ok( ret,
352        "FileTimeToSystemTime() failed with Error %d\n",GetLastError());
353     ok(((st.wYear == 1601) && (st.wMonth  == 1) && (st.wDay    == 1) &&
354         (st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 0) &&
355         (st.wMilliseconds == 0)),
356         "Got Year %4d Month %2d Day %2d\n",  st.wYear, st.wMonth, st.wDay);
357
358     ft.dwHighDateTime = (UINT)(time >> 32);
359     ft.dwLowDateTime  = (UINT)time;
360     ret = FileTimeToSystemTime(&ft, &st);
361     ok( ret,
362        "FileTimeToSystemTime() failed with Error %d\n",GetLastError());
363     ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
364         (st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 1) &&
365         (st.wMilliseconds == 0)),
366        "Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
367        st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
368        st.wMilliseconds);
369 }
370
371 static void test_FileTimeToLocalFileTime(void)
372 {
373     FILETIME ft, lft;
374     SYSTEMTIME st;
375     TIME_ZONE_INFORMATION tzinfo;
376     DWORD res =  GetTimeZoneInformation(&tzinfo);
377     ULONGLONG time = (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970 +
378         (LONGLONG)(tzinfo.Bias + 
379             ( res == TIME_ZONE_ID_STANDARD ? tzinfo.StandardBias :
380             ( res == TIME_ZONE_ID_DAYLIGHT ? tzinfo.DaylightBias : 0 ))) *
381              SECSPERMIN *TICKSPERSEC;
382     BOOL ret;
383
384     ok( res != TIME_ZONE_ID_INVALID , "GetTimeZoneInformation failed\n");
385     ft.dwHighDateTime = (UINT)(time >> 32);
386     ft.dwLowDateTime  = (UINT)time;
387     ret = FileTimeToLocalFileTime(&ft, &lft);
388     ok( ret,
389        "FileTimeToLocalFileTime() failed with Error %d\n",GetLastError());
390     FileTimeToSystemTime(&lft, &st);
391     ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
392         (st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 1) &&
393         (st.wMilliseconds == 0)),
394        "Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
395        st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
396        st.wMilliseconds);
397
398     ok(SetEnvironmentVariableA("TZ","GMT") != 0,
399        "SetEnvironmentVariableA failed\n");
400     ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
401     ret = FileTimeToLocalFileTime(&ft, &lft);
402     ok( ret,
403        "FileTimeToLocalFileTime() failed with Error %d\n",GetLastError());
404     FileTimeToSystemTime(&lft, &st);
405     ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
406         (st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 1) &&
407         (st.wMilliseconds == 0)),
408        "Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
409        st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
410        st.wMilliseconds);
411     ok(SetEnvironmentVariableA("TZ",NULL) != 0,
412        "SetEnvironmentVariableA failed\n");
413 }
414
415 typedef struct {
416     int nr;             /* test case number for easier lookup */
417     TIME_ZONE_INFORMATION *ptz; /* ptr to timezone */
418     SYSTEMTIME slt;     /* system/local time to convert */
419     WORD ehour;        /* expected hour */
420 } TZLT2ST_case;
421
422 static void test_TzSpecificLocalTimeToSystemTime(void)
423 {    
424     TIME_ZONE_INFORMATION tzE, tzW, tzS;
425     SYSTEMTIME result;
426     int i, j, year;
427
428     if (!pTzSpecificLocalTimeToSystemTime || !pSystemTimeToTzSpecificLocalTime)
429     {
430         win_skip("TzSpecificLocalTimeToSystemTime or SystemTimeToTzSpecificLocalTime not available\n");
431         return;
432     }
433
434     ZeroMemory( &tzE, sizeof(tzE));
435     ZeroMemory( &tzW, sizeof(tzW));
436     ZeroMemory( &tzS, sizeof(tzS));
437     /* timezone Eastern hemisphere */
438     tzE.Bias=-600;
439     tzE.StandardBias=0;
440     tzE.DaylightBias=-60;
441     tzE.StandardDate.wMonth=10;
442     tzE.StandardDate.wDayOfWeek=0; /* Sunday */
443     tzE.StandardDate.wDay=5;       /* last (Sunday) of the month */
444     tzE.StandardDate.wHour=3;
445     tzE.DaylightDate.wMonth=3;
446     tzE.DaylightDate.wDay=5;
447     tzE.DaylightDate.wHour=2;
448     /* timezone Western hemisphere */
449     tzW.Bias=240;
450     tzW.StandardBias=0;
451     tzW.DaylightBias=-60;
452     tzW.StandardDate.wMonth=10;
453     tzW.StandardDate.wDayOfWeek=0; /* Sunday */
454     tzW.StandardDate.wDay=4;       /* 4th (Sunday) of the month */
455     tzW.StandardDate.wHour=2;
456     tzW.DaylightDate.wMonth=4;
457     tzW.DaylightDate.wDay=1;
458     tzW.DaylightDate.wHour=2;
459     /* timezone Southern hemisphere */
460     tzS.Bias=240;
461     tzS.StandardBias=0;
462     tzS.DaylightBias=-60;
463     tzS.StandardDate.wMonth=4;
464     tzS.StandardDate.wDayOfWeek=0; /*Sunday */
465     tzS.StandardDate.wDay=1;       /* 1st (Sunday) of the month */
466     tzS.StandardDate.wHour=2;
467     tzS.DaylightDate.wMonth=10;
468     tzS.DaylightDate.wDay=4;
469     tzS.DaylightDate.wHour=2;
470     /*tests*/
471         /* TzSpecificLocalTimeToSystemTime */
472     {   TZLT2ST_case cases[] = {
473             /* standard->daylight transition */
474             { 1, &tzE, {2004,3,-1,28,1,0,0,0}, 15 },
475             { 2, &tzE, {2004,3,-1,28,1,59,59,999}, 15},
476             { 3, &tzE, {2004,3,-1,28,2,0,0,0}, 15},
477             /* daylight->standard transition */
478             { 4, &tzE, {2004,10,-1,31,2,0,0,0} , 15 },
479             { 5, &tzE, {2004,10,-1,31,2,59,59,999}, 15 },
480             { 6, &tzE, {2004,10,-1,31,3,0,0,0}, 17 },
481             /* West and with fixed weekday of the month */
482             { 7, &tzW, {2004,4,-1,4,1,0,0,0}, 5},
483             { 8, &tzW, {2004,4,-1,4,1,59,59,999}, 5},
484             { 9, &tzW, {2004,4,-1,4,2,0,0,0}, 5},
485             { 10, &tzW, {2004,10,-1,24,1,0,0,0}, 4},
486             { 11, &tzW, {2004,10,-1,24,1,59,59,999}, 4},
487             { 12, &tzW, {2004,10,-1,24,2,0,0,0 }, 6},
488             /* and now South */
489             { 13, &tzS, {2004,4,-1,4,1,0,0,0}, 4},
490             { 14, &tzS, {2004,4,-1,4,1,59,59,999}, 4},
491             { 15, &tzS, {2004,4,-1,4,2,0,0,0}, 6},
492             { 16, &tzS, {2004,10,-1,24,1,0,0,0}, 5},
493             { 17, &tzS, {2004,10,-1,24,1,59,59,999}, 5},
494             { 18, &tzS, {2004,10,-1,24,2,0,0,0}, 5},
495             {0}
496         };
497     /*  days of transitions to put into the cases array */
498         int yeardays[][6]=
499         {
500               {28,31,4,24,4,24}  /* 1999 */
501             , {26,29,2,22,2,22}  /* 2000 */
502             , {25,28,1,28,1,28}  /* 2001 */
503             , {31,27,7,27,7,27}  /* 2002 */
504             , {30,26,6,26,6,26}  /* 2003 */
505             , {28,31,4,24,4,24}  /* 2004 */
506             , {27,30,3,23,3,23}  /* 2005 */
507             , {26,29,2,22,2,22}  /* 2006 */
508             , {25,28,1,28,1,28}  /* 2007 */
509             , {30,26,6,26,6,26}  /* 2008 */
510             , {29,25,5,25,5,25}  /* 2009 */
511             , {28,31,4,24,4,24}  /* 2010 */
512             , {27,30,3,23,3,23}  /* 2011 */
513             , {25,28,1,28,1,28}  /* 2012 */
514             , {31,27,7,27,7,27}  /* 2013 */
515             , {30,26,6,26,6,26}  /* 2014 */
516             , {29,25,5,25,5,25}  /* 2015 */
517             , {27,30,3,23,3,23}  /* 2016 */
518             , {26,29,2,22,2,22}  /* 2017 */
519             , {25,28,1,28,1,28}  /* 2018 */
520             , {31,27,7,27,7,27}  /* 2019 */
521             ,{0}
522         };
523         for( j=0 , year = 1999; yeardays[j][0] ; j++, year++) {
524             for (i=0; cases[i].nr; i++) {
525                 if(i) cases[i].nr += 18;
526                 cases[i].slt.wYear = year;
527                 cases[i].slt.wDay = yeardays[j][i/3];
528                 pTzSpecificLocalTimeToSystemTime( cases[i].ptz, &(cases[i].slt), &result);
529                 ok( result.wHour == cases[i].ehour,
530                         "Test TzSpecificLocalTimeToSystemTime #%d. Got %4d-%02d-%02d %02d:%02d. Expect hour =  %02d\n", 
531                         cases[i].nr, result.wYear, result.wMonth, result.wDay,
532                         result.wHour, result.wMinute, cases[i].ehour);
533             }
534         }
535     }
536         /* SystemTimeToTzSpecificLocalTime */
537     {   TZLT2ST_case cases[] = {
538             /* standard->daylight transition */
539             { 1, &tzE, {2004,3,-1,27,15,0,0,0}, 1 },
540             { 2, &tzE, {2004,3,-1,27,15,59,59,999}, 1},
541             { 3, &tzE, {2004,3,-1,27,16,0,0,0}, 3},
542             /* daylight->standard transition */
543             { 4,  &tzE, {2004,10,-1,30,15,0,0,0}, 2 },
544             { 5, &tzE, {2004,10,-1,30,15,59,59,999}, 2 },
545             { 6, &tzE, {2004,10,-1,30,16,0,0,0}, 2 },
546             /* West and with fixed weekday of the month */
547             { 7, &tzW, {2004,4,-1,4,5,0,0,0}, 1},
548             { 8, &tzW, {2004,4,-1,4,5,59,59,999}, 1},
549             { 9, &tzW, {2004,4,-1,4,6,0,0,0}, 3},
550             { 10, &tzW, {2004,10,-1,24,4,0,0,0}, 1},
551             { 11, &tzW, {2004,10,-1,24,4,59,59,999}, 1},
552             { 12, &tzW, {2004,10,-1,24,5,0,0,0 }, 1},
553             /* and now South */
554             { 13, &tzS, {2004,4,-1,4,4,0,0,0}, 1},
555             { 14, &tzS, {2004,4,-1,4,4,59,59,999}, 1},
556             { 15, &tzS, {2004,4,-1,4,5,0,0,0}, 1},
557             { 16, &tzS, {2004,10,-1,24,5,0,0,0}, 1},
558             { 17, &tzS, {2004,10,-1,24,5,59,59,999}, 1},
559             { 18, &tzS, {2004,10,-1,24,6,0,0,0}, 3},
560
561             {0}
562         }; 
563     /*  days of transitions to put into the cases array */
564         int yeardays[][6]=
565         {
566               {27,30,4,24,4,24}  /* 1999 */
567             , {25,28,2,22,2,22}  /* 2000 */
568             , {24,27,1,28,1,28}  /* 2001 */
569             , {30,26,7,27,7,27}  /* 2002 */
570             , {29,25,6,26,6,26}  /* 2003 */
571             , {27,30,4,24,4,24}  /* 2004 */
572             , {26,29,3,23,3,23}  /* 2005 */
573             , {25,28,2,22,2,22}  /* 2006 */
574             , {24,27,1,28,1,28}  /* 2007 */
575             , {29,25,6,26,6,26}  /* 2008 */
576             , {28,24,5,25,5,25}  /* 2009 */
577             , {27,30,4,24,4,24}  /* 2010 */
578             , {26,29,3,23,3,23}  /* 2011 */
579             , {24,27,1,28,1,28}  /* 2012 */
580             , {30,26,7,27,7,27}  /* 2013 */
581             , {29,25,6,26,6,26}  /* 2014 */
582             , {28,24,5,25,5,25}  /* 2015 */
583             , {26,29,3,23,3,23}  /* 2016 */
584             , {25,28,2,22,2,22}  /* 2017 */
585             , {24,27,1,28,1,28}  /* 2018 */
586             , {30,26,7,27,7,27}  /* 2019 */
587             , {0}
588         };
589         for( j=0 , year = 1999; yeardays[j][0] ; j++, year++) {
590             for (i=0; cases[i].nr; i++) {
591                 if(i) cases[i].nr += 18;
592                 cases[i].slt.wYear = year;
593                 cases[i].slt.wDay = yeardays[j][i/3];
594                 pSystemTimeToTzSpecificLocalTime( cases[i].ptz, &(cases[i].slt), &result);
595                 ok( result.wHour == cases[i].ehour,
596                         "Test SystemTimeToTzSpecificLocalTime #%d. Got %4d-%02d-%02d %02d:%02d. Expect hour = %02d\n", 
597                         cases[i].nr, result.wYear, result.wMonth, result.wDay,
598                         result.wHour, result.wMinute, cases[i].ehour);
599             }
600         }
601
602     }        
603 }
604
605 static void test_FileTimeToDosDateTime(void)
606 {
607     FILETIME ft = { 0 };
608     WORD fatdate, fattime;
609     BOOL ret;
610
611     if (0)
612     {
613         /* Crashes */
614         FileTimeToDosDateTime(NULL, NULL, NULL);
615     }
616     /* Parameter checking */
617     SetLastError(0xdeadbeef);
618     ret = FileTimeToDosDateTime(&ft, NULL, NULL);
619     ok(!ret, "expected failure\n");
620     ok(GetLastError() == ERROR_INVALID_PARAMETER,
621        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
622
623     SetLastError(0xdeadbeef);
624     ret = FileTimeToDosDateTime(&ft, &fatdate, NULL);
625     ok(!ret, "expected failure\n");
626     ok(GetLastError() == ERROR_INVALID_PARAMETER,
627        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
628
629     SetLastError(0xdeadbeef);
630     ret = FileTimeToDosDateTime(&ft, NULL, &fattime);
631     ok(!ret, "expected failure\n");
632     ok(GetLastError() == ERROR_INVALID_PARAMETER,
633        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
634
635     SetLastError(0xdeadbeef);
636     ret = FileTimeToDosDateTime(&ft, &fatdate, &fattime);
637     ok(!ret, "expected failure\n");
638     ok(GetLastError() == ERROR_INVALID_PARAMETER,
639        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
640 }
641
642 static void test_GetCalendarInfo(void)
643 {
644     char bufferA[20];
645     WCHAR bufferW[20];
646     DWORD val1, val2;
647     int ret;
648
649     if (!pGetCalendarInfoA || !pGetCalendarInfoW)
650     {
651         trace( "GetCalendarInfo missing\n" );
652         return;
653     }
654
655     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
656                              NULL, 0, &val1 );
657     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
658     ok( ret == sizeof(val1), "wrong size %u\n", ret );
659     ok( val1 >= 2000 && val1 < 2100, "wrong value %u\n", val1 );
660
661     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
662                              NULL, 0, &val2 );
663     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
664     ok( ret == sizeof(val2)/sizeof(WCHAR), "wrong size %u\n", ret );
665     ok( val1 == val2, "A/W mismatch %u/%u\n", val1, val2 );
666
667     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, bufferA, sizeof(bufferA), NULL );
668     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
669     ok( ret == 5, "wrong size %u\n", ret );
670     ok( atoi( bufferA ) == val1, "wrong value %s/%u\n", bufferA, val1 );
671
672     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, bufferW, sizeof(bufferW), NULL );
673     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
674     ok( ret == 5, "wrong size %u\n", ret );
675     memset( bufferA, 0x55, sizeof(bufferA) );
676     WideCharToMultiByte( CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL );
677     ok( atoi( bufferA ) == val1, "wrong value %s/%u\n", bufferA, val1 );
678
679     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
680                              NULL, 0, NULL );
681     ok( !ret, "GetCalendarInfoA succeeded\n" );
682     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
683
684     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, NULL, 0, NULL );
685     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
686     ok( ret == 5, "wrong size %u\n", ret );
687
688     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
689                              NULL, 0, NULL );
690     ok( !ret, "GetCalendarInfoW succeeded\n" );
691     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
692
693     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, NULL, 0, NULL );
694     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
695     ok( ret == 5, "wrong size %u\n", ret );
696 }
697
698 START_TEST(time)
699 {
700     HMODULE hKernel = GetModuleHandle("kernel32");
701     pTzSpecificLocalTimeToSystemTime = (void *)GetProcAddress(hKernel, "TzSpecificLocalTimeToSystemTime");
702     pSystemTimeToTzSpecificLocalTime = (void *)GetProcAddress( hKernel, "SystemTimeToTzSpecificLocalTime");
703     pGetCalendarInfoA = (void *)GetProcAddress(hKernel, "GetCalendarInfoA");
704     pGetCalendarInfoW = (void *)GetProcAddress(hKernel, "GetCalendarInfoW");
705
706     test_conversions();
707     test_invalid_arg();
708     test_GetTimeZoneInformation();
709     test_FileTimeToSystemTime();
710     test_FileTimeToLocalFileTime();
711     test_TzSpecificLocalTimeToSystemTime();
712     test_FileTimeToDosDateTime();
713     test_GetCalendarInfo();
714 }