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 static const int MonthLengths
[2][12] =
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 }
42 #define TICKSPERMIN 600000000
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 ;
50 /* STATIC FUNCTIONS ****************************************************************/
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
74 static int TIME_DayLightCompareDate( const SYSTEMTIME
*date
,
75 const SYSTEMTIME
*compareDate
)
77 int limit_day
, dayinsecs
;
79 if (date
->wMonth
< compareDate
->wMonth
)
80 return -1; /* We are in a month before the date limit. */
82 if (date
->wMonth
> compareDate
->wMonth
)
83 return 1; /* We are in a month after the date limit. */
85 /* if year is 0 then date is in day-of-week format, otherwise
88 if (compareDate
->wYear
== 0)
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
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
)]
105 limit_day
= compareDate
->wDay
;
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
;
114 return dayinsecs
< limit_day
? -1 :
115 dayinsecs
> limit_day
? 1 :
116 0; /* date is equal to the date limit. */
119 /***********************************************************************
120 * TIME_CompTimeZoneID
122 * Computes the local time bias for a given time and time zone.
125 * pTZinfo [in] The time zone data.
126 * lpFileTime [in] The system or local time.
127 * islocal [in] it is local time.
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
135 static DWORD
TIME_CompTimeZoneID ( const TIME_ZONE_INFORMATION
*pTZinfo
,
136 FILETIME
*lpFileTime
, BOOL islocal
)
139 BOOL beforeStandardDate
, afterDaylightDate
;
140 DWORD retval
= TIME_ZONE_ID_INVALID
;
141 LONGLONG llTime
= 0; /* initialized to prevent gcc complaining */
145 if (pTZinfo
->DaylightDate
.wMonth
!= 0)
147 /* if year is 0 then date is in day-of-week format, otherwise
148 * it's absolute date.
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)))
157 SetLastError(ERROR_INVALID_PARAMETER
);
158 return TIME_ZONE_ID_INVALID
;
162 FILETIME2LL( lpFileTime
, llTime
);
163 llTime
-= ( pTZinfo
->Bias
+ pTZinfo
->DaylightBias
)
164 * (LONGLONG
)600000000;
165 LL2FILETIME( llTime
, &ftTemp
)
166 lpFileTime
= &ftTemp
;
169 FileTimeToSystemTime(lpFileTime
, &SysTime
);
171 /* check for daylight savings */
172 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->StandardDate
);
174 return TIME_ZONE_ID_INVALID
;
176 beforeStandardDate
= ret
< 0;
179 llTime
-= ( pTZinfo
->StandardBias
- pTZinfo
->DaylightBias
)
180 * (LONGLONG
)600000000;
181 LL2FILETIME( llTime
, &ftTemp
)
182 FileTimeToSystemTime(lpFileTime
, &SysTime
);
185 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->DaylightDate
);
187 return TIME_ZONE_ID_INVALID
;
189 afterDaylightDate
= ret
>= 0;
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
;
200 /* No transition date */
201 retval
= TIME_ZONE_ID_UNKNOWN
;
206 static BOOL
TIME_GetTimezoneBias( const TIME_ZONE_INFORMATION
*pTZinfo
,
207 FILETIME
*lpFileTime
, BOOL islocal
, LONG
*pBias
)
209 LONG bias
= pTZinfo
->Bias
;
210 DWORD tzid
= TIME_CompTimeZoneID( pTZinfo
, lpFileTime
, islocal
);
212 if( tzid
== TIME_ZONE_ID_INVALID
)
214 if (tzid
== TIME_ZONE_ID_DAYLIGHT
)
215 bias
+= pTZinfo
->DaylightBias
;
216 else if (tzid
== TIME_ZONE_ID_STANDARD
)
217 bias
+= pTZinfo
->StandardBias
;
223 /* EXPORTED FUNCTIONS ****************************************************************/
230 FileTimeToDosDateTime(
231 CONST FILETIME
*lpFileTime
,
236 PDOSTIME pdtime
=(PDOSTIME
) lpFatTime
;
237 PDOSDATE pddate
=(PDOSDATE
) lpFatDate
;
238 SYSTEMTIME SystemTime
= { 0 };
240 if ( lpFileTime
== NULL
)
243 if ( lpFatDate
== NULL
)
246 if ( lpFatTime
== NULL
)
249 FileTimeToSystemTime(
254 pdtime
->Second
= SystemTime
.wSecond
/ 2;
255 pdtime
->Minute
= SystemTime
.wMinute
;
256 pdtime
->Hour
= SystemTime
.wHour
;
258 pddate
->Day
= SystemTime
.wDay
;
259 pddate
->Month
= SystemTime
.wMonth
;
260 pddate
->Year
= SystemTime
.wYear
- 1980;
271 DosDateTimeToFileTime(
274 LPFILETIME lpFileTime
277 PDOSTIME pdtime
= (PDOSTIME
) &wFatTime
;
278 PDOSDATE pddate
= (PDOSDATE
) &wFatDate
;
279 SYSTEMTIME SystemTime
;
281 if ( lpFileTime
== NULL
)
284 SystemTime
.wMilliseconds
= 0;
285 SystemTime
.wSecond
= pdtime
->Second
* 2;
286 SystemTime
.wMinute
= pdtime
->Minute
;
287 SystemTime
.wHour
= pdtime
->Hour
;
289 SystemTime
.wDay
= pddate
->Day
;
290 SystemTime
.wMonth
= pddate
->Month
;
291 SystemTime
.wYear
= 1980 + pddate
->Year
;
293 SystemTimeToFileTime(&SystemTime
,lpFileTime
);
305 CONST FILETIME
*lpFileTime1
,
306 CONST FILETIME
*lpFileTime2
309 if ( lpFileTime1
== NULL
)
311 if ( lpFileTime2
== NULL
)
314 if (*((PLONGLONG
)lpFileTime1
) > *((PLONGLONG
)lpFileTime2
))
316 else if (*((PLONGLONG
)lpFileTime1
) < *((PLONGLONG
)lpFileTime2
))
327 GetSystemTimeAsFileTime (PFILETIME lpFileTime
)
331 lpFileTime
->dwHighDateTime
= SharedUserData
->SystemTime
.High1Time
;
332 lpFileTime
->dwLowDateTime
= SharedUserData
->SystemTime
.LowPart
;
334 while (lpFileTime
->dwHighDateTime
!= (DWORD
)SharedUserData
->SystemTime
.High2Time
);
343 SystemTimeToFileTime(
344 CONST SYSTEMTIME
* lpSystemTime
,
345 LPFILETIME lpFileTime
349 TIME_FIELDS TimeFields
;
350 LARGE_INTEGER liTime
;
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
;
360 if (RtlTimeFieldsToTime (&TimeFields
, &liTime
))
362 lpFileTime
->dwLowDateTime
= liTime
.u
.LowPart
;
363 lpFileTime
->dwHighDateTime
= liTime
.u
.HighPart
;
375 FileTimeToSystemTime(
376 CONST FILETIME
*lpFileTime
,
377 LPSYSTEMTIME lpSystemTime
380 TIME_FIELDS TimeFields
;
381 LARGE_INTEGER liTime
;
383 if(lpFileTime
->dwHighDateTime
& 0x80000000)
386 liTime
.u
.LowPart
= lpFileTime
->dwLowDateTime
;
387 liTime
.u
.HighPart
= lpFileTime
->dwHighDateTime
;
389 RtlTimeToTimeFields(&liTime
, &TimeFields
);
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
;
409 FileTimeToLocalFileTime(
410 CONST FILETIME
*lpFileTime
,
411 LPFILETIME lpLocalFileTime
414 LARGE_INTEGER TimeZoneBias
;
418 TimeZoneBias
.HighPart
= SharedUserData
->TimeZoneBias
.High1Time
;
419 TimeZoneBias
.LowPart
= SharedUserData
->TimeZoneBias
.LowPart
;
421 while (TimeZoneBias
.HighPart
!= SharedUserData
->TimeZoneBias
.High2Time
);
423 *((PLONGLONG
)lpLocalFileTime
) =
424 *((PLONGLONG
)lpFileTime
) - TimeZoneBias
.QuadPart
;
435 LocalFileTimeToFileTime(
436 CONST FILETIME
*lpLocalFileTime
,
437 LPFILETIME lpFileTime
440 LARGE_INTEGER TimeZoneBias
;
444 TimeZoneBias
.HighPart
= SharedUserData
->TimeZoneBias
.High1Time
;
445 TimeZoneBias
.LowPart
= SharedUserData
->TimeZoneBias
.LowPart
;
447 while (TimeZoneBias
.HighPart
!= SharedUserData
->TimeZoneBias
.High2Time
);
449 *((PLONGLONG
)lpFileTime
) =
450 *((PLONGLONG
)lpLocalFileTime
) + TimeZoneBias
.QuadPart
;
460 GetLocalTime(LPSYSTEMTIME lpSystemTime
)
463 FILETIME LocalFileTime
;
465 GetSystemTimeAsFileTime(&FileTime
);
466 FileTimeToLocalFileTime(&FileTime
, &LocalFileTime
);
467 FileTimeToSystemTime(&LocalFileTime
, lpSystemTime
);
475 GetSystemTime(LPSYSTEMTIME lpSystemTime
)
479 GetSystemTimeAsFileTime(&FileTime
);
480 FileTimeToSystemTime(&FileTime
, lpSystemTime
);
488 SetLocalTime(CONST SYSTEMTIME
*lpSystemTime
)
490 FILETIME LocalFileTime
;
491 LARGE_INTEGER FileTime
;
494 SystemTimeToFileTime(lpSystemTime
, &LocalFileTime
);
495 LocalFileTimeToFileTime(&LocalFileTime
, (FILETIME
*)&FileTime
);
496 Status
= NtSetSystemTime(&FileTime
, &FileTime
);
497 if (!NT_SUCCESS(Status
))
507 SetSystemTime(CONST SYSTEMTIME
*lpSystemTime
)
509 LARGE_INTEGER NewSystemTime
;
512 SystemTimeToFileTime(lpSystemTime
, (PFILETIME
)&NewSystemTime
);
513 Status
= NtSetSystemTime(&NewSystemTime
, &NewSystemTime
);
514 if (!NT_SUCCESS(Status
))
524 GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation
)
528 DPRINT("GetTimeZoneInformation()\n");
530 Status
= NtQuerySystemInformation(SystemCurrentTimeZoneInformation
,
531 lpTimeZoneInformation
,
532 sizeof(TIME_ZONE_INFORMATION
),
534 if (!NT_SUCCESS(Status
))
536 SetLastErrorByStatus(Status
);
537 return TIME_ZONE_ID_INVALID
;
540 return(SharedUserData
->TimeZoneId
);
548 SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
)
552 DPRINT("SetTimeZoneInformation()\n");
554 Status
= RtlSetTimeZoneInformation((LPTIME_ZONE_INFORMATION
)lpTimeZoneInformation
);
555 if (!NT_SUCCESS(Status
))
557 DPRINT1("RtlSetTimeZoneInformation() failed (Status %lx)\n", Status
);
558 SetLastErrorByStatus(Status
);
562 Status
= NtSetSystemInformation(SystemCurrentTimeZoneInformation
,
563 (PVOID
)lpTimeZoneInformation
,
564 sizeof(TIME_ZONE_INFORMATION
));
565 if (!NT_SUCCESS(Status
))
567 DPRINT1("NtSetSystemInformation() failed (Status %lx)\n", Status
);
568 SetLastErrorByStatus(Status
);
582 return (DWORD
)((ULONGLONG
)SharedUserData
->TickCountLowDeprecated
* SharedUserData
->TickCountMultiplier
/ 16777216);
592 return (ULONGLONG
)SharedUserData
->TickCountLowDeprecated
* (ULONGLONG
)SharedUserData
->TickCountMultiplier
/ 16777216;
600 SystemTimeToTzSpecificLocalTime(
601 CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
,
602 CONST SYSTEMTIME
*lpUniversalTime
,
603 LPSYSTEMTIME lpLocalTime
606 TIME_ZONE_INFORMATION TimeZoneInformation
;
607 LPTIME_ZONE_INFORMATION lpTzInfo
;
608 LARGE_INTEGER FileTime
;
610 if (!lpTimeZoneInformation
)
612 GetTimeZoneInformation(&TimeZoneInformation
);
613 lpTzInfo
= &TimeZoneInformation
;
616 lpTzInfo
= (LPTIME_ZONE_INFORMATION
)lpTimeZoneInformation
;
618 if (!lpUniversalTime
)
624 SystemTimeToFileTime(lpUniversalTime
, (PFILETIME
)&FileTime
);
625 FileTime
.QuadPart
-= (lpTzInfo
->Bias
* TICKSPERMIN
);
626 FileTimeToSystemTime((PFILETIME
)&FileTime
, lpLocalTime
);
636 GetSystemTimeAdjustment(PDWORD lpTimeAdjustment
,
637 PDWORD lpTimeIncrement
,
638 PBOOL lpTimeAdjustmentDisabled
)
640 SYSTEM_QUERY_TIME_ADJUST_INFORMATION Buffer
;
643 Status
= NtQuerySystemInformation(SystemTimeAdjustmentInformation
,
645 sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION
),
647 if (!NT_SUCCESS(Status
))
649 SetLastErrorByStatus(Status
);
653 *lpTimeAdjustment
= (DWORD
)Buffer
.TimeAdjustment
;
654 *lpTimeIncrement
= (DWORD
)Buffer
.TimeIncrement
;
655 *lpTimeAdjustmentDisabled
= (BOOL
)Buffer
.Enable
;
665 SetSystemTimeAdjustment(DWORD dwTimeAdjustment
,
666 BOOL bTimeAdjustmentDisabled
)
669 SYSTEM_SET_TIME_ADJUST_INFORMATION Buffer
;
671 Buffer
.TimeAdjustment
= (ULONG
)dwTimeAdjustment
;
672 Buffer
.Enable
= (BOOLEAN
)bTimeAdjustmentDisabled
;
674 Status
= NtSetSystemInformation(SystemTimeAdjustmentInformation
,
676 sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION
));
677 if (!NT_SUCCESS(Status
))
679 SetLastErrorByStatus(Status
);
693 LPFILETIME lpIdleTime
,
694 LPFILETIME lpKernelTime
,
695 LPFILETIME lpUserTime
698 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcPerfInfo
;
701 Status
= ZwQuerySystemInformation(SystemProcessorPerformanceInformation
,
703 sizeof(SysProcPerfInfo
),
706 if (!NT_SUCCESS(Status
))
708 SetLastErrorByStatus(Status
);
712 Good only for one processor system.
715 lpIdleTime
->dwLowDateTime
= SysProcPerfInfo
.IdleTime
.LowPart
;
716 lpIdleTime
->dwHighDateTime
= SysProcPerfInfo
.IdleTime
.HighPart
;
718 lpKernelTime
->dwLowDateTime
= SysProcPerfInfo
.KernelTime
.LowPart
;
719 lpKernelTime
->dwHighDateTime
= SysProcPerfInfo
.KernelTime
.HighPart
;
721 lpUserTime
->dwLowDateTime
= SysProcPerfInfo
.UserTime
.LowPart
;
722 lpUserTime
->dwHighDateTime
= SysProcPerfInfo
.UserTime
.HighPart
;
729 * @implemented (ripped from Wine 1.0)
733 TzSpecificLocalTimeToSystemTime(
734 CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
,
735 CONST SYSTEMTIME
*lpLocalTime
,
736 LPSYSTEMTIME lpUniversalTime
742 TIME_ZONE_INFORMATION tzinfo
;
744 if (lpTimeZoneInformation
!= NULL
)
746 tzinfo
= *lpTimeZoneInformation
;
750 if (GetTimeZoneInformation(&tzinfo
) == TIME_ZONE_ID_INVALID
)
754 if (!SystemTimeToFileTime(lpLocalTime
, &ft
))
759 if (!TIME_GetTimezoneBias(&tzinfo
, &ft
, TRUE
, &lBias
))
762 /* convert minutes to 100-nanoseconds-ticks */
763 t
+= (LONGLONG
)lBias
* TICKSPERMIN
;
766 return FileTimeToSystemTime(&ft
, lpUniversalTime
);