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