通过代码在 Windows 操作系统上启用和禁用 DST

Posted

技术标签:

【中文标题】通过代码在 Windows 操作系统上启用和禁用 DST【英文标题】:Enable and disable DST on Windows OS by code 【发布时间】:2019-09-01 19:03:17 【问题描述】:

有没有办法(夏令时)?

我一直在按照下一个link 中提到的步骤进行操作,但没有成功...

我也一直在尝试更改 DYNAMIC_TIME_ZONE_INFORMATION 结构的“Bias”属性,它允许我更改日期时间,但不能启用或禁用 DST...

有没有办法解决这个问题?

下一个源码只禁用夏令时,不过我需要重新启用...

    OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

    TOKEN_PRIVILEGES tp;
    LookupPrivilegeValue(NULL, SE_TIME_ZONE_NAME, &tp.Privileges[0].Luid);
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);

    DYNAMIC_TIME_ZONE_INFORMATION dyTimeZoneInfo;
    ZeroMemory(&dyTimeZoneInfo, sizeof(dyTimeZoneInfo));
    DWORD tzId = GetDynamicTimeZoneInformation(&dyTimeZoneInfo);

    dyTimeZoneInfo.DynamicDaylightTimeDisabled = !dyTimeZoneInfo.DynamicDaylightTimeDisabled;
    dyTimeZoneInfo.DaylightBias = 0;
    dyTimeZoneInfo.StandardDate.wDay = 0;
    dyTimeZoneInfo.StandardDate.wDayOfWeek = 0;
    dyTimeZoneInfo.StandardDate.wHour = 0;
    dyTimeZoneInfo.StandardDate.wMilliseconds = 0;
    dyTimeZoneInfo.StandardDate.wMinute = 0;
    dyTimeZoneInfo.StandardDate.wMonth = 0;
    dyTimeZoneInfo.StandardDate.wSecond = 0;
    dyTimeZoneInfo.StandardDate.wYear = 0;

    dyTimeZoneInfo.DaylightDate.wDay = 0;
    dyTimeZoneInfo.DaylightDate.wDayOfWeek = 0;
    dyTimeZoneInfo.DaylightDate.wHour = 0;
    dyTimeZoneInfo.DaylightDate.wMilliseconds = 0;
    dyTimeZoneInfo.DaylightDate.wMinute = 0;
    dyTimeZoneInfo.DaylightDate.wMonth = 0;
    dyTimeZoneInfo.DaylightDate.wSecond = 0;
    dyTimeZoneInfo.DaylightDate.wYear = 0;

    SetDynamicTimeZoneInformation(&dyTimeZoneInfo);

    tp.Privileges[0].Attributes = NULL;
    AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);

    CloseHandle(hToken);

我将不胜感激。

【问题讨论】:

请出示您的代码。 好的,我已经更新了我的帖子 我相信你应该添加一个返回值检查。不知道函数调用成功与否。 @montonero 我一直在检查所有函数,返回值为'1' 您是否按照here 的规定检查了AdjustTokenPrivileges 的结果? 【参考方案1】:

您的原始代码大部分是正确的。我看到的主要问题是:

dyTimeZoneInfo.DynamicDaylightTimeDisabled = !dyTimeZoneInfo.DynamicDaylightTimeDisabled;

切换自动 DST 功能,而您的其余代码严格禁用它。而是将其设置为 true。

dyTimeZoneInfo.DynamicDaylightTimeDisabled = TRUE;

要重新启用 DST,您需要恢复 DaylightBiasDaylightStartStandardStart 字段的原始值。 (不要假设DaylightBias 总是-60,至少有一个是-30。)

最好只恢复整个DYNAMIC_TIME_ZONE_INFORMATION 结构。为此,请使用EnumDynamicTimeZoneInformation 函数遍历系统上的所有时区,并选择TimeZoneKeyName 与当前时区匹配的时区。

最后,您可能需要考虑为什么需要这样做。通常不再需要通过此机制禁用 DST。这是一个遗留功能。整个世界都有适当的时区条目,包括没有 DST 的地区。如果您只是想在自己的应用程序(可能是系统管理应用程序)中模拟操作系统的设置,那很好。但对于大多数其他目的,您不需要操纵此设置。

【讨论】:

我一直在看timezoneapi.h,它定义了EnumDynamicTimeZoneInformation。此功能仅在 Windows 7 和 8 上支持。目前,我使用的是 Windows 10 操作系统和 x64 解决方案平台。还有其他枚举时区的函数吗? 它在 Windows 8 及更高版本(包括 Windows 10)上受支持。您可能还需要包括 Windows.h。 docs.microsoft.com/en-us/windows/desktop/api/timezoneapi/… 嗨@Matt Johnson,我已经包含了Windows.h,但仍然找不到函数EnumDynamicTimeZoneInformation... 斯坦格。您使用的是最新的 Windows SDK 吗? 我使用的是 Windows SDK 8.1 版【参考方案2】:

这个源代码解决了我的问题。

    HANDLE hToken;
    OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

    TOKEN_PRIVILEGES tp;
    LookupPrivilegeValue(NULL, SE_TIME_ZONE_NAME, &tp.Privileges[0].Luid);
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);

    DYNAMIC_TIME_ZONE_INFORMATION dyTimeZoneInfo;
    ZeroMemory(&dyTimeZoneInfo, sizeof(dyTimeZoneInfo));
    DWORD tzId = GetDynamicTimeZoneInformation(&dyTimeZoneInfo);

    dyTimeZoneInfo.DynamicDaylightTimeDisabled = !dyTimeZoneInfo.DynamicDaylightTimeDisabled;

    if (dyTimeZoneInfo.DynamicDaylightTimeDisabled)
        dyTimeZoneInfo.Bias = dyTimeZoneInfo.StandardBias;
    else
        dyTimeZoneInfo.Bias = dyTimeZoneInfo.DaylightBias;

    SetDynamicTimeZoneInformation(&dyTimeZoneInfo);

    tp.Privileges[0].Attributes = NULL;
    AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);

    CloseHandle(hToken);

【讨论】:

小心。您将StandardBiasDaylightBias 分配给Bias 字段,但文档解释说这些是delta 的。您正在覆盖 Bias 值。请参阅我的答案。

以上是关于通过代码在 Windows 操作系统上启用和禁用 DST的主要内容,如果未能解决你的问题,请参考以下文章

在单个操作上禁用和重新启用按钮

windows进程启动设置时区限制

安全扫描扫到服务器的SSL存在隐患,建议禁用SSL,启用TLS,这个在WINDOWS和LINUX上,如何操作?

使用 C 程序启用禁用键

使用 win32 API 功能启用/禁用任务管理器,而不是通过 Windows 注册表

通过删除属性启用和禁用按钮[重复]