2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
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)
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.
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
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
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. */
42 import java.security.AccessController;
43 import java.security.PrivilegedAction;
44 import java.text.DateFormatSymbols;
47 * This class represents a time zone offset and handles daylight savings.
49 * You can get the default time zone with <code>getDefault</code>.
50 * This represents the time zone where program is running.
52 * Another way to create a time zone is <code>getTimeZone</code>, where
53 * you can give an identifier as parameter. For instance, the identifier
54 * of the Central European Time zone is "CET".
56 * With the <code>getAvailableIDs</code> method, you can get all the
57 * supported time zone identifiers.
61 * @author Jochen Hoenicke
63 public abstract class TimeZone implements java.io.Serializable, Cloneable
67 * Constant used to indicate that a short timezone abbreviation should
68 * be returned, such as "EST"
70 public static final int SHORT = 0;
73 * Constant used to indicate that a long timezone name should be
74 * returned, such as "Eastern Standard Time".
76 public static final int LONG = 1;
79 * The time zone identifier, e.g. PST.
84 * The default time zone, as returned by getDefault.
86 private static TimeZone defaultZone0;
89 * Tries to get the default TimeZone for this system if not already
90 * set. It will call <code>getDefaultTimeZone(String)</code> with
91 * the result of <code>System.getProperty("user.timezone")</code>.
92 * If that fails it calls <code>VMTimeZone.getDefaultTimeZoneId()</code>.
93 * If that also fails GMT is returned.
95 private static synchronized TimeZone defaultZone()
97 /* Look up default timezone */
98 if (defaultZone0 == null)
100 defaultZone0 = (TimeZone) AccessController.doPrivileged
101 (new PrivilegedAction()
105 TimeZone zone = null;
107 // Prefer System property user.timezone.
108 String tzid = System.getProperty("user.timezone");
109 if (tzid != null && !tzid.equals(""))
110 zone = getDefaultTimeZone(tzid);
112 // Try platfom specific way.
114 zone = VMTimeZone.getDefaultTimeZoneId();
118 zone = (TimeZone) timezones().get("GMT");
128 private static final long serialVersionUID = 3581463369166924961L;
131 * HashMap for timezones by ID.
133 private static HashMap timezones0;
134 /* initialize this static field lazily to overhead if
137 // Package-private to avoid a trampoline.
138 static synchronized HashMap timezones()
140 if (timezones0 == null)
142 HashMap timezones = new HashMap();
143 timezones0 = timezones;
146 // Automatically generated by scripts/timezones.pl
147 // XXX - Should we read this data from a file?
148 tz = new SimpleTimeZone(-11000 * 3600, "MIT");
149 timezones0.put("MIT", tz);
150 timezones0.put("Pacific/Apia", tz);
151 timezones0.put("Pacific/Midway", tz);
152 timezones0.put("Pacific/Niue", tz);
153 timezones0.put("Pacific/Pago_Pago", tz);
154 tz = new SimpleTimeZone
155 (-10000 * 3600, "America/Adak",
156 Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
157 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
158 timezones0.put("America/Adak", tz);
159 tz = new SimpleTimeZone(-10000 * 3600, "HST");
160 timezones0.put("HST", tz);
161 timezones0.put("Pacific/Fakaofo", tz);
162 timezones0.put("Pacific/Honolulu", tz);
163 timezones0.put("Pacific/Johnston", tz);
164 timezones0.put("Pacific/Rarotonga", tz);
165 timezones0.put("Pacific/Tahiti", tz);
166 tz = new SimpleTimeZone(-9500 * 3600, "Pacific/Marquesas");
167 timezones0.put("Pacific/Marquesas", tz);
168 tz = new SimpleTimeZone
169 (-9000 * 3600, "AST",
170 Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
171 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
172 timezones0.put("AST", tz);
173 timezones0.put("America/Anchorage", tz);
174 timezones0.put("America/Juneau", tz);
175 timezones0.put("America/Nome", tz);
176 timezones0.put("America/Yakutat", tz);
177 tz = new SimpleTimeZone(-9000 * 3600, "Pacific/Gambier");
178 timezones0.put("Pacific/Gambier", tz);
179 tz = new SimpleTimeZone
180 (-8000 * 3600, "America/Tijuana",
181 Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
182 Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
183 timezones0.put("America/Tijuana", tz);
184 tz = new SimpleTimeZone
185 (-8000 * 3600, "PST",
186 Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
187 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
188 timezones0.put("PST", tz);
189 timezones0.put("PST8PDT", tz);
190 timezones0.put("America/Dawson", tz);
191 timezones0.put("America/Los_Angeles", tz);
192 timezones0.put("America/Vancouver", tz);
193 timezones0.put("America/Whitehorse", tz);
194 timezones0.put("US/Pacific-New", tz);
195 tz = new SimpleTimeZone(-8000 * 3600, "Pacific/Pitcairn");
196 timezones0.put("Pacific/Pitcairn", tz);
197 tz = new SimpleTimeZone
198 (-7000 * 3600, "America/Chihuahua",
199 Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
200 Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
201 timezones0.put("America/Chihuahua", tz);
202 timezones0.put("America/Mazatlan", tz);
203 tz = new SimpleTimeZone(-7000 * 3600, "MST7");
204 timezones0.put("MST7", tz);
205 timezones0.put("PNT", tz);
206 timezones0.put("America/Dawson_Creek", tz);
207 timezones0.put("America/Hermosillo", tz);
208 timezones0.put("America/Phoenix", tz);
209 tz = new SimpleTimeZone
210 (-7000 * 3600, "MST",
211 Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
212 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
213 timezones0.put("MST", tz);
214 timezones0.put("MST7MDT", tz);
215 timezones0.put("America/Boise", tz);
216 timezones0.put("America/Cambridge_Bay", tz);
217 timezones0.put("America/Denver", tz);
218 timezones0.put("America/Edmonton", tz);
219 timezones0.put("America/Inuvik", tz);
220 timezones0.put("America/Shiprock", tz);
221 timezones0.put("America/Yellowknife", tz);
222 tz = new SimpleTimeZone
223 (-6000 * 3600, "America/Cancun",
224 Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
225 Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
226 timezones0.put("America/Cancun", tz);
227 timezones0.put("America/Merida", tz);
228 timezones0.put("America/Mexico_City", tz);
229 timezones0.put("America/Monterrey", tz);
230 tz = new SimpleTimeZone(-6000 * 3600, "America/Belize");
231 timezones0.put("America/Belize", tz);
232 timezones0.put("America/Costa_Rica", tz);
233 timezones0.put("America/El_Salvador", tz);
234 timezones0.put("America/Guatemala", tz);
235 timezones0.put("America/Managua", tz);
236 timezones0.put("America/Regina", tz);
237 timezones0.put("America/Swift_Current", tz);
238 timezones0.put("America/Tegucigalpa", tz);
239 timezones0.put("Pacific/Galapagos", tz);
240 tz = new SimpleTimeZone
241 (-6000 * 3600, "CST",
242 Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
243 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
244 timezones0.put("CST", tz);
245 timezones0.put("CST6CDT", tz);
246 timezones0.put("America/Chicago", tz);
247 timezones0.put("America/Indiana/Knox", tz);
248 timezones0.put("America/Indiana/Petersburg", tz);
249 timezones0.put("America/Indiana/Vincennes", tz);
250 timezones0.put("America/Menominee", tz);
251 timezones0.put("America/North_Dakota/Center", tz);
252 timezones0.put("America/North_Dakota/New_Salem", tz);
253 timezones0.put("America/Rainy_River", tz);
254 timezones0.put("America/Rankin_Inlet", tz);
255 timezones0.put("America/Winnipeg", tz);
256 tz = new SimpleTimeZone
257 (-6000 * 3600, "Pacific/Easter",
258 Calendar.OCTOBER, 2, Calendar.SATURDAY, 22000 * 3600,
259 Calendar.MARCH, 2, Calendar.SATURDAY, 22000 * 3600);
260 timezones0.put("Pacific/Easter", tz);
261 tz = new SimpleTimeZone(-5000 * 3600, "EST5");
262 timezones0.put("EST5", tz);
263 timezones0.put("IET", tz);
264 timezones0.put("America/Atikokan", tz);
265 timezones0.put("America/Bogota", tz);
266 timezones0.put("America/Cayman", tz);
267 timezones0.put("America/Eirunepe", tz);
268 timezones0.put("America/Guayaquil", tz);
269 timezones0.put("America/Jamaica", tz);
270 timezones0.put("America/Lima", tz);
271 timezones0.put("America/Panama", tz);
272 timezones0.put("America/Rio_Branco", tz);
273 tz = new SimpleTimeZone
274 (-5000 * 3600, "America/Havana",
275 Calendar.APRIL, 1, Calendar.SUNDAY, 0 * 3600,
276 Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600);
277 timezones0.put("America/Havana", tz);
278 tz = new SimpleTimeZone
279 (-5000 * 3600, "America/Grand_Turk",
280 Calendar.APRIL, 1, Calendar.SUNDAY, 0 * 3600,
281 Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
282 timezones0.put("America/Grand_Turk", tz);
283 timezones0.put("America/Port-au-Prince", tz);
284 tz = new SimpleTimeZone
285 (-5000 * 3600, "EST",
286 Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
287 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
288 timezones0.put("EST", tz);
289 timezones0.put("EST5EDT", tz);
290 timezones0.put("America/Detroit", tz);
291 timezones0.put("America/Indiana/Indianapolis", tz);
292 timezones0.put("America/Indiana/Marengo", tz);
293 timezones0.put("America/Indiana/Vevay", tz);
294 timezones0.put("America/Iqaluit", tz);
295 timezones0.put("America/Kentucky/Louisville", tz);
296 timezones0.put("America/Kentucky/Monticello", tz);
297 timezones0.put("America/Montreal", tz);
298 timezones0.put("America/Nassau", tz);
299 timezones0.put("America/New_York", tz);
300 timezones0.put("America/Nipigon", tz);
301 timezones0.put("America/Pangnirtung", tz);
302 timezones0.put("America/Thunder_Bay", tz);
303 timezones0.put("America/Toronto", tz);
304 tz = new SimpleTimeZone
305 (-4000 * 3600, "America/Asuncion",
306 Calendar.OCTOBER, 3, Calendar.SUNDAY, 0 * 3600,
307 Calendar.MARCH, 2, Calendar.SUNDAY, 0 * 3600);
308 timezones0.put("America/Asuncion", tz);
309 tz = new SimpleTimeZone(-4000 * 3600, "PRT");
310 timezones0.put("PRT", tz);
311 timezones0.put("America/Anguilla", tz);
312 timezones0.put("America/Antigua", tz);
313 timezones0.put("America/Aruba", tz);
314 timezones0.put("America/Barbados", tz);
315 timezones0.put("America/Blanc-Sablon", tz);
316 timezones0.put("America/Boa_Vista", tz);
317 timezones0.put("America/Caracas", tz);
318 timezones0.put("America/Curacao", tz);
319 timezones0.put("America/Dominica", tz);
320 timezones0.put("America/Grenada", tz);
321 timezones0.put("America/Guadeloupe", tz);
322 timezones0.put("America/Guyana", tz);
323 timezones0.put("America/La_Paz", tz);
324 timezones0.put("America/Manaus", tz);
325 timezones0.put("America/Martinique", tz);
326 timezones0.put("America/Montserrat", tz);
327 timezones0.put("America/Port_of_Spain", tz);
328 timezones0.put("America/Porto_Velho", tz);
329 timezones0.put("America/Puerto_Rico", tz);
330 timezones0.put("America/Santo_Domingo", tz);
331 timezones0.put("America/St_Kitts", tz);
332 timezones0.put("America/St_Lucia", tz);
333 timezones0.put("America/St_Thomas", tz);
334 timezones0.put("America/St_Vincent", tz);
335 timezones0.put("America/Tortola", tz);
336 tz = new SimpleTimeZone
337 (-4000 * 3600, "America/Campo_Grande",
338 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 0 * 3600,
339 Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600);
340 timezones0.put("America/Campo_Grande", tz);
341 timezones0.put("America/Cuiaba", tz);
342 tz = new SimpleTimeZone
343 (-4000 * 3600, "America/Goose_Bay",
344 Calendar.MARCH, 2, Calendar.SUNDAY, 60000,
345 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 60000);
346 timezones0.put("America/Goose_Bay", tz);
347 tz = new SimpleTimeZone
348 (-4000 * 3600, "America/Glace_Bay",
349 Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
350 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
351 timezones0.put("America/Glace_Bay", tz);
352 timezones0.put("America/Halifax", tz);
353 timezones0.put("America/Moncton", tz);
354 timezones0.put("America/Thule", tz);
355 timezones0.put("Atlantic/Bermuda", tz);
356 tz = new SimpleTimeZone
357 (-4000 * 3600, "America/Santiago",
358 Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * 3600,
359 Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * 3600);
360 timezones0.put("America/Santiago", tz);
361 timezones0.put("Antarctica/Palmer", tz);
362 tz = new SimpleTimeZone
363 (-4000 * 3600, "Atlantic/Stanley",
364 Calendar.SEPTEMBER, 1, Calendar.SUNDAY, 2000 * 3600,
365 Calendar.APRIL, 3, Calendar.SUNDAY, 2000 * 3600);
366 timezones0.put("Atlantic/Stanley", tz);
367 tz = new SimpleTimeZone
368 (-3500 * 3600, "CNT",
369 Calendar.MARCH, 2, Calendar.SUNDAY, 60000,
370 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 60000);
371 timezones0.put("CNT", tz);
372 timezones0.put("America/St_Johns", tz);
373 tz = new SimpleTimeZone
374 (-3000 * 3600, "America/Godthab",
375 Calendar.MARCH, 30, -Calendar.SATURDAY, 22000 * 3600,
376 Calendar.OCTOBER, 30, -Calendar.SATURDAY, 23000 * 3600);
377 timezones0.put("America/Godthab", tz);
378 tz = new SimpleTimeZone
379 (-3000 * 3600, "America/Miquelon",
380 Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600,
381 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600);
382 timezones0.put("America/Miquelon", tz);
383 tz = new SimpleTimeZone
384 (-3000 * 3600, "America/Montevideo",
385 Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
386 Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600);
387 timezones0.put("America/Montevideo", tz);
388 tz = new SimpleTimeZone
389 (-3000 * 3600, "America/Sao_Paulo",
390 Calendar.NOVEMBER, 1, Calendar.SUNDAY, 0 * 3600,
391 Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600);
392 timezones0.put("America/Sao_Paulo", tz);
393 tz = new SimpleTimeZone(-3000 * 3600, "AGT");
394 timezones0.put("AGT", tz);
395 timezones0.put("America/Araguaina", tz);
396 timezones0.put("America/Argentina/Buenos_Aires", tz);
397 timezones0.put("America/Argentina/Catamarca", tz);
398 timezones0.put("America/Argentina/Cordoba", tz);
399 timezones0.put("America/Argentina/Jujuy", tz);
400 timezones0.put("America/Argentina/La_Rioja", tz);
401 timezones0.put("America/Argentina/Mendoza", tz);
402 timezones0.put("America/Argentina/Rio_Gallegos", tz);
403 timezones0.put("America/Argentina/San_Juan", tz);
404 timezones0.put("America/Argentina/Tucuman", tz);
405 timezones0.put("America/Argentina/Ushuaia", tz);
406 timezones0.put("America/Bahia", tz);
407 timezones0.put("America/Belem", tz);
408 timezones0.put("America/Cayenne", tz);
409 timezones0.put("America/Fortaleza", tz);
410 timezones0.put("America/Maceio", tz);
411 timezones0.put("America/Paramaribo", tz);
412 timezones0.put("America/Recife", tz);
413 timezones0.put("Antarctica/Rothera", tz);
414 tz = new SimpleTimeZone(-2000 * 3600, "America/Noronha");
415 timezones0.put("America/Noronha", tz);
416 timezones0.put("Atlantic/South_Georgia", tz);
417 tz = new SimpleTimeZone
418 (-1000 * 3600, "America/Scoresbysund",
419 Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
420 Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600);
421 timezones0.put("America/Scoresbysund", tz);
422 timezones0.put("Atlantic/Azores", tz);
423 tz = new SimpleTimeZone(-1000 * 3600, "Atlantic/Cape_Verde");
424 timezones0.put("Atlantic/Cape_Verde", tz);
425 tz = new SimpleTimeZone(0 * 3600, "GMT");
426 timezones0.put("GMT", tz);
427 timezones0.put("UTC", tz);
428 timezones0.put("Africa/Abidjan", tz);
429 timezones0.put("Africa/Accra", tz);
430 timezones0.put("Africa/Bamako", tz);
431 timezones0.put("Africa/Banjul", tz);
432 timezones0.put("Africa/Bissau", tz);
433 timezones0.put("Africa/Casablanca", tz);
434 timezones0.put("Africa/Conakry", tz);
435 timezones0.put("Africa/Dakar", tz);
436 timezones0.put("Africa/El_Aaiun", tz);
437 timezones0.put("Africa/Freetown", tz);
438 timezones0.put("Africa/Lome", tz);
439 timezones0.put("Africa/Monrovia", tz);
440 timezones0.put("Africa/Nouakchott", tz);
441 timezones0.put("Africa/Ouagadougou", tz);
442 timezones0.put("Africa/Sao_Tome", tz);
443 timezones0.put("America/Danmarkshavn", tz);
444 timezones0.put("Atlantic/Reykjavik", tz);
445 timezones0.put("Atlantic/St_Helena", tz);
446 tz = new SimpleTimeZone
448 Calendar.MARCH, -1, Calendar.SUNDAY, 1000 * 3600,
449 Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
450 timezones0.put("WET", tz);
451 timezones0.put("Atlantic/Canary", tz);
452 timezones0.put("Atlantic/Faroe", tz);
453 timezones0.put("Atlantic/Madeira", tz);
454 timezones0.put("Europe/Dublin", tz);
455 timezones0.put("Europe/Guernsey", tz);
456 timezones0.put("Europe/Isle_of_Man", tz);
457 timezones0.put("Europe/Jersey", tz);
458 timezones0.put("Europe/Lisbon", tz);
459 timezones0.put("Europe/London", tz);
460 tz = new SimpleTimeZone(1000 * 3600, "Africa/Algiers");
461 timezones0.put("Africa/Algiers", tz);
462 timezones0.put("Africa/Bangui", tz);
463 timezones0.put("Africa/Brazzaville", tz);
464 timezones0.put("Africa/Douala", tz);
465 timezones0.put("Africa/Kinshasa", tz);
466 timezones0.put("Africa/Lagos", tz);
467 timezones0.put("Africa/Libreville", tz);
468 timezones0.put("Africa/Luanda", tz);
469 timezones0.put("Africa/Malabo", tz);
470 timezones0.put("Africa/Ndjamena", tz);
471 timezones0.put("Africa/Niamey", tz);
472 timezones0.put("Africa/Porto-Novo", tz);
473 tz = new SimpleTimeZone
474 (1000 * 3600, "Africa/Windhoek",
475 Calendar.SEPTEMBER, 1, Calendar.SUNDAY, 2000 * 3600,
476 Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600);
477 timezones0.put("Africa/Windhoek", tz);
478 tz = new SimpleTimeZone
480 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
481 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
482 timezones0.put("CET", tz);
483 timezones0.put("ECT", tz);
484 timezones0.put("MET", tz);
485 timezones0.put("Africa/Ceuta", tz);
486 timezones0.put("Africa/Tunis", tz);
487 timezones0.put("Arctic/Longyearbyen", tz);
488 timezones0.put("Atlantic/Jan_Mayen", tz);
489 timezones0.put("Europe/Amsterdam", tz);
490 timezones0.put("Europe/Andorra", tz);
491 timezones0.put("Europe/Belgrade", tz);
492 timezones0.put("Europe/Berlin", tz);
493 timezones0.put("Europe/Bratislava", tz);
494 timezones0.put("Europe/Brussels", tz);
495 timezones0.put("Europe/Budapest", tz);
496 timezones0.put("Europe/Copenhagen", tz);
497 timezones0.put("Europe/Gibraltar", tz);
498 timezones0.put("Europe/Ljubljana", tz);
499 timezones0.put("Europe/Luxembourg", tz);
500 timezones0.put("Europe/Madrid", tz);
501 timezones0.put("Europe/Malta", tz);
502 timezones0.put("Europe/Monaco", tz);
503 timezones0.put("Europe/Oslo", tz);
504 timezones0.put("Europe/Paris", tz);
505 timezones0.put("Europe/Podgorica", tz);
506 timezones0.put("Europe/Prague", tz);
507 timezones0.put("Europe/Rome", tz);
508 timezones0.put("Europe/San_Marino", tz);
509 timezones0.put("Europe/Sarajevo", tz);
510 timezones0.put("Europe/Skopje", tz);
511 timezones0.put("Europe/Stockholm", tz);
512 timezones0.put("Europe/Tirane", tz);
513 timezones0.put("Europe/Vaduz", tz);
514 timezones0.put("Europe/Vatican", tz);
515 timezones0.put("Europe/Vienna", tz);
516 timezones0.put("Europe/Warsaw", tz);
517 timezones0.put("Europe/Zagreb", tz);
518 timezones0.put("Europe/Zurich", tz);
519 tz = new SimpleTimeZone
521 Calendar.APRIL, -1, Calendar.FRIDAY, 0 * 3600,
522 Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 24000 * 3600);
523 timezones0.put("ART", tz);
524 timezones0.put("Africa/Cairo", tz);
525 tz = new SimpleTimeZone(2000 * 3600, "CAT");
526 timezones0.put("CAT", tz);
527 timezones0.put("Africa/Blantyre", tz);
528 timezones0.put("Africa/Bujumbura", tz);
529 timezones0.put("Africa/Gaborone", tz);
530 timezones0.put("Africa/Harare", tz);
531 timezones0.put("Africa/Johannesburg", tz);
532 timezones0.put("Africa/Kigali", tz);
533 timezones0.put("Africa/Lubumbashi", tz);
534 timezones0.put("Africa/Lusaka", tz);
535 timezones0.put("Africa/Maputo", tz);
536 timezones0.put("Africa/Maseru", tz);
537 timezones0.put("Africa/Mbabane", tz);
538 timezones0.put("Africa/Tripoli", tz);
539 timezones0.put("Asia/Jerusalem", tz);
540 tz = new SimpleTimeZone
541 (2000 * 3600, "Asia/Amman",
542 Calendar.MARCH, -1, Calendar.THURSDAY, 0 * 3600,
543 Calendar.OCTOBER, -1, Calendar.FRIDAY, 1000 * 3600);
544 timezones0.put("Asia/Amman", tz);
545 tz = new SimpleTimeZone
546 (2000 * 3600, "Asia/Beirut",
547 Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
548 Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
549 timezones0.put("Asia/Beirut", tz);
550 tz = new SimpleTimeZone
551 (2000 * 3600, "Asia/Damascus",
552 Calendar.APRIL, 1, 0, 0 * 3600,
553 Calendar.OCTOBER, 1, 0, 0 * 3600);
554 timezones0.put("Asia/Damascus", tz);
555 tz = new SimpleTimeZone
556 (2000 * 3600, "Asia/Gaza",
557 Calendar.APRIL, 1, 0, 0 * 3600,
558 Calendar.OCTOBER, 3, Calendar.FRIDAY, 0 * 3600);
559 timezones0.put("Asia/Gaza", tz);
560 tz = new SimpleTimeZone
562 Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600,
563 Calendar.OCTOBER, -1, Calendar.SUNDAY, 4000 * 3600);
564 timezones0.put("EET", tz);
565 timezones0.put("Asia/Istanbul", tz);
566 timezones0.put("Asia/Nicosia", tz);
567 timezones0.put("Europe/Athens", tz);
568 timezones0.put("Europe/Bucharest", tz);
569 timezones0.put("Europe/Chisinau", tz);
570 timezones0.put("Europe/Helsinki", tz);
571 timezones0.put("Europe/Istanbul", tz);
572 timezones0.put("Europe/Kiev", tz);
573 timezones0.put("Europe/Mariehamn", tz);
574 timezones0.put("Europe/Nicosia", tz);
575 timezones0.put("Europe/Riga", tz);
576 timezones0.put("Europe/Simferopol", tz);
577 timezones0.put("Europe/Sofia", tz);
578 timezones0.put("Europe/Tallinn", tz);
579 timezones0.put("Europe/Uzhgorod", tz);
580 timezones0.put("Europe/Vilnius", tz);
581 timezones0.put("Europe/Zaporozhye", tz);
582 tz = new SimpleTimeZone
583 (2000 * 3600, "Europe/Kaliningrad",
584 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
585 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
586 timezones0.put("Europe/Kaliningrad", tz);
587 timezones0.put("Europe/Minsk", tz);
588 tz = new SimpleTimeZone
589 (3000 * 3600, "Asia/Baghdad",
590 Calendar.APRIL, 1, 0, 3000 * 3600,
591 Calendar.OCTOBER, 1, 0, 4000 * 3600);
592 timezones0.put("Asia/Baghdad", tz);
593 tz = new SimpleTimeZone
594 (3000 * 3600, "Europe/Moscow",
595 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
596 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
597 timezones0.put("Europe/Moscow", tz);
598 timezones0.put("Europe/Volgograd", tz);
599 tz = new SimpleTimeZone(3000 * 3600, "EAT");
600 timezones0.put("EAT", tz);
601 timezones0.put("Africa/Addis_Ababa", tz);
602 timezones0.put("Africa/Asmara", tz);
603 timezones0.put("Africa/Dar_es_Salaam", tz);
604 timezones0.put("Africa/Djibouti", tz);
605 timezones0.put("Africa/Kampala", tz);
606 timezones0.put("Africa/Khartoum", tz);
607 timezones0.put("Africa/Mogadishu", tz);
608 timezones0.put("Africa/Nairobi", tz);
609 timezones0.put("Antarctica/Syowa", tz);
610 timezones0.put("Asia/Aden", tz);
611 timezones0.put("Asia/Bahrain", tz);
612 timezones0.put("Asia/Kuwait", tz);
613 timezones0.put("Asia/Qatar", tz);
614 timezones0.put("Asia/Riyadh", tz);
615 timezones0.put("Indian/Antananarivo", tz);
616 timezones0.put("Indian/Comoro", tz);
617 timezones0.put("Indian/Mayotte", tz);
618 tz = new SimpleTimeZone(3500 * 3600, "Asia/Tehran");
619 timezones0.put("Asia/Tehran", tz);
620 tz = new SimpleTimeZone
621 (4000 * 3600, "Asia/Baku",
622 Calendar.MARCH, -1, Calendar.SUNDAY, 4000 * 3600,
623 Calendar.OCTOBER, -1, Calendar.SUNDAY, 5000 * 3600);
624 timezones0.put("Asia/Baku", tz);
625 tz = new SimpleTimeZone
626 (4000 * 3600, "Asia/Yerevan",
627 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
628 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
629 timezones0.put("Asia/Yerevan", tz);
630 timezones0.put("Europe/Samara", tz);
631 tz = new SimpleTimeZone(4000 * 3600, "NET");
632 timezones0.put("NET", tz);
633 timezones0.put("Asia/Dubai", tz);
634 timezones0.put("Asia/Muscat", tz);
635 timezones0.put("Asia/Tbilisi", tz);
636 timezones0.put("Indian/Mahe", tz);
637 timezones0.put("Indian/Mauritius", tz);
638 timezones0.put("Indian/Reunion", tz);
639 tz = new SimpleTimeZone(4500 * 3600, "Asia/Kabul");
640 timezones0.put("Asia/Kabul", tz);
641 tz = new SimpleTimeZone
642 (5000 * 3600, "Asia/Yekaterinburg",
643 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
644 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
645 timezones0.put("Asia/Yekaterinburg", tz);
646 tz = new SimpleTimeZone(5000 * 3600, "PLT");
647 timezones0.put("PLT", tz);
648 timezones0.put("Asia/Aqtau", tz);
649 timezones0.put("Asia/Aqtobe", tz);
650 timezones0.put("Asia/Ashgabat", tz);
651 timezones0.put("Asia/Dushanbe", tz);
652 timezones0.put("Asia/Karachi", tz);
653 timezones0.put("Asia/Oral", tz);
654 timezones0.put("Asia/Samarkand", tz);
655 timezones0.put("Asia/Tashkent", tz);
656 timezones0.put("Indian/Kerguelen", tz);
657 timezones0.put("Indian/Maldives", tz);
658 tz = new SimpleTimeZone(5500 * 3600, "BST");
659 timezones0.put("BST", tz);
660 timezones0.put("IST", tz);
661 timezones0.put("Asia/Calcutta", tz);
662 timezones0.put("Asia/Colombo", tz);
663 tz = new SimpleTimeZone(5750 * 3600, "Asia/Katmandu");
664 timezones0.put("Asia/Katmandu", tz);
665 tz = new SimpleTimeZone(6000 * 3600, "Antarctica/Mawson");
666 timezones0.put("Antarctica/Mawson", tz);
667 timezones0.put("Antarctica/Vostok", tz);
668 timezones0.put("Asia/Almaty", tz);
669 timezones0.put("Asia/Bishkek", tz);
670 timezones0.put("Asia/Dhaka", tz);
671 timezones0.put("Asia/Qyzylorda", tz);
672 timezones0.put("Asia/Thimphu", tz);
673 timezones0.put("Indian/Chagos", tz);
674 tz = new SimpleTimeZone
675 (6000 * 3600, "Asia/Novosibirsk",
676 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
677 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
678 timezones0.put("Asia/Novosibirsk", tz);
679 timezones0.put("Asia/Omsk", tz);
680 tz = new SimpleTimeZone(6500 * 3600, "Asia/Rangoon");
681 timezones0.put("Asia/Rangoon", tz);
682 timezones0.put("Indian/Cocos", tz);
683 tz = new SimpleTimeZone(7000 * 3600, "VST");
684 timezones0.put("VST", tz);
685 timezones0.put("Antarctica/Davis", tz);
686 timezones0.put("Asia/Bangkok", tz);
687 timezones0.put("Asia/Jakarta", tz);
688 timezones0.put("Asia/Phnom_Penh", tz);
689 timezones0.put("Asia/Pontianak", tz);
690 timezones0.put("Asia/Saigon", tz);
691 timezones0.put("Asia/Vientiane", tz);
692 timezones0.put("Indian/Christmas", tz);
693 tz = new SimpleTimeZone
694 (7000 * 3600, "Asia/Hovd",
695 Calendar.MARCH, -1, Calendar.SATURDAY, 2000 * 3600,
696 Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 2000 * 3600);
697 timezones0.put("Asia/Hovd", tz);
698 tz = new SimpleTimeZone
699 (7000 * 3600, "Asia/Krasnoyarsk",
700 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
701 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
702 timezones0.put("Asia/Krasnoyarsk", tz);
703 tz = new SimpleTimeZone(8000 * 3600, "CTT");
704 timezones0.put("CTT", tz);
705 timezones0.put("Antarctica/Casey", tz);
706 timezones0.put("Asia/Brunei", tz);
707 timezones0.put("Asia/Chongqing", tz);
708 timezones0.put("Asia/Harbin", tz);
709 timezones0.put("Asia/Hong_Kong", tz);
710 timezones0.put("Asia/Kashgar", tz);
711 timezones0.put("Asia/Kuala_Lumpur", tz);
712 timezones0.put("Asia/Kuching", tz);
713 timezones0.put("Asia/Macau", tz);
714 timezones0.put("Asia/Makassar", tz);
715 timezones0.put("Asia/Manila", tz);
716 timezones0.put("Asia/Shanghai", tz);
717 timezones0.put("Asia/Singapore", tz);
718 timezones0.put("Asia/Taipei", tz);
719 timezones0.put("Asia/Urumqi", tz);
720 timezones0.put("Australia/Perth", tz);
721 tz = new SimpleTimeZone
722 (8000 * 3600, "Asia/Irkutsk",
723 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
724 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
725 timezones0.put("Asia/Irkutsk", tz);
726 tz = new SimpleTimeZone
727 (8000 * 3600, "Asia/Ulaanbaatar",
728 Calendar.MARCH, -1, Calendar.SATURDAY, 2000 * 3600,
729 Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 2000 * 3600);
730 timezones0.put("Asia/Ulaanbaatar", tz);
731 tz = new SimpleTimeZone(8750 * 3600, "Australia/Eucla");
732 timezones0.put("Australia/Eucla", tz);
733 tz = new SimpleTimeZone
734 (9000 * 3600, "Asia/Choibalsan",
735 Calendar.MARCH, -1, Calendar.SATURDAY, 2000 * 3600,
736 Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 2000 * 3600);
737 timezones0.put("Asia/Choibalsan", tz);
738 tz = new SimpleTimeZone(9000 * 3600, "JST");
739 timezones0.put("JST", tz);
740 timezones0.put("Asia/Dili", tz);
741 timezones0.put("Asia/Jayapura", tz);
742 timezones0.put("Asia/Pyongyang", tz);
743 timezones0.put("Asia/Seoul", tz);
744 timezones0.put("Asia/Tokyo", tz);
745 timezones0.put("Pacific/Palau", tz);
746 tz = new SimpleTimeZone
747 (9000 * 3600, "Asia/Yakutsk",
748 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
749 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
750 timezones0.put("Asia/Yakutsk", tz);
751 tz = new SimpleTimeZone
752 (9500 * 3600, "Australia/Adelaide",
753 Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
754 Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600);
755 timezones0.put("Australia/Adelaide", tz);
756 timezones0.put("Australia/Broken_Hill", tz);
757 tz = new SimpleTimeZone(9500 * 3600, "ACT");
758 timezones0.put("ACT", tz);
759 timezones0.put("Australia/Darwin", tz);
760 tz = new SimpleTimeZone(10000 * 3600, "Antarctica/DumontDUrville");
761 timezones0.put("Antarctica/DumontDUrville", tz);
762 timezones0.put("Australia/Brisbane", tz);
763 timezones0.put("Australia/Lindeman", tz);
764 timezones0.put("Pacific/Guam", tz);
765 timezones0.put("Pacific/Port_Moresby", tz);
766 timezones0.put("Pacific/Saipan", tz);
767 timezones0.put("Pacific/Truk", tz);
768 tz = new SimpleTimeZone
769 (10000 * 3600, "Asia/Sakhalin",
770 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
771 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
772 timezones0.put("Asia/Sakhalin", tz);
773 timezones0.put("Asia/Vladivostok", tz);
774 tz = new SimpleTimeZone
775 (10000 * 3600, "Australia/Currie",
776 Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
777 Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600);
778 timezones0.put("Australia/Currie", tz);
779 timezones0.put("Australia/Hobart", tz);
780 tz = new SimpleTimeZone
781 (10000 * 3600, "AET",
782 Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
783 Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600);
784 timezones0.put("AET", tz);
785 timezones0.put("Australia/Melbourne", tz);
786 timezones0.put("Australia/Sydney", tz);
787 tz = new SimpleTimeZone
788 (10500 * 3600, "Australia/Lord_Howe",
789 Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
790 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, 500 * 3600);
791 timezones0.put("Australia/Lord_Howe", tz);
792 tz = new SimpleTimeZone
793 (11000 * 3600, "Asia/Magadan",
794 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
795 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
796 timezones0.put("Asia/Magadan", tz);
797 tz = new SimpleTimeZone(11000 * 3600, "SST");
798 timezones0.put("SST", tz);
799 timezones0.put("Pacific/Efate", tz);
800 timezones0.put("Pacific/Guadalcanal", tz);
801 timezones0.put("Pacific/Kosrae", tz);
802 timezones0.put("Pacific/Noumea", tz);
803 timezones0.put("Pacific/Ponape", tz);
804 tz = new SimpleTimeZone(11500 * 3600, "Pacific/Norfolk");
805 timezones0.put("Pacific/Norfolk", tz);
806 tz = new SimpleTimeZone
807 (12000 * 3600, "NST",
808 Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
809 Calendar.MARCH, 3, Calendar.SUNDAY, 3000 * 3600);
810 timezones0.put("NST", tz);
811 timezones0.put("Antarctica/McMurdo", tz);
812 timezones0.put("Antarctica/South_Pole", tz);
813 timezones0.put("Pacific/Auckland", tz);
814 tz = new SimpleTimeZone
815 (12000 * 3600, "Asia/Anadyr",
816 Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
817 Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
818 timezones0.put("Asia/Anadyr", tz);
819 timezones0.put("Asia/Kamchatka", tz);
820 tz = new SimpleTimeZone(12000 * 3600, "Pacific/Fiji");
821 timezones0.put("Pacific/Fiji", tz);
822 timezones0.put("Pacific/Funafuti", tz);
823 timezones0.put("Pacific/Kwajalein", tz);
824 timezones0.put("Pacific/Majuro", tz);
825 timezones0.put("Pacific/Nauru", tz);
826 timezones0.put("Pacific/Tarawa", tz);
827 timezones0.put("Pacific/Wake", tz);
828 timezones0.put("Pacific/Wallis", tz);
829 tz = new SimpleTimeZone
830 (12750 * 3600, "Pacific/Chatham",
831 Calendar.OCTOBER, 1, Calendar.SUNDAY, 2750 * 3600,
832 Calendar.MARCH, 3, Calendar.SUNDAY, 3750 * 3600);
833 timezones0.put("Pacific/Chatham", tz);
834 tz = new SimpleTimeZone(13000 * 3600, "Pacific/Enderbury");
835 timezones0.put("Pacific/Enderbury", tz);
836 timezones0.put("Pacific/Tongatapu", tz);
837 tz = new SimpleTimeZone(14000 * 3600, "Pacific/Kiritimati");
838 timezones0.put("Pacific/Kiritimati", tz);
844 * Maps a time zone name (with optional GMT offset and daylight time
845 * zone name) to one of the known time zones. This method called
846 * with the result of <code>System.getProperty("user.timezone")</code>
847 * or <code>getDefaultTimeZoneId()</code>. Note that giving one of
848 * the standard tz data names from ftp://elsie.nci.nih.gov/pub/ is
850 * The time zone name can be given as follows:
851 * <code>(standard zone name)[(GMT offset)[(DST zone name)[DST offset]]]
854 * If only a (standard zone name) is given (no numbers in the
855 * String) then it gets mapped directly to the TimeZone with that
856 * name, if that fails null is returned.
858 * Alternately, a POSIX-style TZ string can be given, defining the time zone:
859 * <code>std offset dst offset,date/time,date/time</code>
860 * See the glibc manual, or the man page for <code>tzset</code> for details
863 * A GMT offset is the offset to add to the local time to get GMT.
864 * If a (GMT offset) is included (either in seconds or hours) then
865 * an attempt is made to find a TimeZone name matching both the name
866 * and the offset (that doesn't observe daylight time, if the
867 * timezone observes daylight time then you must include a daylight
868 * time zone name after the offset), if that fails then a TimeZone
869 * with the given GMT offset is returned (whether or not the
870 * TimeZone observes daylight time is ignored), if that also fails
871 * the GMT TimeZone is returned.
873 * If the String ends with (GMT offset)(daylight time zone name)
874 * then an attempt is made to find a TimeZone with the given name and
875 * GMT offset that also observes (the daylight time zone name is not
876 * currently used in any other way), if that fails a TimeZone with
877 * the given GMT offset that observes daylight time is returned, if
878 * that also fails the GMT TimeZone is returned.
880 * Examples: In Chicago, the time zone id could be "CST6CDT", but
881 * the preferred name would be "America/Chicago". In Indianapolis
882 * (which does not have Daylight Savings Time) the string could be
883 * "EST5", but the preferred name would be "America/Indianapolis".
884 * The standard time zone name for The Netherlands is "Europe/Amsterdam",
885 * but can also be given as "CET-1CEST".
887 static TimeZone getDefaultTimeZone(String sysTimeZoneId)
889 String stdName = null;
895 int idLength = sysTimeZoneId.length();
903 c = sysTimeZoneId.charAt(index++);
904 while (c != '+' && c != '-' && c != ',' && c != ':'
905 && ! Character.isDigit(c) && c != '\0' && index < idLength);
907 if (index >= idLength)
908 return (TimeZone)timezones().get(sysTimeZoneId);
910 stdName = sysTimeZoneId.substring(0, --index);
913 // get the std offset
915 c = sysTimeZoneId.charAt(index++);
916 while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c))
917 && index < idLength);
918 if (index < idLength)
921 { // convert the dst string to a millis number
922 String offset = sysTimeZoneId.substring(prevIndex, index);
925 if (offset.charAt(0) == '+' || offset.charAt(0) == '-')
926 stdOffs = parseTime(offset.substring(1));
928 stdOffs = parseTime(offset);
930 if (offset.charAt(0) == '-')
933 // TZ timezone offsets are positive when WEST of the meridian.
937 // Done yet? (Format: std offset)
938 if (index >= idLength)
940 // Do we have an existing timezone with that name and offset?
941 TimeZone tz = (TimeZone) timezones().get(stdName);
943 if (tz.getRawOffset() == stdOffs)
947 return new SimpleTimeZone(stdOffs, stdName);
952 c = sysTimeZoneId.charAt(index++);
953 while (c != '+' && c != '-' && c != ',' && c != ':'
954 && ! Character.isDigit(c) && c != '\0' && index < idLength);
956 // Done yet? (Format: std offset dst)
957 if (index >= idLength)
959 // Do we have an existing timezone with that name and offset
961 TimeZone tz = (TimeZone) timezones().get(stdName);
963 if (tz.getRawOffset() == stdOffs && tz.useDaylightTime())
967 return new SimpleTimeZone(stdOffs, stdName);
970 // get the dst offset
971 dstName = sysTimeZoneId.substring(prevIndex, --index);
974 c = sysTimeZoneId.charAt(index++);
975 while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c))
976 && index < idLength);
977 if (index < idLength)
980 { // convert the dst string to a millis number
981 String offset = sysTimeZoneId.substring(prevIndex, index);
984 if (offset.charAt(0) == '+' || offset.charAt(0) == '-')
985 dstOffs = parseTime(offset.substring(1));
987 dstOffs = parseTime(offset);
989 if (offset.charAt(0) == '-')
992 // TZ timezone offsets are positive when WEST of the meridian.
996 // Done yet? (Format: std offset dst offset)
997 // FIXME: We don't support DST without a rule given. Should we?
998 if (index >= idLength)
1000 // Time Zone existing with same name, dst and offsets?
1001 TimeZone tz = (TimeZone) timezones().get(stdName);
1003 if (tz.getRawOffset() == stdOffs && tz.useDaylightTime()
1004 && tz.getDSTSavings() == (dstOffs - stdOffs))
1007 return new SimpleTimeZone(stdOffs, stdName);
1011 if (sysTimeZoneId.charAt(index) == ','
1012 || sysTimeZoneId.charAt(index) == ';')
1016 while (sysTimeZoneId.charAt(index) != ','
1017 && sysTimeZoneId.charAt(index) != ';')
1019 String startTime = sysTimeZoneId.substring(offs, index);
1021 String endTime = sysTimeZoneId.substring(index);
1023 index = startTime.indexOf('/');
1030 startDate = startTime.substring(0, index);
1031 startMillis = parseTime(startTime.substring(index + 1));
1035 startDate = startTime;
1036 // if time isn't given, default to 2:00:00 AM.
1037 startMillis = 2 * 60 * 60 * 1000;
1039 index = endTime.indexOf('/');
1042 endDate = endTime.substring(0, index);
1043 endMillis = parseTime(endTime.substring(index + 1));
1048 // if time isn't given, default to 2:00:00 AM.
1049 endMillis = 2 * 60 * 60 * 1000;
1052 int[] start = getDateParams(startDate);
1053 int[] end = getDateParams(endDate);
1054 return new SimpleTimeZone(stdOffs, stdName, start[0], start[1],
1055 start[2], startMillis, end[0], end[1],
1056 end[2], endMillis, (dstOffs - stdOffs));
1060 // FIXME: Produce a warning here?
1061 catch (IndexOutOfBoundsException _)
1064 catch (NumberFormatException _)
1072 * Parses and returns the params for a POSIX TZ date field,
1073 * in the format int[]{ month, day, dayOfWeek }, following the
1074 * SimpleTimeZone constructor rules.
1076 private static int[] getDateParams(String date)
1078 int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
1081 if (date.charAt(0) == 'M' || date.charAt(0) == 'm')
1085 // Month, week of month, day of week
1086 month = Integer.parseInt(date.substring(1, date.indexOf('.')));
1087 int week = Integer.parseInt(date.substring(date.indexOf('.') + 1,
1088 date.lastIndexOf('.')));
1089 int dayOfWeek = Integer.parseInt(date.substring(date.lastIndexOf('.')
1092 day = -1; // last day of month is -1 in java, 5 in TZ
1094 // first day of week starting on or after.
1095 day = (week - 1) * 7 + 1;
1097 dayOfWeek++; // Java day of week is one-based, Sunday is first day.
1098 month--; // Java month is zero-based.
1099 return new int[] { month, day, dayOfWeek };
1102 // julian day, either zero-based 0<=n<=365 (incl feb 29)
1103 // or one-based 1<=n<=365 (no feb 29)
1104 int julianDay; // Julian day,
1106 if (date.charAt(0) != 'J' || date.charAt(0) != 'j')
1108 julianDay = Integer.parseInt(date.substring(1));
1109 julianDay++; // make 1-based
1110 // Adjust day count to include feb 29.
1111 dayCount = new int[]
1113 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335
1117 // 1-based julian day
1118 julianDay = Integer.parseInt(date);
1122 if (dayCount[i] < julianDay)
1126 julianDay -= dayCount[i];
1128 return new int[] { month, julianDay, 0 };
1132 * Parses a time field hh[:mm[:ss]], returning the result
1133 * in milliseconds. No leading sign.
1135 private static int parseTime(String time)
1140 while (i < time.length())
1141 if (time.charAt(i) == ':')
1145 millis = 60 * 60 * 1000 * Integer.parseInt(time.substring(0, i));
1146 if (i >= time.length())
1150 while (i < time.length())
1151 if (time.charAt(i) == ':')
1155 if (i >= time.length())
1158 millis += 60 * 1000 * Integer.parseInt(time.substring(iprev, i));
1159 millis += 1000 * Integer.parseInt(time.substring(++i));
1164 * Gets the time zone offset, for current date, modified in case of
1165 * daylight savings. This is the offset to add to UTC to get the local
1167 * @param era the era of the given date
1168 * @param year the year of the given date
1169 * @param month the month of the given date, 0 for January.
1170 * @param day the day of month
1171 * @param dayOfWeek the day of week
1172 * @param milliseconds the millis in the day (in local standard time)
1173 * @return the time zone offset in milliseconds.
1175 public abstract int getOffset(int era, int year, int month,
1176 int day, int dayOfWeek, int milliseconds);
1179 * Get the time zone offset for the specified date, modified in case of
1180 * daylight savings. This is the offset to add to UTC to get the local
1182 * @param date the date represented in millisecends
1183 * since January 1, 1970 00:00:00 GMT.
1186 public int getOffset(long date)
1188 return (inDaylightTime(new Date(date))
1189 ? getRawOffset() + getDSTSavings()
1194 * Gets the time zone offset, ignoring daylight savings. This is
1195 * the offset to add to UTC to get the local time.
1196 * @return the time zone offset in milliseconds.
1198 public abstract int getRawOffset();
1201 * Sets the time zone offset, ignoring daylight savings. This is
1202 * the offset to add to UTC to get the local time.
1203 * @param offsetMillis the time zone offset to GMT.
1205 public abstract void setRawOffset(int offsetMillis);
1208 * Gets the identifier of this time zone. For instance, PST for
1209 * Pacific Standard Time.
1210 * @returns the ID of this time zone.
1212 public String getID()
1218 * Sets the identifier of this time zone. For instance, PST for
1219 * Pacific Standard Time.
1220 * @param id the new time zone ID.
1221 * @throws NullPointerException if <code>id</code> is <code>null</code>
1223 public void setID(String id)
1226 throw new NullPointerException();
1232 * This method returns a string name of the time zone suitable
1233 * for displaying to the user. The string returned will be the long
1234 * description of the timezone in the current locale. The name
1235 * displayed will assume daylight savings time is not in effect.
1237 * @return The name of the time zone.
1239 public final String getDisplayName()
1241 return (getDisplayName(false, LONG, Locale.getDefault()));
1245 * This method returns a string name of the time zone suitable
1246 * for displaying to the user. The string returned will be the long
1247 * description of the timezone in the specified locale. The name
1248 * displayed will assume daylight savings time is not in effect.
1250 * @param locale The locale for this timezone name.
1252 * @return The name of the time zone.
1254 public final String getDisplayName(Locale locale)
1256 return (getDisplayName(false, LONG, locale));
1260 * This method returns a string name of the time zone suitable
1261 * for displaying to the user. The string returned will be of the
1262 * specified type in the current locale.
1264 * @param dst Whether or not daylight savings time is in effect.
1265 * @param style <code>LONG</code> for a long name, <code>SHORT</code> for
1266 * a short abbreviation.
1268 * @return The name of the time zone.
1270 public final String getDisplayName(boolean dst, int style)
1272 return (getDisplayName(dst, style, Locale.getDefault()));
1277 * This method returns a string name of the time zone suitable
1278 * for displaying to the user. The string returned will be of the
1279 * specified type in the specified locale.
1281 * @param dst Whether or not daylight savings time is in effect.
1282 * @param style <code>LONG</code> for a long name, <code>SHORT</code> for
1283 * a short abbreviation.
1284 * @param locale The locale for this timezone name.
1286 * @return The name of the time zone.
1288 public String getDisplayName(boolean dst, int style, Locale locale)
1290 DateFormatSymbols dfs;
1293 dfs = new DateFormatSymbols(locale);
1295 // The format of the value returned is defined by us.
1296 String[][]zoneinfo = dfs.getZoneStrings();
1297 for (int i = 0; i < zoneinfo.length; i++)
1299 if (zoneinfo[i][0].equals(getID()))
1304 return (zoneinfo[i][2]);
1306 return (zoneinfo[i][1]);
1311 return (zoneinfo[i][4]);
1313 return (zoneinfo[i][3]);
1318 catch (MissingResourceException e)
1322 return getDefaultDisplayName(dst);
1325 private String getDefaultDisplayName(boolean dst)
1327 int offset = getRawOffset();
1328 if (dst && this instanceof SimpleTimeZone)
1330 // ugly, but this is a design failure of the API:
1331 // getDisplayName takes a dst parameter even though
1332 // TimeZone knows nothing about daylight saving offsets.
1333 offset += ((SimpleTimeZone) this).getDSTSavings();
1336 StringBuffer sb = new StringBuffer(9);
1339 offset = offset / (1000 * 60);
1340 int hours = Math.abs(offset) / 60;
1341 int minutes = Math.abs(offset) % 60;
1343 if (minutes != 0 || hours != 0)
1345 sb.append(offset >= 0 ? '+' : '-');
1346 sb.append((char) ('0' + hours / 10));
1347 sb.append((char) ('0' + hours % 10));
1349 sb.append((char) ('0' + minutes / 10));
1350 sb.append((char) ('0' + minutes % 10));
1353 return sb.toString();
1357 * Returns true, if this time zone uses Daylight Savings Time.
1359 public abstract boolean useDaylightTime();
1362 * Returns true, if the given date is in Daylight Savings Time in this
1364 * @param date the given Date.
1366 public abstract boolean inDaylightTime(Date date);
1369 * Gets the daylight savings offset. This is a positive offset in
1370 * milliseconds with respect to standard time. Typically this
1371 * is one hour, but for some time zones this may be half an our.
1372 * <p>The default implementation returns 3600000 milliseconds
1373 * (one hour) if the time zone uses daylight savings time
1374 * (as specified by {@link #useDaylightTime()}), otherwise
1376 * @return the daylight savings offset in milliseconds.
1379 public int getDSTSavings ()
1381 return useDaylightTime () ? 3600000 : 0;
1385 * Gets the TimeZone for the given ID.
1386 * @param ID the time zone identifier.
1387 * @return The time zone for the identifier or GMT, if no such time
1390 // FIXME: XXX: JCL indicates this and other methods are synchronized.
1391 public static TimeZone getTimeZone(String ID)
1393 // First check timezones hash
1394 TimeZone tz = (TimeZone) timezones().get(ID);
1397 if (tz.getID().equals(ID))
1400 // We always return a timezone with the requested ID.
1401 // This is the same behaviour as with JDK1.2.
1402 tz = (TimeZone) tz.clone();
1404 // We also save the alias, so that we return the same
1405 // object again if getTimeZone is called with the same
1407 timezones().put(ID, tz);
1411 // See if the ID is really a GMT offset form.
1412 // Note that GMT is in the table so we know it is different.
1413 if (ID.startsWith("GMT"))
1416 int offset_direction = 1;
1418 if (ID.charAt(pos) == '-')
1420 offset_direction = -1;
1423 else if (ID.charAt(pos) == '+')
1432 String offset_str = ID.substring(pos);
1433 int idx = offset_str.indexOf(":");
1436 hour = Integer.parseInt(offset_str.substring(0, idx));
1437 minute = Integer.parseInt(offset_str.substring(idx + 1));
1441 int offset_length = offset_str.length();
1442 if (offset_length <= 2)
1445 hour = Integer.parseInt(offset_str);
1450 // hour and minute, not separated by colon
1451 hour = Integer.parseInt
1452 (offset_str.substring(0, offset_length - 2));
1453 minute = Integer.parseInt
1454 (offset_str.substring(offset_length - 2));
1458 return new SimpleTimeZone((hour * (60 * 60 * 1000) +
1459 minute * (60 * 1000))
1460 * offset_direction, ID);
1462 catch (NumberFormatException e)
1467 // Finally, return GMT per spec
1468 return getTimeZone("GMT");
1472 * Gets the available IDs according to the given time zone
1474 * @param rawOffset the given time zone GMT offset.
1475 * @return An array of IDs, where the time zone has the specified GMT
1476 * offset. For example <code>{"Phoenix", "Denver"}</code>, since both have
1477 * GMT-07:00, but differ in daylight savings behaviour.
1479 public static String[] getAvailableIDs(int rawOffset)
1482 Iterator iter = timezones().entrySet().iterator();
1483 while (iter.hasNext())
1485 // Don't iterate the values, since we want to count
1486 // doubled values (aliases)
1487 Map.Entry entry = (Map.Entry) iter.next();
1488 if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset)
1492 String[] ids = new String[count];
1494 iter = timezones().entrySet().iterator();
1495 while (iter.hasNext())
1497 Map.Entry entry = (Map.Entry) iter.next();
1498 if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset)
1499 ids[count++] = (String) entry.getKey();
1505 * Gets all available IDs.
1506 * @return An array of all supported IDs.
1508 public static String[] getAvailableIDs()
1511 timezones().keySet().toArray(new String[timezones().size()]);
1515 * Returns the time zone under which the host is running. This
1516 * can be changed with setDefault.
1518 * @return A clone of the current default time zone for this host.
1521 public static TimeZone getDefault()
1523 return (TimeZone) defaultZone().clone();
1526 public static void setDefault(TimeZone zone)
1528 // Hmmmm. No Security checks?
1529 defaultZone0 = zone;
1533 * Test if the other time zone uses the same rule and only
1534 * possibly differs in ID. This implementation for this particular
1535 * class will return true if the raw offsets are identical. Subclasses
1536 * should override this method if they use daylight savings.
1537 * @return true if this zone has the same raw offset
1539 public boolean hasSameRules(TimeZone other)
1541 return other.getRawOffset() == getRawOffset();
1545 * Returns a clone of this object. I can't imagine, why this is
1546 * useful for a time zone.
1548 public Object clone()
1552 return super.clone();
1554 catch (CloneNotSupportedException ex)