2

I'm writing a software that allows to change the current time zone parameters used in Windows:

enter image description here

So far the only reference to setting a system-wide time zone that I found is the SetTimeZoneInformation API (or its variation SetDynamicTimeZoneInformation.) But I'm not really sure how I can use it to change the current time zone?

For instance, it takes TIME_ZONE_INFORMATION struct with all kinds of information about local time offset, daylight saving settings, etc. I don't understand why do I need to fill all of this info out when all I want to do is, say change the current time zone from "(UTC-08:00) Pacific Time (US & Canada)" to "(UTC-07:00) Mountain Time (US & Canada)".

Am I looking at the correct API to do that?

c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • The API lets you set arbitrary timezone information, you aren't just limited to what's in the registry. If you do want to use one of the pre-defined timezones, you can fill out the structure using the information in the registry. – Jonathan Potter Apr 12 '17 at 02:43
  • @JonathanPotter: You're referring to this registry key, correct? `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones` – c00000fd Apr 12 '17 at 03:29
  • Correct. It's documented on the TIME_ZONE_INFORMATION page so is official. – Jonathan Potter Apr 12 '17 at 03:39
  • Note that there are consequences of not using the predefined time zones, and also that you should always use the "dynamic" forms of these functions unless you are targeting versions of Windows pre-vista. – Matt Johnson-Pint Apr 12 '17 at 18:15
  • @MattJohnson: Yeah, you brought up an interesting point. I'm somewhat struggling to understand the difference between calling `SetDynamicTimeZoneInformation` and `SetTimeZoneInformation`. AFAIK, dynamic function works with specific years. In my case though, all I need is to switch active time zone. How would that affect it? It should work in "general" case and not for a specific year. – c00000fd Apr 12 '17 at 18:47
  • "Dynamic" refers to the "Dynamic DST" data that's in the registry as a subkey under some of the time zones. The system really needs to have access to this data to give accurate time conversions. In other words, even if you think you aren't dealing with a specific year and only need current data, you can't be assured that other processes and applications won't need it. Especially when governments change time zone rules from one year to the next. – Matt Johnson-Pint Apr 12 '17 at 19:26
  • The `DYNAMIC_TIME_ZONE_INFORMATION` structure contains a string reference of a `TimeZoneKeyName`, so it can get at this data. If you set without that, or using the older `TIME_ZONE_INFORMATION` structure, then dynamic data isn't available and conversions might give wrong results. – Matt Johnson-Pint Apr 12 '17 at 19:27
  • Full disclosure - I work for Microsoft and regularly interact with the Windows time zone folks. Don't interpret my words as an official statement, but I can tell you that the concept of "custom time zones" is really something we don't encourage. The team works really hard to keep the actual time zone data accurate and up to date. – Matt Johnson-Pint Apr 12 '17 at 19:29
  • @MattJohnson: Thank you for the explanation. The purpose of the software I'm working on is to allow users to modify time zone parameters where OS updates are not supported (such as XP and Vista) or are disabled. What we've witnessed is that if the DST settings are off in the system, this causes all kinds of problems. And ASAIK Windows itself doesn't have a CP option to adjust time zone parameters. The software in question will not modify tz info willy-nilly. It will allow to change current time zone & adjust DST parameters, such as date it begins and end. Would that still cause issues? – c00000fd Apr 12 '17 at 20:45
  • Well, those are two different things. Changing any of the parameters you showed in the screenshot above is using the OS's tz data from the registry, including whatever updates (or lack thereof) are installed. Allowing the user to adjust when DST starts and ends, what the offsets are, names, etc. are in the realm of custom time zones. Note that we used to ship a utility called `TZEdit.exe` that did exactly what you describe for the second part. However, it doesn't support dynamic time zones, which means that the user ends up having to tweak things as governments change time zone rules. – Matt Johnson-Pint Apr 12 '17 at 21:58
  • @MattJohnson: Yes, I did find `TZEdit.exe` on some third-party site. But it is woefully out of date. That is why I'm writing this updated tool. I'm almost done with it. If you guys are interested I can share it with you. My [contact info](http://stackoverflow.com/users/843732/c00000fd?tab=profile). – c00000fd Apr 12 '17 at 23:17
  • @c00000fd please, have you found a solution? I need the same, just switch timezone from any to "UTC - Coordinated Universal Time", Thanks a lot! – Dom Nov 02 '17 at 14:09
  • @Dom: I posted it in a separate answer as far as I could remember it. – c00000fd Nov 02 '17 at 20:08

2 Answers2

1

It's been a while, so let me try to recap what I ended up doing. Unfortunately my solution was OS specific:

  • For Windows Vista & later:

    1. Set SE_TIME_ZONE_NAME privilege.

    2. Call SetDynamicTimeZoneInformation by specifying the details of the time zone to set.

    3. Remove SE_TIME_ZONE_NAME privilege.

  • For Windows XP:

    1. Set SE_SYSTEMTIME_NAME privilege.

    2. Call SetTimeZoneInformation with information about the time zone to set.

    3. Reset SE_SYSTEMTIME_NAME privilege back.

Lastly for both OS, broadcast the following message to let running applications know that the time zone has changed:

::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)L"intl",
        SMTO_ABORTIFHUNG, 
        2 * 1000,   //the total wait time can be up to the value of uTimeout multiplied by the number of top-level windows.
        NULL);

PS. To get the information on the current time zone use GetDynamicTimeZoneInformation or GetTimeZoneInformation for WinXP.

Additionally you may want to retrieve the list of all available timezones that you may use to choose the info for the new (default) timezone. You can get it from enumerating/parsing the following registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones

Check here and here for the information on its structure.

c00000fd
  • 20,994
  • 29
  • 177
  • 400
0

Honestly, the easiest way is to just use the tzutil.exe utility. If you need to do this in Win32 C++, then just call from ShellExecute. Pass the ID of the time zone, not the display name.

See also my answer for doing this from .NET.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Hmm.. yes. I'd assume it would work. But with this method, 1) you're relying on an outside process that may be changed, or disappear in the next version of the OS, and 2) it complicates things about inter-process synchronization with `tzutil.exe` to know if the outcome was a success. Plus getting an error code in case of error is out of the question. Plus 3) how would I know time zone ID. – c00000fd Apr 12 '17 at 20:48
  • tzutil won't disappear, and it does return an exit code you can check. The IDs are available by passing `/l` to list them. However, you said you were running on xp and vista. tzutil was originally added in Windows 7. An [update](https://blogs.technet.microsoft.com/latam/2011/10/11/new-update-brings-tzutil-command-line-tool-to-windows-vista-and-windows-2008/) made it available for Windows Vista, but it doesn't work on XP. – Matt Johnson-Pint Apr 12 '17 at 22:04
  • Yeah, the lack of XP support is another deal breaker. – c00000fd Apr 12 '17 at 23:13