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 #include "winternl.h"
26 
27 static BOOL (WINAPI *pTzSpecificLocalTimeToSystemTime)(LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME);
28 static BOOL (WINAPI *pSystemTimeToTzSpecificLocalTime)(LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME);
29 static BOOL (WINAPI *pGetSystemTimes)(LPFILETIME, LPFILETIME, LPFILETIME);
30 static int (WINAPI *pGetCalendarInfoA)(LCID,CALID,CALTYPE,LPSTR,int,LPDWORD);
31 static int (WINAPI *pGetCalendarInfoW)(LCID,CALID,CALTYPE,LPWSTR,int,LPDWORD);
32 static DWORD (WINAPI *pGetDynamicTimeZoneInformation)(DYNAMIC_TIME_ZONE_INFORMATION*);
33 static void (WINAPI *pGetSystemTimePreciseAsFileTime)(LPFILETIME);
34 static BOOL (WINAPI *pGetTimeZoneInformationForYear)(USHORT, PDYNAMIC_TIME_ZONE_INFORMATION, LPTIME_ZONE_INFORMATION);
35 
36 #define SECSPERMIN         60
37 #define SECSPERDAY        86400
38 /* 1601 to 1970 is 369 years plus 89 leap days */
39 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
40 #define TICKSPERSEC       10000000
41 #define TICKSPERMSEC      10000
42 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
43 
44 
45 #define NEWYEAR_1980_HI 0x01a8e79f
46 #define NEWYEAR_1980_LO 0xe1d58000
47 
48 #define MAYDAY_2002_HI 0x01c1f107
49 #define MAYDAY_2002_LO 0xb82b6000
50 
51 #define ATIME_HI  0x1c2349b
52 #define ATIME_LOW 0x580716b0
53 
54 #define LOCAL_ATIME_HI  0x01c23471
55 #define LOCAL_ATIME_LOW 0x6f310eb0
56 
57 #define DOS_DATE(y,m,d) ( (((y)-1980)<<9) | ((m)<<5) | (d) )
58 #define DOS_TIME(h,m,s) ( ((h)<<11) | ((m)<<5) | ((s)>>1) )
59 
60 
61 #define SETUP_1980(st) \
62     (st).wYear = 1980; \
63     (st).wMonth = 1; \
64     (st).wDay = 1; \
65     (st).wHour = 0; \
66     (st).wMinute = 0; \
67     (st).wSecond = 0; \
68     (st).wMilliseconds = 0;
69 
70 #define SETUP_2002(st) \
71     (st).wYear = 2002; \
72     (st).wMonth = 5; \
73     (st).wDay = 1; \
74     (st).wHour = 12; \
75     (st).wMinute = 0; \
76     (st).wSecond = 0; \
77     (st).wMilliseconds = 0;
78 
79 #define SETUP_ATIME(st) \
80     (st).wYear = 2002; \
81     (st).wMonth = 7; \
82     (st).wDay = 26; \
83     (st).wHour = 11; \
84     (st).wMinute = 55; \
85     (st).wSecond = 32; \
86     (st).wMilliseconds = 123;
87 
88 #define SETUP_ZEROTIME(st) \
89     (st).wYear = 1601; \
90     (st).wMonth = 1; \
91     (st).wDay = 1; \
92     (st).wHour = 0; \
93     (st).wMinute = 0; \
94     (st).wSecond = 0; \
95     (st).wMilliseconds = 0;
96 
97 #define SETUP_EARLY(st) \
98     (st).wYear = 1600; \
99     (st).wMonth = 12; \
100     (st).wDay = 31; \
101     (st).wHour = 23; \
102     (st).wMinute = 59; \
103     (st).wSecond = 59; \
104     (st).wMilliseconds = 999;
105 
106 
107 static void test_conversions(void)
108 {
109     FILETIME ft;
110     SYSTEMTIME st;
111 
112     memset(&ft,0,sizeof ft);
113 
114     SetLastError(0xdeadbeef);
115     SETUP_EARLY(st)
116     ok (!SystemTimeToFileTime(&st, &ft), "Conversion succeeded EARLY\n");
117     ok (GetLastError() == ERROR_INVALID_PARAMETER ||
118         GetLastError() == 0xdeadbeef, /* win9x */
119         "EARLY should be INVALID\n");
120 
121     SETUP_ZEROTIME(st)
122     ok (SystemTimeToFileTime(&st, &ft), "Conversion failed ZERO_TIME\n");
123     ok( (!((ft.dwHighDateTime != 0) || (ft.dwLowDateTime != 0))),
124         "Wrong time for ATIME: %08x %08x (correct %08x %08x)\n",
125         ft.dwLowDateTime, ft.dwHighDateTime, 0, 0);
126 
127 
128     SETUP_ATIME(st)
129     ok (SystemTimeToFileTime(&st,&ft), "Conversion Failed ATIME\n");
130     ok( (!((ft.dwHighDateTime != ATIME_HI) || (ft.dwLowDateTime!=ATIME_LOW))),
131         "Wrong time for ATIME: %08x %08x (correct %08x %08x)\n",
132         ft.dwLowDateTime, ft.dwHighDateTime, ATIME_LOW, ATIME_HI);
133 
134 
135     SETUP_2002(st)
136     ok (SystemTimeToFileTime(&st, &ft), "Conversion failed 2002\n");
137 
138     ok( (!((ft.dwHighDateTime != MAYDAY_2002_HI) ||
139          (ft.dwLowDateTime!=MAYDAY_2002_LO))),
140         "Wrong time for 2002 %08x %08x (correct %08x %08x)\n", ft.dwLowDateTime,
141         ft.dwHighDateTime, MAYDAY_2002_LO, MAYDAY_2002_HI);
142 
143 
144     SETUP_1980(st)
145     ok((SystemTimeToFileTime(&st, &ft)), "Conversion failed 1980\n");
146 
147     ok( (!((ft.dwHighDateTime!=NEWYEAR_1980_HI) ||
148         (ft.dwLowDateTime!=NEWYEAR_1980_LO))) ,
149         "Wrong time for 1980 %08x %08x (correct %08x %08x)\n", ft.dwLowDateTime,
150          ft.dwHighDateTime, NEWYEAR_1980_LO,NEWYEAR_1980_HI  );
151 
152     ok(DosDateTimeToFileTime(DOS_DATE(1980,1,1),DOS_TIME(0,0,0),&ft),
153         "DosDateTimeToFileTime() failed\n");
154 
155     ok( (!((ft.dwHighDateTime!=NEWYEAR_1980_HI) ||
156          (ft.dwLowDateTime!=NEWYEAR_1980_LO))),
157         "Wrong time DosDateTimeToFileTime %08x %08x (correct %08x %08x)\n",
158         ft.dwHighDateTime, ft.dwLowDateTime, NEWYEAR_1980_HI, NEWYEAR_1980_LO);
159 
160 }
161 
162 static void test_invalid_arg(void)
163 {
164     FILETIME ft;
165     SYSTEMTIME st;
166 
167 
168     /* Invalid argument checks */
169 
170     memset(&ft,0,sizeof ft);
171     ok( DosDateTimeToFileTime(DOS_DATE(1980,1,1),DOS_TIME(0,0,0),&ft), /* this is 1 Jan 1980 00:00:00 */
172         "DosDateTimeToFileTime() failed\n");
173 
174     ok( (ft.dwHighDateTime==NEWYEAR_1980_HI) && (ft.dwLowDateTime==NEWYEAR_1980_LO),
175         "filetime for 1/1/80 00:00:00 was %08x %08x\n", ft.dwHighDateTime, ft.dwLowDateTime);
176 
177     /* now check SystemTimeToFileTime */
178     memset(&ft,0,sizeof ft);
179 
180 
181     /* try with a bad month */
182     SETUP_1980(st)
183     st.wMonth = 0;
184 
185     ok( !SystemTimeToFileTime(&st, &ft), "bad month\n");
186 
187     /* with a bad hour */
188     SETUP_1980(st)
189     st.wHour = 24;
190 
191     ok( !SystemTimeToFileTime(&st, &ft), "bad hour\n");
192 
193     /* with a bad minute */
194     SETUP_1980(st)
195     st.wMinute = 60;
196 
197     ok( !SystemTimeToFileTime(&st, &ft), "bad minute\n");
198 }
199 
200 static LONGLONG system_time_to_minutes(const SYSTEMTIME *st)
201 {
202     BOOL ret;
203     FILETIME ft;
204     LONGLONG minutes;
205 
206     SetLastError(0xdeadbeef);
207     ret = SystemTimeToFileTime(st, &ft);
208     ok(ret, "SystemTimeToFileTime error %u\n", GetLastError());
209 
210     minutes = ((LONGLONG)ft.dwHighDateTime << 32) + ft.dwLowDateTime;
211     minutes /= (LONGLONG)600000000; /* convert to minutes */
212     return minutes;
213 }
214 
215 static LONG get_tz_bias(const TIME_ZONE_INFORMATION *tzinfo, DWORD tz_id)
216 {
217     switch (tz_id)
218     {
219     case TIME_ZONE_ID_DAYLIGHT:
220         if (memcmp(&tzinfo->StandardDate, &tzinfo->DaylightDate, sizeof(tzinfo->DaylightDate)) != 0)
221             return tzinfo->DaylightBias;
222         /* fall through */
223 
224     case TIME_ZONE_ID_STANDARD:
225         return tzinfo->StandardBias;
226 
227     default:
228         trace("unknown time zone id %d\n", tz_id);
229         /* fall through */
230     case TIME_ZONE_ID_UNKNOWN:
231         return 0;
232     }
233 }
234 
235 static void test_GetTimeZoneInformation(void)
236 {
237     char std_name[32], dlt_name[32];
238     TIME_ZONE_INFORMATION tzinfo, tzinfo1;
239     BOOL res;
240     DWORD tz_id;
241     SYSTEMTIME st, current, utc, local;
242     FILETIME l_ft, s_ft;
243     LONGLONG l_time, s_time;
244     LONG diff;
245 
246     GetSystemTime(&st);
247     s_time = system_time_to_minutes(&st);
248 
249     SetLastError(0xdeadbeef);
250     res = SystemTimeToFileTime(&st, &s_ft);
251     ok(res, "SystemTimeToFileTime error %u\n", GetLastError());
252     SetLastError(0xdeadbeef);
253     res = FileTimeToLocalFileTime(&s_ft, &l_ft);
254     ok(res, "FileTimeToLocalFileTime error %u\n", GetLastError());
255     SetLastError(0xdeadbeef);
256     res = FileTimeToSystemTime(&l_ft, &local);
257     ok(res, "FileTimeToSystemTime error %u\n", GetLastError());
258     l_time = system_time_to_minutes(&local);
259 
260     tz_id = GetTimeZoneInformation(&tzinfo);
261     ok(tz_id != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
262 
263     trace("tz_id %u (%s)\n", tz_id,
264           tz_id == TIME_ZONE_ID_DAYLIGHT ? "TIME_ZONE_ID_DAYLIGHT" :
265           (tz_id == TIME_ZONE_ID_STANDARD ? "TIME_ZONE_ID_STANDARD" :
266           (tz_id == TIME_ZONE_ID_UNKNOWN ? "TIME_ZONE_ID_UNKNOWN" :
267           "TIME_ZONE_ID_INVALID")));
268 
269     WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1, std_name, sizeof(std_name), NULL, NULL);
270     WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1, dlt_name, sizeof(dlt_name), NULL, NULL);
271     trace("bias %d, %s - %s\n", tzinfo.Bias, std_name, dlt_name);
272     trace("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
273         tzinfo.StandardDate.wDay, tzinfo.StandardDate.wMonth,
274         tzinfo.StandardDate.wYear, tzinfo.StandardDate.wDayOfWeek,
275         tzinfo.StandardDate.wHour, tzinfo.StandardDate.wMinute,
276         tzinfo.StandardDate.wSecond, tzinfo.StandardDate.wMilliseconds,
277         tzinfo.StandardBias);
278     trace("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
279         tzinfo.DaylightDate.wDay, tzinfo.DaylightDate.wMonth,
280         tzinfo.DaylightDate.wYear, tzinfo.DaylightDate.wDayOfWeek,
281         tzinfo.DaylightDate.wHour, tzinfo.DaylightDate.wMinute,
282         tzinfo.DaylightDate.wSecond, tzinfo.DaylightDate.wMilliseconds,
283         tzinfo.DaylightBias);
284 
285     diff = (LONG)(s_time - l_time);
286     ok(diff == tzinfo.Bias + get_tz_bias(&tzinfo, tz_id),
287        "system/local diff %d != tz bias %d\n",
288        diff, tzinfo.Bias + get_tz_bias(&tzinfo, tz_id));
289 
290     ok(SetEnvironmentVariableA("TZ","GMT0") != 0,
291        "SetEnvironmentVariableA failed\n");
292     res =  GetTimeZoneInformation(&tzinfo1);
293     ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
294 
295     ok(((tzinfo.Bias == tzinfo1.Bias) &&
296 	(tzinfo.StandardBias == tzinfo1.StandardBias) &&
297 	(tzinfo.DaylightBias == tzinfo1.DaylightBias)),
298        "Bias influenced by TZ variable\n");
299     ok(SetEnvironmentVariableA("TZ",NULL) != 0,
300        "SetEnvironmentVariableA failed\n");
301 
302     if (!pSystemTimeToTzSpecificLocalTime)
303     {
304         win_skip("SystemTimeToTzSpecificLocalTime not available\n");
305         return;
306     }
307 
308     diff = get_tz_bias(&tzinfo, tz_id);
309 
310     utc = st;
311     SetLastError(0xdeadbeef);
312     res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &current);
313     if (!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
314     {
315         win_skip("SystemTimeToTzSpecificLocalTime is not implemented\n");
316         return;
317     }
318 
319     ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError());
320     s_time = system_time_to_minutes(&current);
321 
322     tzinfo.StandardBias -= 123;
323     tzinfo.DaylightBias += 456;
324 
325     res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &local);
326     ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError());
327     l_time = system_time_to_minutes(&local);
328     ok(l_time - s_time == diff - get_tz_bias(&tzinfo, tz_id), "got %d, expected %d\n",
329        (LONG)(l_time - s_time), diff - get_tz_bias(&tzinfo, tz_id));
330 
331     /* pretend that there is no transition dates */
332     tzinfo.DaylightDate.wDay = 0;
333     tzinfo.DaylightDate.wMonth = 0;
334     tzinfo.DaylightDate.wYear = 0;
335     tzinfo.StandardDate.wDay = 0;
336     tzinfo.StandardDate.wMonth = 0;
337     tzinfo.StandardDate.wYear = 0;
338 
339     res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &local);
340     ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError());
341     l_time = system_time_to_minutes(&local);
342     ok(l_time - s_time == diff, "got %d, expected %d\n",
343        (LONG)(l_time - s_time), diff);
344 
345     /* test 23:01, 31st of December date */
346     memset(&tzinfo, 0, sizeof(tzinfo));
347     tzinfo.StandardDate.wMonth = 10;
348     tzinfo.StandardDate.wDay = 5;
349     tzinfo.StandardDate.wHour = 2;
350     tzinfo.StandardDate.wMinute = 0;
351     tzinfo.DaylightDate.wMonth = 4;
352     tzinfo.DaylightDate.wDay = 1;
353     tzinfo.DaylightDate.wHour = 2;
354     tzinfo.Bias = 0;
355     tzinfo.StandardBias = 0;
356     tzinfo.DaylightBias = -60;
357     utc.wYear = 2012;
358     utc.wMonth = 12;
359     utc.wDay = 31;
360     utc.wHour = 23;
361     utc.wMinute = 1;
362     res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &local);
363     ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError());
364     ok(local.wYear==2012 && local.wMonth==12 && local.wDay==31 && local.wHour==23 && local.wMinute==1,
365             "got (%d-%d-%d %02d:%02d), expected (2012-12-31 23:01)\n",
366             local.wYear, local.wMonth, local.wDay, local.wHour, local.wMinute);
367 }
368 
369 static void test_FileTimeToSystemTime(void)
370 {
371     FILETIME ft;
372     SYSTEMTIME st;
373     ULONGLONG time = (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
374     BOOL ret;
375 
376     ft.dwHighDateTime = 0;
377     ft.dwLowDateTime  = 0;
378     ret = FileTimeToSystemTime(&ft, &st);
379     ok( ret,
380        "FileTimeToSystemTime() failed with Error %d\n",GetLastError());
381     ok(((st.wYear == 1601) && (st.wMonth  == 1) && (st.wDay    == 1) &&
382 	(st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 0) &&
383 	(st.wMilliseconds == 0)),
384 	"Got Year %4d Month %2d Day %2d\n",  st.wYear, st.wMonth, st.wDay);
385 
386     ft.dwHighDateTime = (UINT)(time >> 32);
387     ft.dwLowDateTime  = (UINT)time;
388     ret = FileTimeToSystemTime(&ft, &st);
389     ok( ret,
390        "FileTimeToSystemTime() failed with Error %d\n",GetLastError());
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 
399 static void test_FileTimeToLocalFileTime(void)
400 {
401     FILETIME ft, lft;
402     SYSTEMTIME st;
403     TIME_ZONE_INFORMATION tzinfo;
404     DWORD res =  GetTimeZoneInformation(&tzinfo);
405     ULONGLONG time = (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970 +
406         (LONGLONG)(tzinfo.Bias +
407             ( res == TIME_ZONE_ID_STANDARD ? tzinfo.StandardBias :
408             ( res == TIME_ZONE_ID_DAYLIGHT ? tzinfo.DaylightBias : 0 ))) *
409              SECSPERMIN *TICKSPERSEC;
410     BOOL ret;
411 
412     ok( res != TIME_ZONE_ID_INVALID , "GetTimeZoneInformation failed\n");
413     ft.dwHighDateTime = (UINT)(time >> 32);
414     ft.dwLowDateTime  = (UINT)time;
415     ret = FileTimeToLocalFileTime(&ft, &lft);
416     ok( ret,
417        "FileTimeToLocalFileTime() failed with Error %d\n",GetLastError());
418     FileTimeToSystemTime(&lft, &st);
419     ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
420 	(st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 1) &&
421 	(st.wMilliseconds == 0)),
422        "Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
423        st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
424        st.wMilliseconds);
425 
426     ok(SetEnvironmentVariableA("TZ","GMT") != 0,
427        "SetEnvironmentVariableA failed\n");
428     ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
429     ret = FileTimeToLocalFileTime(&ft, &lft);
430     ok( ret,
431        "FileTimeToLocalFileTime() failed with Error %d\n",GetLastError());
432     FileTimeToSystemTime(&lft, &st);
433     ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
434 	(st.wHour ==    0) && (st.wMinute == 0) && (st.wSecond == 1) &&
435 	(st.wMilliseconds == 0)),
436        "Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
437        st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
438        st.wMilliseconds);
439     ok(SetEnvironmentVariableA("TZ",NULL) != 0,
440        "SetEnvironmentVariableA failed\n");
441 }
442 
443 typedef struct {
444     int nr;             /* test case number for easier lookup */
445     TIME_ZONE_INFORMATION *ptz; /* ptr to timezone */
446     SYSTEMTIME slt;     /* system/local time to convert */
447     WORD ehour;        /* expected hour */
448 } TZLT2ST_case;
449 
450 static void test_TzSpecificLocalTimeToSystemTime(void)
451 {
452     TIME_ZONE_INFORMATION tzE, tzW, tzS;
453     SYSTEMTIME result;
454     int i, j, year;
455 
456     if (!pTzSpecificLocalTimeToSystemTime || !pSystemTimeToTzSpecificLocalTime)
457     {
458         win_skip("TzSpecificLocalTimeToSystemTime or SystemTimeToTzSpecificLocalTime not available\n");
459         return;
460     }
461 
462     ZeroMemory( &tzE, sizeof(tzE));
463     ZeroMemory( &tzW, sizeof(tzW));
464     ZeroMemory( &tzS, sizeof(tzS));
465     /* timezone Eastern hemisphere */
466     tzE.Bias=-600;
467     tzE.StandardBias=0;
468     tzE.DaylightBias=-60;
469     tzE.StandardDate.wMonth=10;
470     tzE.StandardDate.wDayOfWeek=0; /* Sunday */
471     tzE.StandardDate.wDay=5;       /* last (Sunday) of the month */
472     tzE.StandardDate.wHour=3;
473     tzE.DaylightDate.wMonth=3;
474     tzE.DaylightDate.wDay=5;
475     tzE.DaylightDate.wHour=2;
476     /* timezone Western hemisphere */
477     tzW.Bias=240;
478     tzW.StandardBias=0;
479     tzW.DaylightBias=-60;
480     tzW.StandardDate.wMonth=10;
481     tzW.StandardDate.wDayOfWeek=0; /* Sunday */
482     tzW.StandardDate.wDay=4;       /* 4th (Sunday) of the month */
483     tzW.StandardDate.wHour=2;
484     tzW.DaylightDate.wMonth=4;
485     tzW.DaylightDate.wDay=1;
486     tzW.DaylightDate.wHour=2;
487     /* timezone Southern hemisphere */
488     tzS.Bias=240;
489     tzS.StandardBias=0;
490     tzS.DaylightBias=-60;
491     tzS.StandardDate.wMonth=4;
492     tzS.StandardDate.wDayOfWeek=0; /*Sunday */
493     tzS.StandardDate.wDay=1;       /* 1st (Sunday) of the month */
494     tzS.StandardDate.wHour=2;
495     tzS.DaylightDate.wMonth=10;
496     tzS.DaylightDate.wDay=4;
497     tzS.DaylightDate.wHour=2;
498     /*tests*/
499         /* TzSpecificLocalTimeToSystemTime */
500     {   TZLT2ST_case cases[] = {
501             /* standard->daylight transition */
502             { 1, &tzE, {2004,3,-1,28,1,0,0,0}, 15 },
503             { 2, &tzE, {2004,3,-1,28,1,59,59,999}, 15},
504             { 3, &tzE, {2004,3,-1,28,2,0,0,0}, 15},
505             /* daylight->standard transition */
506             { 4, &tzE, {2004,10,-1,31,2,0,0,0} , 15 },
507             { 5, &tzE, {2004,10,-1,31,2,59,59,999}, 15 },
508             { 6, &tzE, {2004,10,-1,31,3,0,0,0}, 17 },
509             /* West and with fixed weekday of the month */
510             { 7, &tzW, {2004,4,-1,4,1,0,0,0}, 5},
511             { 8, &tzW, {2004,4,-1,4,1,59,59,999}, 5},
512             { 9, &tzW, {2004,4,-1,4,2,0,0,0}, 5},
513             { 10, &tzW, {2004,10,-1,24,1,0,0,0}, 4},
514             { 11, &tzW, {2004,10,-1,24,1,59,59,999}, 4},
515             { 12, &tzW, {2004,10,-1,24,2,0,0,0 }, 6},
516             /* and now South */
517             { 13, &tzS, {2004,4,-1,4,1,0,0,0}, 4},
518             { 14, &tzS, {2004,4,-1,4,1,59,59,999}, 4},
519             { 15, &tzS, {2004,4,-1,4,2,0,0,0}, 6},
520             { 16, &tzS, {2004,10,-1,24,1,0,0,0}, 5},
521             { 17, &tzS, {2004,10,-1,24,1,59,59,999}, 5},
522             { 18, &tzS, {2004,10,-1,24,2,0,0,0}, 5},
523             {0}
524         };
525     /*  days of transitions to put into the cases array */
526         int yeardays[][6]=
527         {
528               {28,31,4,24,4,24}  /* 1999 */
529             , {26,29,2,22,2,22}  /* 2000 */
530             , {25,28,1,28,1,28}  /* 2001 */
531             , {31,27,7,27,7,27}  /* 2002 */
532             , {30,26,6,26,6,26}  /* 2003 */
533             , {28,31,4,24,4,24}  /* 2004 */
534             , {27,30,3,23,3,23}  /* 2005 */
535             , {26,29,2,22,2,22}  /* 2006 */
536             , {25,28,1,28,1,28}  /* 2007 */
537             , {30,26,6,26,6,26}  /* 2008 */
538             , {29,25,5,25,5,25}  /* 2009 */
539             , {28,31,4,24,4,24}  /* 2010 */
540             , {27,30,3,23,3,23}  /* 2011 */
541             , {25,28,1,28,1,28}  /* 2012 */
542             , {31,27,7,27,7,27}  /* 2013 */
543             , {30,26,6,26,6,26}  /* 2014 */
544             , {29,25,5,25,5,25}  /* 2015 */
545             , {27,30,3,23,3,23}  /* 2016 */
546             , {26,29,2,22,2,22}  /* 2017 */
547             , {25,28,1,28,1,28}  /* 2018 */
548             , {31,27,7,27,7,27}  /* 2019 */
549             ,{0}
550         };
551         for( j=0 , year = 1999; yeardays[j][0] ; j++, year++) {
552             for (i=0; cases[i].nr; i++) {
553                 if(i) cases[i].nr += 18;
554                 cases[i].slt.wYear = year;
555                 cases[i].slt.wDay = yeardays[j][i/3];
556                 pTzSpecificLocalTimeToSystemTime( cases[i].ptz, &(cases[i].slt), &result);
557                 ok( result.wHour == cases[i].ehour,
558                         "Test TzSpecificLocalTimeToSystemTime #%d. Got %4d-%02d-%02d %02d:%02d. Expect hour =  %02d\n",
559                         cases[i].nr, result.wYear, result.wMonth, result.wDay,
560                         result.wHour, result.wMinute, cases[i].ehour);
561             }
562         }
563     }
564         /* SystemTimeToTzSpecificLocalTime */
565     {   TZLT2ST_case cases[] = {
566             /* standard->daylight transition */
567             { 1, &tzE, {2004,3,-1,27,15,0,0,0}, 1 },
568             { 2, &tzE, {2004,3,-1,27,15,59,59,999}, 1},
569             { 3, &tzE, {2004,3,-1,27,16,0,0,0}, 3},
570             /* daylight->standard transition */
571             { 4,  &tzE, {2004,10,-1,30,15,0,0,0}, 2 },
572             { 5, &tzE, {2004,10,-1,30,15,59,59,999}, 2 },
573             { 6, &tzE, {2004,10,-1,30,16,0,0,0}, 2 },
574             /* West and with fixed weekday of the month */
575             { 7, &tzW, {2004,4,-1,4,5,0,0,0}, 1},
576             { 8, &tzW, {2004,4,-1,4,5,59,59,999}, 1},
577             { 9, &tzW, {2004,4,-1,4,6,0,0,0}, 3},
578             { 10, &tzW, {2004,10,-1,24,4,0,0,0}, 1},
579             { 11, &tzW, {2004,10,-1,24,4,59,59,999}, 1},
580             { 12, &tzW, {2004,10,-1,24,5,0,0,0 }, 1},
581             /* and now South */
582             { 13, &tzS, {2004,4,-1,4,4,0,0,0}, 1},
583             { 14, &tzS, {2004,4,-1,4,4,59,59,999}, 1},
584             { 15, &tzS, {2004,4,-1,4,5,0,0,0}, 1},
585             { 16, &tzS, {2004,10,-1,24,5,0,0,0}, 1},
586             { 17, &tzS, {2004,10,-1,24,5,59,59,999}, 1},
587             { 18, &tzS, {2004,10,-1,24,6,0,0,0}, 3},
588 
589             {0}
590         };
591     /*  days of transitions to put into the cases array */
592         int yeardays[][6]=
593         {
594               {27,30,4,24,4,24}  /* 1999 */
595             , {25,28,2,22,2,22}  /* 2000 */
596             , {24,27,1,28,1,28}  /* 2001 */
597             , {30,26,7,27,7,27}  /* 2002 */
598             , {29,25,6,26,6,26}  /* 2003 */
599             , {27,30,4,24,4,24}  /* 2004 */
600             , {26,29,3,23,3,23}  /* 2005 */
601             , {25,28,2,22,2,22}  /* 2006 */
602             , {24,27,1,28,1,28}  /* 2007 */
603             , {29,25,6,26,6,26}  /* 2008 */
604             , {28,24,5,25,5,25}  /* 2009 */
605             , {27,30,4,24,4,24}  /* 2010 */
606             , {26,29,3,23,3,23}  /* 2011 */
607             , {24,27,1,28,1,28}  /* 2012 */
608             , {30,26,7,27,7,27}  /* 2013 */
609             , {29,25,6,26,6,26}  /* 2014 */
610             , {28,24,5,25,5,25}  /* 2015 */
611             , {26,29,3,23,3,23}  /* 2016 */
612             , {25,28,2,22,2,22}  /* 2017 */
613             , {24,27,1,28,1,28}  /* 2018 */
614             , {30,26,7,27,7,27}  /* 2019 */
615             , {0}
616         };
617         for( j=0 , year = 1999; yeardays[j][0] ; j++, year++) {
618             for (i=0; cases[i].nr; i++) {
619                 if(i) cases[i].nr += 18;
620                 cases[i].slt.wYear = year;
621                 cases[i].slt.wDay = yeardays[j][i/3];
622                 pSystemTimeToTzSpecificLocalTime( cases[i].ptz, &(cases[i].slt), &result);
623                 ok( result.wHour == cases[i].ehour,
624                         "Test SystemTimeToTzSpecificLocalTime #%d. Got %4d-%02d-%02d %02d:%02d. Expect hour = %02d\n",
625                         cases[i].nr, result.wYear, result.wMonth, result.wDay,
626                         result.wHour, result.wMinute, cases[i].ehour);
627             }
628         }
629 
630     }
631 }
632 
633 static void test_FileTimeToDosDateTime(void)
634 {
635     FILETIME ft = { 0 };
636     WORD fatdate, fattime;
637     BOOL ret;
638 
639     if (0)
640     {
641         /* Crashes */
642         FileTimeToDosDateTime(NULL, NULL, NULL);
643     }
644     /* Parameter checking */
645     SetLastError(0xdeadbeef);
646     ret = FileTimeToDosDateTime(&ft, NULL, NULL);
647     ok(!ret, "expected failure\n");
648     ok(GetLastError() == ERROR_INVALID_PARAMETER,
649        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
650 
651     SetLastError(0xdeadbeef);
652     ret = FileTimeToDosDateTime(&ft, &fatdate, NULL);
653     ok(!ret, "expected failure\n");
654     ok(GetLastError() == ERROR_INVALID_PARAMETER,
655        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
656 
657     SetLastError(0xdeadbeef);
658     ret = FileTimeToDosDateTime(&ft, NULL, &fattime);
659     ok(!ret, "expected failure\n");
660     ok(GetLastError() == ERROR_INVALID_PARAMETER,
661        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
662 
663     SetLastError(0xdeadbeef);
664     ret = FileTimeToDosDateTime(&ft, &fatdate, &fattime);
665     ok(!ret, "expected failure\n");
666     ok(GetLastError() == ERROR_INVALID_PARAMETER,
667        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
668 }
669 
670 static void test_GetCalendarInfo(void)
671 {
672     char bufferA[20];
673     WCHAR bufferW[20];
674     DWORD val1, val2;
675     int ret, ret2;
676 
677     if (!pGetCalendarInfoA || !pGetCalendarInfoW)
678     {
679         trace( "GetCalendarInfo missing\n" );
680         return;
681     }
682 
683     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
684                              NULL, 0, &val1 );
685     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
686     ok( ret == sizeof(val1), "wrong size %u\n", ret );
687     ok( val1 >= 2000 && val1 < 2100, "wrong value %u\n", val1 );
688 
689     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
690                              NULL, 0, &val2 );
691     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
692     ok( ret == sizeof(val2)/sizeof(WCHAR), "wrong size %u\n", ret );
693     ok( val1 == val2, "A/W mismatch %u/%u\n", val1, val2 );
694 
695     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, bufferA, sizeof(bufferA), NULL );
696     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
697     ok( ret == 5, "wrong size %u\n", ret );
698     ok( atoi( bufferA ) == val1, "wrong value %s/%u\n", bufferA, val1 );
699 
700     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, bufferW, sizeof(bufferW), NULL );
701     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
702     ok( ret == 5, "wrong size %u\n", ret );
703     memset( bufferA, 0x55, sizeof(bufferA) );
704     WideCharToMultiByte( CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL );
705     ok( atoi( bufferA ) == val1, "wrong value %s/%u\n", bufferA, val1 );
706 
707     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
708                              NULL, 0, NULL );
709     ok( !ret, "GetCalendarInfoA succeeded\n" );
710     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
711 
712     ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, NULL, 0, NULL );
713     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
714     ok( ret == 5, "wrong size %u\n", ret );
715 
716     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
717                              NULL, 0, NULL );
718     ok( !ret, "GetCalendarInfoW succeeded\n" );
719     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
720 
721     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, NULL, 0, NULL );
722     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
723     ok( ret == 5, "wrong size %u\n", ret );
724 
725     ret = pGetCalendarInfoA( LANG_SYSTEM_DEFAULT, CAL_GREGORIAN, CAL_SDAYNAME1,
726                              bufferA, sizeof(bufferA), NULL);
727     ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
728     ret2 = pGetCalendarInfoA( LANG_SYSTEM_DEFAULT, CAL_GREGORIAN, CAL_SDAYNAME1,
729                               bufferA, 0, NULL);
730     ok( ret2, "GetCalendarInfoA failed err %u\n", GetLastError() );
731     ok( ret == ret2, "got %d, expected %d\n", ret2, ret );
732 
733     ret2 = pGetCalendarInfoW( LANG_SYSTEM_DEFAULT, CAL_GREGORIAN, CAL_SDAYNAME1,
734                               bufferW, sizeof(bufferW), NULL);
735     ok( ret2, "GetCalendarInfoW failed err %u\n", GetLastError() );
736     ret2 = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
737     ok( ret == ret2, "got %d, expected %d\n", ret, ret2 );
738 }
739 
740 static void test_GetDynamicTimeZoneInformation(void)
741 {
742     DYNAMIC_TIME_ZONE_INFORMATION dyninfo;
743     TIME_ZONE_INFORMATION tzinfo;
744     DWORD ret, ret2;
745 
746     if (!pGetDynamicTimeZoneInformation)
747     {
748         win_skip("GetDynamicTimeZoneInformation() is not supported.\n");
749         return;
750     }
751 
752     ret = pGetDynamicTimeZoneInformation(&dyninfo);
753     ret2 = GetTimeZoneInformation(&tzinfo);
754     ok(ret == ret2, "got %d, %d\n", ret, ret2);
755 
756     ok(dyninfo.Bias == tzinfo.Bias, "got %d, %d\n", dyninfo.Bias, tzinfo.Bias);
757     ok(!lstrcmpW(dyninfo.StandardName, tzinfo.StandardName), "got std name %s, %s\n",
758         wine_dbgstr_w(dyninfo.StandardName), wine_dbgstr_w(tzinfo.StandardName));
759     ok(!memcmp(&dyninfo.StandardDate, &tzinfo.StandardDate, sizeof(dyninfo.StandardDate)), "got different StandardDate\n");
760     ok(dyninfo.StandardBias == tzinfo.StandardBias, "got %d, %d\n", dyninfo.StandardBias, tzinfo.StandardBias);
761     ok(!lstrcmpW(dyninfo.DaylightName, tzinfo.DaylightName), "got daylight name %s, %s\n",
762         wine_dbgstr_w(dyninfo.DaylightName), wine_dbgstr_w(tzinfo.DaylightName));
763     ok(!memcmp(&dyninfo.DaylightDate, &tzinfo.DaylightDate, sizeof(dyninfo.DaylightDate)), "got different DaylightDate\n");
764     ok(dyninfo.TimeZoneKeyName[0] != 0, "got empty tz keyname\n");
765     trace("Dyn TimeZoneKeyName %s\n", wine_dbgstr_w(dyninfo.TimeZoneKeyName));
766 }
767 
768 static ULONGLONG get_longlong_time(FILETIME *time)
769 {
770     ULARGE_INTEGER uli;
771     uli.u.LowPart = time->dwLowDateTime;
772     uli.u.HighPart = time->dwHighDateTime;
773     return uli.QuadPart;
774 }
775 
776 static void test_GetSystemTimePreciseAsFileTime(void)
777 {
778     FILETIME ft;
779     ULONGLONG time1, time2;
780     LONGLONG diff;
781 
782     if (!pGetSystemTimePreciseAsFileTime)
783     {
784         win_skip("GetSystemTimePreciseAsFileTime() is not supported.\n");
785         return;
786     }
787 
788     GetSystemTimeAsFileTime(&ft);
789     time1 = get_longlong_time(&ft);
790     pGetSystemTimePreciseAsFileTime(&ft);
791     time2 = get_longlong_time(&ft);
792     diff = time2 - time1;
793     if (diff < 0)
794         diff = -diff;
795     ok(diff < 1000000, "Difference between GetSystemTimeAsFileTime and GetSystemTimePreciseAsFileTime more than 100 ms\n");
796 
797     pGetSystemTimePreciseAsFileTime(&ft);
798     time1 = get_longlong_time(&ft);
799     do {
800         pGetSystemTimePreciseAsFileTime(&ft);
801         time2 = get_longlong_time(&ft);
802     } while (time2 == time1);
803     diff = time2 - time1;
804     ok(diff < 10000 && diff > 0, "GetSystemTimePreciseAsFileTime incremented by more than 1 ms\n");
805 }
806 
807 static void test_GetSystemTimes(void)
808 {
809 
810     FILETIME idletime, kerneltime, usertime;
811     int i;
812     ULARGE_INTEGER ul1, ul2, ul3;
813     SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi;
814     SYSTEM_BASIC_INFORMATION sbi;
815     ULONG ReturnLength;
816     ULARGE_INTEGER total_usertime, total_kerneltime, total_idletime;
817 
818     if (!pGetSystemTimes)
819     {
820         win_skip("GetSystemTimes not available\n");
821         return;
822     }
823 
824     ok( pGetSystemTimes(NULL, NULL, NULL), "GetSystemTimes failed unexpectedly\n" );
825 
826     total_usertime.QuadPart = 0;
827     total_kerneltime.QuadPart = 0;
828     total_idletime.QuadPart = 0;
829     memset( &idletime, 0x11, sizeof(idletime) );
830     memset( &kerneltime, 0x11, sizeof(kerneltime) );
831     memset( &usertime, 0x11, sizeof(usertime) );
832     ok( pGetSystemTimes(&idletime, &kerneltime , &usertime),
833         "GetSystemTimes failed unexpectedly\n" );
834 
835     ul1.LowPart = idletime.dwLowDateTime;
836     ul1.HighPart = idletime.dwHighDateTime;
837     ul2.LowPart = kerneltime.dwLowDateTime;
838     ul2.HighPart = kerneltime.dwHighDateTime;
839     ul3.LowPart = usertime.dwLowDateTime;
840     ul3.HighPart = usertime.dwHighDateTime;
841 
842     ok( !NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), &ReturnLength),
843                                   "NtQuerySystemInformation failed\n" );
844     ok( sizeof(sbi) == ReturnLength, "Inconsistent length %d\n", ReturnLength );
845 
846     /* Check if we have some return values */
847     trace( "Number of Processors : %d\n", sbi.NumberOfProcessors );
848     ok( sbi.NumberOfProcessors > 0, "Expected more than 0 processors, got %d\n",
849         sbi.NumberOfProcessors );
850 
851     sppi = HeapAlloc( GetProcessHeap(), 0,
852                       sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * sbi.NumberOfProcessors);
853 
854     ok( !NtQuerySystemInformation( SystemProcessorPerformanceInformation, sppi,
855                                    sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * sbi.NumberOfProcessors,
856                                    &ReturnLength),
857                                    "NtQuerySystemInformation failed\n" );
858 
859     for (i = 0; i < sbi.NumberOfProcessors; i++)
860     {
861         total_usertime.QuadPart += sppi[i].UserTime.QuadPart;
862         total_kerneltime.QuadPart += sppi[i].KernelTime.QuadPart;
863         total_idletime.QuadPart += sppi[i].IdleTime.QuadPart;
864     }
865 
866     ok( total_idletime.QuadPart - ul1.QuadPart < 10000000, "test idletime failed\n" );
867     ok( total_kerneltime.QuadPart - ul2.QuadPart < 10000000, "test kerneltime failed\n" );
868     ok( total_usertime.QuadPart - ul3.QuadPart < 10000000, "test usertime failed\n" );
869 
870     HeapFree(GetProcessHeap(), 0, sppi);
871 }
872 
873 static WORD day_of_month(const SYSTEMTIME* systemtime, WORD year)
874 {
875     SYSTEMTIME first_of_month = {0};
876     FILETIME filetime;
877     WORD result;
878 
879     if (systemtime->wYear != 0)
880         return systemtime->wDay;
881 
882     first_of_month.wYear = year;
883     first_of_month.wMonth = systemtime->wMonth;
884     first_of_month.wDay = 1;
885 
886     /* round-trip conversion sets day of week field */
887     SystemTimeToFileTime(&first_of_month, &filetime);
888     FileTimeToSystemTime(&filetime, &first_of_month);
889 
890     result = 1 + ((systemtime->wDayOfWeek - first_of_month.wDayOfWeek + 7) % 7) +
891         (7 * (systemtime->wDay - 1));
892 
893     if (systemtime->wDay == 5)
894     {
895         /* make sure this isn't in the next month */
896         SYSTEMTIME result_date;
897 
898         result_date = first_of_month;
899         result_date.wDay = result;
900 
901         SystemTimeToFileTime(&result_date, &filetime);
902         FileTimeToSystemTime(&filetime, &result_date);
903 
904         if (result_date.wDay != result)
905             result = 1 + ((systemtime->wDayOfWeek - first_of_month.wDayOfWeek + 7) % 7) +
906                 (7 * (4 - 1));
907     }
908 
909     return result;
910 }
911 
912 static void test_GetTimeZoneInformationForYear(void)
913 {
914     BOOL ret;
915     SYSTEMTIME systemtime;
916     TIME_ZONE_INFORMATION local_tzinfo, tzinfo, tzinfo2;
917     DYNAMIC_TIME_ZONE_INFORMATION dyn_tzinfo;
918     static const WCHAR std_tzname[] = {'G','r','e','e','n','l','a','n','d',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0};
919     static const WCHAR dlt_tzname[] = {'G','r','e','e','n','l','a','n','d',' ','D','a','y','l','i','g','h','t',' ','T','i','m','e',0};
920     WORD std_day, dlt_day;
921 
922     if (!pGetTimeZoneInformationForYear || !pGetDynamicTimeZoneInformation)
923     {
924         win_skip("GetTimeZoneInformationForYear not available\n");
925         return;
926     }
927 
928     GetLocalTime(&systemtime);
929 
930     GetTimeZoneInformation(&local_tzinfo);
931 
932     ret = pGetTimeZoneInformationForYear(systemtime.wYear, NULL, &tzinfo);
933     ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %u\n", GetLastError());
934     ok(tzinfo.Bias == local_tzinfo.Bias, "Expected Bias %d, got %d\n", local_tzinfo.Bias, tzinfo.Bias);
935     ok(!lstrcmpW(tzinfo.StandardName, local_tzinfo.StandardName),
936         "Expected StandardName %s, got %s\n", wine_dbgstr_w(local_tzinfo.StandardName), wine_dbgstr_w(tzinfo.StandardName));
937     ok(!memcmp(&tzinfo.StandardDate, &local_tzinfo.StandardDate, sizeof(SYSTEMTIME)), "StandardDate does not match\n");
938     ok(tzinfo.StandardBias == local_tzinfo.StandardBias, "Expected StandardBias %d, got %d\n", local_tzinfo.StandardBias, tzinfo.StandardBias);
939     ok(!lstrcmpW(tzinfo.DaylightName, local_tzinfo.DaylightName),
940         "Expected DaylightName %s, got %s\n", wine_dbgstr_w(local_tzinfo.DaylightName), wine_dbgstr_w(tzinfo.DaylightName));
941     ok(!memcmp(&tzinfo.DaylightDate, &local_tzinfo.DaylightDate, sizeof(SYSTEMTIME)), "DaylightDate does not match\n");
942     ok(tzinfo.DaylightBias == local_tzinfo.DaylightBias, "Expected DaylightBias %d, got %d\n", local_tzinfo.DaylightBias, tzinfo.DaylightBias);
943 
944     pGetDynamicTimeZoneInformation(&dyn_tzinfo);
945 
946     ret = pGetTimeZoneInformationForYear(systemtime.wYear, &dyn_tzinfo, &tzinfo);
947     ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %u\n", GetLastError());
948     ok(tzinfo.Bias == local_tzinfo.Bias, "Expected Bias %d, got %d\n", local_tzinfo.Bias, tzinfo.Bias);
949     ok(!lstrcmpW(tzinfo.StandardName, local_tzinfo.StandardName),
950         "Expected StandardName %s, got %s\n", wine_dbgstr_w(local_tzinfo.StandardName), wine_dbgstr_w(tzinfo.StandardName));
951     ok(!memcmp(&tzinfo.StandardDate, &local_tzinfo.StandardDate, sizeof(SYSTEMTIME)), "StandardDate does not match\n");
952     ok(tzinfo.StandardBias == local_tzinfo.StandardBias, "Expected StandardBias %d, got %d\n", local_tzinfo.StandardBias, tzinfo.StandardBias);
953     ok(!lstrcmpW(tzinfo.DaylightName, local_tzinfo.DaylightName),
954         "Expected DaylightName %s, got %s\n", wine_dbgstr_w(local_tzinfo.DaylightName), wine_dbgstr_w(tzinfo.DaylightName));
955     ok(!memcmp(&tzinfo.DaylightDate, &local_tzinfo.DaylightDate, sizeof(SYSTEMTIME)), "DaylightDate does not match\n");
956     ok(tzinfo.DaylightBias == local_tzinfo.DaylightBias, "Expected DaylightBias %d, got %d\n", local_tzinfo.DaylightBias, tzinfo.DaylightBias);
957 
958     memset(&dyn_tzinfo, 0xaa, sizeof(dyn_tzinfo));
959     lstrcpyW(dyn_tzinfo.TimeZoneKeyName, std_tzname);
960     dyn_tzinfo.DynamicDaylightTimeDisabled = FALSE;
961 
962     ret = pGetTimeZoneInformationForYear(2015, &dyn_tzinfo, &tzinfo);
963     ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %u\n", GetLastError());
964     ok(tzinfo.Bias == 180, "Expected Bias 180, got %d\n", tzinfo.Bias);
965     ok(tzinfo.StandardDate.wMonth == 10, "Expected standard month 10, got %d\n", tzinfo.StandardDate.wMonth);
966     std_day = day_of_month(&tzinfo.StandardDate, 2015);
967     ok(std_day == 24, "Expected standard day 24, got %d\n", std_day);
968     ok(tzinfo.StandardBias == 0, "Expected StandardBias 0, got %d\n", tzinfo.StandardBias);
969     ok(tzinfo.DaylightDate.wMonth == 3, "Expected daylight month 3, got %d\n", tzinfo.DaylightDate.wMonth);
970     dlt_day = day_of_month(&tzinfo.DaylightDate, 2015);
971     ok(dlt_day == 28, "Expected daylight day 28, got %d\n", dlt_day);
972     ok(tzinfo.DaylightBias == -60, "Expected DaylightBias -60, got %d\n", tzinfo.DaylightBias);
973 
974     ret = pGetTimeZoneInformationForYear(2016, &dyn_tzinfo, &tzinfo2);
975     ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %u\n", GetLastError());
976     ok(!lstrcmpW(tzinfo.StandardName, tzinfo2.StandardName),
977         "Got differing StandardName values %s and %s\n",
978         wine_dbgstr_w(tzinfo.StandardName), wine_dbgstr_w(tzinfo2.StandardName));
979     ok(!lstrcmpW(tzinfo.DaylightName, tzinfo2.DaylightName),
980         "Got differing DaylightName values %s and %s\n",
981         wine_dbgstr_w(tzinfo.DaylightName), wine_dbgstr_w(tzinfo2.DaylightName));
982 
983     memset(&dyn_tzinfo, 0xaa, sizeof(dyn_tzinfo));
984     lstrcpyW(dyn_tzinfo.TimeZoneKeyName, dlt_tzname);
985 
986     SetLastError(0xdeadbeef);
987     ret = pGetTimeZoneInformationForYear(2015, &dyn_tzinfo, &tzinfo);
988     ok((ret == FALSE && GetLastError() == ERROR_FILE_NOT_FOUND) ||
989        broken(ret == TRUE) /* vista,7 */,
990        "GetTimeZoneInformationForYear err %u\n", GetLastError());
991 }
992 
993 START_TEST(time)
994 {
995     HMODULE hKernel = GetModuleHandleA("kernel32");
996     pTzSpecificLocalTimeToSystemTime = (void *)GetProcAddress(hKernel, "TzSpecificLocalTimeToSystemTime");
997     pSystemTimeToTzSpecificLocalTime = (void *)GetProcAddress( hKernel, "SystemTimeToTzSpecificLocalTime");
998     pGetSystemTimes = (void *)GetProcAddress( hKernel, "GetSystemTimes");
999     pGetCalendarInfoA = (void *)GetProcAddress(hKernel, "GetCalendarInfoA");
1000     pGetCalendarInfoW = (void *)GetProcAddress(hKernel, "GetCalendarInfoW");
1001     pGetDynamicTimeZoneInformation = (void *)GetProcAddress(hKernel, "GetDynamicTimeZoneInformation");
1002     pGetSystemTimePreciseAsFileTime = (void *)GetProcAddress(hKernel, "GetSystemTimePreciseAsFileTime");
1003     pGetTimeZoneInformationForYear = (void *)GetProcAddress(hKernel, "GetTimeZoneInformationForYear");
1004 
1005     test_conversions();
1006     test_invalid_arg();
1007     test_GetTimeZoneInformation();
1008     test_FileTimeToSystemTime();
1009     test_FileTimeToLocalFileTime();
1010     test_TzSpecificLocalTimeToSystemTime();
1011     test_GetSystemTimes();
1012     test_FileTimeToDosDateTime();
1013     test_GetCalendarInfo();
1014     test_GetDynamicTimeZoneInformation();
1015     test_GetSystemTimePreciseAsFileTime();
1016     test_GetTimeZoneInformationForYear();
1017 }
1018