Fixed TzSpecificLocalTimeToSystemTime and

SystemTimeToTzSpecificLocalTime:
- take the time of day into the calculation, so the bias is calculated
  correctly during the transition days;
- the transition times are expressed as local time, not system time;
- correct the daylight logic for use on the southern hemisphere;
- beautify some LONGLONG arithmetic.
This commit is contained in:
Rein Klazes 2004-09-10 19:35:06 +00:00 committed by Alexandre Julliard
parent 6f17eee7a9
commit d788e03057
1 changed files with 76 additions and 69 deletions

View File

@ -53,6 +53,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(time);
#define SETTIME_MAX_ADJUST 120 #define SETTIME_MAX_ADJUST 120
#define CALINFO_MAX_YEAR 2029 #define CALINFO_MAX_YEAR 2029
#define LL2FILETIME( ll, pft )\
(pft)->dwLowDateTime = (UINT)(ll); \
(pft)->dwHighDateTime = (UINT)((ll) >> 32);
#define FILETIME2LL( pft, ll) \
ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime ;
/*********************************************************************** /***********************************************************************
* SetLocalTime (KERNEL32.@) * SetLocalTime (KERNEL32.@)
@ -204,19 +209,11 @@ BOOL WINAPI SetTimeZoneInformation(
*/ */
static int _DayLightCompareDate( static int _DayLightCompareDate(
const LPSYSTEMTIME date, /* [in] The date to compare. */ const LPSYSTEMTIME date, /* [in] The local time to compare. */
const LPSYSTEMTIME compareDate) /* [in] The daylight saving begin or end date */ const LPSYSTEMTIME compareDate) /* [in] The daylight saving begin
or end date */
{ {
int limit_day; int limit_day, dayinsecs;
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) if (date->wMonth < compareDate->wMonth)
return -1; /* We are in a month before the date limit. */ return -1; /* We are in a month before the date limit. */
@ -229,8 +226,8 @@ static int _DayLightCompareDate(
SYSTEMTIME tmp; SYSTEMTIME tmp;
FILETIME tmp_ft; FILETIME tmp_ft;
/* compareDate->wDay is interpreted as number of the week in the month. */ /* compareDate->wDay is interpreted as number of the week in the month
/* 5 means: the last week in the month */ * 5 means: the last week in the month */
int weekofmonth = compareDate->wDay; int weekofmonth = compareDate->wDay;
/* calculate day of week for the first day in the month */ /* calculate day of week for the first day in the month */
@ -253,19 +250,11 @@ static int _DayLightCompareDate(
if (weekofmonth == 5) if (weekofmonth == 5)
{ {
LONGLONG t, one_day; LONGLONG t;
FILETIME2LL( &tmp_ft, t)
t = tmp_ft.dwHighDateTime;
t <<= 32;
t += (UINT)tmp_ft.dwLowDateTime;
/* subtract one day */ /* subtract one day */
one_day = 24*60*60; t -= (LONGLONG) 24*60*60*10000000;
one_day *= 10000000; LL2FILETIME( t, &tmp_ft);
t -= one_day;
tmp_ft.dwLowDateTime = (UINT)t;
tmp_ft.dwHighDateTime = (UINT)(t >> 32);
} }
if (!FileTimeToSystemTime(&tmp_ft, &tmp)) if (!FileTimeToSystemTime(&tmp_ft, &tmp))
@ -295,13 +284,15 @@ static int _DayLightCompareDate(
limit_day = compareDate->wDay; limit_day = compareDate->wDay;
} }
if (date->wDay < limit_day) /* convert to seconds */
return -1; limit_day = ((limit_day * 24 + compareDate->wHour) * 60 +
compareDate->wMinute ) * 60;
if (date->wDay > limit_day) dayinsecs = ((date->wDay * 24 + date->wHour) * 60 +
return 1; date->wMinute ) * 60 + date->wSecond;
/* and compare */
return 0; /* date is equal to the date limit. */ return dayinsecs < limit_day ? -1 :
dayinsecs > limit_day ? 1 :
0; /* date is equal to the date limit. */
} }
@ -316,14 +307,21 @@ static int _DayLightCompareDate(
*/ */
static BOOL _GetTimezoneBias( static BOOL _GetTimezoneBias(
const LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The time zone data. */ const LPTIME_ZONE_INFORMATION
LPSYSTEMTIME lpSystemTime, /* [in] The system time. */ lpTimeZoneInformation, /* [in] The time zone data. */
LONG* pBias) /* [out] The calulated bias in minutes */ LPSYSTEMTIME lpSysOrLocalTime, /* [in] The system or local time. */
BOOL islocal, /* [in] it is local time */
LONG* pBias /* [out] The calulated bias in minutes */
)
{ {
int ret; int ret;
BOOL beforeStandardDate, afterDaylightDate; BOOL beforeStandardDate, afterDaylightDate;
BOOL daylightsaving = FALSE; BOOL daylightsaving = FALSE;
LONG bias = lpTimeZoneInformation->Bias; LONG bias = lpTimeZoneInformation->Bias;
FILETIME ft;
LONGLONG llTime = 0; /* initialized to prevent gcc complaining */
SYSTEMTIME stTemp;
LPSYSTEMTIME lpTime = lpSysOrLocalTime;
if (lpTimeZoneInformation->DaylightDate.wMonth != 0) if (lpTimeZoneInformation->DaylightDate.wMonth != 0)
{ {
@ -337,20 +335,43 @@ static BOOL _GetTimezoneBias(
return FALSE; return FALSE;
} }
if (!islocal) {
if (!SystemTimeToFileTime(lpSysOrLocalTime, &ft)) return -2;
FILETIME2LL( &ft, llTime );
llTime -= ( lpTimeZoneInformation->Bias +
lpTimeZoneInformation->DaylightBias ) * (LONGLONG)600000000;
LL2FILETIME( llTime, &ft)
FileTimeToSystemTime(&ft, &stTemp);
lpTime = &stTemp;
}
/* check for daylight saving */ /* check for daylight saving */
ret = _DayLightCompareDate(lpSystemTime, &lpTimeZoneInformation->StandardDate); ret = _DayLightCompareDate(lpTime, &lpTimeZoneInformation->StandardDate);
if (ret == -2) if (ret == -2)
return FALSE; return FALSE;
beforeStandardDate = ret < 0; beforeStandardDate = ret < 0;
ret = _DayLightCompareDate(lpSystemTime, &lpTimeZoneInformation->DaylightDate); if (!islocal) {
llTime -= ( lpTimeZoneInformation->StandardBias -
lpTimeZoneInformation->DaylightBias ) * (LONGLONG)600000000;
LL2FILETIME( llTime, &ft)
FileTimeToSystemTime(&ft, &stTemp);
lpTime = &stTemp;
}
ret = _DayLightCompareDate(lpTime, &lpTimeZoneInformation->DaylightDate);
if (ret == -2) if (ret == -2)
return FALSE; return FALSE;
afterDaylightDate = ret >= 0; afterDaylightDate = ret >= 0;
if (beforeStandardDate && afterDaylightDate) if( lpTimeZoneInformation->DaylightDate.wMonth < /* Northern */
lpTimeZoneInformation->StandardDate.wMonth ) { /* hemisphere */
if( beforeStandardDate && afterDaylightDate )
daylightsaving = TRUE;
} else /* Down south */
if( beforeStandardDate || afterDaylightDate )
daylightsaving = TRUE; daylightsaving = TRUE;
} }
@ -376,13 +397,14 @@ static BOOL _GetTimezoneBias(
*/ */
BOOL WINAPI SystemTimeToTzSpecificLocalTime( BOOL WINAPI SystemTimeToTzSpecificLocalTime(
LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The desired time zone. */ LPTIME_ZONE_INFORMATION
lpTimeZoneInformation, /* [in] The desired time zone. */
LPSYSTEMTIME lpUniversalTime, /* [in] The utc time to base local time on. */ LPSYSTEMTIME lpUniversalTime, /* [in] The utc time to base local time on. */
LPSYSTEMTIME lpLocalTime) /* [out] The local time in the time zone. */ LPSYSTEMTIME lpLocalTime) /* [out] The local time in the time zone. */
{ {
FILETIME ft; FILETIME ft;
LONG lBias; LONG lBias;
LONGLONG t, bias; LONGLONG llTime;
TIME_ZONE_INFORMATION tzinfo; TIME_ZONE_INFORMATION tzinfo;
if (lpTimeZoneInformation != NULL) if (lpTimeZoneInformation != NULL)
@ -397,19 +419,12 @@ BOOL WINAPI SystemTimeToTzSpecificLocalTime(
if (!SystemTimeToFileTime(lpUniversalTime, &ft)) if (!SystemTimeToFileTime(lpUniversalTime, &ft))
return FALSE; return FALSE;
FILETIME2LL( &ft, llTime)
t = ft.dwHighDateTime; if (!_GetTimezoneBias(&tzinfo, lpUniversalTime, FALSE, &lBias))
t <<= 32;
t += (UINT)ft.dwLowDateTime;
if (!_GetTimezoneBias(&tzinfo, lpUniversalTime, &lBias))
return FALSE; return FALSE;
/* convert minutes to 100-nanoseconds-ticks */
bias = (LONGLONG)lBias * 600000000; /* 60 seconds per minute, 100000 [100-nanoseconds-ticks] per second */ llTime -= (LONGLONG)lBias * 600000000;
t -= bias; LL2FILETIME( llTime, &ft)
ft.dwLowDateTime = (UINT)t;
ft.dwHighDateTime = (UINT)(t >> 32);
return FileTimeToSystemTime(&ft, lpLocalTime); return FileTimeToSystemTime(&ft, lpLocalTime);
} }
@ -431,7 +446,7 @@ BOOL WINAPI TzSpecificLocalTimeToSystemTime(
{ {
FILETIME ft; FILETIME ft;
LONG lBias; LONG lBias;
LONGLONG t, bias; LONGLONG t;
TIME_ZONE_INFORMATION tzinfo; TIME_ZONE_INFORMATION tzinfo;
if (lpTimeZoneInformation != NULL) if (lpTimeZoneInformation != NULL)
@ -446,20 +461,12 @@ BOOL WINAPI TzSpecificLocalTimeToSystemTime(
if (!SystemTimeToFileTime(lpLocalTime, &ft)) if (!SystemTimeToFileTime(lpLocalTime, &ft))
return FALSE; return FALSE;
FILETIME2LL( &ft, t)
t = ft.dwHighDateTime; if (!_GetTimezoneBias(&tzinfo, lpLocalTime, TRUE, &lBias))
t <<= 32;
t += (UINT)ft.dwLowDateTime;
if (!_GetTimezoneBias(&tzinfo, lpLocalTime, &lBias))
return FALSE; return FALSE;
/* convert minutes to 100-nanoseconds-ticks */
bias = (LONGLONG)lBias * 600000000; /* 60 seconds per minute, 100000 [100-nanoseconds-ticks] per second */ t += (LONGLONG)lBias * 600000000;
t += bias; LL2FILETIME( t, &ft)
ft.dwLowDateTime = (UINT)t;
ft.dwHighDateTime = (UINT)(t >> 32);
return FileTimeToSystemTime(&ft, lpUniversalTime); return FileTimeToSystemTime(&ft, lpUniversalTime);
} }