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
8 * DOSDATE and DOSTIME structures from Onno Hovers
13 /* INCLUDES ******************************************************************/
20 /* TYPES *********************************************************************/
22 typedef struct __DOSTIME
29 typedef struct __DOSDATE
36 #define TICKSPERMIN 600000000
38 #define LL2FILETIME( ll, pft )\
39 (pft)->dwLowDateTime = (UINT)(ll); \
40 (pft)->dwHighDateTime = (UINT)((ll) >> 32);
41 #define FILETIME2LL( pft, ll) \
42 ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime ;
44 static const int MonthLengths
[2][12] =
46 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
47 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
50 /* STATIC FUNTIONS **********************************************************/
52 static inline int IsLeapYear(int Year
)
54 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0) ? 1 : 0;
57 /***********************************************************************
58 * TIME_DayLightCompareDate
60 * Compares two dates without looking at the year.
63 * date [in] The local time to compare.
64 * compareDate [in] The daylight savings begin or end date.
68 * -1 if date < compareDate
69 * 0 if date == compareDate
70 * 1 if date > compareDate
71 * -2 if an error occurs
73 static int TIME_DayLightCompareDate( const SYSTEMTIME
*date
,
74 const SYSTEMTIME
*compareDate
)
76 int limit_day
, dayinsecs
;
78 if (date
->wMonth
< compareDate
->wMonth
)
79 return -1; /* We are in a month before the date limit. */
81 if (date
->wMonth
> compareDate
->wMonth
)
82 return 1; /* We are in a month after the date limit. */
84 /* if year is 0 then date is in day-of-week format, otherwise
87 if (compareDate
->wYear
== 0)
90 /* compareDate->wDay is interpreted as number of the week in the month
91 * 5 means: the last week in the month */
92 int weekofmonth
= compareDate
->wDay
;
93 /* calculate the day of the first DayOfWeek in the month */
94 First
= ( 6 + compareDate
->wDayOfWeek
- date
->wDayOfWeek
+ date
->wDay
96 limit_day
= First
+ 7 * (weekofmonth
- 1);
97 /* check needed for the 5th weekday of the month */
98 if(limit_day
> MonthLengths
[date
->wMonth
==2 && IsLeapYear(date
->wYear
)]
104 limit_day
= compareDate
->wDay
;
107 /* convert to seconds */
108 limit_day
= ((limit_day
* 24 + compareDate
->wHour
) * 60 +
109 compareDate
->wMinute
) * 60;
110 dayinsecs
= ((date
->wDay
* 24 + date
->wHour
) * 60 +
111 date
->wMinute
) * 60 + date
->wSecond
;
113 return dayinsecs
< limit_day
? -1 :
114 dayinsecs
> limit_day
? 1 :
115 0; /* date is equal to the date limit. */
118 /***********************************************************************
119 * TIME_CompTimeZoneID
121 * Computes the local time bias for a given time and time zone.
124 * pTZinfo [in] The time zone data.
125 * lpFileTime [in] The system or local time.
126 * islocal [in] it is local time.
129 * TIME_ZONE_ID_INVALID An error occurred
130 * TIME_ZONE_ID_UNKNOWN There are no transition time known
131 * TIME_ZONE_ID_STANDARD Current time is standard time
132 * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time
134 static DWORD
TIME_CompTimeZoneID ( const TIME_ZONE_INFORMATION
*pTZinfo
,
135 FILETIME
*lpFileTime
, BOOL islocal
)
138 BOOL beforeStandardDate
, afterDaylightDate
;
139 DWORD retval
= TIME_ZONE_ID_INVALID
;
140 LONGLONG llTime
= 0; /* initialized to prevent gcc complaining */
144 if (pTZinfo
->DaylightDate
.wMonth
!= 0)
146 /* if year is 0 then date is in day-of-week format, otherwise
147 * it's absolute date.
149 if (pTZinfo
->StandardDate
.wMonth
== 0 ||
150 (pTZinfo
->StandardDate
.wYear
== 0 &&
151 (pTZinfo
->StandardDate
.wDay
<1 ||
152 pTZinfo
->StandardDate
.wDay
>5 ||
153 pTZinfo
->DaylightDate
.wDay
<1 ||
154 pTZinfo
->DaylightDate
.wDay
>5)))
156 SetLastError(ERROR_INVALID_PARAMETER
);
157 return TIME_ZONE_ID_INVALID
;
161 FILETIME2LL( lpFileTime
, llTime
);
162 llTime
-= ( pTZinfo
->Bias
+ pTZinfo
->DaylightBias
)
163 * (LONGLONG
) TICKSPERMIN
;
164 LL2FILETIME( llTime
, &ftTemp
)
165 lpFileTime
= &ftTemp
;
168 FileTimeToSystemTime(lpFileTime
, &SysTime
);
170 /* check for daylight savings */
171 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->StandardDate
);
173 return TIME_ZONE_ID_INVALID
;
175 beforeStandardDate
= ret
< 0;
178 llTime
-= ( pTZinfo
->StandardBias
- pTZinfo
->DaylightBias
)
179 * (LONGLONG
) TICKSPERMIN
;
180 LL2FILETIME( llTime
, &ftTemp
)
181 FileTimeToSystemTime(lpFileTime
, &SysTime
);
184 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->DaylightDate
);
186 return TIME_ZONE_ID_INVALID
;
188 afterDaylightDate
= ret
>= 0;
190 retval
= TIME_ZONE_ID_STANDARD
;
191 if( pTZinfo
->DaylightDate
.wMonth
< pTZinfo
->StandardDate
.wMonth
) {
192 /* Northern hemisphere */
193 if( beforeStandardDate
&& afterDaylightDate
)
194 retval
= TIME_ZONE_ID_DAYLIGHT
;
195 } else /* Down south */
196 if( beforeStandardDate
|| afterDaylightDate
)
197 retval
= TIME_ZONE_ID_DAYLIGHT
;
199 /* No transition date */
200 retval
= TIME_ZONE_ID_UNKNOWN
;
205 /***********************************************************************
206 * TIME_GetTimezoneBias
208 * Calculates the local time bias for a given time zone.
211 * pTZinfo [in] The time zone data.
212 * lpFileTime [in] The system or local time.
213 * islocal [in] It is local time.
214 * pBias [out] The calculated bias in minutes.
217 * TRUE when the time zone bias was calculated.
219 static BOOL
TIME_GetTimezoneBias( const TIME_ZONE_INFORMATION
*pTZinfo
,
220 FILETIME
*lpFileTime
, BOOL islocal
, LONG
*pBias
)
222 LONG bias
= pTZinfo
->Bias
;
223 DWORD tzid
= TIME_CompTimeZoneID( pTZinfo
, lpFileTime
, islocal
);
225 if( tzid
== TIME_ZONE_ID_INVALID
)
227 if (tzid
== TIME_ZONE_ID_DAYLIGHT
)
228 bias
+= pTZinfo
->DaylightBias
;
229 else if (tzid
== TIME_ZONE_ID_STANDARD
)
230 bias
+= pTZinfo
->StandardBias
;
236 /* FUNCTIONS ****************************************************************/
243 FileTimeToDosDateTime(
244 CONST FILETIME
*lpFileTime
,
249 PDOSTIME pdtime
=(PDOSTIME
) lpFatTime
;
250 PDOSDATE pddate
=(PDOSDATE
) lpFatDate
;
251 SYSTEMTIME SystemTime
= { 0 };
253 if ( lpFileTime
== NULL
)
256 if ( lpFatDate
== NULL
)
259 if ( lpFatTime
== NULL
)
262 FileTimeToSystemTime(
267 pdtime
->Second
= SystemTime
.wSecond
/ 2;
268 pdtime
->Minute
= SystemTime
.wMinute
;
269 pdtime
->Hour
= SystemTime
.wHour
;
271 pddate
->Day
= SystemTime
.wDay
;
272 pddate
->Month
= SystemTime
.wMonth
;
273 pddate
->Year
= SystemTime
.wYear
- 1980;
284 DosDateTimeToFileTime(
287 LPFILETIME lpFileTime
290 PDOSTIME pdtime
= (PDOSTIME
) &wFatTime
;
291 PDOSDATE pddate
= (PDOSDATE
) &wFatDate
;
292 SYSTEMTIME SystemTime
;
294 if ( lpFileTime
== NULL
)
297 SystemTime
.wMilliseconds
= 0;
298 SystemTime
.wSecond
= pdtime
->Second
* 2;
299 SystemTime
.wMinute
= pdtime
->Minute
;
300 SystemTime
.wHour
= pdtime
->Hour
;
302 SystemTime
.wDay
= pddate
->Day
;
303 SystemTime
.wMonth
= pddate
->Month
;
304 SystemTime
.wYear
= 1980 + pddate
->Year
;
306 SystemTimeToFileTime(&SystemTime
,lpFileTime
);
318 CONST FILETIME
*lpFileTime1
,
319 CONST FILETIME
*lpFileTime2
322 if ( lpFileTime1
== NULL
)
324 if ( lpFileTime2
== NULL
)
327 if (*((PLONGLONG
)lpFileTime1
) > *((PLONGLONG
)lpFileTime2
))
329 else if (*((PLONGLONG
)lpFileTime1
) < *((PLONGLONG
)lpFileTime2
))
340 GetSystemTimeAsFileTime (PFILETIME lpFileTime
)
344 lpFileTime
->dwHighDateTime
= SharedUserData
->SystemTime
.High1Time
;
345 lpFileTime
->dwLowDateTime
= SharedUserData
->SystemTime
.LowPart
;
347 while (lpFileTime
->dwHighDateTime
!= (DWORD
)SharedUserData
->SystemTime
.High2Time
);
356 SystemTimeToFileTime(
357 CONST SYSTEMTIME
* lpSystemTime
,
358 LPFILETIME lpFileTime
362 TIME_FIELDS TimeFields
;
363 LARGE_INTEGER liTime
;
365 TimeFields
.Year
= lpSystemTime
->wYear
;
366 TimeFields
.Month
= lpSystemTime
->wMonth
;
367 TimeFields
.Day
= lpSystemTime
->wDay
;
368 TimeFields
.Hour
= lpSystemTime
->wHour
;
369 TimeFields
.Minute
= lpSystemTime
->wMinute
;
370 TimeFields
.Second
= lpSystemTime
->wSecond
;
371 TimeFields
.Milliseconds
= lpSystemTime
->wMilliseconds
;
373 if (RtlTimeFieldsToTime (&TimeFields
, &liTime
))
375 lpFileTime
->dwLowDateTime
= liTime
.u
.LowPart
;
376 lpFileTime
->dwHighDateTime
= liTime
.u
.HighPart
;
388 FileTimeToSystemTime(
389 CONST FILETIME
*lpFileTime
,
390 LPSYSTEMTIME lpSystemTime
393 TIME_FIELDS TimeFields
;
394 LARGE_INTEGER liTime
;
396 if(lpFileTime
->dwHighDateTime
& 0x80000000)
399 liTime
.u
.LowPart
= lpFileTime
->dwLowDateTime
;
400 liTime
.u
.HighPart
= lpFileTime
->dwHighDateTime
;
402 RtlTimeToTimeFields(&liTime
, &TimeFields
);
404 lpSystemTime
->wYear
= TimeFields
.Year
;
405 lpSystemTime
->wMonth
= TimeFields
.Month
;
406 lpSystemTime
->wDay
= TimeFields
.Day
;
407 lpSystemTime
->wHour
= TimeFields
.Hour
;
408 lpSystemTime
->wMinute
= TimeFields
.Minute
;
409 lpSystemTime
->wSecond
= TimeFields
.Second
;
410 lpSystemTime
->wMilliseconds
= TimeFields
.Milliseconds
;
411 lpSystemTime
->wDayOfWeek
= TimeFields
.Weekday
;
422 FileTimeToLocalFileTime(
423 CONST FILETIME
*lpFileTime
,
424 LPFILETIME lpLocalFileTime
427 LARGE_INTEGER TimeZoneBias
;
431 TimeZoneBias
.HighPart
= SharedUserData
->TimeZoneBias
.High1Time
;
432 TimeZoneBias
.LowPart
= SharedUserData
->TimeZoneBias
.LowPart
;
434 while (TimeZoneBias
.HighPart
!= SharedUserData
->TimeZoneBias
.High2Time
);
436 *((PLONGLONG
)lpLocalFileTime
) =
437 *((PLONGLONG
)lpFileTime
) - TimeZoneBias
.QuadPart
;
448 LocalFileTimeToFileTime(
449 CONST FILETIME
*lpLocalFileTime
,
450 LPFILETIME lpFileTime
453 LARGE_INTEGER TimeZoneBias
;
457 TimeZoneBias
.HighPart
= SharedUserData
->TimeZoneBias
.High1Time
;
458 TimeZoneBias
.LowPart
= SharedUserData
->TimeZoneBias
.LowPart
;
460 while (TimeZoneBias
.HighPart
!= SharedUserData
->TimeZoneBias
.High2Time
);
462 *((PLONGLONG
)lpFileTime
) =
463 *((PLONGLONG
)lpLocalFileTime
) + TimeZoneBias
.QuadPart
;
473 GetLocalTime(LPSYSTEMTIME lpSystemTime
)
476 FILETIME LocalFileTime
;
478 GetSystemTimeAsFileTime(&FileTime
);
479 FileTimeToLocalFileTime(&FileTime
, &LocalFileTime
);
480 FileTimeToSystemTime(&LocalFileTime
, lpSystemTime
);
488 GetSystemTime(LPSYSTEMTIME lpSystemTime
)
492 GetSystemTimeAsFileTime(&FileTime
);
493 FileTimeToSystemTime(&FileTime
, lpSystemTime
);
501 SetLocalTime(CONST SYSTEMTIME
*lpSystemTime
)
503 FILETIME LocalFileTime
;
504 LARGE_INTEGER FileTime
;
507 SystemTimeToFileTime(lpSystemTime
, &LocalFileTime
);
508 LocalFileTimeToFileTime(&LocalFileTime
, (FILETIME
*)&FileTime
);
509 Status
= NtSetSystemTime(&FileTime
, &FileTime
);
510 if (!NT_SUCCESS(Status
))
520 SetSystemTime(CONST SYSTEMTIME
*lpSystemTime
)
522 LARGE_INTEGER NewSystemTime
;
525 SystemTimeToFileTime(lpSystemTime
, (PFILETIME
)&NewSystemTime
);
526 Status
= NtSetSystemTime(&NewSystemTime
, &NewSystemTime
);
527 if (!NT_SUCCESS(Status
))
537 GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation
)
541 DPRINT("GetTimeZoneInformation()\n");
543 Status
= NtQuerySystemInformation(SystemCurrentTimeZoneInformation
,
544 lpTimeZoneInformation
,
545 sizeof(TIME_ZONE_INFORMATION
),
547 if (!NT_SUCCESS(Status
))
549 SetLastErrorByStatus(Status
);
550 return TIME_ZONE_ID_INVALID
;
553 return(SharedUserData
->TimeZoneId
);
561 SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
)
565 DPRINT("SetTimeZoneInformation()\n");
567 Status
= RtlSetTimeZoneInformation((LPTIME_ZONE_INFORMATION
)lpTimeZoneInformation
);
568 if (!NT_SUCCESS(Status
))
570 DPRINT1("RtlSetTimeZoneInformation() failed (Status %lx)\n", Status
);
571 SetLastErrorByStatus(Status
);
575 Status
= NtSetSystemInformation(SystemCurrentTimeZoneInformation
,
576 (PVOID
)lpTimeZoneInformation
,
577 sizeof(TIME_ZONE_INFORMATION
));
578 if (!NT_SUCCESS(Status
))
580 DPRINT1("NtSetSystemInformation() failed (Status %lx)\n", Status
);
581 SetLastErrorByStatus(Status
);
595 return (DWORD
)((ULONGLONG
)SharedUserData
->TickCountLowDeprecated
* SharedUserData
->TickCountMultiplier
/ 16777216);
605 return (ULONGLONG
)SharedUserData
->TickCountLowDeprecated
* (ULONGLONG
)SharedUserData
->TickCountMultiplier
/ 16777216;
613 SystemTimeToTzSpecificLocalTime(
614 CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
,
615 CONST SYSTEMTIME
*lpUniversalTime
,
616 LPSYSTEMTIME lpLocalTime
619 TIME_ZONE_INFORMATION TimeZoneInformation
;
620 LPTIME_ZONE_INFORMATION lpTzInfo
;
621 LARGE_INTEGER FileTime
;
623 if (!lpTimeZoneInformation
)
625 GetTimeZoneInformation(&TimeZoneInformation
);
626 lpTzInfo
= &TimeZoneInformation
;
629 lpTzInfo
= (LPTIME_ZONE_INFORMATION
)lpTimeZoneInformation
;
631 if (!lpUniversalTime
)
637 SystemTimeToFileTime(lpUniversalTime
, (PFILETIME
)&FileTime
);
638 FileTime
.QuadPart
-= (lpTzInfo
->Bias
* TICKSPERMIN
);
639 FileTimeToSystemTime((PFILETIME
)&FileTime
, lpLocalTime
);
646 * @implemented (Wine 13 sep 2008)
650 TzSpecificLocalTimeToSystemTime(
651 CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
,
652 CONST SYSTEMTIME
*lpLocalTime
,
653 LPSYSTEMTIME lpUniversalTime
659 TIME_ZONE_INFORMATION tzinfo
;
661 if (lpTimeZoneInformation
!= NULL
)
663 tzinfo
= *lpTimeZoneInformation
;
667 if (GetTimeZoneInformation(&tzinfo
) == TIME_ZONE_ID_INVALID
)
671 if (!SystemTimeToFileTime(lpLocalTime
, &ft
))
674 if (!TIME_GetTimezoneBias(&tzinfo
, &ft
, TRUE
, &lBias
))
676 /* convert minutes to 100-nanoseconds-ticks */
677 t
+= (LONGLONG
)lBias
* TICKSPERMIN
;
679 return FileTimeToSystemTime(&ft
, lpUniversalTime
);
687 GetSystemTimeAdjustment(PDWORD lpTimeAdjustment
,
688 PDWORD lpTimeIncrement
,
689 PBOOL lpTimeAdjustmentDisabled
)
691 SYSTEM_QUERY_TIME_ADJUST_INFORMATION Buffer
;
694 Status
= NtQuerySystemInformation(SystemTimeAdjustmentInformation
,
696 sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION
),
698 if (!NT_SUCCESS(Status
))
700 SetLastErrorByStatus(Status
);
704 *lpTimeAdjustment
= (DWORD
)Buffer
.TimeAdjustment
;
705 *lpTimeIncrement
= (DWORD
)Buffer
.TimeIncrement
;
706 *lpTimeAdjustmentDisabled
= (BOOL
)Buffer
.Enable
;
716 SetSystemTimeAdjustment(DWORD dwTimeAdjustment
,
717 BOOL bTimeAdjustmentDisabled
)
720 SYSTEM_SET_TIME_ADJUST_INFORMATION Buffer
;
722 Buffer
.TimeAdjustment
= (ULONG
)dwTimeAdjustment
;
723 Buffer
.Enable
= (BOOLEAN
)bTimeAdjustmentDisabled
;
725 Status
= NtSetSystemInformation(SystemTimeAdjustmentInformation
,
727 sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION
));
728 if (!NT_SUCCESS(Status
))
730 SetLastErrorByStatus(Status
);
744 LPFILETIME lpIdleTime
,
745 LPFILETIME lpKernelTime
,
746 LPFILETIME lpUserTime
749 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcPerfInfo
;
752 Status
= ZwQuerySystemInformation(SystemProcessorPerformanceInformation
,
754 sizeof(SysProcPerfInfo
),
757 if (!NT_SUCCESS(Status
))
759 SetLastErrorByStatus(Status
);
763 Good only for one processor system.
766 lpIdleTime
->dwLowDateTime
= SysProcPerfInfo
.IdleTime
.LowPart
;
767 lpIdleTime
->dwHighDateTime
= SysProcPerfInfo
.IdleTime
.HighPart
;
769 lpKernelTime
->dwLowDateTime
= SysProcPerfInfo
.KernelTime
.LowPart
;
770 lpKernelTime
->dwHighDateTime
= SysProcPerfInfo
.KernelTime
.HighPart
;
772 lpUserTime
->dwLowDateTime
= SysProcPerfInfo
.UserTime
.LowPart
;
773 lpUserTime
->dwHighDateTime
= SysProcPerfInfo
.UserTime
.HighPart
;