- Implement ReplaceFileA/W (not fully)
[reactos.git] / reactos / dll / win32 / kernel32 / misc / time.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/misc/time.c
6 * PURPOSE: Time conversion functions
7 * PROGRAMMER: Ariadne
8 * DOSDATE and DOSTIME structures from Onno Hovers
9 * UPDATE HISTORY:
10 * Created 19/01/99
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <k32.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20 /* TYPES *********************************************************************/
21
22 typedef struct __DOSTIME
23 {
24 WORD Second:5;
25 WORD Minute:6;
26 WORD Hour:5;
27 } DOSTIME, *PDOSTIME;
28
29 typedef struct __DOSDATE
30 {
31 WORD Day:5;
32 WORD Month:4;
33 WORD Year:5;
34 } DOSDATE, *PDOSDATE;
35
36 static const int MonthLengths[2][12] =
37 {
38 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
39 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
40 };
41
42 #define TICKSPERMIN 600000000
43
44 #define LL2FILETIME( ll, pft )\
45 (pft)->dwLowDateTime = (UINT)(ll); \
46 (pft)->dwHighDateTime = (UINT)((ll) >> 32);
47 #define FILETIME2LL( pft, ll) \
48 ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime ;
49
50 /* STATIC FUNCTIONS ****************************************************************/
51
52 static inline int IsLeapYear(int Year)
53 {
54 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
55 }
56
57 /***********************************************************************
58 * TIME_DayLightCompareDate
59 *
60 * Compares two dates without looking at the year.
61 *
62 * PARAMS
63 * date [in] The local time to compare.
64 * compareDate [in] The daylight savings begin or end date.
65 *
66 * RETURNS
67 *
68 * -1 if date < compareDate
69 * 0 if date == compareDate
70 * 1 if date > compareDate
71 * -2 if an error occurs
72 */
73
74 static int TIME_DayLightCompareDate( const SYSTEMTIME *date,
75 const SYSTEMTIME *compareDate )
76 {
77 int limit_day, dayinsecs;
78
79 if (date->wMonth < compareDate->wMonth)
80 return -1; /* We are in a month before the date limit. */
81
82 if (date->wMonth > compareDate->wMonth)
83 return 1; /* We are in a month after the date limit. */
84
85 /* if year is 0 then date is in day-of-week format, otherwise
86 * it's absolute date.
87 */
88 if (compareDate->wYear == 0)
89 {
90 WORD First;
91 /* compareDate->wDay is interpreted as number of the week in the month
92 * 5 means: the last week in the month */
93 int weekofmonth = compareDate->wDay;
94 /* calculate the day of the first DayOfWeek in the month */
95 First = ( 6 + compareDate->wDayOfWeek - date->wDayOfWeek + date->wDay
96 ) % 7 + 1;
97 limit_day = First + 7 * (weekofmonth - 1);
98 /* check needed for the 5th weekday of the month */
99 if(limit_day > MonthLengths[date->wMonth==2 && IsLeapYear(date->wYear)]
100 [date->wMonth - 1])
101 limit_day -= 7;
102 }
103 else
104 {
105 limit_day = compareDate->wDay;
106 }
107
108 /* convert to seconds */
109 limit_day = ((limit_day * 24 + compareDate->wHour) * 60 +
110 compareDate->wMinute ) * 60;
111 dayinsecs = ((date->wDay * 24 + date->wHour) * 60 +
112 date->wMinute ) * 60 + date->wSecond;
113 /* and compare */
114 return dayinsecs < limit_day ? -1 :
115 dayinsecs > limit_day ? 1 :
116 0; /* date is equal to the date limit. */
117 }
118
119 /***********************************************************************
120 * TIME_CompTimeZoneID
121 *
122 * Computes the local time bias for a given time and time zone.
123 *
124 * PARAMS
125 * pTZinfo [in] The time zone data.
126 * lpFileTime [in] The system or local time.
127 * islocal [in] it is local time.
128 *
129 * RETURNS
130 * TIME_ZONE_ID_INVALID An error occurred
131 * TIME_ZONE_ID_UNKNOWN There are no transition time known
132 * TIME_ZONE_ID_STANDARD Current time is standard time
133 * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time
134 */
135 static DWORD TIME_CompTimeZoneID ( const TIME_ZONE_INFORMATION *pTZinfo,
136 FILETIME *lpFileTime, BOOL islocal )
137 {
138 int ret;
139 BOOL beforeStandardDate, afterDaylightDate;
140 DWORD retval = TIME_ZONE_ID_INVALID;
141 LONGLONG llTime = 0; /* initialized to prevent gcc complaining */
142 SYSTEMTIME SysTime;
143 FILETIME ftTemp;
144
145 if (pTZinfo->DaylightDate.wMonth != 0)
146 {
147 /* if year is 0 then date is in day-of-week format, otherwise
148 * it's absolute date.
149 */
150 if (pTZinfo->StandardDate.wMonth == 0 ||
151 (pTZinfo->StandardDate.wYear == 0 &&
152 (pTZinfo->StandardDate.wDay<1 ||
153 pTZinfo->StandardDate.wDay>5 ||
154 pTZinfo->DaylightDate.wDay<1 ||
155 pTZinfo->DaylightDate.wDay>5)))
156 {
157 SetLastError(ERROR_INVALID_PARAMETER);
158 return TIME_ZONE_ID_INVALID;
159 }
160
161 if (!islocal) {
162 FILETIME2LL( lpFileTime, llTime );
163 llTime -= ( pTZinfo->Bias + pTZinfo->DaylightBias )
164 * (LONGLONG)600000000;
165 LL2FILETIME( llTime, &ftTemp)
166 lpFileTime = &ftTemp;
167 }
168
169 FileTimeToSystemTime(lpFileTime, &SysTime);
170
171 /* check for daylight savings */
172 ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->StandardDate);
173 if (ret == -2)
174 return TIME_ZONE_ID_INVALID;
175
176 beforeStandardDate = ret < 0;
177
178 if (!islocal) {
179 llTime -= ( pTZinfo->StandardBias - pTZinfo->DaylightBias )
180 * (LONGLONG)600000000;
181 LL2FILETIME( llTime, &ftTemp)
182 FileTimeToSystemTime(lpFileTime, &SysTime);
183 }
184
185 ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->DaylightDate);
186 if (ret == -2)
187 return TIME_ZONE_ID_INVALID;
188
189 afterDaylightDate = ret >= 0;
190
191 retval = TIME_ZONE_ID_STANDARD;
192 if( pTZinfo->DaylightDate.wMonth < pTZinfo->StandardDate.wMonth ) {
193 /* Northern hemisphere */
194 if( beforeStandardDate && afterDaylightDate )
195 retval = TIME_ZONE_ID_DAYLIGHT;
196 } else /* Down south */
197 if( beforeStandardDate || afterDaylightDate )
198 retval = TIME_ZONE_ID_DAYLIGHT;
199 } else
200 /* No transition date */
201 retval = TIME_ZONE_ID_UNKNOWN;
202
203 return retval;
204 }
205
206 static BOOL TIME_GetTimezoneBias( const TIME_ZONE_INFORMATION *pTZinfo,
207 FILETIME *lpFileTime, BOOL islocal, LONG *pBias )
208 {
209 LONG bias = pTZinfo->Bias;
210 DWORD tzid = TIME_CompTimeZoneID( pTZinfo, lpFileTime, islocal);
211
212 if( tzid == TIME_ZONE_ID_INVALID)
213 return FALSE;
214 if (tzid == TIME_ZONE_ID_DAYLIGHT)
215 bias += pTZinfo->DaylightBias;
216 else if (tzid == TIME_ZONE_ID_STANDARD)
217 bias += pTZinfo->StandardBias;
218 *pBias = bias;
219 return TRUE;
220 }
221
222
223 /* EXPORTED FUNCTIONS ****************************************************************/
224
225 /*
226 * @implemented
227 */
228 BOOL
229 STDCALL
230 FileTimeToDosDateTime(
231 CONST FILETIME *lpFileTime,
232 LPWORD lpFatDate,
233 LPWORD lpFatTime
234 )
235 {
236 PDOSTIME pdtime=(PDOSTIME) lpFatTime;
237 PDOSDATE pddate=(PDOSDATE) lpFatDate;
238 SYSTEMTIME SystemTime = { 0 };
239
240 if ( lpFileTime == NULL )
241 return FALSE;
242
243 if ( lpFatDate == NULL )
244 return FALSE;
245
246 if ( lpFatTime == NULL )
247 return FALSE;
248
249 FileTimeToSystemTime(
250 lpFileTime,
251 &SystemTime
252 );
253
254 pdtime->Second = SystemTime.wSecond / 2;
255 pdtime->Minute = SystemTime.wMinute;
256 pdtime->Hour = SystemTime.wHour;
257
258 pddate->Day = SystemTime.wDay;
259 pddate->Month = SystemTime.wMonth;
260 pddate->Year = SystemTime.wYear - 1980;
261
262 return TRUE;
263 }
264
265
266 /*
267 * @implemented
268 */
269 BOOL
270 STDCALL
271 DosDateTimeToFileTime(
272 WORD wFatDate,
273 WORD wFatTime,
274 LPFILETIME lpFileTime
275 )
276 {
277 PDOSTIME pdtime = (PDOSTIME) &wFatTime;
278 PDOSDATE pddate = (PDOSDATE) &wFatDate;
279 SYSTEMTIME SystemTime;
280
281 if ( lpFileTime == NULL )
282 return FALSE;
283
284 SystemTime.wMilliseconds = 0;
285 SystemTime.wSecond = pdtime->Second * 2;
286 SystemTime.wMinute = pdtime->Minute;
287 SystemTime.wHour = pdtime->Hour;
288
289 SystemTime.wDay = pddate->Day;
290 SystemTime.wMonth = pddate->Month;
291 SystemTime.wYear = 1980 + pddate->Year;
292
293 SystemTimeToFileTime(&SystemTime,lpFileTime);
294
295 return TRUE;
296 }
297
298
299 /*
300 * @implemented
301 */
302 LONG
303 STDCALL
304 CompareFileTime(
305 CONST FILETIME *lpFileTime1,
306 CONST FILETIME *lpFileTime2
307 )
308 {
309 if ( lpFileTime1 == NULL )
310 return 0;
311 if ( lpFileTime2 == NULL )
312 return 0;
313
314 if (*((PLONGLONG)lpFileTime1) > *((PLONGLONG)lpFileTime2))
315 return 1;
316 else if (*((PLONGLONG)lpFileTime1) < *((PLONGLONG)lpFileTime2))
317 return -1;
318
319 return 0;
320 }
321
322
323 /*
324 * @implemented
325 */
326 VOID STDCALL
327 GetSystemTimeAsFileTime (PFILETIME lpFileTime)
328 {
329 do
330 {
331 lpFileTime->dwHighDateTime = SharedUserData->SystemTime.High1Time;
332 lpFileTime->dwLowDateTime = SharedUserData->SystemTime.LowPart;
333 }
334 while (lpFileTime->dwHighDateTime != (DWORD)SharedUserData->SystemTime.High2Time);
335 }
336
337
338 /*
339 * @implemented
340 */
341 BOOL
342 STDCALL
343 SystemTimeToFileTime(
344 CONST SYSTEMTIME * lpSystemTime,
345 LPFILETIME lpFileTime
346 )
347
348 {
349 TIME_FIELDS TimeFields;
350 LARGE_INTEGER liTime;
351
352 TimeFields.Year = lpSystemTime->wYear;
353 TimeFields.Month = lpSystemTime->wMonth;
354 TimeFields.Day = lpSystemTime->wDay;
355 TimeFields.Hour = lpSystemTime->wHour;
356 TimeFields.Minute = lpSystemTime->wMinute;
357 TimeFields.Second = lpSystemTime->wSecond;
358 TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
359
360 if (RtlTimeFieldsToTime (&TimeFields, &liTime))
361 {
362 lpFileTime->dwLowDateTime = liTime.u.LowPart;
363 lpFileTime->dwHighDateTime = liTime.u.HighPart;
364 return TRUE;
365 }
366 return FALSE;
367 }
368
369
370 /*
371 * @implemented
372 */
373 BOOL
374 STDCALL
375 FileTimeToSystemTime(
376 CONST FILETIME *lpFileTime,
377 LPSYSTEMTIME lpSystemTime
378 )
379 {
380 TIME_FIELDS TimeFields;
381 LARGE_INTEGER liTime;
382
383 if(lpFileTime->dwHighDateTime & 0x80000000)
384 return FALSE;
385
386 liTime.u.LowPart = lpFileTime->dwLowDateTime;
387 liTime.u.HighPart = lpFileTime->dwHighDateTime;
388
389 RtlTimeToTimeFields(&liTime, &TimeFields);
390
391 lpSystemTime->wYear = TimeFields.Year;
392 lpSystemTime->wMonth = TimeFields.Month;
393 lpSystemTime->wDay = TimeFields.Day;
394 lpSystemTime->wHour = TimeFields.Hour;
395 lpSystemTime->wMinute = TimeFields.Minute;
396 lpSystemTime->wSecond = TimeFields.Second;
397 lpSystemTime->wMilliseconds = TimeFields.Milliseconds;
398 lpSystemTime->wDayOfWeek = TimeFields.Weekday;
399
400 return TRUE;
401 }
402
403
404 /*
405 * @implemented
406 */
407 BOOL
408 STDCALL
409 FileTimeToLocalFileTime(
410 CONST FILETIME *lpFileTime,
411 LPFILETIME lpLocalFileTime
412 )
413 {
414 LARGE_INTEGER TimeZoneBias;
415
416 do
417 {
418 TimeZoneBias.HighPart = SharedUserData->TimeZoneBias.High1Time;
419 TimeZoneBias.LowPart = SharedUserData->TimeZoneBias.LowPart;
420 }
421 while (TimeZoneBias.HighPart != SharedUserData->TimeZoneBias.High2Time);
422
423 *((PLONGLONG)lpLocalFileTime) =
424 *((PLONGLONG)lpFileTime) - TimeZoneBias.QuadPart;
425
426 return TRUE;
427 }
428
429
430 /*
431 * @implemented
432 */
433 BOOL
434 STDCALL
435 LocalFileTimeToFileTime(
436 CONST FILETIME *lpLocalFileTime,
437 LPFILETIME lpFileTime
438 )
439 {
440 LARGE_INTEGER TimeZoneBias;
441
442 do
443 {
444 TimeZoneBias.HighPart = SharedUserData->TimeZoneBias.High1Time;
445 TimeZoneBias.LowPart = SharedUserData->TimeZoneBias.LowPart;
446 }
447 while (TimeZoneBias.HighPart != SharedUserData->TimeZoneBias.High2Time);
448
449 *((PLONGLONG)lpFileTime) =
450 *((PLONGLONG)lpLocalFileTime) + TimeZoneBias.QuadPart;
451
452 return TRUE;
453 }
454
455
456 /*
457 * @implemented
458 */
459 VOID STDCALL
460 GetLocalTime(LPSYSTEMTIME lpSystemTime)
461 {
462 FILETIME FileTime;
463 FILETIME LocalFileTime;
464
465 GetSystemTimeAsFileTime(&FileTime);
466 FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
467 FileTimeToSystemTime(&LocalFileTime, lpSystemTime);
468 }
469
470
471 /*
472 * @implemented
473 */
474 VOID STDCALL
475 GetSystemTime(LPSYSTEMTIME lpSystemTime)
476 {
477 FILETIME FileTime;
478
479 GetSystemTimeAsFileTime(&FileTime);
480 FileTimeToSystemTime(&FileTime, lpSystemTime);
481 }
482
483
484 /*
485 * @implemented
486 */
487 BOOL STDCALL
488 SetLocalTime(CONST SYSTEMTIME *lpSystemTime)
489 {
490 FILETIME LocalFileTime;
491 LARGE_INTEGER FileTime;
492 NTSTATUS Status;
493
494 SystemTimeToFileTime(lpSystemTime, &LocalFileTime);
495 LocalFileTimeToFileTime(&LocalFileTime, (FILETIME *)&FileTime);
496 Status = NtSetSystemTime(&FileTime, &FileTime);
497 if (!NT_SUCCESS(Status))
498 return FALSE;
499 return TRUE;
500 }
501
502
503 /*
504 * @implemented
505 */
506 BOOL STDCALL
507 SetSystemTime(CONST SYSTEMTIME *lpSystemTime)
508 {
509 LARGE_INTEGER NewSystemTime;
510 NTSTATUS Status;
511
512 SystemTimeToFileTime(lpSystemTime, (PFILETIME)&NewSystemTime);
513 Status = NtSetSystemTime(&NewSystemTime, &NewSystemTime);
514 if (!NT_SUCCESS(Status))
515 return FALSE;
516 return TRUE;
517 }
518
519
520 /*
521 * @implemented
522 */
523 DWORD STDCALL
524 GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
525 {
526 NTSTATUS Status;
527
528 DPRINT("GetTimeZoneInformation()\n");
529
530 Status = NtQuerySystemInformation(SystemCurrentTimeZoneInformation,
531 lpTimeZoneInformation,
532 sizeof(TIME_ZONE_INFORMATION),
533 NULL);
534 if (!NT_SUCCESS(Status))
535 {
536 SetLastErrorByStatus(Status);
537 return TIME_ZONE_ID_INVALID;
538 }
539
540 return(SharedUserData->TimeZoneId);
541 }
542
543
544 /*
545 * @implemented
546 */
547 BOOL STDCALL
548 SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation)
549 {
550 NTSTATUS Status;
551
552 DPRINT("SetTimeZoneInformation()\n");
553
554 Status = RtlSetTimeZoneInformation((LPTIME_ZONE_INFORMATION)lpTimeZoneInformation);
555 if (!NT_SUCCESS(Status))
556 {
557 DPRINT1("RtlSetTimeZoneInformation() failed (Status %lx)\n", Status);
558 SetLastErrorByStatus(Status);
559 return FALSE;
560 }
561
562 Status = NtSetSystemInformation(SystemCurrentTimeZoneInformation,
563 (PVOID)lpTimeZoneInformation,
564 sizeof(TIME_ZONE_INFORMATION));
565 if (!NT_SUCCESS(Status))
566 {
567 DPRINT1("NtSetSystemInformation() failed (Status %lx)\n", Status);
568 SetLastErrorByStatus(Status);
569 return FALSE;
570 }
571
572 return TRUE;
573 }
574
575
576 /*
577 * @implemented
578 */
579 DWORD STDCALL
580 GetTickCount(VOID)
581 {
582 return (DWORD)((ULONGLONG)SharedUserData->TickCountLowDeprecated * SharedUserData->TickCountMultiplier / 16777216);
583 }
584
585
586 /*
587 * @implemented
588 */
589 ULONGLONG WINAPI
590 GetTickCount64(VOID)
591 {
592 return (ULONGLONG)SharedUserData->TickCountLowDeprecated * (ULONGLONG)SharedUserData->TickCountMultiplier / 16777216;
593 }
594
595
596 /*
597 * @implemented
598 */
599 BOOL STDCALL
600 SystemTimeToTzSpecificLocalTime(
601 CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation,
602 CONST SYSTEMTIME *lpUniversalTime,
603 LPSYSTEMTIME lpLocalTime
604 )
605 {
606 TIME_ZONE_INFORMATION TimeZoneInformation;
607 LPTIME_ZONE_INFORMATION lpTzInfo;
608 LARGE_INTEGER FileTime;
609
610 if (!lpTimeZoneInformation)
611 {
612 GetTimeZoneInformation(&TimeZoneInformation);
613 lpTzInfo = &TimeZoneInformation;
614 }
615 else
616 lpTzInfo = (LPTIME_ZONE_INFORMATION)lpTimeZoneInformation;
617
618 if (!lpUniversalTime)
619 return FALSE;
620
621 if (!lpLocalTime)
622 return FALSE;
623
624 SystemTimeToFileTime(lpUniversalTime, (PFILETIME)&FileTime);
625 FileTime.QuadPart -= (lpTzInfo->Bias * TICKSPERMIN);
626 FileTimeToSystemTime((PFILETIME)&FileTime, lpLocalTime);
627
628 return TRUE;
629 }
630
631
632 /*
633 * @implemented
634 */
635 BOOL STDCALL
636 GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,
637 PDWORD lpTimeIncrement,
638 PBOOL lpTimeAdjustmentDisabled)
639 {
640 SYSTEM_QUERY_TIME_ADJUST_INFORMATION Buffer;
641 NTSTATUS Status;
642
643 Status = NtQuerySystemInformation(SystemTimeAdjustmentInformation,
644 &Buffer,
645 sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION),
646 NULL);
647 if (!NT_SUCCESS(Status))
648 {
649 SetLastErrorByStatus(Status);
650 return FALSE;
651 }
652
653 *lpTimeAdjustment = (DWORD)Buffer.TimeAdjustment;
654 *lpTimeIncrement = (DWORD)Buffer.TimeIncrement;
655 *lpTimeAdjustmentDisabled = (BOOL)Buffer.Enable;
656
657 return TRUE;
658 }
659
660
661 /*
662 * @implemented
663 */
664 BOOL STDCALL
665 SetSystemTimeAdjustment(DWORD dwTimeAdjustment,
666 BOOL bTimeAdjustmentDisabled)
667 {
668 NTSTATUS Status;
669 SYSTEM_SET_TIME_ADJUST_INFORMATION Buffer;
670
671 Buffer.TimeAdjustment = (ULONG)dwTimeAdjustment;
672 Buffer.Enable = (BOOLEAN)bTimeAdjustmentDisabled;
673
674 Status = NtSetSystemInformation(SystemTimeAdjustmentInformation,
675 &Buffer,
676 sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION));
677 if (!NT_SUCCESS(Status))
678 {
679 SetLastErrorByStatus(Status);
680 return FALSE;
681 }
682
683 return TRUE;
684 }
685
686
687 /*
688 * @implemented
689 */
690 BOOL
691 STDCALL
692 GetSystemTimes(
693 LPFILETIME lpIdleTime,
694 LPFILETIME lpKernelTime,
695 LPFILETIME lpUserTime
696 )
697 {
698 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcPerfInfo;
699 NTSTATUS Status;
700
701 Status = ZwQuerySystemInformation(SystemProcessorPerformanceInformation,
702 &SysProcPerfInfo,
703 sizeof(SysProcPerfInfo),
704 NULL);
705
706 if (!NT_SUCCESS(Status))
707 {
708 SetLastErrorByStatus(Status);
709 return FALSE;
710 }
711 /*
712 Good only for one processor system.
713 */
714
715 lpIdleTime->dwLowDateTime = SysProcPerfInfo.IdleTime.LowPart;
716 lpIdleTime->dwHighDateTime = SysProcPerfInfo.IdleTime.HighPart;
717
718 lpKernelTime->dwLowDateTime = SysProcPerfInfo.KernelTime.LowPart;
719 lpKernelTime->dwHighDateTime = SysProcPerfInfo.KernelTime.HighPart;
720
721 lpUserTime->dwLowDateTime = SysProcPerfInfo.UserTime.LowPart;
722 lpUserTime->dwHighDateTime = SysProcPerfInfo.UserTime.HighPart;
723
724 return TRUE;
725 }
726
727
728 /*
729 * @implemented (ripped from Wine 1.0)
730 */
731 BOOL
732 STDCALL
733 TzSpecificLocalTimeToSystemTime(
734 CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation,
735 CONST SYSTEMTIME *lpLocalTime,
736 LPSYSTEMTIME lpUniversalTime
737 )
738 {
739 FILETIME ft;
740 LONG lBias;
741 LONGLONG t;
742 TIME_ZONE_INFORMATION tzinfo;
743
744 if (lpTimeZoneInformation != NULL)
745 {
746 tzinfo = *lpTimeZoneInformation;
747 }
748 else
749 {
750 if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
751 return FALSE;
752 }
753
754 if (!SystemTimeToFileTime(lpLocalTime, &ft))
755 return FALSE;
756
757 FILETIME2LL(&ft, t)
758
759 if (!TIME_GetTimezoneBias(&tzinfo, &ft, TRUE, &lBias))
760 return FALSE;
761
762 /* convert minutes to 100-nanoseconds-ticks */
763 t += (LONGLONG)lBias * TICKSPERMIN;
764 LL2FILETIME(t, &ft)
765
766 return FileTimeToSystemTime(&ft, lpUniversalTime);
767 }
768
769 /* EOF */