summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorJochen Hoenicke <jochen@gnu.org>1999-08-26 10:29:17 +0000
committerJochen Hoenicke <jochen@gnu.org>1999-08-26 10:29:17 +0000
commit7d70ddec802494ab1ded5b78b3151b2334a96444 (patch)
treef4865da92db41f4b682a9cdb0b96e5886a3a5e77 /scripts
parent940cbf7979407e716a727f37f738b3aa5b86ec09 (diff)
downloadclasspath-7d70ddec802494ab1ded5b78b3151b2334a96444.tar.gz
added a script to transform the timezone sources (as used by glibc) to
commands that fill the hashtable in java/util/TimeZone.java
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/timezones.pl338
1 files changed, 338 insertions, 0 deletions
diff --git a/scripts/timezones.pl b/scripts/timezones.pl
new file mode 100755
index 000000000..aa63fbdd2
--- /dev/null
+++ b/scripts/timezones.pl
@@ -0,0 +1,338 @@
+#!/usr/bin/perl -w
+# Create the timezone tables for java/util/TimeZone from the
+# standard timezone sources by Arthur David Olson (as used by glibc)
+#
+# This needs the files from the package tzdata1999c which may be found
+# at ftp://elsie.nic.nih.gov/pub/.
+
+$TIMEZONEDIR = "/usr/src/scratch/glibc-2.1.1/timezone";
+@TIMEZONEFILES = ("africa", "antarctica", "asia", "australasia",
+ "europe", "northamerica", "pacificnew", "southamerica");
+
+# rules hash table:
+# key is a rule name
+# value is either "-" (no daylight savings) or a list of three elements:
+# $value[0] = end savings rule (list containing MONTH, DAY and TIME)
+# $value[1] = start savings rule (ditto)
+# $value[2] = daylight offset in milliseconds
+my %rules = ("-" => "-");
+
+# timezones list, list of pairs:
+# $timezones[$i][0] is a timezone name
+# $timezones[$i][1] = raw offset in milliseconds
+# $timezones[$i][2] = rule in the same format as the value of
+# the rules table, but TIME in milliseconds
+# $timezones[$i][3] = list of timezone names with this rule (aliases)
+my @timezones = ( [ "GMT", 0, "-", [ "GMT", "UTC" ] ]);
+
+
+# parse the offset of form +/-hh:mm:ss (:ss is optional) and return it
+# in milliseconds against UTC
+sub parseOffset($) {
+ my $offset = $_[0];
+ $offset =~ /^([+-]?\d+)(:(\d+)(:(\d+))?)?$/
+ or die "Can't parse offset $offset";
+ my $seconds = $1 * 3600;
+ $seconds += $3 * 60 if ($2);
+ $seconds += $5 if ($2 && $4);
+ return $seconds * 1000;
+}
+
+# parse the time of form +/-hh:mm:ss[swguz] (:ss is optional) and return it
+# in milliseconds since midnight in local standard time
+ my $timezonename;
+sub parseTime($$$) {
+ my ($rawoffset, $stdoffset, $time) = @_;
+ $time =~ /^([+-]?\d+):(\d+)(:(\d+))?([swguz]?)$/
+ or die "Can't parse time $time";
+ my ($hour, $min) = ($1, $2);
+ my $sec = ($3) ? $4 : 0;
+ my $millis = ((($hour * 60) + $min) * 60 + $sec) * 1000;
+ if ($5 =~ /[guz]/) {
+ $millis += $rawoffset;
+ } elsif ($5 =~ /w/) {
+ print STDERR "$timezonename not in standard time\n" if $stdoffset;
+ $millis -= $stdoffset;
+ }
+ return $millis;
+}
+
+my %monthnames =
+ ( "Jan" => "1",
+ "Feb" => "2",
+ "Mar" => "3",
+ "Apr" => "4",
+ "May" => "5",
+ "Jun" => "6",
+ "Jul" => "7",
+ "Aug" => "8",
+ "Sep" => "9",
+ "Oct" => "10",
+ "Nov" => "11",
+ "Dec" => "12" );
+sub parseMonth($) {
+ my $month = $monthnames{"$_[0]"} or die "Unknown month $_[0]";
+ return $month;
+}
+
+my %weekdaynames =
+ ( "Sun" => "7",
+ "Mon" => "1",
+ "Tue" => "2",
+ "Wed" => "3",
+ "Thu" => "4",
+ "Fri" => "5",
+ "Sat" => "6" );
+sub parseWeekday($) {
+ my $weekday = $weekdaynames{"$_[0]"} or die "Unknown weekday $_[0]";
+ return $weekday;
+}
+
+my @weekdayjavanames =
+ ( "Calendar.SUNDAY",
+ "Calendar.MONDAY",
+ "Calendar.TUESDAY",
+ "Calendar.WEDNESDAY",
+ "Calendar.THURSDAY",
+ "Calendar.FRIDAY",
+ "Calendar.SATURDAY" );
+my @daysInMonths = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
+sub parseDay($$$) {
+ my ($dayoffset, $month, $day) = @_;
+ if ($day =~ /^\d+$/) {
+ return "$day, 0";
+ } elsif ($day =~ /^last([A-Z][a-z][a-z])$/) {
+ my $weekday = ( parseWeekday($1) + $dayoffset + 7 ) % 7;
+ if ($dayoffset) {
+ my $day = $daysInMonths[$month] + $dayoffset;
+ warn "Can only approximate $day with dayoffset in $file"
+ if ($month == 2);
+ return "$day, -$weekdayjavanames[$weekday]";
+ } else {
+ return "-1, $weekdayjavanames[$weekday]";
+ }
+ } elsif ($day =~ /^([A-Z][a-z][a-z])>=(\d+)$/) {
+ my $start = $2 + $dayoffset;
+ my $weekday = ( parseWeekday($1) + $dayoffset + 7 ) % 7;
+ if (($start % 7) == 1) {
+ $start = ($start + 6) / 7;
+ return "$start, $weekdayjavanames[$weekday]";
+ } else {
+ return "$start, -$weekdayjavanames[$weekday]";
+ }
+ } else {
+ die "Unknown day $day";
+ }
+}
+
+my @monthjavanames =
+ ( "Calendar.JANUARY",
+ "Calendar.FEBRUARY",
+ "Calendar.MARCH",
+ "Calendar.APRIL",
+ "Calendar.MAY",
+ "Calendar.JUNE",
+ "Calendar.JULY",
+ "Calendar.AUGUST",
+ "Calendar.SEPTEMBER",
+ "Calendar.OCTOBER",
+ "Calendar.NOVEMBER",
+ "Calendar.DECEMBER" );
+
+sub parseRule($$$) {
+ my ($rawoffset, $stdoffset, $rule) = @_;
+ my $monthnr = parseMonth($rule->[0]);
+ my $time = parseTime($rawoffset, $stdoffset, $rule->[2]);
+ my $dayoffset = 0;
+ while ($time < 0) {
+ $time += 24*3600*1000;
+ $dayoffset--;
+ }
+ while ($time >= 24*3600*1000) {
+ $time -= 24*3600*1000;
+ $dayoffset++;
+ }
+ $day = parseDay($dayoffset, $monthnr, $rule->[1]);
+ return [ $monthjavanames[$monthnr-1], $day, $time ];
+}
+
+
+sub ruleEquals($$) {
+ my ($rule1, $rule2) = @_;
+ # check month names
+ return (($rule1->[0] eq $rule2->[0])
+ && ($rule1->[1] eq $rule2->[1])
+ && ($rule1->[2] == $rule2->[2]));
+}
+
+sub findAlias($$) {
+ my ($rawoffset, $rule) = @_;
+ foreach $tz (@timezones) {
+ my ($key, $tzoffset, $tzrule, $aliaslist) = @{$tz};
+ next if ($tzoffset != $rawoffset);
+ if ($rule eq "-") {
+ return $tz if ($tzrule eq "-");
+ } elsif ($tzrule ne "-") {
+ next if $rule->[2] != $tzrule->[2];
+ if (ruleEquals($rule->[0], $tzrule->[0])
+ && ruleEquals($rule->[1], $tzrule->[1])) {
+ return $tz;
+ }
+ }
+ }
+ return "";
+}
+
+sub makePretty($) {
+ my ($offset) = @_;
+ if (($offset % 3600) == 0) {
+ $offset /= 3600;
+ return "$offset * 3600";
+ } else {
+ return "$offset";
+ }
+}
+
+foreach $file (@TIMEZONEFILES) {
+# print STDERR "$file\n";
+ open INPUT, "$TIMEZONEDIR/$file" or die "Can't open $TIMEZONEDIR/$file";
+ my $in_time_zone = 0;
+ while (<INPUT>) {
+ $_ = $1 if /^([^\#]*)\#/;
+ next if /^\s*$/;
+ my @entries = split;
+# $, = ","; print "'$_' -> [",@entries,"]\n";
+ if (!$in_time_zone) {
+ if ($entries[0] eq "Rule") {
+ # check if rule still applies
+ # column 3 is TO entry.
+ if ($entries[3] eq "max") {
+ my $rulename = $entries[1];
+ my $month = $entries[5];
+ my $day = $entries[6];
+ my $time = $entries[7];
+ if ($entries[8] eq "0") {
+ # This is the end time rule
+ $rules{"$rulename"}[0] = [ $month, $day, $time ];
+ } else {
+ # This is the start time rule
+ $rules{"$rulename"}[1] = [ $month, $day, $time ];
+ $rules{"$rulename"}[2] = parseOffset($entries[8]);
+ }
+ }
+ } elsif ($entries[0] eq "Zone") {
+ $in_time_zone = 1;
+ shift @entries;
+ $timezonename = shift @entries;
+ } elsif ($entries[0] eq "Link") {
+ my $alias = 0;
+ foreach $tz (@timezones) {
+ foreach $tzname (@{$tz->[3]}) {
+ if ($tzname eq $entries[1]) {
+ $alias = $tz;
+ last;
+ }
+ }
+ }
+
+ die "Unknown link $_" if ! $alias;
+
+ if (($entries[1] =~ /\//)
+ && ($entries[2] !~ /\//)) {
+ # alias is of Country/City form, linkname not
+ # make timezonename the real zone and add an alias
+ # the otherway round.
+ $alias->[0] = $entries[2];
+ }
+ die "@entries" if $entries[1] =~ /^\d+$/;
+ push @{$alias->[3]}, $entries[2];
+ } else {
+ die "Unknown command: $_";
+ }
+ }
+ if ($in_time_zone) {
+ die "early end of Zone: $_" if ($entries[0] =~ /^[A-Za-z]+/);
+ if (@entries <= 3) {
+# print "found ZONE $timezonename $entries[0] $entries[1] $entries[2]\n";
+ # This is the last line and the only we look at.
+ # other lines are for historic time zones.
+ my $rawoffset = parseOffset($entries[0]);
+ my $rule = $rules{"$entries[1]"} || "-";
+ if ($rule ne "-") {
+ if (!defined($rule->[2])) {
+ $rule = "-";
+ } else {
+ # now we can parse the time since we know raw offset.
+ my $savings = $rule->[2];
+ my $endrule = parseRule($rawoffset, $savings,
+ $rule->[0]);
+ my $startrule = parseRule($rawoffset, $savings,
+ $rule->[1]);
+ $rule = [ $endrule, $startrule, $savings ];
+# print "start",@{$rule->[1]}, "end", @{$rule->[0]},
+# "offset", $rule->[2],"\n";
+ }
+ }
+ my $alias = findAlias($rawoffset, $rule);
+ if ($alias) {
+ if (($alias->[0] =~ /\//)
+ && ($timezonename !~ /\//)) {
+ # alias is of Country/City form, timezonename not
+ # make timezonename the real zone name
+ $alias->[0] = $timezonename;
+ }
+ push @{$alias->[3]}, $timezonename;
+ } else {
+ push @timezones, [ $timezonename, $rawoffset, $rule,
+ [ $timezonename ] ];
+ }
+ $in_time_zone = 0;
+ }
+ }
+ }
+ close INPUT;
+}
+
+@timezones = sort { if ($a->[1] != $b->[1]) { $a->[1] <=> $b->[1] }
+ else { $a->[0] cmp $b->[0] } } @timezones;
+for (@timezones) {
+ my ($name, $rawoffset, $rule, $aliaslist) = @{$_};
+ $rawoffset = makePretty($rawoffset);
+ if ($rule eq "-") {
+ print <<EOF
+ tz = new SimpleTimeZone($rawoffset, \"$name\");
+EOF
+ } else {
+ my ($endmonth, $endday, $endtime) = @{$rule->[0]};
+ my ($startmonth, $startday, $starttime) = @{$rule->[1]};
+ $endtime = makePretty($endtime);
+ $starttime = makePretty($starttime);
+ my $savings = $rule->[2];
+ if ($savings == 3600 * 1000) {
+ print <<EOF
+ tz = new SimpleTimeZone
+ ($rawoffset, \"$name\",
+ $startmonth, $startday, $starttime,
+ $endmonth, $endday, $endtime);
+EOF
+ } else {
+ $savings = makePretty($savings);
+ print <<EOF
+ tz = new SimpleTimeZone
+ ($rawoffset, \"$name\",
+ $startmonth, $startday, $starttime,
+ $endmonth, $endday, $endtime, $savings);
+EOF
+ }
+ }
+ my @aliases = sort { return ($a eq $name) ? -1
+ : ($b eq $name) ? 1
+ : $a cmp $b } @{$aliaslist};
+ for (@aliases) {
+ print <<EOF
+ timezones.put(\"$_\", tz);
+EOF
+ }
+}
+
+