Some hypervisors for virtual machines do not properly support sending a fake system time to the guest operating system, thus making Windows guests display the wrong time if their timezone is set to anything except UTC. This happens because Windows, by default, keeps the system clock set to the local time. This is stupid.
The same problems can occur on dual-booted computers, for instance where Windows and Linux attempt to co-exist on the same hardware. Linux will, unless told to do otherwise, set the system clock to UTC, and Windows will keep changing it to whatever the local time is. Linux can of course be told to keep the system time in the local time zone, but a less known feature of Windows allows you to do the opposite.
The magic registry key is HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\RealTimeIsUniversal

Create a new 32-bit DWORD and set it to 1, then reboot.
There’s exhaustive reading material on the subject here (local archive) if you’re interested.
2 Comments
I’ve run into this exact issue when dual-booting Linux and Windows! The constant time switching drove me crazy until I found that registry key fix. It’s wild that Windows defaults to local time for the hardware clock when UTC makes so much more sense for modern systems. Thanks for documenting the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation path – this should save people a lot of headaches.
Ugh, that dual-boot time conflict is so annoying—I’ve had my Linux install constantly overwriting the hardware clock to UTC while Windows keeps switching it back to local time. I didn’t know about that `TimeZoneInf` registry key to make Windows use UTC instead; that’s way cleaner than telling Linux to use local time. Thanks for sharing that fix, finally I can stop the clock wars every time I reboot.