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:
parent
6f17eee7a9
commit
d788e03057
|
@ -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
|
||||||
LPSYSTEMTIME lpUniversalTime, /* [in] The utc time to base local time on. */
|
lpTimeZoneInformation, /* [in] The desired time zone. */
|
||||||
LPSYSTEMTIME lpLocalTime) /* [out] The local time in the time zone. */
|
LPSYSTEMTIME lpUniversalTime, /* [in] The utc time to base local time on. */
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue