mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[NTOS:EX] Various fixes for Daylight Saving Time transitions (#5868)
* [NTOS:EX] Various fixes for Daylight Saving Time transitions * Fix automatic time changes when DST starts and ends. * Currently it takes two cycles of the update provided by w32time to make the actual change. * Convert Eric Kohl's TimeZoneID code contained in ExRefreshTimeZoneInformation to a new function. * Use this new function in ExpSetTimeZoneInformation and ExRefreshTimeZoneInformation functions. CORE-19290
This commit is contained in:
parent
28eb4e726a
commit
69ebfd671d
1 changed files with 173 additions and 87 deletions
|
@ -30,6 +30,100 @@ ULONG ExpTimerResolutionCount = 0;
|
||||||
|
|
||||||
/* FUNCTIONS ****************************************************************/
|
/* FUNCTIONS ****************************************************************/
|
||||||
|
|
||||||
|
/*++
|
||||||
|
* If successful, this function sets the following global variable:
|
||||||
|
* ExpTimeZoneInfo
|
||||||
|
*--*/
|
||||||
|
static
|
||||||
|
BOOLEAN
|
||||||
|
ExpGetTimeZoneId(
|
||||||
|
_In_ PLARGE_INTEGER TimeNow,
|
||||||
|
_Out_ PULONG TimeZoneId,
|
||||||
|
_Out_ PLARGE_INTEGER NewTimeZoneBias)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER StandardTime;
|
||||||
|
LARGE_INTEGER DaylightTime;
|
||||||
|
LARGE_INTEGER LocalTimeNow = *TimeNow;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
DPRINT("ExpGetTimeZoneId\n");
|
||||||
|
|
||||||
|
/* Read time zone information from the registry */
|
||||||
|
Status = RtlQueryTimeZoneInformation(&ExpTimeZoneInfo);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("RtlQueryTimeZoneInformation failed (Status 0x%08lx)\n", Status);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the default bias */
|
||||||
|
NewTimeZoneBias->QuadPart = (LONGLONG)ExpTimeZoneInfo.Bias * TICKSPERMINUTE;
|
||||||
|
|
||||||
|
if (ExpTimeZoneInfo.StandardDate.Month != 0 &&
|
||||||
|
ExpTimeZoneInfo.DaylightDate.Month != 0)
|
||||||
|
{
|
||||||
|
/* Get this year's standard start time */
|
||||||
|
if (!RtlCutoverTimeToSystemTime(&ExpTimeZoneInfo.StandardDate,
|
||||||
|
&StandardTime,
|
||||||
|
&LocalTimeNow,
|
||||||
|
TRUE))
|
||||||
|
{
|
||||||
|
DPRINT1("RtlCutoverTimeToSystemTime for StandardDate failed\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get this year's daylight start time */
|
||||||
|
if (!RtlCutoverTimeToSystemTime(&ExpTimeZoneInfo.DaylightDate,
|
||||||
|
&DaylightTime,
|
||||||
|
&LocalTimeNow,
|
||||||
|
TRUE))
|
||||||
|
{
|
||||||
|
DPRINT1("RtlCutoverTimeToSystemTime for DaylightDate failed\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine the time zone id and update the time zone bias */
|
||||||
|
if (DaylightTime.QuadPart < StandardTime.QuadPart)
|
||||||
|
{
|
||||||
|
if ((LocalTimeNow.QuadPart >= DaylightTime.QuadPart) &&
|
||||||
|
(LocalTimeNow.QuadPart < StandardTime.QuadPart))
|
||||||
|
{
|
||||||
|
DPRINT("Daylight time\n");
|
||||||
|
*TimeZoneId = TIME_ZONE_ID_DAYLIGHT;
|
||||||
|
NewTimeZoneBias->QuadPart += (LONGLONG)ExpTimeZoneInfo.DaylightBias * TICKSPERMINUTE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT("Standard time\n");
|
||||||
|
*TimeZoneId = TIME_ZONE_ID_STANDARD;
|
||||||
|
NewTimeZoneBias->QuadPart += (LONGLONG)ExpTimeZoneInfo.StandardBias * TICKSPERMINUTE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((LocalTimeNow.QuadPart >= StandardTime.QuadPart) &&
|
||||||
|
(LocalTimeNow.QuadPart < DaylightTime.QuadPart))
|
||||||
|
{
|
||||||
|
DPRINT("Standard time\n");
|
||||||
|
*TimeZoneId = TIME_ZONE_ID_STANDARD;
|
||||||
|
NewTimeZoneBias->QuadPart += (LONGLONG)ExpTimeZoneInfo.StandardBias * TICKSPERMINUTE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT("Daylight time\n");
|
||||||
|
*TimeZoneId = TIME_ZONE_ID_DAYLIGHT;
|
||||||
|
NewTimeZoneBias->QuadPart += (LONGLONG)ExpTimeZoneInfo.DaylightBias * TICKSPERMINUTE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*TimeZoneId = TIME_ZONE_ID_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
* @name ExAcquireTimeRefreshLock
|
* @name ExAcquireTimeRefreshLock
|
||||||
*
|
*
|
||||||
|
@ -225,105 +319,39 @@ BOOLEAN
|
||||||
NTAPI
|
NTAPI
|
||||||
ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime)
|
ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER StandardTime;
|
LARGE_INTEGER CurrentTime, NewTimeZoneBias;
|
||||||
LARGE_INTEGER DaylightTime;
|
BOOLEAN Success;
|
||||||
LARGE_INTEGER CurrentTime;
|
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
/* Read time zone information from the registry */
|
DPRINT("ExRefreshTimeZoneInformation\n");
|
||||||
Status = RtlQueryTimeZoneInformation(&ExpTimeZoneInfo);
|
|
||||||
if (!NT_SUCCESS(Status))
|
/* Set the global data for ExpTimeZoneBias and the Time Zone ID */
|
||||||
|
Success = ExpGetTimeZoneId(CurrentBootTime, &ExpTimeZoneId, &NewTimeZoneBias);
|
||||||
|
if (!Success)
|
||||||
{
|
{
|
||||||
DPRINT1("RtlQueryTimeZoneInformation() failed (Status 0x%08lx)\n", Status);
|
DPRINT1("ExpGetTimeZoneId failed\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
DPRINT("ExpTimeZoneId is %lu\n", ExpTimeZoneId);
|
||||||
|
|
||||||
/* Get the default bias */
|
ExpTimeZoneBias = NewTimeZoneBias;
|
||||||
ExpTimeZoneBias.QuadPart = (LONGLONG)ExpTimeZoneInfo.Bias * TICKSPERMINUTE;
|
|
||||||
|
|
||||||
if (ExpTimeZoneInfo.StandardDate.Month != 0 &&
|
/* Change SharedUserData->TimeZoneBias for user-mode applications */
|
||||||
ExpTimeZoneInfo.DaylightDate.Month != 0)
|
|
||||||
{
|
|
||||||
/* Get this years standard start time */
|
|
||||||
if (!RtlCutoverTimeToSystemTime(&ExpTimeZoneInfo.StandardDate,
|
|
||||||
&StandardTime,
|
|
||||||
CurrentBootTime,
|
|
||||||
TRUE))
|
|
||||||
{
|
|
||||||
DPRINT1("RtlCutoverTimeToSystemTime() for StandardDate failed!\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get this years daylight start time */
|
|
||||||
if (!RtlCutoverTimeToSystemTime(&ExpTimeZoneInfo.DaylightDate,
|
|
||||||
&DaylightTime,
|
|
||||||
CurrentBootTime,
|
|
||||||
TRUE))
|
|
||||||
{
|
|
||||||
DPRINT1("RtlCutoverTimeToSystemTime() for DaylightDate failed!\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine the time zone id and update the time zone bias */
|
|
||||||
if (DaylightTime.QuadPart < StandardTime.QuadPart)
|
|
||||||
{
|
|
||||||
if ((CurrentBootTime->QuadPart >= DaylightTime.QuadPart) &&
|
|
||||||
(CurrentBootTime->QuadPart < StandardTime.QuadPart))
|
|
||||||
{
|
|
||||||
DPRINT("Daylight time!\n");
|
|
||||||
ExpTimeZoneId = TIME_ZONE_ID_DAYLIGHT;
|
|
||||||
ExpTimeZoneBias.QuadPart += (LONGLONG)ExpTimeZoneInfo.DaylightBias * TICKSPERMINUTE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DPRINT("Standard time!\n");
|
|
||||||
ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
|
|
||||||
ExpTimeZoneBias.QuadPart += (LONGLONG)ExpTimeZoneInfo.StandardBias * TICKSPERMINUTE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((CurrentBootTime->QuadPart >= StandardTime.QuadPart) &&
|
|
||||||
(CurrentBootTime->QuadPart < DaylightTime.QuadPart))
|
|
||||||
{
|
|
||||||
DPRINT("Standard time!\n");
|
|
||||||
ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
|
|
||||||
ExpTimeZoneBias.QuadPart += (LONGLONG)ExpTimeZoneInfo.StandardBias * TICKSPERMINUTE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DPRINT("Daylight time!\n");
|
|
||||||
ExpTimeZoneId = TIME_ZONE_ID_DAYLIGHT;
|
|
||||||
ExpTimeZoneBias.QuadPart += (LONGLONG)ExpTimeZoneInfo.DaylightBias * TICKSPERMINUTE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExpTimeZoneId = TIME_ZONE_ID_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Change it for user-mode applications */
|
|
||||||
SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
|
|
||||||
SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
|
SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
|
||||||
SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
|
SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
|
||||||
|
SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
|
||||||
SharedUserData->TimeZoneId = ExpTimeZoneId;
|
SharedUserData->TimeZoneId = ExpTimeZoneId;
|
||||||
|
|
||||||
/* Convert boot time from local time to UTC */
|
/* Convert boot time from local time to UTC */
|
||||||
KeBootTime.QuadPart += ExpTimeZoneBias.QuadPart;
|
KeBootTime.QuadPart += ExpTimeZoneBias.QuadPart;
|
||||||
|
|
||||||
/* Convert system time from local time to UTC */
|
/* Convert system time from local time to UTC */
|
||||||
do
|
KeQuerySystemTime(&CurrentTime);;
|
||||||
{
|
|
||||||
CurrentTime.u.HighPart = SharedUserData->SystemTime.High1Time;
|
|
||||||
CurrentTime.u.LowPart = SharedUserData->SystemTime.LowPart;
|
|
||||||
} while (CurrentTime.u.HighPart != SharedUserData->SystemTime.High2Time);
|
|
||||||
|
|
||||||
/* Change it for user-mode applications */
|
/* Change it for user-mode applications */
|
||||||
CurrentTime.QuadPart += ExpTimeZoneBias.QuadPart;
|
CurrentTime.QuadPart += ExpTimeZoneBias.QuadPart;
|
||||||
|
SharedUserData->SystemTime.High2Time = CurrentTime.u.HighPart;
|
||||||
SharedUserData->SystemTime.LowPart = CurrentTime.u.LowPart;
|
SharedUserData->SystemTime.LowPart = CurrentTime.u.LowPart;
|
||||||
SharedUserData->SystemTime.High1Time = CurrentTime.u.HighPart;
|
SharedUserData->SystemTime.High1Time = CurrentTime.u.HighPart;
|
||||||
SharedUserData->SystemTime.High2Time = CurrentTime.u.HighPart;
|
|
||||||
|
|
||||||
/* Return success */
|
/* Return success */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -332,9 +360,43 @@ ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime)
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
ExpSetTimeZoneInformation(PRTL_TIME_ZONE_INFORMATION TimeZoneInformation)
|
ExpSetTimeZoneInformation(PRTL_TIME_ZONE_INFORMATION TimeZoneInformation)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER LocalTime, SystemTime, OldTime;
|
LARGE_INTEGER LocalTime, SystemTime, OldTime, NewTimeZoneBias;
|
||||||
TIME_FIELDS TimeFields;
|
TIME_FIELDS TimeFields;
|
||||||
DPRINT("ExpSetTimeZoneInformation() called\n");
|
BOOLEAN Success;
|
||||||
|
NTSTATUS Status;
|
||||||
|
LARGE_INTEGER LocalTimeNow;
|
||||||
|
|
||||||
|
DPRINT("ExpSetTimeZoneInformation called\n");
|
||||||
|
|
||||||
|
/* Read time zone information from the registry */
|
||||||
|
Status = RtlQueryTimeZoneInformation(&ExpTimeZoneInfo);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("RtlQueryTimeZoneInformation failed (Status 0x%08lx)\n", Status);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the default bias */
|
||||||
|
NewTimeZoneBias.QuadPart = (LONGLONG)ExpTimeZoneInfo.Bias * TICKSPERMINUTE;
|
||||||
|
|
||||||
|
/* Get the Shared User Data System Time into the local SystemTime */
|
||||||
|
KeQuerySystemTime(&SystemTime);
|
||||||
|
|
||||||
|
LocalTimeNow = SystemTime;
|
||||||
|
|
||||||
|
/* Adjust LocalTimeNow for Time Zone Bias to use UTC for comparisons */
|
||||||
|
LocalTimeNow.QuadPart -= NewTimeZoneBias.QuadPart;
|
||||||
|
|
||||||
|
/* Set the Global Data for ExpTimeZoneBias and ExpTimeZoneId */
|
||||||
|
Success = ExpGetTimeZoneId(&LocalTimeNow, &ExpTimeZoneId, &NewTimeZoneBias);
|
||||||
|
if (!Success)
|
||||||
|
{
|
||||||
|
DPRINT1("ExpGetTimeZoneId failed\n");
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
DPRINT("ExpTimeZoneId is %lu\n", ExpTimeZoneId);
|
||||||
|
|
||||||
|
ExpTimeZoneBias = NewTimeZoneBias;
|
||||||
|
|
||||||
DPRINT("Old time zone bias: %d minutes\n", ExpTimeZoneInfo.Bias);
|
DPRINT("Old time zone bias: %d minutes\n", ExpTimeZoneInfo.Bias);
|
||||||
DPRINT("Old time zone standard bias: %d minutes\n",
|
DPRINT("Old time zone standard bias: %d minutes\n",
|
||||||
|
@ -347,13 +409,14 @@ ExpSetTimeZoneInformation(PRTL_TIME_ZONE_INFORMATION TimeZoneInformation)
|
||||||
HalQueryRealTimeClock(&TimeFields);
|
HalQueryRealTimeClock(&TimeFields);
|
||||||
RtlTimeFieldsToTime(&TimeFields, &LocalTime);
|
RtlTimeFieldsToTime(&TimeFields, &LocalTime);
|
||||||
|
|
||||||
/* FIXME: Calculate transition dates */
|
/* Calculate the bias */
|
||||||
|
|
||||||
/* Calculate the bias and set the ID */
|
|
||||||
ExpTimeZoneBias.QuadPart = ((LONGLONG)(TimeZoneInformation->Bias +
|
ExpTimeZoneBias.QuadPart = ((LONGLONG)(TimeZoneInformation->Bias +
|
||||||
TimeZoneInformation->StandardBias)) *
|
TimeZoneInformation->StandardBias)) *
|
||||||
TICKSPERMINUTE;
|
TICKSPERMINUTE;
|
||||||
ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
|
|
||||||
|
/* If Daylight Savings Time then add the DayLightBias to the Time Zone Bias */
|
||||||
|
if (ExpTimeZoneId == TIME_ZONE_ID_DAYLIGHT)
|
||||||
|
ExpTimeZoneBias.QuadPart += (LONGLONG)ExpTimeZoneInfo.DaylightBias * TICKSPERMINUTE;
|
||||||
|
|
||||||
/* Copy the timezone information */
|
/* Copy the timezone information */
|
||||||
RtlCopyMemory(&ExpTimeZoneInfo,
|
RtlCopyMemory(&ExpTimeZoneInfo,
|
||||||
|
@ -377,7 +440,7 @@ ExpSetTimeZoneInformation(PRTL_TIME_ZONE_INFORMATION TimeZoneInformation)
|
||||||
PoNotifySystemTimeSet();
|
PoNotifySystemTimeSet();
|
||||||
|
|
||||||
/* Return success */
|
/* Return success */
|
||||||
DPRINT("ExpSetTimeZoneInformation() done\n");
|
DPRINT("ExpSetTimeZoneInformation done\n");
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,6 +464,8 @@ NtSetSystemTime(IN PLARGE_INTEGER SystemTime,
|
||||||
TIME_FIELDS TimeFields;
|
TIME_FIELDS TimeFields;
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
RTL_TIME_ZONE_INFORMATION TimeZoneInformation = { 0 };
|
||||||
|
ULONG TimeZoneIdSave;
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
@ -468,6 +533,27 @@ NtSetSystemTime(IN PLARGE_INTEGER SystemTime,
|
||||||
_SEH2_END;
|
_SEH2_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read time zone information from the registry and set the clock */
|
||||||
|
Status = RtlQueryTimeZoneInformation(&TimeZoneInformation);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("RtlQueryTimeZoneInformation failed (Status 0x%08lx)\n", Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test if we went from Daylight to Standard Time or vice versa */
|
||||||
|
TimeZoneIdSave = ExpTimeZoneId;
|
||||||
|
ExpSetTimeZoneInformation(&TimeZoneInformation);
|
||||||
|
|
||||||
|
if (ExpTimeZoneId != TimeZoneIdSave)
|
||||||
|
{
|
||||||
|
/* Going from DT to ST or vice versa we need to repeat this */
|
||||||
|
DPRINT("Daylight Time and Standard Time are switching\n");
|
||||||
|
|
||||||
|
/* Set the system time and notify the system */
|
||||||
|
KeSetSystemTime(&NewSystemTime, &OldSystemTime, FALSE, NULL);
|
||||||
|
PoNotifySystemTimeSet();
|
||||||
|
}
|
||||||
|
|
||||||
/* Return status */
|
/* Return status */
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue