Dead
[official-gcc.git] / gomp-20050608-branch / libjava / classpath / scripts / timezones.pl
blob142ea4b758215c7126f27955d3626a099264eb47
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/.
8 $TIMEZONEDIR = "tzdata";
9 @TIMEZONEFILES = ("africa", "antarctica", "asia", "australasia",
10 "europe", "northamerica", "pacificnew", "southamerica",
11 "../tzabbrevs");
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 = ("-" => "-");
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" ] ]);
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;
42 return $seconds * 1000;
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;
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;
64 return $millis;
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;
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;
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]";
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]";
130 } else {
131 die "Unknown day $day";
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" );
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--;
158 while ($time > 24*3600*1000) {
159 $time -= 24*3600*1000;
160 $dayoffset++;
162 $day = parseDay($dayoffset, $monthnr, $rule->[1]);
163 return [ $monthjavanames[$monthnr-1], $day, $time ];
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]));
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;
190 return "";
193 sub makePretty($) {
194 my ($offset) = @_;
195 if (($offset % 3600) == 0) {
196 $offset /= 3600;
197 return "$offset * 3600";
198 } else {
199 return "$offset";
203 sub tzcompare($$) {
204 my ($a, $b) = @_;
205 if (($a =~ /\//) != ($b =~ /\//)) {
206 return ($a =~ /\//) ? 1 : -1;
207 } else {
208 return $a cmp $b;
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]);
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;
254 if ($found) {
255 if ($tz->[0] eq $entries[1]) {
256 $tz->[0] = $newaliases[0];
258 $tz->[3] = \@newaliases;
259 last;
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;
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: $_";
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";
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;
313 push @{$alias->[3]}, $timezonename;
314 } else {
315 push @timezones, [ $timezonename, $rawoffset, $rule,
316 [ $timezonename ] ];
318 $in_time_zone = 0;
322 close INPUT;
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\");
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);
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);
359 for (@aliases) {
360 print <<EOF
361 timezones0.put(\"$_\", tz);