1 /* java.util.TimeZone
2    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2012
3    Free Software Foundation, Inc.
4 
5 This file is part of GNU Classpath.
6 
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21 
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26 
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38 
39 
40 package java.util;
41 
42 import gnu.classpath.SystemProperties;
43 import gnu.java.lang.CPStringBuilder;
44 import gnu.java.util.ZoneInfo;
45 
46 import java.io.File;
47 import java.security.AccessController;
48 import java.security.PrivilegedAction;
49 import java.text.DateFormatSymbols;
50 
51 /**
52  * This class represents a time zone offset and handles daylight savings.
53  *
54  * You can get the default time zone with <code>getDefault</code>.
55  * This represents the time zone where program is running.
56  *
57  * Another way to create a time zone is <code>getTimeZone</code>, where
58  * you can give an identifier as parameter.  For instance, the identifier
59  * of the Central European Time zone is "CET".
60  *
61  * With the <code>getAvailableIDs</code> method, you can get all the
62  * supported time zone identifiers.
63  *
64  * @see Calendar
65  * @see SimpleTimeZone
66  * @author Jochen Hoenicke
67  */
68 public abstract class TimeZone implements java.io.Serializable, Cloneable
69 {
70 
71   /**
72    * Constant used to indicate that a short timezone abbreviation should
73    * be returned, such as "EST"
74    */
75   public static final int SHORT = 0;
76 
77   /**
78    * Constant used to indicate that a long timezone name should be
79    * returned, such as "Eastern Standard Time".
80    */
81   public static final int LONG = 1;
82 
83   /**
84    * The time zone identifier, e.g. PST.
85    */
86   private String ID;
87 
88   /**
89    * The default time zone, as returned by getDefault.
90    */
91   private static TimeZone defaultZone0;
92 
93   /**
94    * Tries to get the default TimeZone for this system if not already
95    * set.  It will call <code>getDefaultTimeZone(String)</code> with
96    * the result of <code>System.getProperty("user.timezone")</code>.
97    * If that fails it calls <code>VMTimeZone.getDefaultTimeZoneId()</code>.
98    * If that also fails GMT is returned.
99    */
defaultZone()100   private static synchronized TimeZone defaultZone()
101   {
102     /* Look up default timezone */
103     if (defaultZone0 == null)
104       {
105         defaultZone0 = AccessController.doPrivileged
106           (new PrivilegedAction<TimeZone>()
107             {
108               public TimeZone run()
109               {
110                 TimeZone zone = null;
111 
112                 // Prefer System property user.timezone.
113                 String tzid = System.getProperty("user.timezone");
114                 if (tzid != null && !tzid.equals(""))
115                   zone = getDefaultTimeZone(tzid);
116 
117                 // Try platfom specific way.
118                 if (zone == null)
119                   zone = VMTimeZone.getDefaultTimeZoneId();
120 
121                 // Fall back on GMT.
122                 if (zone == null)
123                   zone = getTimeZone ("GMT");
124 
125                 return zone;
126               }
127             });
128       }
129 
130     return defaultZone0;
131   }
132 
133   private static final long serialVersionUID = 3581463369166924961L;
134 
135   /**
136    * Flag whether zoneinfo data should be used,
137    * otherwise builtin timezone data will be provided.
138    */
139   private static String zoneinfo_dir;
140 
141   /**
142    * Cached copy of getAvailableIDs().
143    */
144   private static String[] availableIDs = null;
145 
146   /**
147    * JDK 1.1.x compatibility aliases.
148    */
149   private static HashMap<String,String> aliases0;
150 
151   /**
152    * HashMap for timezones by ID.
153    */
154   private static HashMap<String,TimeZone> timezones0;
155   /* initialize this static field lazily to overhead if
156    * it is not needed:
157    */
158   // Package-private to avoid a trampoline.
timezones()159   static HashMap<String,TimeZone> timezones()
160   {
161     if (timezones0 == null)
162       {
163         HashMap<String,TimeZone> timezones = new HashMap<String,TimeZone>();
164         timezones0 = timezones;
165 
166         zoneinfo_dir = SystemProperties.getProperty("gnu.java.util.zoneinfo.dir");
167         if (zoneinfo_dir != null && !new File(zoneinfo_dir).isDirectory())
168           zoneinfo_dir = null;
169 
170         if (zoneinfo_dir != null)
171           {
172             aliases0 = new HashMap<String,String>();
173 
174             // These deprecated aliases for JDK 1.1.x compatibility
175             // should take precedence over data files read from
176             // /usr/share/zoneinfo.
177             aliases0.put("ACT", "Australia/Darwin");
178             aliases0.put("AET", "Australia/Sydney");
179             aliases0.put("AGT", "America/Argentina/Buenos_Aires");
180             aliases0.put("ART", "Africa/Cairo");
181             aliases0.put("AST", "America/Juneau");
182             aliases0.put("BST", "Asia/Colombo");
183             aliases0.put("CAT", "Africa/Gaborone");
184             aliases0.put("CNT", "America/St_Johns");
185             aliases0.put("CST", "CST6CDT");
186             aliases0.put("CTT", "Asia/Brunei");
187             aliases0.put("EAT", "Indian/Comoro");
188             aliases0.put("ECT", "CET");
189             aliases0.put("EST", "EST5EDT");
190             aliases0.put("EST5", "EST5EDT");
191             aliases0.put("IET", "EST5EDT");
192             aliases0.put("IST", "Asia/Calcutta");
193             aliases0.put("JST", "Asia/Seoul");
194             aliases0.put("MIT", "Pacific/Niue");
195             aliases0.put("MST", "MST7MDT");
196             aliases0.put("MST7", "MST7MDT");
197             aliases0.put("NET", "Indian/Mauritius");
198             aliases0.put("NST", "Pacific/Auckland");
199             aliases0.put("PLT", "Indian/Kerguelen");
200             aliases0.put("PNT", "MST7MDT");
201             aliases0.put("PRT", "America/Anguilla");
202             aliases0.put("PST", "PST8PDT");
203             aliases0.put("SST", "Pacific/Ponape");
204             aliases0.put("VST", "Asia/Bangkok");
205             return timezones;
206           }
207 
208         TimeZone tz;
209         // Automatically generated by scripts/timezones.pl
210         // XXX - Should we read this data from a file?
211         tz = new SimpleTimeZone(-11000 * 3600, "MIT");
212         timezones0.put("MIT", tz);
213         timezones0.put("Pacific/Apia", tz);
214         timezones0.put("Pacific/Midway", tz);
215         timezones0.put("Pacific/Niue", tz);
216         timezones0.put("Pacific/Pago_Pago", tz);
217         tz = new SimpleTimeZone
218           (-10000 * 3600, "America/Adak",
219            Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
220            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
221         timezones0.put("America/Adak", tz);
222         tz = new SimpleTimeZone(-10000 * 3600, "HST");
223         timezones0.put("HST", tz);
224         timezones0.put("Pacific/Fakaofo", tz);
225         timezones0.put("Pacific/Honolulu", tz);
226         timezones0.put("Pacific/Johnston", tz);
227         timezones0.put("Pacific/Rarotonga", tz);
228         timezones0.put("Pacific/Tahiti", tz);
229         tz = new SimpleTimeZone(-9500 * 3600, "Pacific/Marquesas");
230         timezones0.put("Pacific/Marquesas", tz);
231         tz = new SimpleTimeZone
232           (-9000 * 3600, "AST",
233            Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
234            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
235         timezones0.put("AST", tz);
236         timezones0.put("America/Anchorage", tz);
237         timezones0.put("America/Juneau", tz);
238         timezones0.put("America/Nome", tz);
239         timezones0.put("America/Yakutat", tz);
240         tz = new SimpleTimeZone(-9000 * 3600, "Pacific/Gambier");
241         timezones0.put("Pacific/Gambier", tz);
242         tz = new SimpleTimeZone
243           (-8000 * 3600, "America/Tijuana",
244            Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
245            Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
246         timezones0.put("America/Tijuana", tz);
247         tz = new SimpleTimeZone
248           (-8000 * 3600, "PST",
249            Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
250            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
251         timezones0.put("PST", tz);
252         timezones0.put("PST8PDT", tz);
253         timezones0.put("America/Dawson", tz);
254         timezones0.put("America/Los_Angeles", tz);
255         timezones0.put("America/Vancouver", tz);
256         timezones0.put("America/Whitehorse", tz);
257         timezones0.put("US/Pacific-New", tz);
258         tz = new SimpleTimeZone(-8000 * 3600, "Pacific/Pitcairn");
259         timezones0.put("Pacific/Pitcairn", tz);
260         tz = new SimpleTimeZone
261           (-7000 * 3600, "America/Chihuahua",
262            Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
263            Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
264         timezones0.put("America/Chihuahua", tz);
265         timezones0.put("America/Mazatlan", tz);
266         tz = new SimpleTimeZone(-7000 * 3600, "MST7");
267         timezones0.put("MST7", tz);
268         timezones0.put("PNT", tz);
269         timezones0.put("America/Dawson_Creek", tz);
270         timezones0.put("America/Hermosillo", tz);
271         timezones0.put("America/Phoenix", tz);
272         tz = new SimpleTimeZone
273           (-7000 * 3600, "MST",
274            Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
275            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
276         timezones0.put("MST", tz);
277         timezones0.put("MST7MDT", tz);
278         timezones0.put("America/Boise", tz);
279         timezones0.put("America/Cambridge_Bay", tz);
280         timezones0.put("America/Denver", tz);
281         timezones0.put("America/Edmonton", tz);
282         timezones0.put("America/Inuvik", tz);
283         timezones0.put("America/Shiprock", tz);
284         timezones0.put("America/Yellowknife", tz);
285         tz = new SimpleTimeZone
286           (-6000 * 3600, "America/Cancun",
287            Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
288            Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
289         timezones0.put("America/Cancun", tz);
290         timezones0.put("America/Merida", tz);
291         timezones0.put("America/Mexico_City", tz);
292         timezones0.put("America/Monterrey", tz);
293         tz = new SimpleTimeZone(-6000 * 3600, "America/Belize");
294         timezones0.put("America/Belize", tz);
295         timezones0.put("America/Costa_Rica", tz);
296         timezones0.put("America/El_Salvador", tz);
297         timezones0.put("America/Guatemala", tz);
298         timezones0.put("America/Managua", tz);
299         timezones0.put("America/Regina", tz);
300         timezones0.put("America/Swift_Current", tz);
301         timezones0.put("America/Tegucigalpa", tz);
302         timezones0.put("Pacific/Galapagos", tz);
303         tz = new SimpleTimeZone
304           (-6000 * 3600, "CST",
305            Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
306            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
307         timezones0.put("CST", tz);
308         timezones0.put("CST6CDT", tz);
309         timezones0.put("America/Chicago", tz);
310         timezones0.put("America/Indiana/Knox", tz);
311         timezones0.put("America/Indiana/Petersburg", tz);
312         timezones0.put("America/Indiana/Vincennes", tz);
313         timezones0.put("America/Menominee", tz);
314         timezones0.put("America/North_Dakota/Center", tz);
315         timezones0.put("America/North_Dakota/New_Salem", tz);
316         timezones0.put("America/Rainy_River", tz);
317         timezones0.put("America/Rankin_Inlet", tz);
318         timezones0.put("America/Winnipeg", tz);
319         tz = new SimpleTimeZone
320           (-6000 * 3600, "Pacific/Easter",
321            Calendar.OCTOBER, 2, Calendar.SATURDAY, 22000 * 3600,
322            Calendar.MARCH, 2, Calendar.SATURDAY, 22000 * 3600);
323         timezones0.put("Pacific/Easter", tz);
324         tz = new SimpleTimeZone(-5000 * 3600, "EST5");
325         timezones0.put("EST5", tz);
326         timezones0.put("IET", tz);
327         timezones0.put("America/Atikokan", tz);
328         timezones0.put("America/Bogota", tz);
329         timezones0.put("America/Cayman", tz);
330         timezones0.put("America/Eirunepe", tz);
331         timezones0.put("America/Guayaquil", tz);
332         timezones0.put("America/Jamaica", tz);
333         timezones0.put("America/Lima", tz);
334         timezones0.put("America/Panama", tz);
335         timezones0.put("America/Rio_Branco", tz);
336         tz = new SimpleTimeZone
337           (-5000 * 3600, "America/Havana",
338            Calendar.APRIL, 1, Calendar.SUNDAY, 0 * 3600,
339            Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600);
340         timezones0.put("America/Havana", tz);
341         tz = new SimpleTimeZone
342           (-5000 * 3600, "America/Grand_Turk",
343            Calendar.APRIL, 1, Calendar.SUNDAY, 0 * 3600,
344            Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
345         timezones0.put("America/Grand_Turk", tz);
346         timezones0.put("America/Port-au-Prince", tz);
347         tz = new SimpleTimeZone
348           (-5000 * 3600, "EST",
349            Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
350            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
351         timezones0.put("EST", tz);
352         timezones0.put("EST5EDT", tz);
353         timezones0.put("America/Detroit", tz);
354         timezones0.put("America/Indiana/Indianapolis", tz);
355         timezones0.put("America/Indiana/Marengo", tz);
356         timezones0.put("America/Indiana/Vevay", tz);
357         timezones0.put("America/Iqaluit", tz);
358         timezones0.put("America/Kentucky/Louisville", tz);
359         timezones0.put("America/Kentucky/Monticello", tz);
360         timezones0.put("America/Montreal", tz);
361         timezones0.put("America/Nassau", tz);
362         timezones0.put("America/New_York", tz);
363         timezones0.put("America/Nipigon", tz);
364         timezones0.put("America/Pangnirtung", tz);
365         timezones0.put("America/Thunder_Bay", tz);
366         timezones0.put("America/Toronto", tz);
367         tz = new SimpleTimeZone
368           (-4000 * 3600, "America/Asuncion",
369            Calendar.OCTOBER, 3, Calendar.SUNDAY, 0 * 3600,
370            Calendar.MARCH, 2, Calendar.SUNDAY, 0 * 3600);
371         timezones0.put("America/Asuncion", tz);
372         tz = new SimpleTimeZone(-4000 * 3600, "PRT");
373         timezones0.put("PRT", tz);
374         timezones0.put("America/Anguilla", tz);
375         timezones0.put("America/Antigua", tz);
376         timezones0.put("America/Aruba", tz);
377         timezones0.put("America/Barbados", tz);
378         timezones0.put("America/Blanc-Sablon", tz);
379         timezones0.put("America/Boa_Vista", tz);
380         timezones0.put("America/Caracas", tz);
381         timezones0.put("America/Curacao", tz);
382         timezones0.put("America/Dominica", tz);
383         timezones0.put("America/Grenada", tz);
384         timezones0.put("America/Guadeloupe", tz);
385         timezones0.put("America/Guyana", tz);
386         timezones0.put("America/La_Paz", tz);
387         timezones0.put("America/Manaus", tz);
388         timezones0.put("America/Martinique", tz);
389         timezones0.put("America/Montserrat", tz);
390         timezones0.put("America/Port_of_Spain", tz);
391         timezones0.put("America/Porto_Velho", tz);
392         timezones0.put("America/Puerto_Rico", tz);
393         timezones0.put("America/Santo_Domingo", tz);
394         timezones0.put("America/St_Kitts", tz);
395         timezones0.put("America/St_Lucia", tz);
396         timezones0.put("America/St_Thomas", tz);
397         timezones0.put("America/St_Vincent", tz);
398         timezones0.put("America/Tortola", tz);
399         tz = new SimpleTimeZone
400           (-4000 * 3600, "America/Campo_Grande",
401            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 0 * 3600,
402            Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600);
403         timezones0.put("America/Campo_Grande", tz);
404         timezones0.put("America/Cuiaba", tz);
405         tz = new SimpleTimeZone
406           (-4000 * 3600, "America/Goose_Bay",
407            Calendar.MARCH, 2, Calendar.SUNDAY, 60000,
408            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 60000);
409         timezones0.put("America/Goose_Bay", tz);
410         tz = new SimpleTimeZone
411           (-4000 * 3600, "America/Glace_Bay",
412            Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
413            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
414         timezones0.put("America/Glace_Bay", tz);
415         timezones0.put("America/Halifax", tz);
416         timezones0.put("America/Moncton", tz);
417         timezones0.put("America/Thule", tz);
418         timezones0.put("Atlantic/Bermuda", tz);
419         tz = new SimpleTimeZone
420           (-4000 * 3600, "America/Santiago",
421            Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * 3600,
422            Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * 3600);
423         timezones0.put("America/Santiago", tz);
424         timezones0.put("Antarctica/Palmer", tz);
425         tz = new SimpleTimeZone
426           (-4000 * 3600, "Atlantic/Stanley",
427            Calendar.SEPTEMBER, 1, Calendar.SUNDAY, 2000 * 3600,
428            Calendar.APRIL, 3, Calendar.SUNDAY, 2000 * 3600);
429         timezones0.put("Atlantic/Stanley", tz);
430         tz = new SimpleTimeZone
431           (-3500 * 3600, "CNT",
432            Calendar.MARCH, 2, Calendar.SUNDAY, 60000,
433            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 60000);
434         timezones0.put("CNT", tz);
435         timezones0.put("America/St_Johns", tz);
436         tz = new SimpleTimeZone
437           (-3000 * 3600, "America/Godthab",
438            Calendar.MARCH, 30, -Calendar.SATURDAY, 22000 * 3600,
439            Calendar.OCTOBER, 30, -Calendar.SATURDAY, 23000 * 3600);
440         timezones0.put("America/Godthab", tz);
441         tz = new SimpleTimeZone
442           (-3000 * 3600, "America/Miquelon",
443            Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
444            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
445         timezones0.put("America/Miquelon", tz);
446         tz = new SimpleTimeZone
447           (-3000 * 3600, "America/Montevideo",
448            Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
449            Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600);
450         timezones0.put("America/Montevideo", tz);
451         tz = new SimpleTimeZone
452           (-3000 * 3600, "America/Sao_Paulo",
453            Calendar.NOVEMBER, 1, Calendar.SUNDAY, 0 * 3600,
454            Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600);
455         timezones0.put("America/Sao_Paulo", tz);
456         tz = new SimpleTimeZone(-3000 * 3600, "AGT");
457         timezones0.put("AGT", tz);
458         timezones0.put("America/Araguaina", tz);
459         timezones0.put("America/Argentina/Buenos_Aires", tz);
460         timezones0.put("America/Argentina/Catamarca", tz);
461         timezones0.put("America/Argentina/Cordoba", tz);
462         timezones0.put("America/Argentina/Jujuy", tz);
463         timezones0.put("America/Argentina/La_Rioja", tz);
464         timezones0.put("America/Argentina/Mendoza", tz);
465         timezones0.put("America/Argentina/Rio_Gallegos", tz);
466         timezones0.put("America/Argentina/San_Juan", tz);
467         timezones0.put("America/Argentina/Tucuman", tz);
468         timezones0.put("America/Argentina/Ushuaia", tz);
469         timezones0.put("America/Bahia", tz);
470         timezones0.put("America/Belem", tz);
471         timezones0.put("America/Cayenne", tz);
472         timezones0.put("America/Fortaleza", tz);
473         timezones0.put("America/Maceio", tz);
474         timezones0.put("America/Paramaribo", tz);
475         timezones0.put("America/Recife", tz);
476         timezones0.put("Antarctica/Rothera", tz);
477         tz = new SimpleTimeZone(-2000 * 3600, "America/Noronha");
478         timezones0.put("America/Noronha", tz);
479         timezones0.put("Atlantic/South_Georgia", tz);
480         tz = new SimpleTimeZone
481           (-1000 * 3600, "America/Scoresbysund",
482            Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
483            Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600);
484         timezones0.put("America/Scoresbysund", tz);
485         timezones0.put("Atlantic/Azores", tz);
486         tz = new SimpleTimeZone(-1000 * 3600, "Atlantic/Cape_Verde");
487         timezones0.put("Atlantic/Cape_Verde", tz);
488         tz = new SimpleTimeZone(0 * 3600, "GMT");
489         timezones0.put("GMT", tz);
490         timezones0.put("UTC", tz);
491         timezones0.put("Africa/Abidjan", tz);
492         timezones0.put("Africa/Accra", tz);
493         timezones0.put("Africa/Bamako", tz);
494         timezones0.put("Africa/Banjul", tz);
495         timezones0.put("Africa/Bissau", tz);
496         timezones0.put("Africa/Casablanca", tz);
497         timezones0.put("Africa/Conakry", tz);
498         timezones0.put("Africa/Dakar", tz);
499         timezones0.put("Africa/El_Aaiun", tz);
500         timezones0.put("Africa/Freetown", tz);
501         timezones0.put("Africa/Lome", tz);
502         timezones0.put("Africa/Monrovia", tz);
503         timezones0.put("Africa/Nouakchott", tz);
504         timezones0.put("Africa/Ouagadougou", tz);
505         timezones0.put("Africa/Sao_Tome", tz);
506         timezones0.put("America/Danmarkshavn", tz);
507         timezones0.put("Atlantic/Reykjavik", tz);
508         timezones0.put("Atlantic/St_Helena", tz);
509         tz = new SimpleTimeZone
510           (0 * 3600, "WET",
511            Calendar.MARCH, -1, Calendar.SUNDAY, 1000 * 3600,
512            Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
513         timezones0.put("WET", tz);
514         timezones0.put("Atlantic/Canary", tz);
515         timezones0.put("Atlantic/Faroe", tz);
516         timezones0.put("Atlantic/Madeira", tz);
517         timezones0.put("Europe/Dublin", tz);
518         timezones0.put("Europe/Guernsey", tz);
519         timezones0.put("Europe/Isle_of_Man", tz);
520         timezones0.put("Europe/Jersey", tz);
521         timezones0.put("Europe/Lisbon", tz);
522         timezones0.put("Europe/London", tz);
523         tz = new SimpleTimeZone(1000 * 3600, "Africa/Algiers");
524         timezones0.put("Africa/Algiers", tz);
525         timezones0.put("Africa/Bangui", tz);
526         timezones0.put("Africa/Brazzaville", tz);
527         timezones0.put("Africa/Douala", tz);
528         timezones0.put("Africa/Kinshasa", tz);
529         timezones0.put("Africa/Lagos", tz);
530         timezones0.put("Africa/Libreville", tz);
531         timezones0.put("Africa/Luanda", tz);
532         timezones0.put("Africa/Malabo", tz);
533         timezones0.put("Africa/Ndjamena", tz);
534         timezones0.put("Africa/Niamey", tz);
535         timezones0.put("Africa/Porto-Novo", tz);
536         tz = new SimpleTimeZone
537           (1000 * 3600, "Africa/Windhoek",
538            Calendar.SEPTEMBER, 1, Calendar.SUNDAY, 2000 * 3600,
539            Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600);
540         timezones0.put("Africa/Windhoek", tz);
541         tz = new SimpleTimeZone
542           (1000 * 3600, "CET",
543            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
544            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
545         timezones0.put("CET", tz);
546         timezones0.put("ECT", tz);
547         timezones0.put("MET", tz);
548         timezones0.put("Africa/Ceuta", tz);
549         timezones0.put("Africa/Tunis", tz);
550         timezones0.put("Arctic/Longyearbyen", tz);
551         timezones0.put("Atlantic/Jan_Mayen", tz);
552         timezones0.put("Europe/Amsterdam", tz);
553         timezones0.put("Europe/Andorra", tz);
554         timezones0.put("Europe/Belgrade", tz);
555         timezones0.put("Europe/Berlin", tz);
556         timezones0.put("Europe/Bratislava", tz);
557         timezones0.put("Europe/Brussels", tz);
558         timezones0.put("Europe/Budapest", tz);
559         timezones0.put("Europe/Copenhagen", tz);
560         timezones0.put("Europe/Gibraltar", tz);
561         timezones0.put("Europe/Ljubljana", tz);
562         timezones0.put("Europe/Luxembourg", tz);
563         timezones0.put("Europe/Madrid", tz);
564         timezones0.put("Europe/Malta", tz);
565         timezones0.put("Europe/Monaco", tz);
566         timezones0.put("Europe/Oslo", tz);
567         timezones0.put("Europe/Paris", tz);
568         timezones0.put("Europe/Podgorica", tz);
569         timezones0.put("Europe/Prague", tz);
570         timezones0.put("Europe/Rome", tz);
571         timezones0.put("Europe/San_Marino", tz);
572         timezones0.put("Europe/Sarajevo", tz);
573         timezones0.put("Europe/Skopje", tz);
574         timezones0.put("Europe/Stockholm", tz);
575         timezones0.put("Europe/Tirane", tz);
576         timezones0.put("Europe/Vaduz", tz);
577         timezones0.put("Europe/Vatican", tz);
578         timezones0.put("Europe/Vienna", tz);
579         timezones0.put("Europe/Warsaw", tz);
580         timezones0.put("Europe/Zagreb", tz);
581         timezones0.put("Europe/Zurich", tz);
582         tz = new SimpleTimeZone
583           (2000 * 3600, "ART",
584            Calendar.APRIL, -1, Calendar.FRIDAY, 0 * 3600,
585            Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 24000 * 3600);
586         timezones0.put("ART", tz);
587         timezones0.put("Africa/Cairo", tz);
588         tz = new SimpleTimeZone(2000 * 3600, "CAT");
589         timezones0.put("CAT", tz);
590         timezones0.put("Africa/Blantyre", tz);
591         timezones0.put("Africa/Bujumbura", tz);
592         timezones0.put("Africa/Gaborone", tz);
593         timezones0.put("Africa/Harare", tz);
594         timezones0.put("Africa/Johannesburg", tz);
595         timezones0.put("Africa/Kigali", tz);
596         timezones0.put("Africa/Lubumbashi", tz);
597         timezones0.put("Africa/Lusaka", tz);
598         timezones0.put("Africa/Maputo", tz);
599         timezones0.put("Africa/Maseru", tz);
600         timezones0.put("Africa/Mbabane", tz);
601         timezones0.put("Africa/Tripoli", tz);
602         timezones0.put("Asia/Jerusalem", tz);
603         tz = new SimpleTimeZone
604           (2000 * 3600, "Asia/Amman",
605            Calendar.MARCH, -1, Calendar.THURSDAY, 0 * 3600,
606            Calendar.OCTOBER, -1, Calendar.FRIDAY, 1000 * 3600);
607         timezones0.put("Asia/Amman", tz);
608         tz = new SimpleTimeZone
609           (2000 * 3600, "Asia/Beirut",
610            Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
611            Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
612         timezones0.put("Asia/Beirut", tz);
613         tz = new SimpleTimeZone
614           (2000 * 3600, "Asia/Damascus",
615            Calendar.APRIL, 1, 0, 0 * 3600,
616            Calendar.OCTOBER, 1, 0, 0 * 3600);
617         timezones0.put("Asia/Damascus", tz);
618         tz = new SimpleTimeZone
619           (2000 * 3600, "Asia/Gaza",
620            Calendar.APRIL, 1, 0, 0 * 3600,
621            Calendar.OCTOBER, 3, Calendar.FRIDAY, 0 * 3600);
622         timezones0.put("Asia/Gaza", tz);
623         tz = new SimpleTimeZone
624           (2000 * 3600, "EET",
625            Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600,
626            Calendar.OCTOBER, -1, Calendar.SUNDAY, 4000 * 3600);
627         timezones0.put("EET", tz);
628         timezones0.put("Asia/Istanbul", tz);
629         timezones0.put("Asia/Nicosia", tz);
630         timezones0.put("Europe/Athens", tz);
631         timezones0.put("Europe/Bucharest", tz);
632         timezones0.put("Europe/Chisinau", tz);
633         timezones0.put("Europe/Helsinki", tz);
634         timezones0.put("Europe/Istanbul", tz);
635         timezones0.put("Europe/Kiev", tz);
636         timezones0.put("Europe/Mariehamn", tz);
637         timezones0.put("Europe/Nicosia", tz);
638         timezones0.put("Europe/Riga", tz);
639         timezones0.put("Europe/Simferopol", tz);
640         timezones0.put("Europe/Sofia", tz);
641         timezones0.put("Europe/Tallinn", tz);
642         timezones0.put("Europe/Uzhgorod", tz);
643         timezones0.put("Europe/Vilnius", tz);
644         timezones0.put("Europe/Zaporozhye", tz);
645         tz = new SimpleTimeZone
646           (2000 * 3600, "Europe/Kaliningrad",
647            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
648            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
649         timezones0.put("Europe/Kaliningrad", tz);
650         timezones0.put("Europe/Minsk", tz);
651         tz = new SimpleTimeZone
652           (3000 * 3600, "Asia/Baghdad",
653            Calendar.APRIL, 1, 0, 3000 * 3600,
654            Calendar.OCTOBER, 1, 0, 4000 * 3600);
655         timezones0.put("Asia/Baghdad", tz);
656         tz = new SimpleTimeZone
657           (3000 * 3600, "Europe/Moscow",
658            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
659            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
660         timezones0.put("Europe/Moscow", tz);
661         timezones0.put("Europe/Volgograd", tz);
662         tz = new SimpleTimeZone(3000 * 3600, "EAT");
663         timezones0.put("EAT", tz);
664         timezones0.put("Africa/Addis_Ababa", tz);
665         timezones0.put("Africa/Asmara", tz);
666         timezones0.put("Africa/Dar_es_Salaam", tz);
667         timezones0.put("Africa/Djibouti", tz);
668         timezones0.put("Africa/Kampala", tz);
669         timezones0.put("Africa/Khartoum", tz);
670         timezones0.put("Africa/Mogadishu", tz);
671         timezones0.put("Africa/Nairobi", tz);
672         timezones0.put("Antarctica/Syowa", tz);
673         timezones0.put("Asia/Aden", tz);
674         timezones0.put("Asia/Bahrain", tz);
675         timezones0.put("Asia/Kuwait", tz);
676         timezones0.put("Asia/Qatar", tz);
677         timezones0.put("Asia/Riyadh", tz);
678         timezones0.put("Indian/Antananarivo", tz);
679         timezones0.put("Indian/Comoro", tz);
680         timezones0.put("Indian/Mayotte", tz);
681         tz = new SimpleTimeZone(3500 * 3600, "Asia/Tehran");
682         timezones0.put("Asia/Tehran", tz);
683         tz = new SimpleTimeZone
684           (4000 * 3600, "Asia/Baku",
685            Calendar.MARCH, -1, Calendar.SUNDAY, 4000 * 3600,
686            Calendar.OCTOBER, -1, Calendar.SUNDAY, 5000 * 3600);
687         timezones0.put("Asia/Baku", tz);
688         tz = new SimpleTimeZone
689           (4000 * 3600, "Asia/Yerevan",
690            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
691            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
692         timezones0.put("Asia/Yerevan", tz);
693         timezones0.put("Europe/Samara", tz);
694         tz = new SimpleTimeZone(4000 * 3600, "NET");
695         timezones0.put("NET", tz);
696         timezones0.put("Asia/Dubai", tz);
697         timezones0.put("Asia/Muscat", tz);
698         timezones0.put("Asia/Tbilisi", tz);
699         timezones0.put("Indian/Mahe", tz);
700         timezones0.put("Indian/Mauritius", tz);
701         timezones0.put("Indian/Reunion", tz);
702         tz = new SimpleTimeZone(4500 * 3600, "Asia/Kabul");
703         timezones0.put("Asia/Kabul", tz);
704         tz = new SimpleTimeZone
705           (5000 * 3600, "Asia/Yekaterinburg",
706            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
707            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
708         timezones0.put("Asia/Yekaterinburg", tz);
709         tz = new SimpleTimeZone(5000 * 3600, "PLT");
710         timezones0.put("PLT", tz);
711         timezones0.put("Asia/Aqtau", tz);
712         timezones0.put("Asia/Aqtobe", tz);
713         timezones0.put("Asia/Ashgabat", tz);
714         timezones0.put("Asia/Dushanbe", tz);
715         timezones0.put("Asia/Karachi", tz);
716         timezones0.put("Asia/Oral", tz);
717         timezones0.put("Asia/Samarkand", tz);
718         timezones0.put("Asia/Tashkent", tz);
719         timezones0.put("Indian/Kerguelen", tz);
720         timezones0.put("Indian/Maldives", tz);
721         tz = new SimpleTimeZone(5500 * 3600, "BST");
722         timezones0.put("BST", tz);
723         timezones0.put("IST", tz);
724         timezones0.put("Asia/Calcutta", tz);
725         timezones0.put("Asia/Colombo", tz);
726         tz = new SimpleTimeZone(5750 * 3600, "Asia/Katmandu");
727         timezones0.put("Asia/Katmandu", tz);
728         tz = new SimpleTimeZone(6000 * 3600, "Antarctica/Mawson");
729         timezones0.put("Antarctica/Mawson", tz);
730         timezones0.put("Antarctica/Vostok", tz);
731         timezones0.put("Asia/Almaty", tz);
732         timezones0.put("Asia/Bishkek", tz);
733         timezones0.put("Asia/Dhaka", tz);
734         timezones0.put("Asia/Qyzylorda", tz);
735         timezones0.put("Asia/Thimphu", tz);
736         timezones0.put("Indian/Chagos", tz);
737         tz = new SimpleTimeZone
738           (6000 * 3600, "Asia/Novosibirsk",
739            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
740            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
741         timezones0.put("Asia/Novosibirsk", tz);
742         timezones0.put("Asia/Omsk", tz);
743         tz = new SimpleTimeZone(6500 * 3600, "Asia/Rangoon");
744         timezones0.put("Asia/Rangoon", tz);
745         timezones0.put("Indian/Cocos", tz);
746         tz = new SimpleTimeZone(7000 * 3600, "VST");
747         timezones0.put("VST", tz);
748         timezones0.put("Antarctica/Davis", tz);
749         timezones0.put("Asia/Bangkok", tz);
750         timezones0.put("Asia/Jakarta", tz);
751         timezones0.put("Asia/Phnom_Penh", tz);
752         timezones0.put("Asia/Pontianak", tz);
753         timezones0.put("Asia/Saigon", tz);
754         timezones0.put("Asia/Vientiane", tz);
755         timezones0.put("Indian/Christmas", tz);
756         tz = new SimpleTimeZone
757           (7000 * 3600, "Asia/Hovd",
758            Calendar.MARCH, -1, Calendar.SATURDAY, 2000 * 3600,
759            Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 2000 * 3600);
760         timezones0.put("Asia/Hovd", tz);
761         tz = new SimpleTimeZone
762           (7000 * 3600, "Asia/Krasnoyarsk",
763            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
764            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
765         timezones0.put("Asia/Krasnoyarsk", tz);
766         tz = new SimpleTimeZone(8000 * 3600, "CTT");
767         timezones0.put("CTT", tz);
768         timezones0.put("Antarctica/Casey", tz);
769         timezones0.put("Asia/Brunei", tz);
770         timezones0.put("Asia/Chongqing", tz);
771         timezones0.put("Asia/Harbin", tz);
772         timezones0.put("Asia/Hong_Kong", tz);
773         timezones0.put("Asia/Kashgar", tz);
774         timezones0.put("Asia/Kuala_Lumpur", tz);
775         timezones0.put("Asia/Kuching", tz);
776         timezones0.put("Asia/Macau", tz);
777         timezones0.put("Asia/Makassar", tz);
778         timezones0.put("Asia/Manila", tz);
779         timezones0.put("Asia/Shanghai", tz);
780         timezones0.put("Asia/Singapore", tz);
781         timezones0.put("Asia/Taipei", tz);
782         timezones0.put("Asia/Urumqi", tz);
783         timezones0.put("Australia/Perth", tz);
784         tz = new SimpleTimeZone
785           (8000 * 3600, "Asia/Irkutsk",
786            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
787            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
788         timezones0.put("Asia/Irkutsk", tz);
789         tz = new SimpleTimeZone
790           (8000 * 3600, "Asia/Ulaanbaatar",
791            Calendar.MARCH, -1, Calendar.SATURDAY, 2000 * 3600,
792            Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 2000 * 3600);
793         timezones0.put("Asia/Ulaanbaatar", tz);
794         tz = new SimpleTimeZone(8750 * 3600, "Australia/Eucla");
795         timezones0.put("Australia/Eucla", tz);
796         tz = new SimpleTimeZone
797           (9000 * 3600, "Asia/Choibalsan",
798            Calendar.MARCH, -1, Calendar.SATURDAY, 2000 * 3600,
799            Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 2000 * 3600);
800         timezones0.put("Asia/Choibalsan", tz);
801         tz = new SimpleTimeZone(9000 * 3600, "JST");
802         timezones0.put("JST", tz);
803         timezones0.put("Asia/Dili", tz);
804         timezones0.put("Asia/Jayapura", tz);
805         timezones0.put("Asia/Pyongyang", tz);
806         timezones0.put("Asia/Seoul", tz);
807         timezones0.put("Asia/Tokyo", tz);
808         timezones0.put("Pacific/Palau", tz);
809         tz = new SimpleTimeZone
810           (9000 * 3600, "Asia/Yakutsk",
811            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
812            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
813         timezones0.put("Asia/Yakutsk", tz);
814         tz = new SimpleTimeZone
815           (9500 * 3600, "Australia/Adelaide",
816            Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
817            Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600);
818         timezones0.put("Australia/Adelaide", tz);
819         timezones0.put("Australia/Broken_Hill", tz);
820         tz = new SimpleTimeZone(9500 * 3600, "ACT");
821         timezones0.put("ACT", tz);
822         timezones0.put("Australia/Darwin", tz);
823         tz = new SimpleTimeZone(10000 * 3600, "Antarctica/DumontDUrville");
824         timezones0.put("Antarctica/DumontDUrville", tz);
825         timezones0.put("Australia/Brisbane", tz);
826         timezones0.put("Australia/Lindeman", tz);
827         timezones0.put("Pacific/Guam", tz);
828         timezones0.put("Pacific/Port_Moresby", tz);
829         timezones0.put("Pacific/Saipan", tz);
830         timezones0.put("Pacific/Truk", tz);
831         tz = new SimpleTimeZone
832           (10000 * 3600, "Asia/Sakhalin",
833            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
834            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
835         timezones0.put("Asia/Sakhalin", tz);
836         timezones0.put("Asia/Vladivostok", tz);
837         tz = new SimpleTimeZone
838           (10000 * 3600, "Australia/Currie",
839            Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
840            Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600);
841         timezones0.put("Australia/Currie", tz);
842         timezones0.put("Australia/Hobart", tz);
843         tz = new SimpleTimeZone
844           (10000 * 3600, "AET",
845            Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
846            Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600);
847         timezones0.put("AET", tz);
848         timezones0.put("Australia/Melbourne", tz);
849         timezones0.put("Australia/Sydney", tz);
850         tz = new SimpleTimeZone
851           (10500 * 3600, "Australia/Lord_Howe",
852           Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
853           Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, 500 * 3600);
854         timezones0.put("Australia/Lord_Howe", tz);
855         tz = new SimpleTimeZone
856           (11000 * 3600, "Asia/Magadan",
857            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
858            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
859         timezones0.put("Asia/Magadan", tz);
860         tz = new SimpleTimeZone(11000 * 3600, "SST");
861         timezones0.put("SST", tz);
862         timezones0.put("Pacific/Efate", tz);
863         timezones0.put("Pacific/Guadalcanal", tz);
864         timezones0.put("Pacific/Kosrae", tz);
865         timezones0.put("Pacific/Noumea", tz);
866         timezones0.put("Pacific/Ponape", tz);
867         tz = new SimpleTimeZone(11500 * 3600, "Pacific/Norfolk");
868         timezones0.put("Pacific/Norfolk", tz);
869         tz = new SimpleTimeZone
870           (12000 * 3600, "NST",
871            Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
872            Calendar.MARCH, 3, Calendar.SUNDAY, 3000 * 3600);
873         timezones0.put("NST", tz);
874         timezones0.put("Antarctica/McMurdo", tz);
875         timezones0.put("Antarctica/South_Pole", tz);
876         timezones0.put("Pacific/Auckland", tz);
877         tz = new SimpleTimeZone
878           (12000 * 3600, "Asia/Anadyr",
879            Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
880            Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
881         timezones0.put("Asia/Anadyr", tz);
882         timezones0.put("Asia/Kamchatka", tz);
883         tz = new SimpleTimeZone(12000 * 3600, "Pacific/Fiji");
884         timezones0.put("Pacific/Fiji", tz);
885         timezones0.put("Pacific/Funafuti", tz);
886         timezones0.put("Pacific/Kwajalein", tz);
887         timezones0.put("Pacific/Majuro", tz);
888         timezones0.put("Pacific/Nauru", tz);
889         timezones0.put("Pacific/Tarawa", tz);
890         timezones0.put("Pacific/Wake", tz);
891         timezones0.put("Pacific/Wallis", tz);
892         tz = new SimpleTimeZone
893           (12750 * 3600, "Pacific/Chatham",
894            Calendar.OCTOBER, 1, Calendar.SUNDAY, 2750 * 3600,
895            Calendar.MARCH, 3, Calendar.SUNDAY, 3750 * 3600);
896         timezones0.put("Pacific/Chatham", tz);
897         tz = new SimpleTimeZone(13000 * 3600, "Pacific/Enderbury");
898         timezones0.put("Pacific/Enderbury", tz);
899         timezones0.put("Pacific/Tongatapu", tz);
900         tz = new SimpleTimeZone(14000 * 3600, "Pacific/Kiritimati");
901         timezones0.put("Pacific/Kiritimati", tz);
902       }
903     return timezones0;
904   }
905 
906   /**
907    * Maps a time zone name (with optional GMT offset and daylight time
908    * zone name) to one of the known time zones.  This method called
909    * with the result of <code>System.getProperty("user.timezone")</code>
910    * or <code>getDefaultTimeZoneId()</code>.  Note that giving one of
911    * the standard tz data names from ftp://elsie.nci.nih.gov/pub/ is
912    * preferred.
913    * The time zone name can be given as follows:
914    * <code>(standard zone name)[(GMT offset)[(DST zone name)[DST offset]]]
915    * </code>
916    * <p>
917    * If only a (standard zone name) is given (no numbers in the
918    * String) then it gets mapped directly to the TimeZone with that
919    * name, if that fails null is returned.
920    * <p>
921    * Alternately, a POSIX-style TZ string can be given, defining the time zone:
922    * <code>std offset dst offset,date/time,date/time</code>
923    * See the glibc manual, or the man page for <code>tzset</code> for details
924    * of this format.
925    * <p>
926    * A GMT offset is the offset to add to the local time to get GMT.
927    * If a (GMT offset) is included (either in seconds or hours) then
928    * an attempt is made to find a TimeZone name matching both the name
929    * and the offset (that doesn't observe daylight time, if the
930    * timezone observes daylight time then you must include a daylight
931    * time zone name after the offset), if that fails then a TimeZone
932    * with the given GMT offset is returned (whether or not the
933    * TimeZone observes daylight time is ignored), if that also fails
934    * the GMT TimeZone is returned.
935    * <p>
936    * If the String ends with (GMT offset)(daylight time zone name)
937    * then an attempt is made to find a TimeZone with the given name and
938    * GMT offset that also observes (the daylight time zone name is not
939    * currently used in any other way), if that fails a TimeZone with
940    * the given GMT offset that observes daylight time is returned, if
941    * that also fails the GMT TimeZone is returned.
942    * <p>
943    * Examples: In Chicago, the time zone id could be "CST6CDT", but
944    * the preferred name would be "America/Chicago".  In Indianapolis
945    * (which does not have Daylight Savings Time) the string could be
946    * "EST5", but the preferred name would be "America/Indianapolis".
947    * The standard time zone name for The Netherlands is "Europe/Amsterdam",
948    * but can also be given as "CET-1CEST".
949    */
getDefaultTimeZone(String sysTimeZoneId)950   static TimeZone getDefaultTimeZone(String sysTimeZoneId)
951   {
952     String stdName = null;
953     int stdOffs;
954     int dstOffs;
955     try
956       {
957         int idLength = sysTimeZoneId.length();
958 
959         int index = 0;
960         int prevIndex;
961         char c;
962 
963         // get std
964         do
965           c = sysTimeZoneId.charAt(index);
966         while (c != '+' && c != '-' && c != ',' && c != ':'
967                && ! Character.isDigit(c) && c != '\0' && ++index < idLength);
968 
969         if (index >= idLength)
970           return getTimeZoneInternal(sysTimeZoneId);
971 
972         stdName = sysTimeZoneId.substring(0, index);
973         prevIndex = index;
974 
975         // get the std offset
976         do
977           c = sysTimeZoneId.charAt(index++);
978         while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c))
979                && index < idLength);
980         if (index < idLength)
981           index--;
982 
983         { // convert the dst string to a millis number
984             String offset = sysTimeZoneId.substring(prevIndex, index);
985             prevIndex = index;
986 
987             if (offset.charAt(0) == '+' || offset.charAt(0) == '-')
988               stdOffs = parseTime(offset.substring(1));
989             else
990               stdOffs = parseTime(offset);
991 
992             if (offset.charAt(0) == '-')
993               stdOffs = -stdOffs;
994 
995             // TZ timezone offsets are positive when WEST of the meridian.
996             stdOffs = -stdOffs;
997         }
998 
999         // Done yet? (Format: std offset)
1000         if (index >= idLength)
1001           {
1002             // Do we have an existing timezone with that name and offset?
1003             TimeZone tz = getTimeZoneInternal(stdName);
1004             if (tz != null)
1005               if (tz.getRawOffset() == stdOffs)
1006                 return tz;
1007 
1008             // Custom then.
1009             return new SimpleTimeZone(stdOffs, stdName);
1010           }
1011 
1012         // get dst
1013         do
1014           c = sysTimeZoneId.charAt(index);
1015         while (c != '+' && c != '-' && c != ',' && c != ':'
1016                && ! Character.isDigit(c) && c != '\0' && ++index < idLength);
1017 
1018         // Done yet? (Format: std offset dst)
1019         if (index >= idLength)
1020           {
1021             // Do we have an existing timezone with that name and offset
1022             // which has DST?
1023             TimeZone tz = getTimeZoneInternal(stdName);
1024             if (tz != null)
1025               if (tz.getRawOffset() == stdOffs && tz.useDaylightTime())
1026                 return tz;
1027 
1028             // Custom then.
1029             return new SimpleTimeZone(stdOffs, stdName);
1030           }
1031 
1032         // get the dst offset
1033         prevIndex = index;
1034         do
1035           c = sysTimeZoneId.charAt(index++);
1036         while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c))
1037                && index < idLength);
1038         if (index < idLength)
1039           index--;
1040 
1041         if (index == prevIndex && (c == ',' || c == ';'))
1042           {
1043             // Missing dst offset defaults to one hour ahead of standard
1044             // time.
1045             dstOffs = stdOffs + 60 * 60 * 1000;
1046           }
1047         else
1048           { // convert the dst string to a millis number
1049             String offset = sysTimeZoneId.substring(prevIndex, index);
1050             prevIndex = index;
1051 
1052             if (offset.charAt(0) == '+' || offset.charAt(0) == '-')
1053               dstOffs = parseTime(offset.substring(1));
1054             else
1055               dstOffs = parseTime(offset);
1056 
1057             if (offset.charAt(0) == '-')
1058               dstOffs = -dstOffs;
1059 
1060             // TZ timezone offsets are positive when WEST of the meridian.
1061             dstOffs = -dstOffs;
1062           }
1063 
1064         // Done yet? (Format: std offset dst offset)
1065         // FIXME: We don't support DST without a rule given. Should we?
1066         if (index >= idLength)
1067           {
1068             // Time Zone existing with same name, dst and offsets?
1069             TimeZone tz = getTimeZoneInternal(stdName);
1070             if (tz != null)
1071               if (tz.getRawOffset() == stdOffs && tz.useDaylightTime()
1072                   && tz.getDSTSavings() == (dstOffs - stdOffs))
1073                 return tz;
1074 
1075             return new SimpleTimeZone(stdOffs, stdName);
1076           }
1077 
1078         // get the DST rule
1079         if (sysTimeZoneId.charAt(index) == ','
1080             || sysTimeZoneId.charAt(index) == ';')
1081           {
1082             index++;
1083             int offs = index;
1084             while (sysTimeZoneId.charAt(index) != ','
1085                    && sysTimeZoneId.charAt(index) != ';')
1086               index++;
1087             String startTime = sysTimeZoneId.substring(offs, index);
1088             index++;
1089             String endTime = sysTimeZoneId.substring(index);
1090 
1091             index = startTime.indexOf('/');
1092             int startMillis;
1093             int endMillis;
1094             String startDate;
1095             String endDate;
1096             if (index != -1)
1097               {
1098                 startDate = startTime.substring(0, index);
1099                 startMillis = parseTime(startTime.substring(index + 1));
1100               }
1101             else
1102               {
1103                 startDate = startTime;
1104                 // if time isn't given, default to 2:00:00 AM.
1105                 startMillis = 2 * 60 * 60 * 1000;
1106               }
1107             index = endTime.indexOf('/');
1108             if (index != -1)
1109               {
1110                 endDate = endTime.substring(0, index);
1111                 endMillis = parseTime(endTime.substring(index + 1));
1112               }
1113             else
1114               {
1115                 endDate = endTime;
1116                 // if time isn't given, default to 2:00:00 AM.
1117                 endMillis = 2 * 60 * 60 * 1000;
1118               }
1119 
1120             int[] start = getDateParams(startDate);
1121             int[] end = getDateParams(endDate);
1122             return new SimpleTimeZone(stdOffs, stdName, start[0], start[1],
1123                                       start[2], startMillis, end[0], end[1],
1124                                       end[2], endMillis, (dstOffs - stdOffs));
1125           }
1126       }
1127 
1128     // FIXME: Produce a warning here?
1129     catch (IndexOutOfBoundsException _)
1130       {
1131       }
1132     catch (NumberFormatException _)
1133       {
1134       }
1135 
1136     return null;
1137   }
1138 
1139   /**
1140    * Parses and returns the params for a POSIX TZ date field,
1141    * in the format int[]{ month, day, dayOfWeek }, following the
1142    * SimpleTimeZone constructor rules.
1143    */
getDateParams(String date)1144   private static int[] getDateParams(String date)
1145   {
1146     int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
1147     int month;
1148 
1149     if (date.charAt(0) == 'M' || date.charAt(0) == 'm')
1150       {
1151         int day;
1152 
1153         // Month, week of month, day of week
1154 
1155         // "Mm.w.d".  d is between 0 (Sunday) and 6.  Week w is
1156         // between 1 and 5; Week 1 is the first week in which day d
1157         // occurs and Week 5 specifies the last d day in the month.
1158         // Month m is between 1 and 12.
1159 
1160         month = Integer.parseInt(date.substring(1, date.indexOf('.')));
1161         int week = Integer.parseInt(date.substring(date.indexOf('.') + 1,
1162                                                    date.lastIndexOf('.')));
1163         int dayOfWeek = Integer.parseInt(date.substring(date.lastIndexOf('.')
1164                                                         + 1));
1165         dayOfWeek++; // Java day of week is one-based, Sunday is first day.
1166 
1167         if (week == 5)
1168           day = -1; // last day of month is -1 in java, 5 in TZ
1169         else
1170           {
1171             // First day of week starting on or after.  For example,
1172             // to specify the second Sunday of April, set month to
1173             // APRIL, day-of-month to 8, and day-of-week to -SUNDAY.
1174             day = (week - 1) * 7 + 1;
1175             dayOfWeek = -dayOfWeek;
1176           }
1177 
1178         month--; // Java month is zero-based.
1179         return new int[] { month, day, dayOfWeek };
1180       }
1181 
1182     // julian day, either zero-based 0<=n<=365 (incl feb 29)
1183     // or one-based 1<=n<=365 (no feb 29)
1184     int julianDay; // Julian day,
1185 
1186     if (date.charAt(0) != 'J' || date.charAt(0) != 'j')
1187       {
1188         julianDay = Integer.parseInt(date.substring(1));
1189         julianDay++; // make 1-based
1190         // Adjust day count to include feb 29.
1191         dayCount = new int[]
1192                    {
1193                      0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335
1194                    };
1195       }
1196     else
1197       // 1-based julian day
1198       julianDay = Integer.parseInt(date);
1199 
1200     int i = 11;
1201     while (i > 0)
1202       if (dayCount[i] < julianDay)
1203         break;
1204       else
1205         i--;
1206     julianDay -= dayCount[i];
1207     month = i;
1208     return new int[] { month, julianDay, 0 };
1209   }
1210 
1211   /**
1212    * Parses a time field hh[:mm[:ss]], returning the result
1213    * in milliseconds. No leading sign.
1214    */
parseTime(String time)1215   private static int parseTime(String time)
1216   {
1217     int millis = 0;
1218     int i = 0;
1219 
1220     while (i < time.length())
1221       if (time.charAt(i) == ':')
1222         break;
1223       else
1224         i++;
1225     millis = 60 * 60 * 1000 * Integer.parseInt(time.substring(0, i));
1226     if (i >= time.length())
1227       return millis;
1228 
1229     int iprev = ++i;
1230     while (i < time.length())
1231       if (time.charAt(i) == ':')
1232         break;
1233       else
1234         i++;
1235     millis += 60 * 1000 * Integer.parseInt(time.substring(iprev, i));
1236     if (i >= time.length())
1237       return millis;
1238 
1239     millis += 1000 * Integer.parseInt(time.substring(++i));
1240     return millis;
1241   }
1242 
1243   /**
1244    * Gets the time zone offset, for current date, modified in case of
1245    * daylight savings.  This is the offset to add to UTC to get the local
1246    * time.
1247    * @param era the era of the given date
1248    * @param year the year of the given date
1249    * @param month the month of the given date, 0 for January.
1250    * @param day the day of month
1251    * @param dayOfWeek the day of week
1252    * @param milliseconds the millis in the day (in local standard time)
1253    * @return the time zone offset in milliseconds.
1254    */
getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds)1255   public abstract int getOffset(int era, int year, int month,
1256                                 int day, int dayOfWeek, int milliseconds);
1257 
1258   /**
1259    * Get the time zone offset for the specified date, modified in case of
1260    * daylight savings.  This is the offset to add to UTC to get the local
1261    * time.
1262    * @param date the date represented in millisecends
1263    * since January 1, 1970 00:00:00 GMT.
1264    * @since 1.4
1265    */
getOffset(long date)1266   public int getOffset(long date)
1267   {
1268     return (inDaylightTime(new Date(date))
1269             ? getRawOffset() + getDSTSavings()
1270             : getRawOffset());
1271   }
1272 
1273   /**
1274    * Gets the time zone offset, ignoring daylight savings.  This is
1275    * the offset to add to UTC to get the local time.
1276    * @return the time zone offset in milliseconds.
1277    */
getRawOffset()1278   public abstract int getRawOffset();
1279 
1280   /**
1281    * Sets the time zone offset, ignoring daylight savings.  This is
1282    * the offset to add to UTC to get the local time.
1283    * @param offsetMillis the time zone offset to GMT.
1284    */
setRawOffset(int offsetMillis)1285   public abstract void setRawOffset(int offsetMillis);
1286 
1287   /**
1288    * Gets the identifier of this time zone. For instance, PST for
1289    * Pacific Standard Time.
1290    * @returns the ID of this time zone.
1291    */
getID()1292   public String getID()
1293   {
1294     return ID;
1295   }
1296 
1297   /**
1298    * Sets the identifier of this time zone. For instance, PST for
1299    * Pacific Standard Time.
1300    * @param id the new time zone ID.
1301    * @throws NullPointerException if <code>id</code> is <code>null</code>
1302    */
setID(String id)1303   public void setID(String id)
1304   {
1305     if (id == null)
1306       throw new NullPointerException();
1307 
1308     this.ID = id;
1309   }
1310 
1311   /**
1312    * This method returns a string name of the time zone suitable
1313    * for displaying to the user.  The string returned will be the long
1314    * description of the timezone in the current locale.  The name
1315    * displayed will assume daylight savings time is not in effect.
1316    *
1317    * @return The name of the time zone.
1318    */
getDisplayName()1319   public final String getDisplayName()
1320   {
1321     return (getDisplayName(false, LONG, Locale.getDefault()));
1322   }
1323 
1324   /**
1325    * This method returns a string name of the time zone suitable
1326    * for displaying to the user.  The string returned will be the long
1327    * description of the timezone in the specified locale. The name
1328    * displayed will assume daylight savings time is not in effect.
1329    *
1330    * @param locale The locale for this timezone name.
1331    *
1332    * @return The name of the time zone.
1333    */
getDisplayName(Locale locale)1334   public final String getDisplayName(Locale locale)
1335   {
1336     return (getDisplayName(false, LONG, locale));
1337   }
1338 
1339   /**
1340    * This method returns a string name of the time zone suitable
1341    * for displaying to the user.  The string returned will be of the
1342    * specified type in the current locale.
1343    *
1344    * @param dst Whether or not daylight savings time is in effect.
1345    * @param style <code>LONG</code> for a long name, <code>SHORT</code> for
1346    * a short abbreviation.
1347    *
1348    * @return The name of the time zone.
1349    */
getDisplayName(boolean dst, int style)1350   public final String getDisplayName(boolean dst, int style)
1351   {
1352     return (getDisplayName(dst, style, Locale.getDefault()));
1353   }
1354 
1355 
1356   /**
1357    * This method returns a string name of the time zone suitable
1358    * for displaying to the user.  The string returned will be of the
1359    * specified type in the specified locale.
1360    *
1361    * @param dst Whether or not daylight savings time is in effect.
1362    * @param style <code>LONG</code> for a long name, <code>SHORT</code> for
1363    * a short abbreviation.
1364    * @param locale The locale for this timezone name.
1365    *
1366    * @return The name of the time zone.
1367    */
getDisplayName(boolean dst, int style, Locale locale)1368   public String getDisplayName(boolean dst, int style, Locale locale)
1369   {
1370     DateFormatSymbols dfs;
1371     try
1372       {
1373         dfs = new DateFormatSymbols(locale);
1374 
1375         // The format of the value returned is defined by us.
1376         String[][]zoneinfo = dfs.getZoneStrings();
1377         for (int i = 0; i < zoneinfo.length; i++)
1378           {
1379             if (zoneinfo[i][0].equals(getID()))
1380               {
1381                 if (!dst)
1382                   {
1383                     if (style == SHORT)
1384                       return (zoneinfo[i][2]);
1385                     else
1386                       return (zoneinfo[i][1]);
1387                   }
1388                 else
1389                   {
1390                     if (style == SHORT)
1391                       return (zoneinfo[i][4]);
1392                     else
1393                       return (zoneinfo[i][3]);
1394                   }
1395               }
1396           }
1397       }
1398     catch (MissingResourceException e)
1399       {
1400       }
1401 
1402     return getDefaultDisplayName(dst);
1403   }
1404 
getDefaultDisplayName(boolean dst)1405   private String getDefaultDisplayName(boolean dst)
1406   {
1407     int offset = getRawOffset() + (dst ? getDSTSavings() : 0);
1408 
1409     CPStringBuilder sb = new CPStringBuilder(9);
1410     sb.append("GMT");
1411 
1412     offset = offset / (1000 * 60);
1413     int hours = Math.abs(offset) / 60;
1414     int minutes = Math.abs(offset) % 60;
1415 
1416     if (minutes != 0 || hours != 0)
1417       {
1418         sb.append(offset >= 0 ? '+' : '-');
1419         sb.append((char) ('0' + hours / 10));
1420         sb.append((char) ('0' + hours % 10));
1421         sb.append(':');
1422         sb.append((char) ('0' + minutes / 10));
1423         sb.append((char) ('0' + minutes % 10));
1424       }
1425 
1426     return sb.toString();
1427   }
1428 
1429   /**
1430    * Returns true, if this time zone uses Daylight Savings Time.
1431    */
useDaylightTime()1432   public abstract boolean useDaylightTime();
1433 
1434   /**
1435    * Returns true, if the given date is in Daylight Savings Time in this
1436    * time zone.
1437    * @param date the given Date.
1438    */
inDaylightTime(Date date)1439   public abstract boolean inDaylightTime(Date date);
1440 
1441   /**
1442    * Gets the daylight savings offset.  This is a positive offset in
1443    * milliseconds with respect to standard time.  Typically this
1444    * is one hour, but for some time zones this may be half an our.
1445    * <p>The default implementation returns 3600000 milliseconds
1446    * (one hour) if the time zone uses daylight savings time
1447    * (as specified by {@link #useDaylightTime()}), otherwise
1448    * it returns 0.
1449    * @return the daylight savings offset in milliseconds.
1450    * @since 1.4
1451    */
getDSTSavings()1452   public int getDSTSavings ()
1453   {
1454     return useDaylightTime () ? 3600000 : 0;
1455   }
1456 
1457   /**
1458    * Gets the TimeZone for the given ID.
1459    * @param ID the time zone identifier.
1460    * @return The time zone for the identifier or GMT, if no such time
1461    * zone exists.
1462    */
getTimeZoneInternal(String ID)1463   private static TimeZone getTimeZoneInternal(String ID)
1464   {
1465     // First check timezones hash
1466     TimeZone tz = null;
1467     TimeZone tznew = null;
1468     for (int pass = 0; pass < 2; pass++)
1469       {
1470         synchronized (TimeZone.class)
1471           {
1472             tz = timezones().get(ID);
1473             if (tz != null)
1474               {
1475                 if (!tz.getID().equals(ID))
1476                   {
1477                     // We always return a timezone with the requested ID.
1478                     // This is the same behaviour as with JDK1.2.
1479                     tz = (TimeZone) tz.clone();
1480                     tz.setID(ID);
1481                     // We also save the alias, so that we return the same
1482                     // object again if getTimeZone is called with the same
1483                     // alias.
1484                     timezones().put(ID, tz);
1485                   }
1486                 return tz;
1487               }
1488             else if (tznew != null)
1489               {
1490                 timezones().put(ID, tznew);
1491                 return tznew;
1492               }
1493           }
1494 
1495         if (pass == 1 || zoneinfo_dir == null)
1496           return null;
1497 
1498         // aliases0 is never changing after first timezones(), so should
1499         // be safe without synchronization.
1500         String zonename = aliases0.get(ID);
1501         if (zonename == null)
1502           zonename = ID;
1503 
1504         // Read the file outside of the critical section, it is expensive.
1505         tznew = ZoneInfo.readTZFile (ID, zoneinfo_dir
1506                                      + File.separatorChar + zonename);
1507         if (tznew == null)
1508           return null;
1509       }
1510 
1511     return null;
1512   }
1513 
1514   /**
1515    * Gets the TimeZone for the given ID.
1516    * @param ID the time zone identifier.
1517    * @return The time zone for the identifier or GMT, if no such time
1518    * zone exists.
1519    */
getTimeZone(String ID)1520   public static TimeZone getTimeZone(String ID)
1521   {
1522     // Check for custom IDs first
1523     if (ID.startsWith("GMT") && ID.length() > 3)
1524       {
1525         int pos = 3;
1526         int offset_direction = 1;
1527 
1528         if (ID.charAt(pos) == '-')
1529           {
1530             offset_direction = -1;
1531             pos++;
1532           }
1533         else if (ID.charAt(pos) == '+')
1534           {
1535             pos++;
1536           }
1537 
1538         try
1539           {
1540             int hour, minute;
1541 
1542             String offset_str = ID.substring(pos);
1543             int idx = offset_str.indexOf(":");
1544             if (idx != -1)
1545               {
1546                 hour = Integer.parseInt(offset_str.substring(0, idx));
1547                 minute = Integer.parseInt(offset_str.substring(idx + 1));
1548               }
1549             else
1550               {
1551                 int offset_length = offset_str.length();
1552                 if (offset_length <= 2)
1553                   {
1554                     // Only hour
1555                     hour = Integer.parseInt(offset_str);
1556                     minute = 0;
1557                   }
1558                 else
1559                   {
1560                     // hour and minute, not separated by colon
1561                     hour = Integer.parseInt
1562                       (offset_str.substring(0, offset_length - 2));
1563                     minute = Integer.parseInt
1564                       (offset_str.substring(offset_length - 2));
1565                   }
1566               }
1567 
1568             // Custom IDs have to be normalized
1569             CPStringBuilder sb = new CPStringBuilder(9);
1570             sb.append("GMT");
1571 
1572             sb.append(offset_direction >= 0 ? '+' : '-');
1573             sb.append((char) ('0' + hour / 10));
1574             sb.append((char) ('0' + hour % 10));
1575             sb.append(':');
1576             sb.append((char) ('0' + minute / 10));
1577             sb.append((char) ('0' + minute % 10));
1578             ID = sb.toString();
1579 
1580             return new SimpleTimeZone((hour * (60 * 60 * 1000)
1581                                        + minute * (60 * 1000))
1582                                       * offset_direction, ID);
1583           }
1584         catch (NumberFormatException e)
1585           {
1586           }
1587       }
1588 
1589     TimeZone tz = getTimeZoneInternal(ID);
1590     if (tz != null)
1591       return tz;
1592 
1593     return new SimpleTimeZone(0, "GMT");
1594   }
1595 
1596   /**
1597    * Gets the available IDs according to the given time zone
1598    * offset.
1599    * @param rawOffset the given time zone GMT offset.
1600    * @return An array of IDs, where the time zone has the specified GMT
1601    * offset. For example <code>{"Phoenix", "Denver"}</code>, since both have
1602    * GMT-07:00, but differ in daylight savings behaviour.
1603    */
getAvailableIDs(int rawOffset)1604   public static String[] getAvailableIDs(int rawOffset)
1605   {
1606     synchronized (TimeZone.class)
1607       {
1608         HashMap<String,TimeZone> h = timezones();
1609         int count = 0;
1610         if (zoneinfo_dir == null)
1611           {
1612             Iterator<Map.Entry<String,TimeZone>> iter = h.entrySet().iterator();
1613             while (iter.hasNext())
1614               {
1615                 // Don't iterate the values, since we want to count
1616                 // doubled values (aliases)
1617                 Map.Entry<String,TimeZone> entry = iter.next();
1618                 if (entry.getValue().getRawOffset() == rawOffset)
1619                   count++;
1620               }
1621 
1622             String[] ids = new String[count];
1623             count = 0;
1624             iter = h.entrySet().iterator();
1625             while (iter.hasNext())
1626               {
1627                 Map.Entry<String,TimeZone> entry = iter.next();
1628                 if (entry.getValue().getRawOffset() == rawOffset)
1629                   ids[count++] = (String) entry.getKey();
1630               }
1631             return ids;
1632           }
1633       }
1634 
1635     String[] s = getAvailableIDs();
1636     int count = 0;
1637     for (int i = 0; i < s.length; i++)
1638       {
1639         TimeZone t = getTimeZoneInternal(s[i]);
1640         if (t == null || t.getRawOffset() != rawOffset)
1641           s[i] = null;
1642         else
1643           count++;
1644       }
1645     String[] ids = new String[count];
1646     count = 0;
1647     for (int i = 0; i < s.length; i++)
1648     if (s[i] != null)
1649       ids[count++] = s[i];
1650 
1651     return ids;
1652   }
1653 
getAvailableIDs(File d, String prefix, ArrayList<String[]> list)1654   private static int getAvailableIDs(File d, String prefix, ArrayList<String[]> list)
1655     {
1656       String[] files = d.list();
1657       int count = files.length;
1658       boolean top = prefix.length() == 0;
1659       list.add (files);
1660       for (int i = 0; i < files.length; i++)
1661         {
1662           if (top
1663               && (files[i].equals("posix")
1664                   || files[i].equals("right")
1665                   || files[i].endsWith(".tab")
1666                   || aliases0.get(files[i]) != null))
1667             {
1668               files[i] = null;
1669               count--;
1670               continue;
1671             }
1672 
1673           File f = new File(d, files[i]);
1674           if (f.isDirectory())
1675             {
1676               count += getAvailableIDs(f, prefix + files[i]
1677                                        + File.separatorChar, list) - 1;
1678               files[i] = null;
1679             }
1680           else
1681             files[i] = prefix + files[i];
1682         }
1683       return count;
1684     }
1685 
1686   /**
1687    * Gets all available IDs.
1688    * @return An array of all supported IDs.
1689    */
getAvailableIDs()1690   public static String[] getAvailableIDs()
1691   {
1692     synchronized (TimeZone.class)
1693       {
1694         HashMap<String,TimeZone> h = timezones();
1695         if (zoneinfo_dir == null)
1696           return h.keySet().toArray(new String[h.size()]);
1697 
1698         if (availableIDs != null)
1699           {
1700             String[] ids = new String[availableIDs.length];
1701             for (int i = 0; i < availableIDs.length; i++)
1702               ids[i] = availableIDs[i];
1703             return ids;
1704           }
1705 
1706         File d = new File(zoneinfo_dir);
1707         ArrayList<String[]> list = new ArrayList<String[]>(30);
1708         int count = getAvailableIDs(d, "", list) + aliases0.size();
1709         availableIDs = new String[count];
1710         String[] ids = new String[count];
1711 
1712         count = 0;
1713         for (int i = 0; i < list.size(); i++)
1714           {
1715             String[] s = list.get(i);
1716             for (int j = 0; j < s.length; j++)
1717               if (s[j] != null)
1718                 {
1719                   availableIDs[count] = s[j];
1720                   ids[count++] = s[j];
1721                 }
1722           }
1723 
1724         Iterator<Map.Entry<String,String>> iter = aliases0.entrySet().iterator();
1725         while (iter.hasNext())
1726           {
1727             Map.Entry<String,String> entry = iter.next();
1728             availableIDs[count] = entry.getKey();
1729             ids[count++] = entry.getKey();
1730           }
1731 
1732         return ids;
1733       }
1734   }
1735 
1736   /**
1737    * Returns the time zone under which the host is running.  This
1738    * can be changed with setDefault.
1739    *
1740    * @return A clone of the current default time zone for this host.
1741    * @see #setDefault
1742    */
getDefault()1743   public static TimeZone getDefault()
1744   {
1745     return (TimeZone) defaultZone().clone();
1746   }
1747 
setDefault(TimeZone zone)1748   public static void setDefault(TimeZone zone)
1749   {
1750     // Hmmmm. No Security checks?
1751     defaultZone0 = zone;
1752   }
1753 
1754   /**
1755    * Test if the other time zone uses the same rule and only
1756    * possibly differs in ID.  This implementation for this particular
1757    * class will return true if the raw offsets are identical.  Subclasses
1758    * should override this method if they use daylight savings.
1759    * @return true if this zone has the same raw offset
1760    */
hasSameRules(TimeZone other)1761   public boolean hasSameRules(TimeZone other)
1762   {
1763     return other.getRawOffset() == getRawOffset();
1764   }
1765 
1766   /**
1767    * Returns a clone of this object.  I can't imagine, why this is
1768    * useful for a time zone.
1769    */
clone()1770   public Object clone()
1771   {
1772     try
1773       {
1774         return super.clone();
1775       }
1776     catch (CloneNotSupportedException ex)
1777       {
1778         return null;
1779       }
1780   }
1781 }
1782