Fixed regression in loading of builtin apps from the system dir when
[wine] / dlls / kernel / time.c
1 /*
2  * Win32 kernel time functions
3  *
4  * Copyright 1995 Martin von Loewis and Cameron Heide
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24 #ifdef HAVE_UNISTD_H
25 # include <unistd.h>
26 #endif
27 #include <stdlib.h>
28 #ifdef HAVE_SYS_TIME_H
29 # include <sys/time.h>
30 #endif
31 #ifdef HAVE_SYS_TIMES_H
32 # include <sys/times.h>
33 #endif
34
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
37 #include "ntstatus.h"
38 #include "file.h"
39 #include "winternl.h"
40 #include "winerror.h"
41 #include "winnls.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(win32);
46
47 /* maximum time adjustment in seconds for SetLocalTime and SetSystemTime */
48 #define SETTIME_MAX_ADJUST 120
49 #define CALINFO_MAX_YEAR 2029
50
51
52 /***********************************************************************
53  *              SetLocalTime            (KERNEL32.@)
54  *
55  *  Set the local time using current time zone and daylight
56  *  savings settings.
57  *
58  * RETURNS
59  *  Success: TRUE. The time was set
60  *  Failure: FALSE, if the time was invalid or caller does not have
61  *           permission to change the time.
62  */
63 BOOL WINAPI SetLocalTime(
64     const SYSTEMTIME *systime) /* [in] The desired local time. */
65 {
66     FILETIME ft;
67     LARGE_INTEGER st, st2;
68     NTSTATUS status;
69
70     SystemTimeToFileTime( systime, &ft );
71     st.s.LowPart = ft.dwLowDateTime;
72     st.s.HighPart = ft.dwHighDateTime;
73     RtlLocalTimeToSystemTime( &st, &st2 );
74
75     if ((status = NtSetSystemTime(&st2, NULL)))
76         SetLastError( RtlNtStatusToDosError(status) );
77     return !status;
78 }
79
80
81 /***********************************************************************
82  *           GetSystemTimeAdjustment     (KERNEL32.@)
83  *
84  *  Get the period between clock interrupts and the amount the clock
85  *  is adjusted each interrupt so as to keep it in sync with an external source.
86  *
87  * RETURNS
88  *  TRUE.
89  *
90  * BUGS
91  *  Only the special case of disabled time adjustments is supported.
92  */
93 BOOL WINAPI GetSystemTimeAdjustment(
94     PDWORD lpTimeAdjustment,         /* [out] The clock adjustment per interupt in 100's of nanoseconds. */
95     PDWORD lpTimeIncrement,          /* [out] The time between clock interupts in 100's of nanoseconds. */
96     PBOOL  lpTimeAdjustmentDisabled) /* [out] The clock synchonisation has been disabled. */
97 {
98     *lpTimeAdjustment = 0;
99     *lpTimeIncrement = 0;
100     *lpTimeAdjustmentDisabled = TRUE;
101     return TRUE;
102 }
103
104
105 /***********************************************************************
106  *              SetSystemTime            (KERNEL32.@)
107  *
108  *  Set the system time in utc.
109  *
110  * RETURNS
111  *  Success: TRUE. The time was set
112  *  Failure: FALSE, if the time was invalid or caller does not have
113  *           permission to change the time.
114  */
115 BOOL WINAPI SetSystemTime(
116     const SYSTEMTIME *systime) /* [in] The desired system time. */
117 {
118     FILETIME ft;
119     LARGE_INTEGER t;
120     NTSTATUS status;
121
122     SystemTimeToFileTime( systime, &ft );
123     t.s.LowPart = ft.dwLowDateTime;
124     t.s.HighPart = ft.dwHighDateTime;
125     if ((status = NtSetSystemTime(&t, NULL)))
126         SetLastError( RtlNtStatusToDosError(status) );
127     return !status;
128 }
129
130 /***********************************************************************
131  *              SetSystemTimeAdjustment  (KERNEL32.@)
132  *
133  *  Enables or disables the timing adjustments to the system's clock.
134  *
135  * RETURNS
136  *  Success: TRUE.
137  *  Failure: FALSE.
138  */
139 BOOL WINAPI SetSystemTimeAdjustment(
140     DWORD dwTimeAdjustment,
141     BOOL bTimeAdjustmentDisabled)
142 {
143     /* Fake function for now... */
144     FIXME("(%08lx,%d): stub !\n", dwTimeAdjustment, bTimeAdjustmentDisabled);
145     return TRUE;
146 }
147
148
149 /***********************************************************************
150  *              GetTimeZoneInformation  (KERNEL32.@)
151  *
152  *  Get information about the current local time zone.
153  *
154  * RETURNS
155  *  Success: TIME_ZONE_ID_STANDARD. tzinfo contains the time zone info.
156  *  Failure: TIME_ZONE_ID_INVALID.
157  */
158 DWORD WINAPI GetTimeZoneInformation(
159     LPTIME_ZONE_INFORMATION tzinfo) /* [out] Destination for time zone information */
160 {
161     NTSTATUS status;
162     if ((status = RtlQueryTimeZoneInformation(tzinfo)))
163         SetLastError( RtlNtStatusToDosError(status) );
164     return TIME_ZONE_ID_STANDARD;
165 }
166
167
168 /***********************************************************************
169  *              SetTimeZoneInformation  (KERNEL32.@)
170  *
171  *  Change the settings of the current local time zone.
172  *
173  * RETURNS
174  *  Success: TRUE. The time zone was updated with the settings from tzinfo
175  *  Failure: FALSE.
176  */
177 BOOL WINAPI SetTimeZoneInformation(
178     const LPTIME_ZONE_INFORMATION tzinfo) /* [in] The new time zone. */
179 {
180     NTSTATUS status;
181     if ((status = RtlSetTimeZoneInformation(tzinfo)))
182         SetLastError( RtlNtStatusToDosError(status) );
183     return !status;
184 }
185
186
187 /***********************************************************************
188  *  _DayLightCompareDate
189  *
190  *  Compares two dates without looking at the year
191  *
192  * RETURNS
193  *
194  *  -1 if date < compareDate
195  *   0 if date == compareDate
196  *   1 if date > compareDate
197  *  -2 if an error occures
198  */
199
200 static int _DayLightCompareDate(
201     const LPSYSTEMTIME date,                       /* [in] The date to compare. */
202     const LPSYSTEMTIME compareDate)                /* [in] The daylight saving begin or end date */
203 {
204     int limit_day;
205
206     if (compareDate->wYear != 0)
207     {
208         if (date->wMonth < compareDate->wMonth)
209             return -1; /* We are in a year before the date limit. */
210
211         if (date->wMonth > compareDate->wMonth)
212             return 1; /* We are in a year after the date limit. */
213     }
214
215     if (date->wMonth < compareDate->wMonth)
216         return -1; /* We are in a month before the date limit. */
217
218     if (date->wMonth > compareDate->wMonth)
219         return 1; /* We are in a month after the date limit. */
220
221     if (compareDate->wDayOfWeek <= 6)
222     {
223        SYSTEMTIME tmp;
224        FILETIME tmp_ft;
225
226        /* compareDate->wDay is interpreted as number of the week in the month. */
227        /* 5 means: the last week in the month */
228        int weekofmonth = compareDate->wDay;
229
230          /* calculate day of week for the first day in the month */
231         memcpy(&tmp, date, sizeof(SYSTEMTIME));
232         tmp.wDay = 1;
233         tmp.wDayOfWeek = -1;
234
235         if (weekofmonth == 5)
236         {
237              /* Go to the beginning of the next month. */
238             if (++tmp.wMonth > 12)
239             {
240                 tmp.wMonth = 1;
241                 ++tmp.wYear;
242             }
243         }
244
245         if (!SystemTimeToFileTime(&tmp, &tmp_ft))
246             return -2;
247
248         if (weekofmonth == 5)
249         {
250           LONGLONG t, one_day;
251
252           t = tmp_ft.dwHighDateTime;
253           t <<= 32;
254           t += (UINT)tmp_ft.dwLowDateTime;
255
256           /* subtract one day */
257           one_day = 24*60*60;
258           one_day *= 10000000;
259           t -= one_day;
260
261           tmp_ft.dwLowDateTime  = (UINT)t;
262           tmp_ft.dwHighDateTime = (UINT)(t >> 32);
263         }
264
265         if (!FileTimeToSystemTime(&tmp_ft, &tmp))
266             return -2;
267
268        if (weekofmonth == 5)
269        {
270           /* calculate the last matching day of the week in this month */
271           int dif = tmp.wDayOfWeek - compareDate->wDayOfWeek;
272           if (dif < 0)
273              dif += 7;
274
275           limit_day = tmp.wDay - dif;
276        }
277        else
278        {
279           /* calculate the matching day of the week in the given week */
280           int dif = compareDate->wDayOfWeek - tmp.wDayOfWeek;
281           if (dif < 0)
282              dif += 7;
283
284           limit_day = tmp.wDay + 7*(weekofmonth-1) + dif;
285        }
286     }
287     else
288     {
289        limit_day = compareDate->wDay;
290     }
291
292     if (date->wDay < limit_day)
293         return -1;
294
295     if (date->wDay > limit_day)
296         return 1;
297
298     return 0;   /* date is equal to the date limit. */
299 }
300
301
302 /***********************************************************************
303  *  _GetTimezoneBias
304  *
305  *  Calculates the local time bias for a given time zone
306  *
307  * RETURNS
308  *
309  *  Returns TRUE when the time zone bias was calculated.
310  */
311
312 static BOOL _GetTimezoneBias(
313     const LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The time zone data.            */
314     LPSYSTEMTIME                  lpSystemTime,          /* [in] The system time.               */
315     LONG*                         pBias)                 /* [out] The calulated bias in minutes */
316 {
317     int ret;
318     BOOL beforeStandardDate, afterDaylightDate;
319     BOOL daylightsaving = FALSE;
320     LONG bias = lpTimeZoneInformation->Bias;
321
322     if (lpTimeZoneInformation->DaylightDate.wMonth != 0)
323     {
324         if (lpTimeZoneInformation->StandardDate.wMonth == 0 ||
325             lpTimeZoneInformation->StandardDate.wDay<1 ||
326             lpTimeZoneInformation->StandardDate.wDay>5 ||
327             lpTimeZoneInformation->DaylightDate.wDay<1 ||
328             lpTimeZoneInformation->DaylightDate.wDay>5)
329         {
330             SetLastError(ERROR_INVALID_PARAMETER);
331             return FALSE;
332         }
333
334          /* check for daylight saving */
335         ret = _DayLightCompareDate(lpSystemTime, &lpTimeZoneInformation->StandardDate);
336         if (ret == -2)
337           return FALSE;
338
339         beforeStandardDate = ret < 0;
340
341         ret = _DayLightCompareDate(lpSystemTime, &lpTimeZoneInformation->DaylightDate);
342         if (ret == -2)
343           return FALSE;
344
345         afterDaylightDate = ret >= 0;
346
347         if (beforeStandardDate && afterDaylightDate)
348             daylightsaving = TRUE;
349     }
350
351     if (daylightsaving)
352         bias += lpTimeZoneInformation->DaylightBias;
353     else if (lpTimeZoneInformation->StandardDate.wMonth != 0)
354         bias += lpTimeZoneInformation->StandardBias;
355
356     *pBias = bias;
357
358     return TRUE;
359 }
360
361
362 /***********************************************************************
363  *              SystemTimeToTzSpecificLocalTime  (KERNEL32.@)
364  *
365  *  Convert a utc system time to a local time in a given time zone.
366  *
367  * RETURNS
368  *  Success: TRUE. lpLocalTime contains the converted time
369  *  Failure: FALSE.
370  */
371
372 BOOL WINAPI SystemTimeToTzSpecificLocalTime(
373     LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The desired time zone. */
374     LPSYSTEMTIME            lpUniversalTime,       /* [in] The utc time to base local time on. */
375     LPSYSTEMTIME            lpLocalTime)           /* [out] The local time in the time zone. */
376 {
377     FILETIME ft;
378     LONG lBias;
379     LONGLONG t, bias;
380     TIME_ZONE_INFORMATION tzinfo;
381
382     if (lpTimeZoneInformation != NULL)
383     {
384         memcpy(&tzinfo, lpTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION));
385     }
386     else
387     {
388         if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
389             return FALSE;
390     }
391
392     if (!SystemTimeToFileTime(lpUniversalTime, &ft))
393         return FALSE;
394
395     t = ft.dwHighDateTime;
396     t <<= 32;
397     t += (UINT)ft.dwLowDateTime;
398
399     if (!_GetTimezoneBias(&tzinfo, lpUniversalTime, &lBias))
400         return FALSE;
401
402     bias = (LONGLONG)lBias * 600000000; /* 60 seconds per minute, 100000 [100-nanoseconds-ticks] per second */
403     t -= bias;
404
405     ft.dwLowDateTime  = (UINT)t;
406     ft.dwHighDateTime = (UINT)(t >> 32);
407
408     return FileTimeToSystemTime(&ft, lpLocalTime);
409 }
410
411
412 /***********************************************************************
413  *              TzSpecificLocalTimeToSystemTime  (KERNEL32.@)
414  *
415  *  Converts a local time to a time in utc.
416  *
417  * RETURNS
418  *  Success: TRUE. lpUniversalTime contains the converted time
419  *  Failure: FALSE.
420  */
421 BOOL WINAPI TzSpecificLocalTimeToSystemTime(
422     LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The desired time zone. */
423     LPSYSTEMTIME            lpLocalTime,           /* [in] The local time. */
424     LPSYSTEMTIME            lpUniversalTime)       /* [out] The calculated utc time. */
425 {
426     FILETIME ft;
427     LONG lBias;
428     LONGLONG t, bias;
429     TIME_ZONE_INFORMATION tzinfo;
430
431     if (lpTimeZoneInformation != NULL)
432     {
433         memcpy(&tzinfo, lpTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION));
434     }
435     else
436     {
437         if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
438             return FALSE;
439     }
440
441     if (!SystemTimeToFileTime(lpLocalTime, &ft))
442         return FALSE;
443
444     t = ft.dwHighDateTime;
445     t <<= 32;
446     t += (UINT)ft.dwLowDateTime;
447
448     if (!_GetTimezoneBias(&tzinfo, lpLocalTime, &lBias))
449         return FALSE;
450
451     bias = (LONGLONG)lBias * 600000000; /* 60 seconds per minute, 100000 [100-nanoseconds-ticks] per second */
452     t += bias;
453
454     ft.dwLowDateTime  = (UINT)t;
455     ft.dwHighDateTime = (UINT)(t >> 32);
456
457     return FileTimeToSystemTime(&ft, lpUniversalTime);
458 }
459
460
461 /***********************************************************************
462  *              GetSystemTimeAsFileTime  (KERNEL32.@)
463  *
464  *  Get the current time in utc format.
465  *
466  *  RETURNS
467  *   Nothing.
468  */
469 VOID WINAPI GetSystemTimeAsFileTime(
470     LPFILETIME time) /* [out] Destination for the current utc time */
471 {
472     LARGE_INTEGER t;
473     NtQuerySystemTime( &t );
474     time->dwLowDateTime = t.s.LowPart;
475     time->dwHighDateTime = t.s.HighPart;
476 }
477
478
479 /*********************************************************************
480  *      TIME_ClockTimeToFileTime    (olorin@fandra.org, 20-Sep-1998)
481  *
482  *  Used by GetProcessTimes to convert clock_t into FILETIME.
483  *
484  *      Differences to UnixTimeToFileTime:
485  *          1) Divided by CLK_TCK
486  *          2) Time is relative. There is no 'starting date', so there is
487  *             no need for offset correction, like in UnixTimeToFileTime
488  */
489 static void TIME_ClockTimeToFileTime(clock_t unix_time, LPFILETIME filetime)
490 {
491     ULONGLONG secs = RtlEnlargedUnsignedMultiply( unix_time, 10000000 );
492     secs = RtlExtendedLargeIntegerDivide( secs, CLK_TCK, NULL );
493     filetime->dwLowDateTime  = (DWORD)secs;
494     filetime->dwHighDateTime = (DWORD)(secs >> 32);
495 }
496
497 /*********************************************************************
498  *      GetProcessTimes                         (KERNEL32.@)
499  *
500  *  Get the user and kernel execution times of a process,
501  *  along with the creation and exit times if known.
502  *
503  * RETURNS
504  *  TRUE.
505  *
506  * NOTES
507  *  olorin@fandra.org:
508  *  Would be nice to subtract the cpu time used by Wine at startup.
509  *  Also, there is a need to separate times used by different applications.
510  *
511  * BUGS
512  *  lpCreationTime and lpExitTime are not initialised in the Wine implementation.
513  */
514 BOOL WINAPI GetProcessTimes(
515     HANDLE     hprocess,       /* [in] The process to be queried (obtained from PROCESS_QUERY_INFORMATION). */
516     LPFILETIME lpCreationTime, /* [out] The creation time of the process. */
517     LPFILETIME lpExitTime,     /* [out] The exit time of the process if exited. */
518     LPFILETIME lpKernelTime,   /* [out] The time spent in kernal routines in 100's of nanoseconds. */
519     LPFILETIME lpUserTime)     /* [out] The time spent in user routines in 100's of nanoseconds. */
520 {
521     struct tms tms;
522
523     times(&tms);
524     TIME_ClockTimeToFileTime(tms.tms_utime,lpUserTime);
525     TIME_ClockTimeToFileTime(tms.tms_stime,lpKernelTime);
526     return TRUE;
527 }
528
529 /*********************************************************************
530  *      GetCalendarInfoA                                (KERNEL32.@)
531  *
532  */
533 int WINAPI GetCalendarInfoA(LCID Locale, CALID Calendar, CALTYPE CalType,
534                             LPSTR lpCalData, int cchData, LPDWORD lpValue)
535 {
536     int ret;
537     LPWSTR lpCalDataW = NULL;
538
539     FIXME("(%08lx,%08lx,%08lx,%p,%d,%p): quarter-stub\n",
540           Locale, Calendar, CalType, lpCalData, cchData, lpValue);
541     /* FIXME: Should verify if Locale is allowable in ANSI, as per MSDN */
542
543     if(cchData)
544       if(!(lpCalDataW = HeapAlloc(GetProcessHeap(), 0, cchData*sizeof(WCHAR)))) return 0;
545
546     ret = GetCalendarInfoW(Locale, Calendar, CalType, lpCalDataW, cchData, lpValue);
547     if(ret && lpCalDataW && lpCalData)
548       WideCharToMultiByte(CP_ACP, 0, lpCalDataW, cchData, lpCalData, cchData, NULL, NULL);
549     if(lpCalDataW)
550       HeapFree(GetProcessHeap(), 0, lpCalDataW);
551
552     return ret;
553 }
554
555 /*********************************************************************
556  *      GetCalendarInfoW                                (KERNEL32.@)
557  *
558  * See GetCalendarInfoA.
559  */
560 int WINAPI GetCalendarInfoW(LCID Locale, CALID Calendar, CALTYPE CalType,
561                             LPWSTR lpCalData, int cchData, LPDWORD lpValue)
562 {
563     FIXME("(%08lx,%08lx,%08lx,%p,%d,%p): quarter-stub\n",
564           Locale, Calendar, CalType, lpCalData, cchData, lpValue);
565
566     if (CalType & CAL_NOUSEROVERRIDE)
567         FIXME("flag CAL_NOUSEROVERRIDE used, not fully implemented\n");
568     if (CalType & CAL_USE_CP_ACP)
569         FIXME("flag CAL_USE_CP_ACP used, not fully implemented\n");
570
571     if (CalType & CAL_RETURN_NUMBER) {
572         if (lpCalData != NULL)
573             WARN("lpCalData not NULL (%p) when it should!\n", lpCalData);
574         if (cchData != 0)
575             WARN("cchData not 0 (%d) when it should!\n", cchData);
576     } else {
577         if (lpValue != NULL)
578             WARN("lpValue not NULL (%p) when it should!\n", lpValue);
579     }
580
581     /* FIXME: No verification is made yet wrt Locale
582      * for the CALTYPES not requiring GetLocaleInfoA */
583     switch (CalType & ~(CAL_NOUSEROVERRIDE|CAL_RETURN_NUMBER|CAL_USE_CP_ACP)) {
584         case CAL_ICALINTVALUE:
585             FIXME("Unimplemented caltype %ld\n", CalType & 0xffff);
586             return E_FAIL;
587         case CAL_SCALNAME:
588             FIXME("Unimplemented caltype %ld\n", CalType & 0xffff);
589             return E_FAIL;
590         case CAL_IYEAROFFSETRANGE:
591             FIXME("Unimplemented caltype %ld\n", CalType & 0xffff);
592             return E_FAIL;
593         case CAL_SERASTRING:
594             FIXME("Unimplemented caltype %ld\n", CalType & 0xffff);
595             return E_FAIL;
596         case CAL_SSHORTDATE:
597             return GetLocaleInfoW(Locale, LOCALE_SSHORTDATE, lpCalData, cchData);
598         case CAL_SLONGDATE:
599             return GetLocaleInfoW(Locale, LOCALE_SLONGDATE, lpCalData, cchData);
600         case CAL_SDAYNAME1:
601             return GetLocaleInfoW(Locale, LOCALE_SDAYNAME1, lpCalData, cchData);
602         case CAL_SDAYNAME2:
603             return GetLocaleInfoW(Locale, LOCALE_SDAYNAME2, lpCalData, cchData);
604         case CAL_SDAYNAME3:
605             return GetLocaleInfoW(Locale, LOCALE_SDAYNAME3, lpCalData, cchData);
606         case CAL_SDAYNAME4:
607             return GetLocaleInfoW(Locale, LOCALE_SDAYNAME4, lpCalData, cchData);
608         case CAL_SDAYNAME5:
609             return GetLocaleInfoW(Locale, LOCALE_SDAYNAME5, lpCalData, cchData);
610         case CAL_SDAYNAME6:
611             return GetLocaleInfoW(Locale, LOCALE_SDAYNAME6, lpCalData, cchData);
612         case CAL_SDAYNAME7:
613             return GetLocaleInfoW(Locale, LOCALE_SDAYNAME7, lpCalData, cchData);
614         case CAL_SABBREVDAYNAME1:
615             return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME1, lpCalData, cchData);
616         case CAL_SABBREVDAYNAME2:
617             return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME2, lpCalData, cchData);
618         case CAL_SABBREVDAYNAME3:
619             return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME3, lpCalData, cchData);
620         case CAL_SABBREVDAYNAME4:
621             return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME4, lpCalData, cchData);
622         case CAL_SABBREVDAYNAME5:
623             return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME5, lpCalData, cchData);
624         case CAL_SABBREVDAYNAME6:
625             return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME6, lpCalData, cchData);
626         case CAL_SABBREVDAYNAME7:
627             return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME7, lpCalData, cchData);
628         case CAL_SMONTHNAME1:
629             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME1, lpCalData, cchData);
630         case CAL_SMONTHNAME2:
631             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME2, lpCalData, cchData);
632         case CAL_SMONTHNAME3:
633             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME3, lpCalData, cchData);
634         case CAL_SMONTHNAME4:
635             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME4, lpCalData, cchData);
636         case CAL_SMONTHNAME5:
637             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME5, lpCalData, cchData);
638         case CAL_SMONTHNAME6:
639             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME6, lpCalData, cchData);
640         case CAL_SMONTHNAME7:
641             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME7, lpCalData, cchData);
642         case CAL_SMONTHNAME8:
643             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME8, lpCalData, cchData);
644         case CAL_SMONTHNAME9:
645             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME9, lpCalData, cchData);
646         case CAL_SMONTHNAME10:
647             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME10, lpCalData, cchData);
648         case CAL_SMONTHNAME11:
649             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME11, lpCalData, cchData);
650         case CAL_SMONTHNAME12:
651             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME12, lpCalData, cchData);
652         case CAL_SMONTHNAME13:
653             return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME13, lpCalData, cchData);
654         case CAL_SABBREVMONTHNAME1:
655             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME1, lpCalData, cchData);
656         case CAL_SABBREVMONTHNAME2:
657             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME2, lpCalData, cchData);
658         case CAL_SABBREVMONTHNAME3:
659             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME3, lpCalData, cchData);
660         case CAL_SABBREVMONTHNAME4:
661             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME4, lpCalData, cchData);
662         case CAL_SABBREVMONTHNAME5:
663             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME5, lpCalData, cchData);
664         case CAL_SABBREVMONTHNAME6:
665             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME6, lpCalData, cchData);
666         case CAL_SABBREVMONTHNAME7:
667             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME7, lpCalData, cchData);
668         case CAL_SABBREVMONTHNAME8:
669             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME8, lpCalData, cchData);
670         case CAL_SABBREVMONTHNAME9:
671             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME9, lpCalData, cchData);
672         case CAL_SABBREVMONTHNAME10:
673             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME10, lpCalData, cchData);
674         case CAL_SABBREVMONTHNAME11:
675             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME11, lpCalData, cchData);
676         case CAL_SABBREVMONTHNAME12:
677             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME12, lpCalData, cchData);
678         case CAL_SABBREVMONTHNAME13:
679             return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME13, lpCalData, cchData);
680         case CAL_SYEARMONTH:
681             return GetLocaleInfoW(Locale, LOCALE_SYEARMONTH, lpCalData, cchData);
682         case CAL_ITWODIGITYEARMAX:
683             if (lpValue) *lpValue = CALINFO_MAX_YEAR;
684             break;
685         default: MESSAGE("Unknown caltype %ld\n",CalType & 0xffff);
686                  return E_FAIL;
687     }
688     return 0;
689 }
690
691 /*********************************************************************
692  *      SetCalendarInfoA                                (KERNEL32.@)
693  *
694  */
695 int WINAPI      SetCalendarInfoA(LCID Locale, CALID Calendar, CALTYPE CalType, LPCSTR lpCalData)
696 {
697     FIXME("(%08lx,%08lx,%08lx,%s): stub\n",
698           Locale, Calendar, CalType, debugstr_a(lpCalData));
699     return 0;
700 }
701
702 /*********************************************************************
703  *      SetCalendarInfoW                                (KERNEL32.@)
704  *
705  * See SetCalendarInfoA.
706  */
707 int WINAPI      SetCalendarInfoW(LCID Locale, CALID Calendar, CALTYPE CalType, LPCWSTR lpCalData)
708 {
709     FIXME("(%08lx,%08lx,%08lx,%s): stub\n",
710           Locale, Calendar, CalType, debugstr_w(lpCalData));
711     return 0;
712 }
713
714 /*********************************************************************
715  *      LocalFileTimeToFileTime                         (KERNEL32.@)
716  */
717 BOOL WINAPI LocalFileTimeToFileTime( const FILETIME *localft, LPFILETIME utcft )
718 {
719     NTSTATUS status;
720     LARGE_INTEGER local, utc;
721
722     local.s.LowPart = localft->dwLowDateTime;
723     local.s.HighPart = localft->dwHighDateTime;
724     if (!(status = RtlLocalTimeToSystemTime( &local, &utc )))
725     {
726         utcft->dwLowDateTime = utc.s.LowPart;
727         utcft->dwHighDateTime = utc.s.HighPart;
728     }
729     else SetLastError( RtlNtStatusToDosError(status) );
730
731     return !status;
732 }
733
734 /*********************************************************************
735  *      FileTimeToLocalFileTime                         (KERNEL32.@)
736  */
737 BOOL WINAPI FileTimeToLocalFileTime( const FILETIME *utcft, LPFILETIME localft )
738 {
739     NTSTATUS status;
740     LARGE_INTEGER local, utc;
741
742     utc.s.LowPart = utcft->dwLowDateTime;
743     utc.s.HighPart = utcft->dwHighDateTime;
744     if (!(status = RtlSystemTimeToLocalTime( &utc, &local )))
745     {
746         localft->dwLowDateTime = local.s.LowPart;
747         localft->dwHighDateTime = local.s.HighPart;
748     }
749     else SetLastError( RtlNtStatusToDosError(status) );
750
751     return !status;
752 }
753
754 /*********************************************************************
755  *      FileTimeToSystemTime                            (KERNEL32.@)
756  */
757 BOOL WINAPI FileTimeToSystemTime( const FILETIME *ft, LPSYSTEMTIME syst )
758 {
759     TIME_FIELDS tf;
760     LARGE_INTEGER t;
761
762     t.s.LowPart = ft->dwLowDateTime;
763     t.s.HighPart = ft->dwHighDateTime;
764     RtlTimeToTimeFields(&t, &tf);
765
766     syst->wYear = tf.Year;
767     syst->wMonth = tf.Month;
768     syst->wDay = tf.Day;
769     syst->wHour = tf.Hour;
770     syst->wMinute = tf.Minute;
771     syst->wSecond = tf.Second;
772     syst->wMilliseconds = tf.Milliseconds;
773     syst->wDayOfWeek = tf.Weekday;
774     return TRUE;
775 }
776
777 /*********************************************************************
778  *      SystemTimeToFileTime                            (KERNEL32.@)
779  */
780 BOOL WINAPI SystemTimeToFileTime( const SYSTEMTIME *syst, LPFILETIME ft )
781 {
782     TIME_FIELDS tf;
783     LARGE_INTEGER t;
784
785     tf.Year = syst->wYear;
786     tf.Month = syst->wMonth;
787     tf.Day = syst->wDay;
788     tf.Hour = syst->wHour;
789     tf.Minute = syst->wMinute;
790     tf.Second = syst->wSecond;
791     tf.Milliseconds = syst->wMilliseconds;
792
793     RtlTimeFieldsToTime(&tf, &t);
794     ft->dwLowDateTime = t.s.LowPart;
795     ft->dwHighDateTime = t.s.HighPart;
796     return TRUE;
797 }
798
799 /*********************************************************************
800  *      CompareFileTime                                 (KERNEL32.@)
801  *
802  * Compare two FILETIME's to each other.
803  *
804  * PARAMS
805  *  x [I] First time
806  *  y [I] time to compare to x
807  *
808  * RETURNS
809  *  -1, 0, or 1 indicating that x is less than, equal to, or greater
810  *  than y respectively.
811  */
812 INT WINAPI CompareFileTime( const FILETIME *x, const FILETIME *y )
813 {
814     if (!x || !y) return -1;
815
816     if (x->dwHighDateTime > y->dwHighDateTime)
817         return 1;
818     if (x->dwHighDateTime < y->dwHighDateTime)
819         return -1;
820     if (x->dwLowDateTime > y->dwLowDateTime)
821         return 1;
822     if (x->dwLowDateTime < y->dwLowDateTime)
823         return -1;
824     return 0;
825 }
826
827 /*********************************************************************
828  *      GetLocalTime                                    (KERNEL32.@)
829  *
830  * Get the current local time.
831  *
832  * RETURNS
833  *  Nothing.
834  */
835 VOID WINAPI GetLocalTime(LPSYSTEMTIME systime) /* [O] Destination for current time */
836 {
837     FILETIME lft;
838     LARGE_INTEGER ft, ft2;
839
840     NtQuerySystemTime(&ft);
841     RtlSystemTimeToLocalTime(&ft, &ft2);
842     lft.dwLowDateTime = ft2.s.LowPart;
843     lft.dwHighDateTime = ft2.s.HighPart;
844     FileTimeToSystemTime(&lft, systime);
845 }
846
847 /*********************************************************************
848  *      GetSystemTime                                   (KERNEL32.@)
849  *
850  * Get the current system time.
851  *
852  * RETURNS
853  *  Nothing.
854  */
855 VOID WINAPI GetSystemTime(LPSYSTEMTIME systime) /* [O] Destination for current time */
856 {
857     FILETIME ft;
858     LARGE_INTEGER t;
859
860     NtQuerySystemTime(&t);
861     ft.dwLowDateTime = t.s.LowPart;
862     ft.dwHighDateTime = t.s.HighPart;
863     FileTimeToSystemTime(&ft, systime);
864 }