Sorry, did send it to the wrong list. ---------- Forwarded Message ---------- Subject: Implementation of SystemTimeToTzSpecificLocalTime() and TzSpecificLocalTimeToSystemTime() Date: Fri, 13 Dec 2002 21:45:35 +0100 From: Martin Fuchs <martin-fuchs@gmx.net> To: wine-devel <wine-devel@winehq.com> Implementation of SystemTimeToTzSpecificLocalTime() and TzSpecificLocalTimeToSystemTime() -- Martin Fuchs martin-fuchs@gmx.net
Index: dlls/kernel/kernel32.spec =================================================================== RCS file: /home/wine/wine/dlls/kernel/kernel32.spec,v retrieving revision 1.84 diff -u -r1.84 kernel32.spec --- dlls/kernel/kernel32.spec 12 Dec 2002 03:55:05 -0000 1.84 +++ dlls/kernel/kernel32.spec 13 Dec 2002 20:43:14 -0000 @@ -801,6 +801,7 @@ @ stdcall SuspendThread(long) SuspendThread @ stdcall SystemTimeToFileTime(ptr ptr) SystemTimeToFileTime @ stdcall SystemTimeToTzSpecificLocalTime (ptr ptr ptr) SystemTimeToTzSpecificLocalTime +@ stdcall TzSpecificLocalTimeToSystemTime (ptr ptr ptr) TzSpecificLocalTimeToSystemTime @ stub TerminateJobObject @ stdcall TerminateProcess(long long) TerminateProcess @ stdcall TerminateThread(long long) TerminateThread Index: dlls/kernel/time.c =================================================================== RCS file: /home/wine/wine/dlls/kernel/time.c,v retrieving revision 1.27 diff -u -r1.27 time.c --- dlls/kernel/time.c 13 Dec 2002 20:30:07 -0000 1.27 +++ dlls/kernel/time.c 13 Dec 2002 20:43:15 -0000 @@ -163,6 +163,181 @@ /*********************************************************************** + * _DayLightCompareDate + * + * Compares two dates without looking at the year + * + * RETURNS + * + * -1 if date < compareDate + * 0 if date == compareDate + * 1 if date > compareDate + * -2 if an error occures + */ + +static int _DayLightCompareDate( + const LPSYSTEMTIME date, /* [in] The date to compare. */ + const LPSYSTEMTIME compareDate) /* [in] The daylight saving begin or end date */ +{ + int limit_day; + + if (compareDate->wYear != 0) + { + if (date->wMonth < compareDate->wMonth) + return -1; /* We are in a year before the date limit. */ + + if (date->wMonth > compareDate->wMonth) + return 1; /* We are in a year after the date limit. */ + } + + if (date->wMonth < compareDate->wMonth) + return -1; /* We are in a month before the date limit. */ + + if (date->wMonth > compareDate->wMonth) + return 1; /* We are in a month after the date limit. */ + + if (compareDate->wDayOfWeek <= 6) + { + SYSTEMTIME tmp; + FILETIME tmp_ft; + + /* compareDate->wDay is interpreted as number of the week in the month. */ + /* 5 means: the last week in the month */ + int weekofmonth = compareDate->wDay; + + /* calculate day of week for the first day in the month */ + memcpy(&tmp, date, sizeof(SYSTEMTIME)); + tmp.wDay = 1; + tmp.wDayOfWeek = -1; + + if (weekofmonth == 5) + { + /* Go to the beginning of the next month. */ + if (++tmp.wMonth > 12) + { + tmp.wMonth = 1; + ++tmp.wYear; + } + } + + if (!SystemTimeToFileTime(&tmp, &tmp_ft)) + return -2; + + if (weekofmonth == 5) + { + long long int t, one_day; + + t = tmp_ft.dwHighDateTime; + t <<= 32; + t += (UINT)tmp_ft.dwLowDateTime; + + /* substract one day */ + one_day = 24*60*60; + one_day *= 10000000; + t -= one_day; + + tmp_ft.dwLowDateTime = (UINT)t; + tmp_ft.dwHighDateTime = (UINT)(t >> 32); + } + + if (!FileTimeToSystemTime(&tmp_ft, &tmp)) + return -2; + + if (weekofmonth == 5) + { + /* calculate the last matching day of the week in this month */ + int dif = tmp.wDayOfWeek - compareDate->wDayOfWeek; + if (dif < 0) + dif += 7; + + limit_day = tmp.wDay - dif; + } + else + { + /* calulcate the matching day of the week in the given week */ + int dif = compareDate->wDayOfWeek - tmp.wDayOfWeek; + if (dif < 0) + dif += 7; + + limit_day = tmp.wDay + 7*(weekofmonth-1) + dif; + } + } + else + { + limit_day = compareDate->wDay; + } + + if (date->wDay < limit_day) + return -1; + + if (date->wDay > limit_day) + return 1; + + return 0; /* date is equal to the date limit. */ +} + + +/*********************************************************************** + * _GetTimezoneBias + * + * Calculates the local time bias for a given time zone + * + * RETURNS + * + * Returns TRUE when the time zone bias was calculated. + */ + +static BOOL _GetTimezoneBias( + const LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The time zone data. */ + LPSYSTEMTIME lpSystemTime, /* [in] The system time. */ + LONG* pBias) /* [out] The calulated bias in minutes */ +{ + int ret; + BOOL beforedaylightsaving, afterdaylightsaving; + BOOL daylightsaving = FALSE; + LONG bias = lpTimeZoneInformation->Bias; + + if (lpTimeZoneInformation->DaylightDate.wMonth != 0) + { + if (lpTimeZoneInformation->StandardDate.wMonth == 0 || + lpTimeZoneInformation->StandardDate.wDay<1 || + lpTimeZoneInformation->StandardDate.wDay>5 || + lpTimeZoneInformation->DaylightDate.wDay<1 || + lpTimeZoneInformation->DaylightDate.wDay>5) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* check for daylight saving */ + ret = _DayLightCompareDate(lpSystemTime, &lpTimeZoneInformation->StandardDate); + if (ret == -2) + return FALSE; + + beforedaylightsaving = ret < 0; + + _DayLightCompareDate(lpSystemTime, &lpTimeZoneInformation->DaylightDate); + if (ret == -2) + return FALSE; + + afterdaylightsaving = ret >= 0; + + if (!beforedaylightsaving && !afterdaylightsaving) + daylightsaving = TRUE; + } + + if (daylightsaving) + bias += lpTimeZoneInformation->DaylightBias; + else if (lpTimeZoneInformation->StandardDate.wMonth != 0) + bias += lpTimeZoneInformation->StandardBias; + + *pBias = bias; + + return TRUE; +} + + +/*********************************************************************** * SystemTimeToTzSpecificLocalTime (KERNEL32.@) * * Converts the system time (utc) to the local time in the specified time zone. @@ -170,20 +345,100 @@ * RETURNS * * Returns true when the local time was calculated. + * Returns TRUE when the local time was calculated. * - * BUGS - * - * Does not handle daylight savings time adjustments correctly. */ + BOOL WINAPI SystemTimeToTzSpecificLocalTime( LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The desired time zone. */ LPSYSTEMTIME lpUniversalTime, /* [in] The utc time to base local time on. */ LPSYSTEMTIME lpLocalTime) /* [out] The local time in the time zone. */ { - FIXME(":stub\n"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + FILETIME ft; + LONG lBias; + long long int t, bias; + TIME_ZONE_INFORMATION tzinfo; + + if (lpTimeZoneInformation != NULL) + { + memcpy(&tzinfo, lpTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION)); + } + else + { + if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID) + return FALSE; + } + + if (!SystemTimeToFileTime(lpUniversalTime, &ft)) + return FALSE; + + t = ft.dwHighDateTime; + t <<= 32; + t += (UINT)ft.dwLowDateTime; + + if (!_GetTimezoneBias(&tzinfo, lpUniversalTime, &lBias)) + return FALSE; + + bias = lBias * 600000000; /* 60 seconds per minute, 100000 [100-nanoseconds-ticks] per second */ + t += bias; + + ft.dwLowDateTime = (UINT)t; + ft.dwHighDateTime = (UINT)(t >> 32); + + return FileTimeToSystemTime(&ft, lpLocalTime); +} + + +/*********************************************************************** + * TzSpecificLocalTimeToSystemTime (KERNEL32.@) + * + * Converts a local time to a time in Coordinated Universal Time (UTC). + * + * RETURNS + * + * Returns TRUE when the utc time was calculated. + */ + +BOOL WINAPI TzSpecificLocalTimeToSystemTime( + LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The desired time zone. */ + LPSYSTEMTIME lpLocalTime, /* [in] The local time. */ + LPSYSTEMTIME lpUniversalTime) /* [out] The calculated utc time. */ +{ + FILETIME ft; + LONG lBias; + long long int t, bias; + TIME_ZONE_INFORMATION tzinfo; + + if (lpTimeZoneInformation != NULL) + { + memcpy(&tzinfo, lpTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION)); + } + else + { + if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID) + return FALSE; + } + + if (!SystemTimeToFileTime(lpLocalTime, &ft)) + return FALSE; + + t = ft.dwHighDateTime; + t <<= 32; + t += (UINT)ft.dwLowDateTime; + + if (!_GetTimezoneBias(&tzinfo, lpUniversalTime, &lBias)) + return FALSE; + + bias = lBias * 600000000; /* 60 seconds per minute, 100000 [100-nanoseconds-ticks] per second */ + t -= bias; + + ft.dwLowDateTime = (UINT)t; + ft.dwHighDateTime = (UINT)(t >> 32); + + return FileTimeToSystemTime(&ft, lpUniversalTime); } + + /***********************************************************************