Subject: | Determining local time zone in Windows will fail for non-English Windows and other issues |
There are a few issues my attached patch intends to fix:
1)
LMachine/SYSTEM/CurrentControlSet/Control/TimeZoneInformation/StandardName
simply stores the localized name of the Windows time zone. This name
changes in non-English language versions of Windows. In those versions
of Windows, you will be unable to select a correct time zone, as those
names are not in the list of Windows time zones DateTime-TimeZone maps
to the Olson time zones.
An example of this can be seen by selecting the time zone for Jerusalem
on any English version of Windows. The "StandardName" value is
"Jerusalem Standard Time," but the time zone key name is "Israel
Standard Time." By using the time zone keys rather than the
"StandardName" value, not only is the value in the list already in this
module, but the key name is also identical across non-English versions
of Windows as well.
The patch fixes the problem by looking up the StandardName value, just
as before, but then comparing it to the "Std" value located in each time
zone subkey under:
LMachine/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones/
It is this value that is copied to the CurrentControlSet when you select
a time zone on Windows. I tested this and it works on a Japanese version
of Windows Server 2003. The previous DateTime-TimeZone code did not work.
I should note that on Vista and Windows Server 2008, the change in the
TimeZoneInformation key to use "TimeZoneKeyName" meant that no
additional lookup was necessary for those systems. In the patch, I also
included the registry keys for Windows 95, Windows 98 and Windows ME,
but I based that on Microsoft documentation in various support articles.
I did not have a system to test the code on there.
I changed the pod documentation slightly to reflect the changes in this
patch.
2)
The hash converting Windows time zones to Olson time zones contained
duplicate keys for 'GMT Standard Time' and 'Tasmania Standard Time.'
These are removed in my patch and in the case of 'GMT Standard Time,'
which in the current code points to two different Olson time zones and
ends up selecting the incorrect zone, now corrects the zone to point to
Europe/London.
3) The hash of Windows time zones is missing some recently added time
zones. I've added the following Windows time zones to the patch:
'Armenian Standard Time' => 'Asia/Yerevan',
'Montevideo Standard Time' => 'America/Montevideo',
'Venezuela Standard Time' => 'America/Caracas',
Subject: | Win32.patch |
Index: D:/FootPrints/FPSQL/bin/Perl/site/lib/DateTime/TimeZone/Local/Win32.pm
===================================================================
--- C:/Perl/site/lib/DateTime/TimeZone/Local/Win32.pm (revision 4346)
+++ C:/Perl/site/lib/DateTime/TimeZone/Local/Win32.pm (revision 4379)
@@ -25,6 +25,7 @@
'Arabian' => 'Asia/Muscat',
'Arabian Standard Time' => 'Asia/Muscat',
'Arabic Standard Time' => 'Asia/Baghdad',
+ 'Armenian Standard Time' => 'Asia/Yerevan',
'Atlantic' => 'America/Halifax',
'Atlantic Standard Time' => 'America/Halifax',
'AUS Central' => 'Australia/Darwin',
@@ -84,7 +85,6 @@
'GFT Standard Time' => 'Europe/Athens',
'GMT' => 'Europe/London',
'GMT Standard Time' => 'Europe/London',
- 'GMT Standard Time' => 'GMT',
'Greenland Standard Time' => 'America/Godthab',
'Greenwich' => 'GMT',
'Greenwich Standard Time' => 'GMT',
@@ -107,6 +107,7 @@
'Mid-Atlantic' => 'Atlantic/South_Georgia',
'Mid-Atlantic Standard Time' => 'Atlantic/South_Georgia',
'Middle East Standard Time' => 'Asia/Beirut',
+ 'Montevideo Standard Time' => 'America/Montevideo',
'Mountain' => 'America/Denver',
'Mountain Standard Time' => 'America/Denver',
'Mountain Standard Time (Mexico)' => 'America/Chihuahua',
@@ -153,7 +154,6 @@
'Taipei Standard Time' => 'Asia/Taipei',
'Tasmania' => 'Australia/Hobart',
'Tasmania Standard Time' => 'Australia/Hobart',
- 'Tasmania Standard Time' => 'Australia/Hobart',
'Tokyo' => 'Asia/Tokyo',
'Tokyo Standard Time' => 'Asia/Tokyo',
'Tonga Standard Time' => 'Pacific/Tongatapu',
@@ -161,6 +161,7 @@
'US Eastern Standard Time' => 'America/Indianapolis',
'US Mountain' => 'America/Phoenix',
'US Mountain Standard Time' => 'America/Phoenix',
+ 'Venezuela Standard Time' => 'America/Caracas',
'Vladivostok' => 'Asia/Vladivostok',
'Vladivostok Standard Time' => 'Asia/Vladivostok',
'W. Australia' => 'Australia/Perth',
@@ -178,19 +179,40 @@
'Yakutsk Standard Time' => 'Asia/Yakutsk',
);
- my $Key =
- 'LMachine/SYSTEM/CurrentControlSet/Control/TimeZoneInformation';
-
sub FromRegistry
{
my $class = shift;
- my $keyObject = $Registry->Open( $Key, { Access => KEY_READ } );
+ my $LMachine = $Registry->Open( 'LMachine/', { Access => KEY_READ } );
+ my $TimeZoneInfo =
+ $LMachine->{'SYSTEM/CurrentControlSet/Control/TimeZoneInformation/'};
- my $win_name =
- defined $keyObject->{'/TimeZoneKeyName'} && $keyObject->{'/TimeZoneKeyName'} ne ''
- ? $keyObject->{'/TimeZoneKeyName'}
- : $keyObject->{'/StandardName'};
+ my $win_name;
+
+ # Windows Vista, Windows 2008 Server
+ if (defined $TimeZoneInfo->{'/TimeZoneKeyName'} &&
+ $TimeZoneInfo->{'/TimeZoneKeyName'} ne '')
+ {
+ $win_name = $TimeZoneInfo->{'/TimeZoneKeyName'};
+ }
+ else
+ {
+ my $AllTimeZones =
+ $LMachine->{'SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones/'}
+ # Windows NT, Windows 2000, Windows XP, Windows 2003 Server
+ ? $LMachine->{'SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones/'}
+ # Windows 95, Windows 98, Windows Millenium Edition
+ : $LMachine->{'SOFTWARE/Microsoft/Windows/CurrentVersion/Time Zones/'};
+
+ foreach my $zone ($AllTimeZones->SubKeyNames())
+ {
+ if ($AllTimeZones->{"${zone}/Std"} eq $TimeZoneInfo->{'/StandardName'})
+ {
+ $win_name = $zone;
+ last;
+ }
+ }
+ }
# On Windows 2008 Server, there is additional junk after a
# null character.
@@ -243,10 +265,12 @@
=item * Windows Registry
We check for a registry key called
-"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\StandardName".
+"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation".
-If this exists, it contains a Windows name for the time zone. We use a
-lookup table to translate this into an equivalent time zone name.
+If this exists, we use its values to determine the currently selected time
+zone key from the registry. The name of this key is the Windows name for
+the time zone. We use a lookup table to translate this into an equivalent
+time zone name.
This lookup table was borrowed from the Chronos Smalltalk
library.