1 /* $Id: timezone.c 52819 2011-07-23 18:54:29Z ion $
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 #define TICKSPERMIN 600000000
24 #define LL2FILETIME( ll, pft )\
25 (pft)->dwLowDateTime = (UINT)(ll); \
26 (pft)->dwHighDateTime = (UINT)((ll) >> 32);
27 #define FILETIME2LL( pft, ll) \
28 ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime ;
30 static const int MonthLengths
[2][12] =
32 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
33 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
36 /* STATIC FUNTIONS **********************************************************/
38 static inline int IsLeapYear(int Year
)
40 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0) ? 1 : 0;
43 /***********************************************************************
44 * TIME_DayLightCompareDate
46 * Compares two dates without looking at the year.
49 * date [in] The local time to compare.
50 * compareDate [in] The daylight savings begin or end date.
54 * -1 if date < compareDate
55 * 0 if date == compareDate
56 * 1 if date > compareDate
57 * -2 if an error occurs
60 TIME_DayLightCompareDate(const SYSTEMTIME
*date
, const SYSTEMTIME
*compareDate
)
62 int limit_day
, dayinsecs
;
64 if (date
->wMonth
< compareDate
->wMonth
)
65 return -1; /* We are in a month before the date limit. */
67 if (date
->wMonth
> compareDate
->wMonth
)
68 return 1; /* We are in a month after the date limit. */
70 /* if year is 0 then date is in day-of-week format, otherwise
73 if (compareDate
->wYear
== 0)
76 /* compareDate->wDay is interpreted as number of the week in the month
77 * 5 means: the last week in the month */
78 int weekofmonth
= compareDate
->wDay
;
79 /* calculate the day of the first DayOfWeek in the month */
80 First
= ( 6 + compareDate
->wDayOfWeek
- date
->wDayOfWeek
+ date
->wDay
82 limit_day
= First
+ 7 * (weekofmonth
- 1);
83 /* check needed for the 5th weekday of the month */
84 if(limit_day
> MonthLengths
[date
->wMonth
==2 && IsLeapYear(date
->wYear
)]
90 limit_day
= compareDate
->wDay
;
93 /* convert to seconds */
94 limit_day
= ((limit_day
* 24 + compareDate
->wHour
) * 60 +
95 compareDate
->wMinute
) * 60;
96 dayinsecs
= ((date
->wDay
* 24 + date
->wHour
) * 60 +
97 date
->wMinute
) * 60 + date
->wSecond
;
99 return dayinsecs
< limit_day
? -1 :
100 dayinsecs
> limit_day
? 1 :
101 0; /* date is equal to the date limit. */
104 /***********************************************************************
105 * TIME_CompTimeZoneID
107 * Computes the local time bias for a given time and time zone.
110 * pTZinfo [in] The time zone data.
111 * lpFileTime [in] The system or local time.
112 * islocal [in] it is local time.
115 * TIME_ZONE_ID_INVALID An error occurred
116 * TIME_ZONE_ID_UNKNOWN There are no transition time known
117 * TIME_ZONE_ID_STANDARD Current time is standard time
118 * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time
122 TIME_CompTimeZoneID( const TIME_ZONE_INFORMATION
*pTZinfo
, FILETIME
*lpFileTime
, BOOL islocal
)
125 BOOL beforeStandardDate
, afterDaylightDate
;
126 DWORD retval
= TIME_ZONE_ID_INVALID
;
127 LONGLONG llTime
= 0; /* initialized to prevent gcc complaining */
131 if (pTZinfo
->DaylightDate
.wMonth
!= 0)
133 /* if year is 0 then date is in day-of-week format, otherwise
134 * it's absolute date.
136 if (pTZinfo
->StandardDate
.wMonth
== 0 ||
137 (pTZinfo
->StandardDate
.wYear
== 0 &&
138 (pTZinfo
->StandardDate
.wDay
<1 ||
139 pTZinfo
->StandardDate
.wDay
>5 ||
140 pTZinfo
->DaylightDate
.wDay
<1 ||
141 pTZinfo
->DaylightDate
.wDay
>5)))
143 SetLastError(ERROR_INVALID_PARAMETER
);
144 return TIME_ZONE_ID_INVALID
;
148 FILETIME2LL( lpFileTime
, llTime
);
149 llTime
-= ( pTZinfo
->Bias
+ pTZinfo
->DaylightBias
)
150 * (LONGLONG
)TICKSPERMIN
;
151 LL2FILETIME( llTime
, &ftTemp
)
152 lpFileTime
= &ftTemp
;
155 FileTimeToSystemTime(lpFileTime
, &SysTime
);
157 /* check for daylight savings */
158 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->StandardDate
);
160 return TIME_ZONE_ID_INVALID
;
162 beforeStandardDate
= ret
< 0;
165 llTime
-= ( pTZinfo
->StandardBias
- pTZinfo
->DaylightBias
)
166 * (LONGLONG
)TICKSPERMIN
;
167 LL2FILETIME( llTime
, &ftTemp
)
168 FileTimeToSystemTime(lpFileTime
, &SysTime
);
171 ret
= TIME_DayLightCompareDate( &SysTime
, &pTZinfo
->DaylightDate
);
173 return TIME_ZONE_ID_INVALID
;
175 afterDaylightDate
= ret
>= 0;
177 retval
= TIME_ZONE_ID_STANDARD
;
178 if( pTZinfo
->DaylightDate
.wMonth
< pTZinfo
->StandardDate
.wMonth
) {
179 /* Northern hemisphere */
180 if( beforeStandardDate
&& afterDaylightDate
)
181 retval
= TIME_ZONE_ID_DAYLIGHT
;
182 } else /* Down south */
183 if( beforeStandardDate
|| afterDaylightDate
)
184 retval
= TIME_ZONE_ID_DAYLIGHT
;
186 /* No transition date */
187 retval
= TIME_ZONE_ID_UNKNOWN
;
192 /***********************************************************************
195 * Calculates whether daylight savings is on now.
198 * pTzi [in] Timezone info.
201 * TIME_ZONE_ID_INVALID An error occurred
202 * TIME_ZONE_ID_UNKNOWN There are no transition time known
203 * TIME_ZONE_ID_STANDARD Current time is standard time
204 * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time
206 static DWORD
TIME_ZoneID( const TIME_ZONE_INFORMATION
*pTzi
)
209 GetSystemTimeAsFileTime( &ftTime
);
210 return TIME_CompTimeZoneID( pTzi
, &ftTime
, FALSE
);
213 /***********************************************************************
214 * TIME_GetTimezoneBias
216 * Calculates the local time bias for a given time zone.
219 * pTZinfo [in] The time zone data.
220 * lpFileTime [in] The system or local time.
221 * islocal [in] It is local time.
222 * pBias [out] The calculated bias in minutes.
225 * TRUE when the time zone bias was calculated.
228 TIME_GetTimezoneBias(const TIME_ZONE_INFORMATION
*pTZinfo
, FILETIME
*lpFileTime
, BOOL islocal
, LONG
*pBias
)
230 LONG bias
= pTZinfo
->Bias
;
231 DWORD tzid
= TIME_CompTimeZoneID(pTZinfo
, lpFileTime
, islocal
);
233 if( tzid
== TIME_ZONE_ID_INVALID
)
235 if (tzid
== TIME_ZONE_ID_DAYLIGHT
)
236 bias
+= pTZinfo
->DaylightBias
;
237 else if (tzid
== TIME_ZONE_ID_STANDARD
)
238 bias
+= pTZinfo
->StandardBias
;
244 /* FUNCTIONS ****************************************************************/
251 GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation
)
255 DPRINT("GetTimeZoneInformation()\n");
257 Status
= NtQuerySystemInformation(SystemCurrentTimeZoneInformation
,
258 lpTimeZoneInformation
,
259 sizeof(TIME_ZONE_INFORMATION
),
261 if (!NT_SUCCESS(Status
))
263 BaseSetLastNTError(Status
);
264 return TIME_ZONE_ID_INVALID
;
267 return TIME_ZoneID(lpTimeZoneInformation
);
276 SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
)
280 DPRINT("SetTimeZoneInformation()\n");
282 Status
= RtlSetTimeZoneInformation((LPTIME_ZONE_INFORMATION
)lpTimeZoneInformation
);
283 if (!NT_SUCCESS(Status
))
285 DPRINT1("RtlSetTimeZoneInformation() failed (Status %lx)\n", Status
);
286 BaseSetLastNTError(Status
);
290 Status
= NtSetSystemInformation(SystemCurrentTimeZoneInformation
,
291 (PVOID
)lpTimeZoneInformation
,
292 sizeof(TIME_ZONE_INFORMATION
));
293 if (!NT_SUCCESS(Status
))
295 DPRINT1("NtSetSystemInformation() failed (Status %lx)\n", Status
);
296 BaseSetLastNTError(Status
);
308 SystemTimeToTzSpecificLocalTime(CONST TIME_ZONE_INFORMATION
*lpTimeZoneInformation
,
309 CONST SYSTEMTIME
*lpUniversalTime
,
310 LPSYSTEMTIME lpLocalTime
)
312 TIME_ZONE_INFORMATION TzInfo
;
317 if (lpTimeZoneInformation
!= NULL
)
319 TzInfo
= *lpTimeZoneInformation
;
323 if (GetTimeZoneInformation(&TzInfo
) == TIME_ZONE_ID_INVALID
)
327 if (!lpUniversalTime
|| !lpLocalTime
)
330 if (!SystemTimeToFileTime(lpUniversalTime
, &FileTime
))
333 FILETIME2LL(&FileTime
, llTime
)
335 if (!TIME_GetTimezoneBias(&TzInfo
, &FileTime
, FALSE
, &lBias
))
338 /* convert minutes to 100-nanoseconds-ticks */
339 llTime
-= (LONGLONG
)lBias
* TICKSPERMIN
;
341 LL2FILETIME( llTime
, &FileTime
)
343 return FileTimeToSystemTime(&FileTime
, lpLocalTime
);
348 * @implemented (Wine 13 sep 2008)
352 TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation
,
353 LPSYSTEMTIME lpLocalTime
,
354 LPSYSTEMTIME lpUniversalTime
)
359 TIME_ZONE_INFORMATION tzinfo
;
361 if (lpTimeZoneInformation
!= NULL
)
363 tzinfo
= *lpTimeZoneInformation
;
367 if (GetTimeZoneInformation(&tzinfo
) == TIME_ZONE_ID_INVALID
)
371 if (!SystemTimeToFileTime(lpLocalTime
, &ft
))
374 if (!TIME_GetTimezoneBias(&tzinfo
, &ft
, TRUE
, &lBias
))
376 /* convert minutes to 100-nanoseconds-ticks */
377 t
+= (LONGLONG
)lBias
* TICKSPERMIN
;
379 return FileTimeToSystemTime(&ft
, lpUniversalTime
);