1package DateTime::TimeZone::Local::Win32; 2 3use strict; 4use warnings; 5 6use base 'DateTime::TimeZone::Local'; 7 8use Win32::TieRegistry ( 'KEY_READ', Delimiter => q{/} ); 9 10 11sub Methods { return qw( FromEnv FromRegistry ) } 12 13sub EnvVars { return 'TZ' } 14 15{ 16 # This list comes (mostly) in the zipball for the Chronos project 17 # - a Smalltalk datetime library. Thanks, Chronos! 18 my %WinToOlson = 19 ( 'Afghanistan' => 'Asia/Kabul', 20 'Afghanistan Standard Time' => 'Asia/Kabul', 21 'Alaskan' => 'America/Anchorage', 22 'Alaskan Standard Time' => 'America/Anchorage', 23 'Arab' => 'Asia/Riyadh', 24 'Arab Standard Time' => 'Asia/Riyadh', 25 'Arabian' => 'Asia/Muscat', 26 'Arabian Standard Time' => 'Asia/Muscat', 27 'Arabic Standard Time' => 'Asia/Baghdad', 28 'Argentina Standard Time' => 'America/Argentina/Buenos_Aires', 29 'Armenian Standard Time' => 'Asia/Yerevan', 30 'Atlantic' => 'America/Halifax', 31 'Atlantic Standard Time' => 'America/Halifax', 32 'AUS Central' => 'Australia/Darwin', 33 'AUS Central Standard Time' => 'Australia/Darwin', 34 'AUS Eastern' => 'Australia/Sydney', 35 'AUS Eastern Standard Time' => 'Australia/Sydney', 36 'Azerbaijan Standard Time' => 'Asia/Baku', 37 'Azores' => 'Atlantic/Azores', 38 'Azores Standard Time' => 'Atlantic/Azores', 39 'Bangkok' => 'Asia/Bangkok', 40 'Bangkok Standard Time' => 'Asia/Bangkok', 41 'Beijing' => 'Asia/Shanghai', 42 'Canada Central' => 'America/Regina', 43 'Canada Central Standard Time' => 'America/Regina', 44 'Cape Verde Standard Time' => 'Atlantic/Cape_Verde', 45 'Caucasus' => 'Asia/Yerevan', 46 'Caucasus Standard Time' => 'Asia/Yerevan', 47 'Cen. Australia' => 'Australia/Adelaide', 48 'Cen. Australia Standard Time' => 'Australia/Adelaide', 49 'Central' => 'America/Chicago', 50 'Central America Standard Time' => 'America/Regina', 51 'Central Asia' => 'Asia/Dhaka', 52 'Central Asia Standard Time' => 'Asia/Dhaka', 53 'Central Brazilian Standard Time' => 'America/Manaus', 54 'Central Europe' => 'Europe/Prague', 55 'Central Europe Standard Time' => 'Europe/Prague', 56 'Central European' => 'Europe/Belgrade', 57 'Central European Standard Time' => 'Europe/Belgrade', 58 'Central Pacific' => 'Pacific/Guadalcanal', 59 'Central Pacific Standard Time' => 'Pacific/Guadalcanal', 60 'Central Standard Time' => 'America/Chicago', 61 'Central Standard Time (Mexico)' => 'America/Mexico_City', 62 'China' => 'Asia/Shanghai', 63 'China Standard Time' => 'Asia/Shanghai', 64 'Dateline' => 'Pacific/Majuro', 65 'Dateline Standard Time' => 'Pacific/Majuro', 66 'E. Africa' => 'Africa/Nairobi', 67 'E. Africa Standard Time' => 'Africa/Nairobi', 68 'E. Australia' => 'Australia/Brisbane', 69 'E. Australia Standard Time' => 'Australia/Brisbane', 70 'E. Europe' => 'Europe/Minsk', 71 'E. Europe Standard Time' => 'Europe/Minsk', 72 'E. South America' => 'America/Sao_Paulo', 73 'E. South America Standard Time' => 'America/Sao_Paulo', 74 'Eastern' => 'America/New_York', 75 'Eastern Standard Time' => 'America/New_York', 76 'Egypt' => 'Africa/Cairo', 77 'Egypt Standard Time' => 'Africa/Cairo', 78 'Ekaterinburg' => 'Asia/Yekaterinburg', 79 'Ekaterinburg Standard Time' => 'Asia/Yekaterinburg', 80 'Fiji' => 'Pacific/Fiji', 81 'Fiji Standard Time' => 'Pacific/Fiji', 82 'FLE' => 'Europe/Helsinki', 83 'FLE Standard Time' => 'Europe/Helsinki', 84 'Georgian Standard Time' => 'Asia/Tbilisi', 85 'GFT' => 'Europe/Athens', 86 'GFT Standard Time' => 'Europe/Athens', 87 'GMT' => 'Europe/London', 88 'GMT Standard Time' => 'Europe/London', 89 'Greenland Standard Time' => 'America/Godthab', 90 'Greenwich' => 'GMT', 91 'Greenwich Standard Time' => 'GMT', 92 'GTB' => 'Europe/Athens', 93 'GTB Standard Time' => 'Europe/Athens', 94 'Hawaiian' => 'Pacific/Honolulu', 95 'Hawaiian Standard Time' => 'Pacific/Honolulu', 96 'India' => 'Asia/Calcutta', 97 'India Standard Time' => 'Asia/Calcutta', 98 'Iran' => 'Asia/Tehran', 99 'Iran Standard Time' => 'Asia/Tehran', 100 'Israel' => 'Asia/Jerusalem', 101 'Israel Standard Time' => 'Asia/Jerusalem', 102 'Jordan Standard Time' => 'Asia/Amman', 103 'Kamchatka Standard Time' => 'Asia/Kamchatka', 104 'Korea' => 'Asia/Seoul', 105 'Korea Standard Time' => 'Asia/Seoul', 106 'Mauritius Standard Time' => 'Indian/Mauritius', 107 'Mexico' => 'America/Mexico_City', 108 'Mexico Standard Time' => 'America/Mexico_City', 109 'Mexico Standard Time 2' => 'America/Chihuahua', 110 'Mid-Atlantic' => 'Atlantic/South_Georgia', 111 'Mid-Atlantic Standard Time' => 'Atlantic/South_Georgia', 112 'Middle East Standard Time' => 'Asia/Beirut', 113 'Montevideo Standard Time' => 'America/Montevideo', 114 'Morocco Standard Time' => 'Africa/Casablanca', 115 'Mountain' => 'America/Denver', 116 'Mountain Standard Time' => 'America/Denver', 117 'Mountain Standard Time (Mexico)' => 'America/Chihuahua', 118 'Myanmar Standard Time' => 'Asia/Rangoon', 119 'N. Central Asia Standard Time' => 'Asia/Novosibirsk', 120 'Namibia Standard Time' => 'Africa/Windhoek', 121 'Nepal Standard Time' => 'Asia/Katmandu', 122 'New Zealand' => 'Pacific/Auckland', 123 'New Zealand Standard Time' => 'Pacific/Auckland', 124 'Newfoundland' => 'America/St_Johns', 125 'Newfoundland Standard Time' => 'America/St_Johns', 126 'North Asia East Standard Time' => 'Asia/Irkutsk', 127 'North Asia Standard Time' => 'Asia/Krasnoyarsk', 128 'Pacific' => 'America/Los_Angeles', 129 'Pacific SA' => 'America/Santiago', 130 'Pacific SA Standard Time' => 'America/Santiago', 131 'Pacific Standard Time' => 'America/Los_Angeles', 132 'Pacific Standard Time (Mexico)' => 'America/Tijuana', 133 'Pakistan Standard Time' => 'Asia/Karachi', 134 'Paraguay Standard Time' => 'America/Asuncion', 135 'Prague Bratislava' => 'Europe/Prague', 136 'Romance' => 'Europe/Paris', 137 'Romance Standard Time' => 'Europe/Paris', 138 'Russian' => 'Europe/Moscow', 139 'Russian Standard Time' => 'Europe/Moscow', 140 'SA Eastern' => 'America/Buenos_Aires', 141 'SA Eastern Standard Time' => 'America/Buenos_Aires', 142 'SA Pacific' => 'America/Bogota', 143 'SA Pacific Standard Time' => 'America/Bogota', 144 'SA Western' => 'America/Caracas', 145 'SA Western Standard Time' => 'America/Caracas', 146 'Samoa' => 'Pacific/Apia', 147 'Samoa Standard Time' => 'Pacific/Apia', 148 'Saudi Arabia' => 'Asia/Riyadh', 149 'Saudi Arabia Standard Time' => 'Asia/Riyadh', 150 'SE Asia' => 'Asia/Bangkok', 151 'SE Asia Standard Time' => 'Asia/Bangkok', 152 'Singapore' => 'Asia/Singapore', 153 'Singapore Standard Time' => 'Asia/Singapore', 154 'South Africa' => 'Africa/Harare', 155 'South Africa Standard Time' => 'Africa/Harare', 156 'Sri Lanka' => 'Asia/Colombo', 157 'Sri Lanka Standard Time' => 'Asia/Colombo', 158 'Sydney Standard Time' => 'Australia/Sydney', 159 'Taipei' => 'Asia/Taipei', 160 'Taipei Standard Time' => 'Asia/Taipei', 161 'Tasmania' => 'Australia/Hobart', 162 'Tasmania Standard Time' => 'Australia/Hobart', 163 'Tokyo' => 'Asia/Tokyo', 164 'Tokyo Standard Time' => 'Asia/Tokyo', 165 'Tonga Standard Time' => 'Pacific/Tongatapu', 166 'Ulaanbaatar Standard Time' => 'Asia/Ulaanbaatar', 167 'US Eastern' => 'America/Indianapolis', 168 'US Eastern Standard Time' => 'America/Indianapolis', 169 'US Mountain' => 'America/Phoenix', 170 'US Mountain Standard Time' => 'America/Phoenix', 171 'UTC' => 'UTC', 172 'Venezuela Standard Time' => 'America/Caracas', 173 'Vladivostok' => 'Asia/Vladivostok', 174 'Vladivostok Standard Time' => 'Asia/Vladivostok', 175 'W. Australia' => 'Australia/Perth', 176 'W. Australia Standard Time' => 'Australia/Perth', 177 'W. Central Africa Standard Time' => 'Africa/Luanda', 178 'W. Europe' => 'Europe/Berlin', 179 'W. Europe Standard Time' => 'Europe/Berlin', 180 'Warsaw' => 'Europe/Warsaw', 181 'West Asia' => 'Asia/Karachi', 182 'West Asia Standard Time' => 'Asia/Karachi', 183 'West Pacific' => 'Pacific/Guam', 184 'West Pacific Standard Time' => 'Pacific/Guam', 185 'Western Brazilian Standard Time' => 'America/Rio_Branco', 186 'Yakutsk' => 'Asia/Yakutsk', 187 'Yakutsk Standard Time' => 'Asia/Yakutsk', 188 ); 189 190 sub FromRegistry 191 { 192 my $class = shift; 193 194 my $win_name = $class->_FindWindowsTZName(); 195 196 # On Windows 2008 Server, there is additional junk after a 197 # null character. 198 $win_name =~ s/\0.*$// 199 if defined $win_name; 200 201 return unless defined $win_name; 202 203 my $olson = $WinToOlson{$win_name}; 204 205 return unless $olson; 206 207 return unless $class->_IsValidName($olson); 208 209 local $@; 210 local $SIG{__DIE__}; 211 return eval { DateTime::TimeZone->new( name => $olson ) }; 212 } 213} 214 215sub _FindWindowsTZName 216{ 217 my $class = shift; 218 219 my $LMachine = $Registry->Open( 'LMachine/', { Access => KEY_READ } ); 220 221 my $TimeZoneInfo = 222 $LMachine->{'SYSTEM/CurrentControlSet/Control/TimeZoneInformation/'}; 223 224 # Windows Vista, Windows 2008 Server 225 if ( defined $TimeZoneInfo->{'/TimeZoneKeyName'} && 226 $TimeZoneInfo->{'/TimeZoneKeyName'} ne '' ) 227 { 228 return $TimeZoneInfo->{'/TimeZoneKeyName'}; 229 } 230 else 231 { 232 my $AllTimeZones = 233 $LMachine->{'SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones/'} 234 # Windows NT, Windows 2000, Windows XP, Windows 2003 Server 235 ? $LMachine->{'SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones/'} 236 # Windows 95, Windows 98, Windows Millenium Edition 237 : $LMachine->{'SOFTWARE/Microsoft/Windows/CurrentVersion/Time Zones/'}; 238 239 foreach my $zone ( $AllTimeZones->SubKeyNames() ) 240 { 241 if ( $AllTimeZones->{ $zone . '/Std' } eq $TimeZoneInfo->{'/StandardName'} ) 242 { 243 return $zone; 244 } 245 } 246 } 247 248 return; 249} 250 251 2521; 253 254__END__ 255 256=head1 NAME 257 258DateTime::TimeZone::Local::Win32 - Determine the local system's time zone on Windows 259 260=head1 SYNOPSIS 261 262 my $tz = DateTime::TimeZone->new( name => 'local' ); 263 264 my $tz = DateTime::TimeZone::Local->TimeZone(); 265 266=head1 DESCRIPTION 267 268This module provides methods for determining the local time zone on a 269Windows platform. 270 271=head1 HOW THE TIME ZONE IS DETERMINED 272 273This class tries the following methods of determining the local time 274zone: 275 276=over 4 277 278=item * $ENV{TZ} 279 280It checks C<< $ENV{TZ} >> for a valid time zone name. 281 282=item * Windows Registry 283 284When using the registry, we look for the Windows time zone and use a 285mapping to translate this to an Olson time zone name. 286 287=over 8 288 289=item * Windows Vista and 2008 290 291We look in "SYSTEM/CurrentControlSet/Control/TimeZoneInformation/" for 292a node named "/TimeZoneKeyName". If this exists, we use this key to 293look up the Olson time zone name in our mapping. 294 295=item * Windows NT, Windows 2000, Windows XP, Windows 2003 Server 296 297We look in "SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones/" 298and loop through all of its sub keys. 299 300For each sub key, we compare the value of the key with "/Std" appended 301to the end to the value of 302"SYSTEM/CurrentControlSet/Control/TimeZoneInformation/StandardName". This 303gives us the I<English> name of the Windows time zone, which we use to 304look up the Olson time zone name. 305 306=item * Windows 95, Windows 98, Windows Millenium Edition 307 308The algorithm is the same as for NT, but we loop through the sub keys 309of "SOFTWARE/Microsoft/Windows/CurrentVersion/Time Zones/" 310 311=back 312 313=back 314 315=head1 AUTHOR 316 317Dave Rolsky, <autarch@urth.org> 318 319=head1 COPYRIGHT & LICENSE 320 321Copyright (c) 2003-2008 David Rolsky. All rights reserved. This 322program is free software; you can redistribute it and/or modify it 323under the same terms as Perl itself. 324 325The full text of the license can be found in the LICENSE file included 326with this module. 327 328=cut 329