OSDN Git Service

Imported Classpath 0.18.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / scripts / timezones.pl
1 #!/usr/bin/perl -w
2 # Create the timezone tables  for java/util/TimeZone from the 
3 # standard timezone sources by Arthur David Olson (as used by glibc)
4
5 # This needs the files from the package tzdata2000h which may be found
6 # at ftp://ftp.cs.mu.oz.au/pub/.
7
8 $TIMEZONEDIR = "tzdata";
9 @TIMEZONEFILES = ("africa", "antarctica", "asia", "australasia",
10                   "europe", "northamerica", "pacificnew", "southamerica",
11                   "../tzabbrevs");
12
13 # rules hash table:
14 #  key is a rule name
15 #  value is either "-" (no daylight savings) or a list of three elements:
16 #     $value[0] = end savings rule  (list containing MONTH, DAY and TIME)
17 #     $value[1] = start savings rule (ditto)
18 #     $value[2] = daylight offset in milliseconds
19 my %rules = ("-" => "-");
20
21 # timezones list, list of pairs:
22 #  $timezones[$i][0] is a timezone name
23 #  $timezones[$i][1] = raw offset in milliseconds
24 #  $timezones[$i][2] = rule in the same format as the value of 
25 #                      the rules table, but TIME in milliseconds
26 #  $timezones[$i][3] = list of timezone names with this rule (aliases)
27 my @timezones = ( [ "GMT", 0, "-", [ "GMT", "UTC" ] ]);
28
29
30 # parse the offset of form +/-hh:mm:ss  (:ss is optional) and return it
31 # in milliseconds against UTC
32 sub parseOffset($) {
33     my $offset = $_[0];
34     $offset =~ /^([+-]?)(\d+)(:(\d+)(:(\d+))?)?$/
35         or die "Can't parse offset $offset";
36     my $seconds = $2 * 3600;
37     $seconds += $4 * 60 if ($3);
38     $seconds += $6 if ($3 && $5);
39     if ($1 eq "-") {
40         $seconds = - $seconds;
41     }
42     return $seconds * 1000;
43 }
44
45 # parse the time of form +/-hh:mm:ss[swguz]  (:ss is optional) and return it
46 # in milliseconds since midnight in local wall time
47     my $timezonename;
48 sub parseTime($$$) {
49     my ($rawoffset, $stdoffset, $time) = @_;
50     $time =~ /^([+-]?)(\d+):(\d+)(:(\d+))?([swguz]?)$/
51         or die "Can't parse time $time";
52     my ($hour, $min) = ($2, $3);
53     my $sec = ($4) ? $5 : 0;
54     my $millis =  ((($hour * 60) + $min) * 60 + $sec) * 1000;
55     if ($1 eq "-") {
56       $millis = -$millis;
57     }
58     # Normally millis is in wall time, adjust for utc and standard time.
59     if ($6 =~ /[guz]/) {
60         $millis += $rawoffset + $stdoffset;
61     } elsif ($6 =~ /s/) {
62         $millis += $stdoffset;
63     }
64     return $millis;
65 }
66
67 my %monthnames = 
68     ( "Jan" => "1",
69       "Feb" => "2",
70       "Mar" => "3",
71       "Apr" => "4",
72       "May" => "5",
73       "Jun" => "6",
74       "Jul" => "7",
75       "Aug" => "8",
76       "Sep" => "9",
77       "Oct" => "10",
78       "Nov" => "11",
79       "Dec" => "12" );
80 sub parseMonth($) {
81     my $month = $monthnames{"$_[0]"} or die "Unknown month $_[0]";
82     return $month;
83 }
84
85 my %weekdaynames = 
86     ( "Sun" => "7",
87       "Mon" => "1",
88       "Tue" => "2",
89       "Wed" => "3",
90       "Thu" => "4",
91       "Fri" => "5",
92       "Sat" => "6" );
93 sub parseWeekday($) {
94     my $weekday = $weekdaynames{"$_[0]"} or die "Unknown weekday $_[0]";
95     return $weekday;
96 }
97
98 my @weekdayjavanames = 
99     ( "Calendar.SUNDAY",
100       "Calendar.MONDAY",
101       "Calendar.TUESDAY",
102       "Calendar.WEDNESDAY",
103       "Calendar.THURSDAY",
104       "Calendar.FRIDAY",
105       "Calendar.SATURDAY" );
106 my @daysInMonths = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
107 sub parseDay($$$) {
108     my ($dayoffset, $month, $day) = @_;
109     if ($day =~ /^\d+$/) {
110         return "$day, 0";
111     } elsif ($day =~ /^last([A-Z][a-z][a-z])$/) {
112         my $weekday = ( parseWeekday($1) + $dayoffset + 7 ) % 7;
113         if ($dayoffset) {
114             my $day = $daysInMonths[$month - 1] + $dayoffset;
115             warn "Can only approximate $day with dayoffset in $file" 
116                 if ($month == 2);
117             return "$day, -$weekdayjavanames[$weekday]";
118         } else {
119             return "-1, $weekdayjavanames[$weekday]";
120         }
121     } elsif ($day =~ /^([A-Z][a-z][a-z])>=(\d+)$/) {
122         my $start = $2 + $dayoffset;
123         my $weekday = ( parseWeekday($1) + $dayoffset + 7 ) % 7;
124         if (($start % 7) == 1) {
125             $start = ($start + 6) / 7;
126             return "$start, $weekdayjavanames[$weekday]";
127         } else {
128             return "$start, -$weekdayjavanames[$weekday]";
129         }
130     } else {
131         die "Unknown day $day";
132     }
133 }
134
135 my @monthjavanames = 
136     ( "Calendar.JANUARY",
137       "Calendar.FEBRUARY",
138       "Calendar.MARCH",
139       "Calendar.APRIL",
140       "Calendar.MAY",
141       "Calendar.JUNE",
142       "Calendar.JULY",
143       "Calendar.AUGUST",
144       "Calendar.SEPTEMBER",
145       "Calendar.OCTOBER",
146       "Calendar.NOVEMBER",
147       "Calendar.DECEMBER" );
148
149 sub parseRule($$$) {
150     my ($rawoffset, $stdoffset, $rule) = @_;
151     my $monthnr = parseMonth($rule->[0]);
152     my $time  = parseTime($rawoffset, $stdoffset, $rule->[2]);
153     my $dayoffset = 0;
154     while ($time < 0) {
155         $time += 24*3600*1000;
156         $dayoffset--;
157     }
158     while ($time > 24*3600*1000) {
159         $time -= 24*3600*1000;
160         $dayoffset++;
161     }
162     $day = parseDay($dayoffset, $monthnr, $rule->[1]);
163     return [ $monthjavanames[$monthnr-1], $day, $time ];
164 }
165
166
167 sub ruleEquals($$) {
168     my ($rule1, $rule2) = @_;
169     # check month names
170     return (($rule1->[0] eq $rule2->[0])
171             && ($rule1->[1] eq $rule2->[1])
172             && ($rule1->[2] == $rule2->[2]));
173 }
174
175 sub findAlias($$) {
176     my ($rawoffset, $rule) = @_;
177     foreach $tz (@timezones) {
178         my ($key, $tzoffset, $tzrule, $aliaslist) = @{$tz};
179         next if ($tzoffset != $rawoffset);
180         if ($rule eq "-") {
181             return $tz if ($tzrule eq "-");
182         } elsif ($tzrule ne "-") {
183             next if $rule->[2] != $tzrule->[2];
184             if (ruleEquals($rule->[0], $tzrule->[0])
185                 && ruleEquals($rule->[1], $tzrule->[1])) {
186                 return $tz;
187             }
188         }
189     }
190     return "";
191 }
192
193 sub makePretty($) {
194     my ($offset) = @_;
195     if (($offset % 3600) == 0) {
196         $offset /= 3600;
197         return "$offset * 3600";
198     } else {
199         return "$offset";
200     }
201 }
202
203 sub tzcompare($$) {
204     my ($a, $b) = @_;
205     if (($a =~ /\//) != ($b =~ /\//)) {
206       return ($a =~ /\//) ? 1 : -1;
207     } else {
208       return $a cmp $b;
209     }
210 }
211
212 foreach $file (@TIMEZONEFILES) {
213 #    print STDERR "$file\n";
214     open INPUT, "$TIMEZONEDIR/$file" or die "Can't open $TIMEZONEDIR/$file";
215     my $in_time_zone = 0;
216     while (<INPUT>) {
217         $_ = $1 if /^([^\#]*)\#/;
218         next if /^\s*$/;
219         my @entries = split;
220 #       $, = ","; print "'$_' -> [",@entries,"]\n";
221         if (!$in_time_zone) {
222             if ($entries[0] eq "Rule") {
223                 # check if rule still applies
224                 # column 3 is TO entry.
225                 if ($entries[3] eq "max") {
226                     my $rulename = $entries[1];
227                     my $month = $entries[5];
228                     my $day  = $entries[6];
229                     my $time = $entries[7];
230                     if ($entries[8] eq "0") {
231                         # This is the end time rule
232                         $rules{"$rulename"}[0] = [ $month, $day, $time ];
233                     } else {
234                         # This is the start time rule
235                         $rules{"$rulename"}[1] = [ $month, $day, $time ];
236                         $rules{"$rulename"}[2] = parseOffset($entries[8]);
237                     }
238                 }
239             } elsif ($entries[0] eq "Zone") {
240                 $in_time_zone = 1;
241                 shift @entries;
242                 $timezonename = shift @entries;
243             } elsif ($entries[0] eq "Remove") {
244                 my $found = 0;
245                 foreach $tz (@timezones) {
246                     my @newaliases;
247                     foreach $tzname (@{$tz->[3]}) {
248                         if ($tzname eq $entries[1]) {
249                             $found = 1;
250                         } else {
251                             push @newaliases, $tzname;
252                         }
253                     }
254                     if ($found) {
255                         if ($tz->[0] eq $entries[1]) {
256                           $tz->[0] = $newaliases[0];
257                         }
258                         $tz->[3] = \@newaliases;
259                         last;
260                     }
261                 }
262
263                 die "Unknown link $_" if ! $found;
264             } elsif ($entries[0] eq "Link") {
265                 my $alias = 0;
266                 foreach $tz (@timezones) {
267                     foreach $tzname (@{$tz->[3]}) {
268                         if ($tzname eq $entries[1]) {
269                             $alias = $tz;
270                             last;
271                         }
272                     }
273                 }
274
275                 die "Unknown link $_" if ! $alias;
276                 die "@entries" if $entries[1] =~ /^\d+$/;
277                 push @{$alias->[3]}, $entries[2];
278             } else {
279                 die "Unknown command: $_";
280             }
281         }
282         if ($in_time_zone) {
283             die "early end of Zone: $_" if ($entries[0] =~ /^[A-Za-z]+/);
284             if (@entries <= 3) {
285 #               print "found ZONE $timezonename $entries[0] $entries[1] $entries[2]\n";
286                 # This is the last line and the only we look at.
287                 # other lines are for historic time zones.
288                 my $rawoffset = parseOffset($entries[0]);
289                 my $rule = $rules{"$entries[1]"} || "-";
290                 if ($rule ne "-") {
291                     if (!defined($rule->[2])) {
292                         $rule = "-";
293                     } else {
294                         # now we can parse the time since we know raw offset.
295                         my $savings = $rule->[2];
296                         my $endrule = parseRule($rawoffset, $savings, 
297                                                 $rule->[0]);
298                         my $startrule = parseRule($rawoffset, $savings, 
299                                                   $rule->[1]);
300                         $rule = [ $endrule, $startrule, $savings ];
301 #                       print "start",@{$rule->[1]}, "end", @{$rule->[0]}, 
302 #                       "offset", $rule->[2],"\n";
303                     }
304                 }
305                 my $alias = findAlias($rawoffset, $rule);
306                 if ($alias) {
307                     if (($alias->[0] =~ /\//)
308                         && ($timezonename !~ /\//)) {
309                         # alias is of Country/City form, timezonename not
310                         # make timezonename the real zone name
311                         $alias->[0] = $timezonename;
312                     }
313                     push @{$alias->[3]}, $timezonename;
314                 } else {
315                     push @timezones, [ $timezonename, $rawoffset, $rule, 
316                                        [ $timezonename ] ];
317                 }
318                 $in_time_zone = 0;
319             }
320         }
321     }
322     close INPUT;
323 }
324
325 @timezones = sort { if ($a->[1] != $b->[1]) { $a->[1] <=> $b->[1] } 
326                     else { $a->[0] cmp $b->[0] } } @timezones;
327 for (@timezones) {
328     my ($name, $rawoffset, $rule, $aliaslist) = @{$_};
329     my @aliases = sort { tzcompare($a, $b); } @{$aliaslist};
330     $name = $aliases[0];
331     $rawoffset = makePretty($rawoffset);
332     if ($rule eq "-") {
333         print <<EOF
334         tz = new SimpleTimeZone($rawoffset, \"$name\");
335 EOF
336     } else {
337         my ($endmonth, $endday, $endtime) = @{$rule->[0]};
338         my ($startmonth, $startday, $starttime) = @{$rule->[1]};
339         $endtime = makePretty($endtime);
340         $starttime = makePretty($starttime);
341         my $savings = $rule->[2];
342         if ($savings == 3600 * 1000) {
343             print <<EOF
344         tz = new SimpleTimeZone
345           ($rawoffset, \"$name\",
346            $startmonth, $startday, $starttime,
347            $endmonth, $endday, $endtime);
348 EOF
349         } else {
350             $savings = makePretty($savings);
351             print <<EOF
352         tz = new SimpleTimeZone
353           ($rawoffset, \"$name\",
354           $startmonth, $startday, $starttime,
355           $endmonth, $endday, $endtime, $savings);
356 EOF
357         }
358     }
359     for (@aliases) {
360     print <<EOF
361         timezones0.put(\"$_\", tz);
362 EOF
363     }
364 }
365
366