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