[contrib/timezone-gen] Fix timezone gen (#2215)
* [contrib/timezone-gen] Move timezone-gen.pl to own folder * [contrib/timezone-gen] Add fixTzstr * [contrib/timezone-gen] Add tests and zone data getter - tests.pl can be used to verify that the generated timezone conf will produce the correct datetimes by testing them against what the system's `date` says - build-zonedata.pl will download the latest tzdb data and build the posix timezone data files. It only builds what is needed rather than adding extraneous "right/" and "posix/" timezones. FreeSWITCH doesn't seem to be able to use the "right/" timezone files. - data/ is where the various files needed to generate the timezones gets stored
This commit is contained in:
parent
0df47beebe
commit
07f192ca03
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
my $remote_version = `wget --quiet https://data.iana.org/time-zones/tzdb/version --output-document -` =~ s/\n//r;
|
||||||
|
my $local_version;
|
||||||
|
|
||||||
|
if ( open my $in, "<data/version" ) {
|
||||||
|
$local_version = do { local $/; <$in> };
|
||||||
|
close $in;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $up_to_date = defined($local_version) && $local_version eq $remote_version;
|
||||||
|
|
||||||
|
if ( ! $up_to_date ) {
|
||||||
|
open my $out, ">data/version";
|
||||||
|
print $out $remote_version;
|
||||||
|
close $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
$local_version = $remote_version;
|
||||||
|
|
||||||
|
`wget --quiet --timestamping --directory-prefix=data https://data.iana.org/time-zones/tzdb-latest.tar.lz`;
|
||||||
|
`tar --extract --file=data/tzdb-latest.tar.lz --directory=data`;
|
||||||
|
`make DESTDIR=../ TZDIR=zones-$local_version --directory=data/tzdb-$local_version posix_only`;
|
||||||
|
|
||||||
|
print("Yay. Now you can run\n ./timezone-gen.pl --base=data/zones-$local_version --output=timezones-$local_version.conf.xml")
|
|
@ -0,0 +1,4 @@
|
||||||
|
tzdb-*
|
||||||
|
zones-*
|
||||||
|
version
|
||||||
|
tzdb-latest.tar.lz
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
sub fixTzstr {
|
||||||
|
# switch_time.c expects POSIX-style TZ rule, but it won't process quoted TZ
|
||||||
|
# rules that look like this: <-04>4 or <-04>4<-03>
|
||||||
|
# See https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
|
||||||
|
|
||||||
|
# Instead it defaults to UTC for these values. Here we process the quoted
|
||||||
|
# values and convert them into letters. If the zone name has "GMT", we use
|
||||||
|
# that as the replacement prefix, otherwise a default "STD" is used. Zones
|
||||||
|
# that have a quoted suffix have their suffix replaced with "DST".
|
||||||
|
|
||||||
|
my ($tzstr, $name) = @_;
|
||||||
|
|
||||||
|
if ( $tzstr =~ /(<(?<std>[^>]+)>)([^<]+)(?<dst><.+>)?(?<rest>.+)?/ ) {
|
||||||
|
my ($tzprefix, $tzsuffix, $tzrest, $offset, $offsetprefix) = ("") x 5;
|
||||||
|
|
||||||
|
if ( defined($+{std}) ) {
|
||||||
|
my $std = $+{std};
|
||||||
|
|
||||||
|
if ( lc($name) =~ m/gmt/) {
|
||||||
|
$tzprefix = "GMT";
|
||||||
|
} else {
|
||||||
|
$tzprefix = "STD";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $std =~ m/\+/ ) {
|
||||||
|
$offset = sprintf "%d", $std =~ s/\+//r;
|
||||||
|
$offsetprefix = "-";
|
||||||
|
} else {
|
||||||
|
$offset = sprintf "%d", $std =~ s/\-//r;
|
||||||
|
}
|
||||||
|
|
||||||
|
my @chars = split(//, $offset);
|
||||||
|
if ( @chars > 2 ) {
|
||||||
|
my $hours = $chars[-3];
|
||||||
|
if ( defined( $chars[-4] ) ) {
|
||||||
|
$hours = $chars[-4].$hours;
|
||||||
|
}
|
||||||
|
|
||||||
|
$offset = $hours.":".$chars[-2].$chars[-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$offset = $offsetprefix.$offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined($+{dst}) ) {
|
||||||
|
$tzsuffix = "DST";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined($+{rest}) ) {
|
||||||
|
$tzrest = $+{rest};
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tzprefix.$offset.$tzsuffix.$tzrest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tzstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
|
@ -0,0 +1,65 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
=pod
|
||||||
|
Tests to verify that the provided modifications to timezone formats produce
|
||||||
|
the correct results. The first set of tests verify the fixTzstr subroutine
|
||||||
|
converts the quoted values to something that won't make FreeSWITCH default to
|
||||||
|
UTC.
|
||||||
|
|
||||||
|
The second set of tests confirms that those timezone changes actually produce
|
||||||
|
the correct timestamps.
|
||||||
|
|
||||||
|
Make sure FreeSWITCH already has already loaded the timezones.conf.xml that you
|
||||||
|
want to test.
|
||||||
|
|
||||||
|
To run tests:
|
||||||
|
|
||||||
|
TIMEZONES_XML_PATH=path/to/timezones.conf.xml prove tests.pl
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Test::More;
|
||||||
|
use ESL;
|
||||||
|
use XML::LibXML::Reader;
|
||||||
|
|
||||||
|
require "./fix-tzstr.pl";
|
||||||
|
|
||||||
|
use Env qw(TIMEZONES_XML_PATH);
|
||||||
|
die "The TIMEZONES_XML_PATH environment variable must be set to test timezones." unless ( defined($TIMEZONES_XML_PATH) );
|
||||||
|
|
||||||
|
ok( fixTzstr("<-02>2", "doesntmatterhere") eq "STD2" );
|
||||||
|
ok( fixTzstr("EST5EDT,M3.2.0,M11.1.0", "US/Eastern") eq "EST5EDT,M3.2.0,M11.1.0" );
|
||||||
|
ok( fixTzstr("<+11>-11", "GMT-11") eq "GMT-11" );
|
||||||
|
ok( fixTzstr("<-02>2<-01>,M3.5.0/-1,M10.5.0/0", "America/Godthab") eq "STD2DST,M3.5.0/-1,M10.5.0/0" );
|
||||||
|
|
||||||
|
my $test_count = 4;
|
||||||
|
|
||||||
|
my $tz_fmt = "%Y-%m-%d %H:%M:%S";
|
||||||
|
my $c = new ESL::ESLconnection("127.0.0.1", "8021", "ClueCon");
|
||||||
|
$c->api("reloadxml")->getBody();
|
||||||
|
my $epoch = $c->api("strepoch")->getBody();
|
||||||
|
run_tests($epoch);
|
||||||
|
run_tests("1699613236"); # testing DST, add more epochs as needed
|
||||||
|
|
||||||
|
sub run_tests {
|
||||||
|
my $epoch = shift;
|
||||||
|
my $reader = XML::LibXML::Reader->new(location => $TIMEZONES_XML_PATH);
|
||||||
|
while ($reader->read) {
|
||||||
|
my $tag = $reader;
|
||||||
|
if ( $tag->name eq "zone" && $tag->hasAttributes() ) {
|
||||||
|
my $zn = $tag->getAttribute("name");
|
||||||
|
|
||||||
|
my $cmd = `TZ='$zn' date +'$tz_fmt' --date='\@$epoch'`;
|
||||||
|
my $sys_time = $cmd =~ s/\n//r;
|
||||||
|
my $fs_time = $c->api("strftime_tz $zn $epoch|$tz_fmt")->getBody();
|
||||||
|
|
||||||
|
ok ( $sys_time eq $fs_time, $zn ) or diag(
|
||||||
|
" (sys) $sys_time\t(fs) $fs_time"
|
||||||
|
);
|
||||||
|
|
||||||
|
$test_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done_testing($test_count);
|
|
@ -1,10 +1,12 @@
|
||||||
#!/usr/bin/perl
|
#!/usr/bin/perl
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
use warnings;
|
||||||
use Getopt::Long;
|
use Getopt::Long;
|
||||||
use XML::Entities;
|
use XML::Entities;
|
||||||
use HTML::Entities;
|
use HTML::Entities;
|
||||||
|
|
||||||
|
require "./fix-tzstr.pl";
|
||||||
|
|
||||||
my $base = "/usr/share/zoneinfo";
|
my $base = "/usr/share/zoneinfo";
|
||||||
my $output = "timezones.conf.xml";
|
my $output = "timezones.conf.xml";
|
||||||
|
@ -18,7 +20,7 @@ my $res = GetOptions(
|
||||||
"base=s" => \$base,
|
"base=s" => \$base,
|
||||||
"debug+" => \$debug,
|
"debug+" => \$debug,
|
||||||
"help" => \$help,
|
"help" => \$help,
|
||||||
"output" => \$output
|
"output=s" => \$output
|
||||||
);
|
);
|
||||||
if ( !$res || $help ) {
|
if ( !$res || $help ) {
|
||||||
print "$0 [--base=/usr/share/zoneinfo] [--output=timezones.conf.xml] [--debug] [--help]\n";
|
print "$0 [--base=/usr/share/zoneinfo] [--output=timezones.conf.xml] [--debug] [--help]\n";
|
||||||
|
@ -64,7 +66,9 @@ foreach my $name ( sort( keys(%name_to_file) ) ) {
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
$zones{$name} = pop(@strings);
|
my $tzstr = fixTzstr( pop(@strings), $name );
|
||||||
|
|
||||||
|
$zones{$name} = $tzstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
open( my $out, ">$output" );
|
open( my $out, ">$output" );
|
||||||
|
@ -83,7 +87,7 @@ foreach my $zone ( sort( keys(%zones) ) ) {
|
||||||
}
|
}
|
||||||
$lastprefix = $newprefix;
|
$lastprefix = $newprefix;
|
||||||
|
|
||||||
print $out "\t<zone name=\"$zone\" value=\"$str\" />\n";
|
print $out " " x 8, "<zone name=\"$zone\" value=\"$str\" />\n";
|
||||||
}
|
}
|
||||||
print $out " " x 4, "</timezones>\n";
|
print $out " " x 4, "</timezones>\n";
|
||||||
print $out "</configuration>\n";
|
print $out "</configuration>\n";
|
Loading…
Reference in New Issue