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
* (LONGLONG
)TICKSPERMIN
;
149 LL2FILETIME( llTime
, &ftTemp
)
150 lpFileTime
= &ftTemp
;
153 FileTimeToSystemTime(lpFileTime
, &SysTime
);
154 year
= SysTime
.wYear
;
157 llTime
-= pTZinfo
->DaylightBias
* (LONGLONG
)TICKSPERMIN
;
158 LL2FILETIME( llTime
, &ftTemp
)
159 FileTimeToSystemTime(lpFileTime
, &SysTime
);
162 /* check for daylight savings */
163 if(year
== SysTime
.wYear
) {
164 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->StandardDate
);
166 return TIME_ZONE_ID_INVALID
;
168 beforeStandardDate
= ret
< 0;
170 beforeStandardDate
= SysTime
.wYear
< year
;
173 llTime
-= ( pTZinfo
->StandardBias
- pTZinfo
->DaylightBias
)
174 * (LONGLONG
)TICKSPERMIN
;
175 LL2FILETIME( llTime
, &ftTemp
)
176 FileTimeToSystemTime(lpFileTime
, &SysTime
);
179 if(year
== SysTime
.wYear
) {
180 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->DaylightDate
);
182 return TIME_ZONE_ID_INVALID
;
184 afterDaylightDate
= ret
>= 0;
186 afterDaylightDate
= SysTime
.wYear
> year
;
188 retval
= TIME_ZONE_ID_STANDARD
;
189 if( pTZinfo
->DaylightDate
.wMonth
< pTZinfo
->StandardDate
.wMonth
) {
190 /* Northern hemisphere */
191 if( beforeStandardDate
&& afterDaylightDate
)
192 retval
= TIME_ZONE_ID_DAYLIGHT
;
193 } else /* Down south */
194 if( beforeStandardDate
|| afterDaylightDate
)
195 retval
= TIME_ZONE_ID_DAYLIGHT
;
197 /* No transition date */
198 retval
= TIME_ZONE_ID_UNKNOWN
;
203 /***********************************************************************
206 * Calculates whether daylight savings is on now.
209 * pTzi [in] Timezone info.
212 * TIME_ZONE_ID_INVALID An error occurred
213 * TIME_ZONE_ID_UNKNOWN There are no transition time known
214 * TIME_ZONE_ID_STANDARD Current time is standard time
215 * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time
217 static DWORD
TIME_ZoneID( const TIME_ZONE_INFORMATION
*pTzi
)
220 GetSystemTimeAsFileTime( &ftTime
);
221 return TIME_CompTimeZoneID( pTzi
, &ftTime
, FALSE
);
224 /***********************************************************************
225 * TIME_GetTimezoneBias
227 * Calculates the local time bias for a given time zone.
230 * pTZinfo [in] The time zone data.
231 * lpFileTime [in] The system or local time.
232 * islocal [in] It is local time.
233 * pBias [out] The calculated bias in minutes.
236 * TRUE when the time zone bias was calculated.
239 TIME_GetTimezoneBias(const TIME_ZONE_INFORMATION
*pTZinfo
, FILETIME
*lpFileTime
, BOOL islocal
, LONG
*pBias
)
241 LONG bias
= pTZinfo
->Bias
;
242 DWORD tzid
= TIME_CompTimeZoneID(pTZinfo
, lpFileTime
, islocal
);
244 if( tzid
== TIME_ZONE_ID_INVALID
)
246 if (tzid
== TIME_ZONE_ID_DAYLIGHT
)
247 bias
+= pTZinfo
->DaylightBias
;
248 else if (tzid
== TIME_ZONE_ID_STANDARD
)
249 bias
+= pTZinfo
->StandardBias
;
255 /* FUNCTIONS ****************************************************************/
262 GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation
)
266 DPRINT("GetTimeZoneInformation()\n");
268 Status
= NtQuerySystemInformation(SystemCurrentTimeZoneInformation
,
269 lpTimeZoneInformation
,
270 sizeof(TIME_ZONE_INFORMATION
),
272 if (!NT_SUCCESS(Status
))
274 BaseSetLastNTError(Status
);
275 return TIME_ZONE_ID_INVALID
;
278 return TIME_ZoneID(lpTimeZoneInformation
);
287 SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
)
291 DPRINT("SetTimeZoneInformation()\n");
293 Status
= RtlSetTimeZoneInformation((LPTIME_ZONE_INFORMATION
)lpTimeZoneInformation
);
294 if (!NT_SUCCESS(Status
))
296 DPRINT1("RtlSetTimeZoneInformation() failed (Status %lx)\n", Status
);
297 BaseSetLastNTError(Status
);
301 Status
= NtSetSystemInformation(SystemCurrentTimeZoneInformation
,
302 (PVOID
)lpTimeZoneInformation
,
303 sizeof(TIME_ZONE_INFORMATION
));
304 if (!NT_SUCCESS(Status
))
306 DPRINT1("NtSetSystemInformation() failed (Status %lx)\n", Status
);
307 BaseSetLastNTError(Status
);
319 SystemTimeToTzSpecificLocalTime(CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
,
320 CONST SYSTEMTIME
*lpUniversalTime
,
321 LPSYSTEMTIME lpLocalTime
)
323 TIME_ZONE_INFORMATION TzInfo
;
328 if (lpTimeZoneInformation
!= NULL
)
330 TzInfo
= *lpTimeZoneInformation
;
334 if (GetTimeZoneInformation(&TzInfo
) == TIME_ZONE_ID_INVALID
)
338 if (!lpUniversalTime
|| !lpLocalTime
)
341 if (!SystemTimeToFileTime(lpUniversalTime
, &FileTime
))
344 FILETIME2LL(&FileTime
, llTime
)
346 if (!TIME_GetTimezoneBias(&TzInfo
, &FileTime
, FALSE
, &lBias
))
349 /* convert minutes to 100-nanoseconds-ticks */
350 llTime
-= (LONGLONG
)lBias
* TICKSPERMIN
;
352 LL2FILETIME( llTime
, &FileTime
)
354 return FileTimeToSystemTime(&FileTime
, lpLocalTime
);
359 * @implemented (Wine 13 sep 2008)
363 TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation
,
364 LPSYSTEMTIME lpLocalTime
,
365 LPSYSTEMTIME lpUniversalTime
)
370 TIME_ZONE_INFORMATION tzinfo
;
372 if (lpTimeZoneInformation
!= NULL
)
374 tzinfo
= *lpTimeZoneInformation
;
378 if (GetTimeZoneInformation(&tzinfo
) == TIME_ZONE_ID_INVALID
)
382 if (!SystemTimeToFileTime(lpLocalTime
, &ft
))
385 if (!TIME_GetTimezoneBias(&tzinfo
, &ft
, TRUE
, &lBias
))
387 /* convert minutes to 100-nanoseconds-ticks */
388 t
+= (LONGLONG
)lBias
* TICKSPERMIN
;
390 return FileTimeToSystemTime(&ft
, lpUniversalTime
);