################################################################# # # win32tzlist.pl -- compare Windows timezone information # # Copyright (c) 2008-2021, PostgreSQL Global Development Group # # src/tools/win32tzlist.pl ################################################################# # # This script compares the timezone information in the Windows registry # with that in src/bin/initdb/findtimezone.c. A list of changes will be # written to stdout - no attempt is made to automatically edit the file. # # Run the script from the top-level PG source directory. # use strict; use warnings; use Win32::Registry; my $tzfile = 'src/bin/initdb/findtimezone.c'; # # Fetch all timezones in the registry # my $basekey; $HKEY_LOCAL_MACHINE->Open( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", $basekey) or die $!; my @subkeys; $basekey->GetKeys(\@subkeys); my @system_zones; foreach my $keyname (@subkeys) { my $subkey; my %vals; $basekey->Open($keyname, $subkey) or die $!; $subkey->GetValues(\%vals) or die $!; $subkey->Close(); die "Incomplete timezone data for $keyname!\n" unless ($vals{Std} && $vals{Dlt} && $vals{Display}); push @system_zones, { 'std' => $vals{Std}->[2], 'dlt' => $vals{Dlt}->[2], 'display' => clean_displayname($vals{Display}->[2]), }; } $basekey->Close(); # # Fetch all timezones currently in the file # my @file_zones; my $pgtz; open(my $tzfh, '<', $tzfile) or die "Could not open $tzfile!\n"; { local $/ = undef; $pgtz = <$tzfh>; } close($tzfh); # Attempt to locate and extract the complete win32_tzmap struct $pgtz =~ /win32_tzmap\[\] =\s+{\s+\/\*[^\/]+\*\/\s+(.+?)};/gs or die "Could not locate struct win32_tzmap in $tzfile!"; $pgtz = $1; # Extract each individual record from the struct while ($pgtz =~ m/{\s+\/\*(.+?)\*\/\s+"([^"]+)",\s+"([^"]+)",\s+"([^"]+)",?\s+},/gs) { push @file_zones, { 'display' => clean_displayname($1), 'std' => $2, 'dlt' => $3, 'match' => $4, }; } # # Look for anything that has changed # my @add; for my $sys (@system_zones) { my $match = 0; for my $file (@file_zones) { if ($sys->{std} eq $file->{std}) { $match = 1; if ($sys->{dlt} ne $file->{dlt}) { print "Timezone $sys->{std}, changed name of daylight zone!\n"; } if ($sys->{display} ne $file->{display}) { print "Timezone $sys->{std} changed displayname ('$sys->{display}' from '$file->{display}')!\n"; } last; } } unless ($match) { push @add, $sys; } } if (@add) { print "\n\nOther than that, add the following timezones:\n"; for my $z (@add) { print "\t{\n\t\t/* $z->{display} */\n\t\t\"$z->{std}\", \"$z->{dlt}\",\n\t\t\"FIXME\"\n\t},\n"; } } sub clean_displayname { my $dn = shift; $dn =~ s/\*//gs; $dn =~ s/\s+/ /gs; $dn =~ s/^\s+//gs; $dn =~ s/\s+$//gs; return $dn; }