2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/misc/time.c
5 * PURPOSE: Time conversion functions
7 * DOSDATE and DOSTIME structures from Onno Hovers
12 /* INCLUDES ******************************************************************/
19 /* TYPES *********************************************************************/
21 #define TICKSPERMIN 600000000
23 #define LL2FILETIME( ll, pft )\
24 (pft)->dwLowDateTime = (UINT)(ll); \
25 (pft)->dwHighDateTime = (UINT)((ll) >> 32);
26 #define FILETIME2LL( pft, ll) \
27 ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime ;
29 static const int MonthLengths
[2][12] =
31 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
32 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
35 /* STATIC FUNTIONS **********************************************************/
37 static inline int IsLeapYear(int Year
)
39 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0) ? 1 : 0;
42 /***********************************************************************
43 * TIME_DayLightCompareDate
45 * Compares two dates without looking at the year.
48 * date [in] The local time to compare.
49 * compareDate [in] The daylight savings begin or end date.
53 * -1 if date < compareDate
54 * 0 if date == compareDate
55 * 1 if date > compareDate
56 * -2 if an error occurs
59 TIME_DayLightCompareDate(const SYSTEMTIME
*date
, const SYSTEMTIME
*compareDate
)
61 int limit_day
, dayinsecs
;
63 if (date
->wMonth
< compareDate
->wMonth
)
64 return -1; /* We are in a month before the date limit. */
66 if (date
->wMonth
> compareDate
->wMonth
)
67 return 1; /* We are in a month after the date limit. */
69 /* if year is 0 then date is in day-of-week format, otherwise
72 if (compareDate
->wYear
== 0)
75 /* compareDate->wDay is interpreted as number of the week in the month
76 * 5 means: the last week in the month */
77 int weekofmonth
= compareDate
->wDay
;
78 /* calculate the day of the first DayOfWeek in the month */
79 First
= ( 6 + compareDate
->wDayOfWeek
- date
->wDayOfWeek
+ date
->wDay
81 limit_day
= First
+ 7 * (weekofmonth
- 1);
82 /* check needed for the 5th weekday of the month */
83 if(limit_day
> MonthLengths
[date
->wMonth
==2 && IsLeapYear(date
->wYear
)]
89 limit_day
= compareDate
->wDay
;
92 /* convert to seconds */
93 limit_day
= ((limit_day
* 24 + compareDate
->wHour
) * 60 +
94 compareDate
->wMinute
) * 60;
95 dayinsecs
= ((date
->wDay
* 24 + date
->wHour
) * 60 +
96 date
->wMinute
) * 60 + date
->wSecond
;
98 return dayinsecs
< limit_day
? -1 :
99 dayinsecs
> limit_day
? 1 :
100 0; /* date is equal to the date limit. */
103 /***********************************************************************
104 * TIME_CompTimeZoneID
106 * Computes the local time bias for a given time and time zone.
109 * pTZinfo [in] The time zone data.
110 * lpFileTime [in] The system or local time.
111 * islocal [in] it is local time.
114 * TIME_ZONE_ID_INVALID An error occurred
115 * TIME_ZONE_ID_UNKNOWN There are no transition time known
116 * TIME_ZONE_ID_STANDARD Current time is standard time
117 * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time
121 TIME_CompTimeZoneID( const TIME_ZONE_INFORMATION
*pTZinfo
, FILETIME
*lpFileTime
, BOOL islocal
)
124 BOOL beforeStandardDate
, afterDaylightDate
;
125 DWORD retval
= TIME_ZONE_ID_INVALID
;
126 LONGLONG llTime
= 0; /* initialized to prevent gcc complaining */
130 if (pTZinfo
->DaylightDate
.wMonth
!= 0)
132 /* if year is 0 then date is in day-of-week format, otherwise
133 * it's absolute date.
135 if (pTZinfo
->StandardDate
.wMonth
== 0 ||
136 (pTZinfo
->StandardDate
.wYear
== 0 &&
137 (pTZinfo
->StandardDate
.wDay
<1 ||
138 pTZinfo
->StandardDate
.wDay
>5 ||
139 pTZinfo
->DaylightDate
.wDay
<1 ||
140 pTZinfo
->DaylightDate
.wDay
>5)))
142 SetLastError(ERROR_INVALID_PARAMETER
);
143 return TIME_ZONE_ID_INVALID
;
147 FILETIME2LL( lpFileTime
, llTime
);
148 llTime
-= ( pTZinfo
->Bias
+ pTZinfo
->DaylightBias
)
149 * (LONGLONG
)TICKSPERMIN
;
150 LL2FILETIME( llTime
, &ftTemp
)
151 lpFileTime
= &ftTemp
;
154 FileTimeToSystemTime(lpFileTime
, &SysTime
);
156 /* check for daylight savings */
157 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->StandardDate
);
159 return TIME_ZONE_ID_INVALID
;
161 beforeStandardDate
= ret
< 0;
164 llTime
-= ( pTZinfo
->StandardBias
- pTZinfo
->DaylightBias
)
165 * (LONGLONG
)TICKSPERMIN
;
166 LL2FILETIME( llTime
, &ftTemp
)
167 FileTimeToSystemTime(lpFileTime
, &SysTime
);
170 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->DaylightDate
);
172 return TIME_ZONE_ID_INVALID
;
174 afterDaylightDate
= ret
>= 0;
176 retval
= TIME_ZONE_ID_STANDARD
;
177 if( pTZinfo
->DaylightDate
.wMonth
< pTZinfo
->StandardDate
.wMonth
) {
178 /* Northern hemisphere */
179 if( beforeStandardDate
&& afterDaylightDate
)
180 retval
= TIME_ZONE_ID_DAYLIGHT
;
181 } else /* Down south */
182 if( beforeStandardDate
|| afterDaylightDate
)
183 retval
= TIME_ZONE_ID_DAYLIGHT
;
185 /* No transition date */
186 retval
= TIME_ZONE_ID_UNKNOWN
;
191 /***********************************************************************
194 * Calculates whether daylight savings is on now.
197 * pTzi [in] Timezone info.
200 * TIME_ZONE_ID_INVALID An error occurred
201 * TIME_ZONE_ID_UNKNOWN There are no transition time known
202 * TIME_ZONE_ID_STANDARD Current time is standard time
203 * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time
205 static DWORD
TIME_ZoneID( const TIME_ZONE_INFORMATION
*pTzi
)
208 GetSystemTimeAsFileTime( &ftTime
);
209 return TIME_CompTimeZoneID( pTzi
, &ftTime
, FALSE
);
212 /***********************************************************************
213 * TIME_GetTimezoneBias
215 * Calculates the local time bias for a given time zone.
218 * pTZinfo [in] The time zone data.
219 * lpFileTime [in] The system or local time.
220 * islocal [in] It is local time.
221 * pBias [out] The calculated bias in minutes.
224 * TRUE when the time zone bias was calculated.
227 TIME_GetTimezoneBias(const TIME_ZONE_INFORMATION
*pTZinfo
, FILETIME
*lpFileTime
, BOOL islocal
, LONG
*pBias
)
229 LONG bias
= pTZinfo
->Bias
;
230 DWORD tzid
= TIME_CompTimeZoneID(pTZinfo
, lpFileTime
, islocal
);
232 if( tzid
== TIME_ZONE_ID_INVALID
)
234 if (tzid
== TIME_ZONE_ID_DAYLIGHT
)
235 bias
+= pTZinfo
->DaylightBias
;
236 else if (tzid
== TIME_ZONE_ID_STANDARD
)
237 bias
+= pTZinfo
->StandardBias
;
243 /* FUNCTIONS ****************************************************************/
250 GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation
)
254 DPRINT("GetTimeZoneInformation()\n");
256 Status
= NtQuerySystemInformation(SystemCurrentTimeZoneInformation
,
257 lpTimeZoneInformation
,
258 sizeof(TIME_ZONE_INFORMATION
),
260 if (!NT_SUCCESS(Status
))
262 BaseSetLastNTError(Status
);
263 return TIME_ZONE_ID_INVALID
;
266 return TIME_ZoneID(lpTimeZoneInformation
);
275 SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
)
279 DPRINT("SetTimeZoneInformation()\n");
281 Status
= RtlSetTimeZoneInformation((LPTIME_ZONE_INFORMATION
)lpTimeZoneInformation
);
282 if (!NT_SUCCESS(Status
))
284 DPRINT1("RtlSetTimeZoneInformation() failed (Status %lx)\n", Status
);
285 BaseSetLastNTError(Status
);
289 Status
= NtSetSystemInformation(SystemCurrentTimeZoneInformation
,
290 (PVOID
)lpTimeZoneInformation
,
291 sizeof(TIME_ZONE_INFORMATION
));
292 if (!NT_SUCCESS(Status
))
294 DPRINT1("NtSetSystemInformation() failed (Status %lx)\n", Status
);
295 BaseSetLastNTError(Status
);
307 SystemTimeToTzSpecificLocalTime(CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
,
308 CONST SYSTEMTIME
*lpUniversalTime
,
309 LPSYSTEMTIME lpLocalTime
)
311 TIME_ZONE_INFORMATION TzInfo
;
316 if (lpTimeZoneInformation
!= NULL
)
318 TzInfo
= *lpTimeZoneInformation
;
322 if (GetTimeZoneInformation(&TzInfo
) == TIME_ZONE_ID_INVALID
)
326 if (!lpUniversalTime
|| !lpLocalTime
)
329 if (!SystemTimeToFileTime(lpUniversalTime
, &FileTime
))
332 FILETIME2LL(&FileTime
, llTime
)
334 if (!TIME_GetTimezoneBias(&TzInfo
, &FileTime
, FALSE
, &lBias
))
337 /* convert minutes to 100-nanoseconds-ticks */
338 llTime
-= (LONGLONG
)lBias
* TICKSPERMIN
;
340 LL2FILETIME( llTime
, &FileTime
)
342 return FileTimeToSystemTime(&FileTime
, lpLocalTime
);
347 * @implemented (Wine 13 sep 2008)
351 TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation
,
352 LPSYSTEMTIME lpLocalTime
,
353 LPSYSTEMTIME lpUniversalTime
)
358 TIME_ZONE_INFORMATION tzinfo
;
360 if (lpTimeZoneInformation
!= NULL
)
362 tzinfo
= *lpTimeZoneInformation
;
366 if (GetTimeZoneInformation(&tzinfo
) == TIME_ZONE_ID_INVALID
)
370 if (!SystemTimeToFileTime(lpLocalTime
, &ft
))
373 if (!TIME_GetTimezoneBias(&tzinfo
, &ft
, TRUE
, &lBias
))
375 /* convert minutes to 100-nanoseconds-ticks */
376 t
+= (LONGLONG
)lBias
* TICKSPERMIN
;
378 return FileTimeToSystemTime(&ft
, lpUniversalTime
);