Print this page
rev 5696 : 6336885: RFE: Locale Data Deployment Enhancements
4609153: Provide locale data for Indic locales
5104387: Support for gl_ES locale (galician language)
6337471: desktop/system locale preferences support
7056139: (cal) SPI support for locale-dependent Calendar parameters
7058206: Provide CalendarData SPI for week params and display field value names
7073852: Support multiple scripts for digits and decimal symbols per locale
7079560: [Fmt-Da] Context dependent month names support in SimpleDateFormat
7171324: getAvailableLocales() of locale sensitive services should return the actual availability of locales
7151414: (cal) Support calendar type identification
7168528: LocaleServiceProvider needs to be aware of Locale extensions
7171372: (cal) locale's default Calendar should be created if unknown calendar is specified
Summary: JEP 127: Improve Locale Data Packaging and Adopt Unicode CLDR Data (part 1 w/o packaging changes. by Naoto Sato and Masayoshi Okutsu)
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/java/util/TimeZone.java
+++ new/src/share/classes/java/util/TimeZone.java
1 1 /*
2 2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 /*
27 27 * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
28 28 * (C) Copyright IBM Corp. 1996 - All Rights Reserved
29 29 *
30 30 * The original version of this source code and documentation is copyrighted
31 31 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32 32 * materials are provided under terms of a License Agreement between Taligent
33 33 * and Sun. This technology is protected by multiple US and International
34 34 * patents. This notice and attribution to Taligent may not be removed.
35 35 * Taligent is a registered trademark of Taligent, Inc.
36 36 *
37 37 */
38 38
↓ open down ↓ |
38 lines elided |
↑ open up ↑ |
39 39 package java.util;
40 40
41 41 import java.io.Serializable;
42 42 import java.lang.ref.SoftReference;
43 43 import java.security.AccessController;
44 44 import java.security.PrivilegedAction;
45 45 import java.util.concurrent.ConcurrentHashMap;
46 46 import sun.misc.SharedSecrets;
47 47 import sun.misc.JavaAWTAccess;
48 48 import sun.security.action.GetPropertyAction;
49 -import sun.util.TimeZoneNameUtility;
49 +import sun.util.locale.provider.TimeZoneNameUtility;
50 50 import sun.util.calendar.ZoneInfo;
51 51 import sun.util.calendar.ZoneInfoFile;
52 52
53 53 /**
54 54 * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
55 55 * savings.
56 56 *
57 57 * <p>
58 58 * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
59 59 * which creates a <code>TimeZone</code> based on the time zone where the program
60 60 * is running. For example, for a program running in Japan, <code>getDefault</code>
61 61 * creates a <code>TimeZone</code> object based on Japanese Standard Time.
62 62 *
63 63 * <p>
64 64 * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
65 65 * along with a time zone ID. For instance, the time zone ID for the
66 66 * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
67 67 * U.S. Pacific Time <code>TimeZone</code> object with:
68 68 * <blockquote><pre>
69 69 * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
70 70 * </pre></blockquote>
71 71 * You can use the <code>getAvailableIDs</code> method to iterate through
72 72 * all the supported time zone IDs. You can then choose a
73 73 * supported ID to get a <code>TimeZone</code>.
74 74 * If the time zone you want is not represented by one of the
75 75 * supported IDs, then a custom time zone ID can be specified to
76 76 * produce a TimeZone. The syntax of a custom time zone ID is:
77 77 *
78 78 * <blockquote><pre>
79 79 * <a name="CustomID"><i>CustomID:</i></a>
80 80 * <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
81 81 * <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
82 82 * <code>GMT</code> <i>Sign</i> <i>Hours</i>
83 83 * <i>Sign:</i> one of
84 84 * <code>+ -</code>
85 85 * <i>Hours:</i>
86 86 * <i>Digit</i>
87 87 * <i>Digit</i> <i>Digit</i>
88 88 * <i>Minutes:</i>
89 89 * <i>Digit</i> <i>Digit</i>
90 90 * <i>Digit:</i> one of
91 91 * <code>0 1 2 3 4 5 6 7 8 9</code>
92 92 * </pre></blockquote>
93 93 *
94 94 * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
95 95 * between 00 to 59. For example, "GMT+10" and "GMT+0010" mean ten
96 96 * hours and ten minutes ahead of GMT, respectively.
97 97 * <p>
98 98 * The format is locale independent and digits must be taken from the
99 99 * Basic Latin block of the Unicode standard. No daylight saving time
100 100 * transition schedule can be specified with a custom time zone ID. If
101 101 * the specified string doesn't match the syntax, <code>"GMT"</code>
102 102 * is used.
103 103 * <p>
104 104 * When creating a <code>TimeZone</code>, the specified custom time
105 105 * zone ID is normalized in the following syntax:
106 106 * <blockquote><pre>
107 107 * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
108 108 * <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
109 109 * <i>Sign:</i> one of
110 110 * <code>+ -</code>
111 111 * <i>TwoDigitHours:</i>
112 112 * <i>Digit</i> <i>Digit</i>
113 113 * <i>Minutes:</i>
114 114 * <i>Digit</i> <i>Digit</i>
115 115 * <i>Digit:</i> one of
116 116 * <code>0 1 2 3 4 5 6 7 8 9</code>
117 117 * </pre></blockquote>
118 118 * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
119 119 *
120 120 * <h4>Three-letter time zone IDs</h4>
121 121 *
122 122 * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
123 123 * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
124 124 * use is deprecated</strong> because the same abbreviation is often used
125 125 * for multiple time zones (for example, "CST" could be U.S. "Central Standard
126 126 * Time" and "China Standard Time"), and the Java platform can then only
127 127 * recognize one of them.
128 128 *
129 129 *
130 130 * @see Calendar
131 131 * @see GregorianCalendar
132 132 * @see SimpleTimeZone
133 133 * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
134 134 * @since JDK1.1
135 135 */
136 136 abstract public class TimeZone implements Serializable, Cloneable {
137 137 /**
138 138 * Sole constructor. (For invocation by subclass constructors, typically
139 139 * implicit.)
140 140 */
141 141 public TimeZone() {
142 142 }
143 143
144 144 /**
145 145 * A style specifier for <code>getDisplayName()</code> indicating
146 146 * a short name, such as "PST."
147 147 * @see #LONG
148 148 * @since 1.2
149 149 */
150 150 public static final int SHORT = 0;
151 151
152 152 /**
153 153 * A style specifier for <code>getDisplayName()</code> indicating
154 154 * a long name, such as "Pacific Standard Time."
155 155 * @see #SHORT
156 156 * @since 1.2
157 157 */
158 158 public static final int LONG = 1;
159 159
160 160 // Constants used internally; unit is milliseconds
161 161 private static final int ONE_MINUTE = 60*1000;
162 162 private static final int ONE_HOUR = 60*ONE_MINUTE;
163 163 private static final int ONE_DAY = 24*ONE_HOUR;
164 164
165 165 // Proclaim serialization compatibility with JDK 1.1
166 166 static final long serialVersionUID = 3581463369166924961L;
167 167
168 168 /**
169 169 * Gets the time zone offset, for current date, modified in case of
170 170 * daylight savings. This is the offset to add to UTC to get local time.
171 171 * <p>
172 172 * This method returns a historically correct offset if an
173 173 * underlying <code>TimeZone</code> implementation subclass
174 174 * supports historical Daylight Saving Time schedule and GMT
175 175 * offset changes.
176 176 *
177 177 * @param era the era of the given date.
178 178 * @param year the year in the given date.
179 179 * @param month the month in the given date.
180 180 * Month is 0-based. e.g., 0 for January.
181 181 * @param day the day-in-month of the given date.
182 182 * @param dayOfWeek the day-of-week of the given date.
183 183 * @param milliseconds the milliseconds in day in <em>standard</em>
184 184 * local time.
185 185 *
186 186 * @return the offset in milliseconds to add to GMT to get local time.
187 187 *
188 188 * @see Calendar#ZONE_OFFSET
189 189 * @see Calendar#DST_OFFSET
190 190 */
191 191 public abstract int getOffset(int era, int year, int month, int day,
192 192 int dayOfWeek, int milliseconds);
193 193
194 194 /**
195 195 * Returns the offset of this time zone from UTC at the specified
196 196 * date. If Daylight Saving Time is in effect at the specified
197 197 * date, the offset value is adjusted with the amount of daylight
198 198 * saving.
199 199 * <p>
200 200 * This method returns a historically correct offset value if an
201 201 * underlying TimeZone implementation subclass supports historical
202 202 * Daylight Saving Time schedule and GMT offset changes.
203 203 *
204 204 * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
205 205 * @return the amount of time in milliseconds to add to UTC to get local time.
206 206 *
207 207 * @see Calendar#ZONE_OFFSET
208 208 * @see Calendar#DST_OFFSET
209 209 * @since 1.4
210 210 */
211 211 public int getOffset(long date) {
212 212 if (inDaylightTime(new Date(date))) {
213 213 return getRawOffset() + getDSTSavings();
214 214 }
215 215 return getRawOffset();
216 216 }
217 217
218 218 /**
219 219 * Gets the raw GMT offset and the amount of daylight saving of this
220 220 * time zone at the given time.
221 221 * @param date the milliseconds (since January 1, 1970,
222 222 * 00:00:00.000 GMT) at which the time zone offset and daylight
223 223 * saving amount are found
224 224 * @param offset an array of int where the raw GMT offset
225 225 * (offset[0]) and daylight saving amount (offset[1]) are stored,
226 226 * or null if those values are not needed. The method assumes that
227 227 * the length of the given array is two or larger.
228 228 * @return the total amount of the raw GMT offset and daylight
229 229 * saving at the specified date.
230 230 *
231 231 * @see Calendar#ZONE_OFFSET
232 232 * @see Calendar#DST_OFFSET
233 233 */
234 234 int getOffsets(long date, int[] offsets) {
235 235 int rawoffset = getRawOffset();
236 236 int dstoffset = 0;
237 237 if (inDaylightTime(new Date(date))) {
238 238 dstoffset = getDSTSavings();
239 239 }
240 240 if (offsets != null) {
241 241 offsets[0] = rawoffset;
242 242 offsets[1] = dstoffset;
243 243 }
244 244 return rawoffset + dstoffset;
245 245 }
246 246
247 247 /**
248 248 * Sets the base time zone offset to GMT.
249 249 * This is the offset to add to UTC to get local time.
250 250 * <p>
251 251 * If an underlying <code>TimeZone</code> implementation subclass
252 252 * supports historical GMT offset changes, the specified GMT
253 253 * offset is set as the latest GMT offset and the difference from
254 254 * the known latest GMT offset value is used to adjust all
255 255 * historical GMT offset values.
256 256 *
257 257 * @param offsetMillis the given base time zone offset to GMT.
258 258 */
259 259 abstract public void setRawOffset(int offsetMillis);
260 260
261 261 /**
262 262 * Returns the amount of time in milliseconds to add to UTC to get
263 263 * standard time in this time zone. Because this value is not
264 264 * affected by daylight saving time, it is called <I>raw
265 265 * offset</I>.
266 266 * <p>
267 267 * If an underlying <code>TimeZone</code> implementation subclass
268 268 * supports historical GMT offset changes, the method returns the
269 269 * raw offset value of the current date. In Honolulu, for example,
270 270 * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
271 271 * this method always returns -36000000 milliseconds (i.e., -10
272 272 * hours).
273 273 *
274 274 * @return the amount of raw offset time in milliseconds to add to UTC.
275 275 * @see Calendar#ZONE_OFFSET
276 276 */
277 277 public abstract int getRawOffset();
278 278
279 279 /**
280 280 * Gets the ID of this time zone.
281 281 * @return the ID of this time zone.
282 282 */
283 283 public String getID()
284 284 {
285 285 return ID;
286 286 }
287 287
288 288 /**
289 289 * Sets the time zone ID. This does not change any other data in
290 290 * the time zone object.
291 291 * @param ID the new time zone ID.
292 292 */
293 293 public void setID(String ID)
294 294 {
295 295 if (ID == null) {
296 296 throw new NullPointerException();
297 297 }
298 298 this.ID = ID;
299 299 }
300 300
301 301 /**
302 302 * Returns a long standard time name of this {@code TimeZone} suitable for
303 303 * presentation to the user in the default locale.
304 304 *
305 305 * <p>This method is equivalent to:
306 306 * <pre><blockquote>
307 307 * getDisplayName(false, {@link #LONG},
308 308 * Locale.getDefault({@link Locale.Category#DISPLAY}))
309 309 * </blockquote></pre>
310 310 *
311 311 * @return the human-readable name of this time zone in the default locale.
312 312 * @since 1.2
313 313 * @see #getDisplayName(boolean, int, Locale)
314 314 * @see Locale#getDefault(Locale.Category)
315 315 * @see Locale.Category
316 316 */
317 317 public final String getDisplayName() {
318 318 return getDisplayName(false, LONG,
319 319 Locale.getDefault(Locale.Category.DISPLAY));
320 320 }
321 321
322 322 /**
323 323 * Returns a long standard time name of this {@code TimeZone} suitable for
324 324 * presentation to the user in the specified {@code locale}.
325 325 *
326 326 * <p>This method is equivalent to:
327 327 * <pre><blockquote>
328 328 * getDisplayName(false, {@link #LONG}, locale)
329 329 * </blockquote></pre>
330 330 *
331 331 * @param locale the locale in which to supply the display name.
332 332 * @return the human-readable name of this time zone in the given locale.
333 333 * @exception NullPointerException if {@code locale} is {@code null}.
334 334 * @since 1.2
335 335 * @see #getDisplayName(boolean, int, Locale)
336 336 */
337 337 public final String getDisplayName(Locale locale) {
338 338 return getDisplayName(false, LONG, locale);
339 339 }
340 340
341 341 /**
342 342 * Returns a name in the specified {@code style} of this {@code TimeZone}
343 343 * suitable for presentation to the user in the default locale. If the
344 344 * specified {@code daylight} is {@code true}, a Daylight Saving Time name
345 345 * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
346 346 * Time). Otherwise, a Standard Time name is returned.
347 347 *
348 348 * <p>This method is equivalent to:
349 349 * <pre><blockquote>
350 350 * getDisplayName(daylight, style,
351 351 * Locale.getDefault({@link Locale.Category#DISPLAY}))
352 352 * </blockquote></pre>
353 353 *
354 354 * @param daylight {@code true} specifying a Daylight Saving Time name, or
355 355 * {@code false} specifying a Standard Time name
356 356 * @param style either {@link #LONG} or {@link #SHORT}
357 357 * @return the human-readable name of this time zone in the default locale.
358 358 * @exception IllegalArgumentException if {@code style} is invalid.
359 359 * @since 1.2
360 360 * @see #getDisplayName(boolean, int, Locale)
361 361 * @see Locale#getDefault(Locale.Category)
362 362 * @see Locale.Category
363 363 * @see java.text.DateFormatSymbols#getZoneStrings()
364 364 */
365 365 public final String getDisplayName(boolean daylight, int style) {
366 366 return getDisplayName(daylight, style,
367 367 Locale.getDefault(Locale.Category.DISPLAY));
368 368 }
369 369
370 370 /**
371 371 * Returns a name in the specified {@code style} of this {@code TimeZone}
372 372 * suitable for presentation to the user in the specified {@code
373 373 * locale}. If the specified {@code daylight} is {@code true}, a Daylight
374 374 * Saving Time name is returned (even if this {@code TimeZone} doesn't
375 375 * observe Daylight Saving Time). Otherwise, a Standard Time name is
376 376 * returned.
377 377 *
378 378 * <p>When looking up a time zone name, the {@linkplain
379 379 * ResourceBundle.Control#getCandidateLocales(String,Locale) default
380 380 * <code>Locale</code> search path of <code>ResourceBundle</code>} derived
381 381 * from the specified {@code locale} is used. (No {@linkplain
382 382 * ResourceBundle.Control#getFallbackLocale(String,Locale) fallback
383 383 * <code>Locale</code>} search is performed.) If a time zone name in any
384 384 * {@code Locale} of the search path, including {@link Locale#ROOT}, is
385 385 * found, the name is returned. Otherwise, a string in the
386 386 * <a href="#NormalizedCustomID">normalized custom ID format</a> is returned.
387 387 *
388 388 * @param daylight {@code true} specifying a Daylight Saving Time name, or
389 389 * {@code false} specifying a Standard Time name
390 390 * @param style either {@link #LONG} or {@link #SHORT}
391 391 * @param locale the locale in which to supply the display name.
392 392 * @return the human-readable name of this time zone in the given locale.
393 393 * @exception IllegalArgumentException if {@code style} is invalid.
394 394 * @exception NullPointerException if {@code locale} is {@code null}.
395 395 * @since 1.2
↓ open down ↓ |
336 lines elided |
↑ open up ↑ |
396 396 * @see java.text.DateFormatSymbols#getZoneStrings()
397 397 */
398 398 public String getDisplayName(boolean daylight, int style, Locale locale) {
399 399 if (style != SHORT && style != LONG) {
400 400 throw new IllegalArgumentException("Illegal style: " + style);
401 401 }
402 402
403 403 String id = getID();
404 404 String[] names = getDisplayNames(id, locale);
405 405 if (names == null) {
406 - if (id.startsWith("GMT")) {
406 + if (id.startsWith("GMT") && id.length() > 3) {
407 407 char sign = id.charAt(3);
408 408 if (sign == '+' || sign == '-') {
409 409 return id;
410 410 }
411 411 }
412 412 int offset = getRawOffset();
413 413 if (daylight) {
414 414 offset += getDSTSavings();
415 415 }
416 416 return ZoneInfoFile.toCustomID(offset);
417 417 }
418 418
419 419 int index = daylight ? 3 : 1;
420 420 if (style == SHORT) {
421 421 index++;
422 422 }
423 423 return names[index];
424 424 }
425 425
426 426 private static class DisplayNames {
427 427 // Cache for managing display names per timezone per locale
428 428 // The structure is:
429 429 // Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
430 430 private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
431 431 new ConcurrentHashMap<>();
432 432 }
433 433
434 434 private static final String[] getDisplayNames(String id, Locale locale) {
435 435 Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
436 436
437 437 SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
438 438 if (ref != null) {
439 439 Map<Locale, String[]> perLocale = ref.get();
440 440 if (perLocale != null) {
441 441 String[] names = perLocale.get(locale);
442 442 if (names != null) {
443 443 return names;
444 444 }
445 445 names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
446 446 if (names != null) {
447 447 perLocale.put(locale, names);
448 448 }
449 449 return names;
450 450 }
451 451 }
452 452
453 453 String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
454 454 if (names != null) {
455 455 Map<Locale, String[]> perLocale = new ConcurrentHashMap<>();
456 456 perLocale.put(locale, names);
457 457 ref = new SoftReference<>(perLocale);
458 458 displayNames.put(id, ref);
459 459 }
460 460 return names;
461 461 }
462 462
463 463 /**
464 464 * Returns the amount of time to be added to local standard time
465 465 * to get local wall clock time.
466 466 *
467 467 * <p>The default implementation returns 3600000 milliseconds
468 468 * (i.e., one hour) if a call to {@link #useDaylightTime()}
469 469 * returns {@code true}. Otherwise, 0 (zero) is returned.
470 470 *
471 471 * <p>If an underlying {@code TimeZone} implementation subclass
472 472 * supports historical and future Daylight Saving Time schedule
473 473 * changes, this method returns the amount of saving time of the
474 474 * last known Daylight Saving Time rule that can be a future
475 475 * prediction.
476 476 *
477 477 * <p>If the amount of saving time at any given time stamp is
478 478 * required, construct a {@link Calendar} with this {@code
479 479 * TimeZone} and the time stamp, and call {@link Calendar#get(int)
480 480 * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
481 481 *
482 482 * @return the amount of saving time in milliseconds
483 483 * @since 1.4
484 484 * @see #inDaylightTime(Date)
485 485 * @see #getOffset(long)
486 486 * @see #getOffset(int,int,int,int,int,int)
487 487 * @see Calendar#ZONE_OFFSET
488 488 */
489 489 public int getDSTSavings() {
490 490 if (useDaylightTime()) {
491 491 return 3600000;
492 492 }
493 493 return 0;
494 494 }
495 495
496 496 /**
497 497 * Queries if this {@code TimeZone} uses Daylight Saving Time.
498 498 *
499 499 * <p>If an underlying {@code TimeZone} implementation subclass
500 500 * supports historical and future Daylight Saving Time schedule
501 501 * changes, this method refers to the last known Daylight Saving Time
502 502 * rule that can be a future prediction and may not be the same as
503 503 * the current rule. Consider calling {@link #observesDaylightTime()}
504 504 * if the current rule should also be taken into account.
505 505 *
506 506 * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
507 507 * {@code false}, otherwise.
508 508 * @see #inDaylightTime(Date)
509 509 * @see Calendar#DST_OFFSET
510 510 */
511 511 public abstract boolean useDaylightTime();
512 512
513 513 /**
514 514 * Returns {@code true} if this {@code TimeZone} is currently in
515 515 * Daylight Saving Time, or if a transition from Standard Time to
516 516 * Daylight Saving Time occurs at any future time.
517 517 *
518 518 * <p>The default implementation returns {@code true} if
519 519 * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
520 520 * returns {@code true}.
521 521 *
522 522 * @return {@code true} if this {@code TimeZone} is currently in
523 523 * Daylight Saving Time, or if a transition from Standard Time to
524 524 * Daylight Saving Time occurs at any future time; {@code false}
525 525 * otherwise.
526 526 * @since 1.7
527 527 * @see #useDaylightTime()
528 528 * @see #inDaylightTime(Date)
529 529 * @see Calendar#DST_OFFSET
530 530 */
531 531 public boolean observesDaylightTime() {
532 532 return useDaylightTime() || inDaylightTime(new Date());
533 533 }
534 534
535 535 /**
536 536 * Queries if the given {@code date} is in Daylight Saving Time in
537 537 * this time zone.
538 538 *
539 539 * @param date the given Date.
540 540 * @return {@code true} if the given date is in Daylight Saving Time,
541 541 * {@code false}, otherwise.
542 542 */
543 543 abstract public boolean inDaylightTime(Date date);
544 544
545 545 /**
546 546 * Gets the <code>TimeZone</code> for the given ID.
547 547 *
548 548 * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
549 549 * such as "PST", a full name such as "America/Los_Angeles", or a custom
550 550 * ID such as "GMT-8:00". Note that the support of abbreviations is
551 551 * for JDK 1.1.x compatibility only and full names should be used.
552 552 *
553 553 * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
554 554 * cannot be understood.
555 555 */
556 556 public static synchronized TimeZone getTimeZone(String ID) {
557 557 return getTimeZone(ID, true);
558 558 }
559 559
560 560 private static TimeZone getTimeZone(String ID, boolean fallback) {
561 561 TimeZone tz = ZoneInfo.getTimeZone(ID);
562 562 if (tz == null) {
563 563 tz = parseCustomTimeZone(ID);
564 564 if (tz == null && fallback) {
565 565 tz = new ZoneInfo(GMT_ID, 0);
566 566 }
567 567 }
568 568 return tz;
569 569 }
570 570
571 571 /**
572 572 * Gets the available IDs according to the given time zone offset in milliseconds.
573 573 *
574 574 * @param rawOffset the given time zone GMT offset in milliseconds.
575 575 * @return an array of IDs, where the time zone for that ID has
576 576 * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
577 577 * both have GMT-07:00, but differ in daylight saving behavior.
578 578 * @see #getRawOffset()
579 579 */
580 580 public static synchronized String[] getAvailableIDs(int rawOffset) {
581 581 return ZoneInfo.getAvailableIDs(rawOffset);
582 582 }
583 583
584 584 /**
585 585 * Gets all the available IDs supported.
586 586 * @return an array of IDs.
587 587 */
588 588 public static synchronized String[] getAvailableIDs() {
589 589 return ZoneInfo.getAvailableIDs();
590 590 }
591 591
592 592 /**
593 593 * Gets the platform defined TimeZone ID.
594 594 **/
595 595 private static native String getSystemTimeZoneID(String javaHome,
596 596 String country);
597 597
598 598 /**
599 599 * Gets the custom time zone ID based on the GMT offset of the
600 600 * platform. (e.g., "GMT+08:00")
601 601 */
602 602 private static native String getSystemGMTOffsetID();
603 603
604 604 /**
605 605 * Gets the default <code>TimeZone</code> for this host.
606 606 * The source of the default <code>TimeZone</code>
607 607 * may vary with implementation.
608 608 * @return a default <code>TimeZone</code>.
609 609 * @see #setDefault
610 610 */
611 611 public static TimeZone getDefault() {
612 612 return (TimeZone) getDefaultRef().clone();
613 613 }
614 614
615 615 /**
616 616 * Returns the reference to the default TimeZone object. This
617 617 * method doesn't create a clone.
618 618 */
619 619 static TimeZone getDefaultRef() {
620 620 TimeZone defaultZone = getDefaultInAppContext();
621 621 if (defaultZone == null) {
622 622 defaultZone = defaultTimeZone;
623 623 if (defaultZone == null) {
624 624 // Need to initialize the default time zone.
625 625 defaultZone = setDefaultZone();
626 626 assert defaultZone != null;
627 627 }
628 628 }
629 629 // Don't clone here.
630 630 return defaultZone;
631 631 }
632 632
633 633 private static synchronized TimeZone setDefaultZone() {
634 634 TimeZone tz = null;
635 635 // get the time zone ID from the system properties
636 636 String zoneID = AccessController.doPrivileged(
637 637 new GetPropertyAction("user.timezone"));
638 638
639 639 // if the time zone ID is not set (yet), perform the
640 640 // platform to Java time zone ID mapping.
641 641 if (zoneID == null || zoneID.equals("")) {
642 642 String country = AccessController.doPrivileged(
643 643 new GetPropertyAction("user.country"));
644 644 String javaHome = AccessController.doPrivileged(
645 645 new GetPropertyAction("java.home"));
646 646 try {
647 647 zoneID = getSystemTimeZoneID(javaHome, country);
648 648 if (zoneID == null) {
649 649 zoneID = GMT_ID;
650 650 }
651 651 } catch (NullPointerException e) {
652 652 zoneID = GMT_ID;
653 653 }
654 654 }
655 655
656 656 // Get the time zone for zoneID. But not fall back to
657 657 // "GMT" here.
658 658 tz = getTimeZone(zoneID, false);
659 659
660 660 if (tz == null) {
661 661 // If the given zone ID is unknown in Java, try to
662 662 // get the GMT-offset-based time zone ID,
663 663 // a.k.a. custom time zone ID (e.g., "GMT-08:00").
664 664 String gmtOffsetID = getSystemGMTOffsetID();
665 665 if (gmtOffsetID != null) {
666 666 zoneID = gmtOffsetID;
667 667 }
668 668 tz = getTimeZone(zoneID, true);
669 669 }
670 670 assert tz != null;
671 671
672 672 final String id = zoneID;
673 673 AccessController.doPrivileged(new PrivilegedAction<Object>() {
674 674 public Object run() {
675 675 System.setProperty("user.timezone", id);
676 676 return null;
677 677 }
678 678 });
679 679
680 680 defaultTimeZone = tz;
681 681 return tz;
682 682 }
683 683
684 684 private static boolean hasPermission() {
685 685 boolean hasPermission = true;
686 686 SecurityManager sm = System.getSecurityManager();
687 687 if (sm != null) {
688 688 try {
689 689 sm.checkPermission(new PropertyPermission
690 690 ("user.timezone", "write"));
691 691 } catch (SecurityException e) {
692 692 hasPermission = false;
693 693 }
694 694 }
695 695 return hasPermission;
696 696 }
697 697
698 698 /**
699 699 * Sets the <code>TimeZone</code> that is
700 700 * returned by the <code>getDefault</code> method. If <code>zone</code>
701 701 * is null, reset the default to the value it had originally when the
702 702 * VM first started.
703 703 * @param zone the new default time zone
704 704 * @see #getDefault
705 705 */
706 706 public static void setDefault(TimeZone zone)
707 707 {
708 708 if (hasPermission()) {
709 709 synchronized (TimeZone.class) {
710 710 defaultTimeZone = zone;
711 711 setDefaultInAppContext(null);
712 712 }
713 713 } else {
714 714 setDefaultInAppContext(zone);
715 715 }
716 716 }
717 717
718 718 /**
719 719 * Returns the default TimeZone in an AppContext if any AppContext
720 720 * has ever used. null is returned if any AppContext hasn't been
721 721 * used or if the AppContext doesn't have the default TimeZone.
722 722 */
723 723 private synchronized static TimeZone getDefaultInAppContext() {
724 724 // JavaAWTAccess provides access implementation-private methods without using reflection.
725 725 JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess();
726 726
727 727 // Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't
728 728 // been loaded. If so, it implies that AWTSecurityManager is not our
729 729 // SecurityManager and we can use a local static variable.
730 730 // This works around a build time issue.
731 731 if (javaAWTAccess == null) {
732 732 return mainAppContextDefault;
733 733 } else {
734 734 if (!javaAWTAccess.isDisposed()) {
735 735 TimeZone tz = (TimeZone)
736 736 javaAWTAccess.get(TimeZone.class);
737 737 if (tz == null && javaAWTAccess.isMainAppContext()) {
738 738 return mainAppContextDefault;
739 739 } else {
740 740 return tz;
741 741 }
742 742 }
743 743 }
744 744 return null;
745 745 }
746 746
747 747 /**
748 748 * Sets the default TimeZone in the AppContext to the given
749 749 * tz. null is handled special: do nothing if any AppContext
750 750 * hasn't been used, remove the default TimeZone in the
751 751 * AppContext otherwise.
752 752 */
753 753 private synchronized static void setDefaultInAppContext(TimeZone tz) {
754 754 // JavaAWTAccess provides access implementation-private methods without using reflection.
755 755 JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess();
756 756
757 757 // Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't
758 758 // been loaded. If so, it implies that AWTSecurityManager is not our
759 759 // SecurityManager and we can use a local static variable.
760 760 // This works around a build time issue.
761 761 if (javaAWTAccess == null) {
762 762 mainAppContextDefault = tz;
763 763 } else {
764 764 if (!javaAWTAccess.isDisposed()) {
765 765 javaAWTAccess.put(TimeZone.class, tz);
766 766 if (javaAWTAccess.isMainAppContext()) {
767 767 mainAppContextDefault = null;
768 768 }
769 769 }
770 770 }
771 771 }
772 772
773 773 /**
774 774 * Returns true if this zone has the same rule and offset as another zone.
775 775 * That is, if this zone differs only in ID, if at all. Returns false
776 776 * if the other zone is null.
777 777 * @param other the <code>TimeZone</code> object to be compared with
778 778 * @return true if the other zone is not null and is the same as this one,
779 779 * with the possible exception of the ID
780 780 * @since 1.2
781 781 */
782 782 public boolean hasSameRules(TimeZone other) {
783 783 return other != null && getRawOffset() == other.getRawOffset() &&
784 784 useDaylightTime() == other.useDaylightTime();
785 785 }
786 786
787 787 /**
788 788 * Creates a copy of this <code>TimeZone</code>.
789 789 *
790 790 * @return a clone of this <code>TimeZone</code>
791 791 */
792 792 public Object clone()
793 793 {
794 794 try {
795 795 TimeZone other = (TimeZone) super.clone();
796 796 other.ID = ID;
797 797 return other;
798 798 } catch (CloneNotSupportedException e) {
799 799 throw new InternalError(e);
800 800 }
801 801 }
802 802
803 803 /**
804 804 * The null constant as a TimeZone.
805 805 */
806 806 static final TimeZone NO_TIMEZONE = null;
807 807
808 808 // =======================privates===============================
809 809
810 810 /**
811 811 * The string identifier of this <code>TimeZone</code>. This is a
812 812 * programmatic identifier used internally to look up <code>TimeZone</code>
813 813 * objects from the system table and also to map them to their localized
814 814 * display names. <code>ID</code> values are unique in the system
815 815 * table but may not be for dynamically created zones.
816 816 * @serial
817 817 */
818 818 private String ID;
819 819 private static volatile TimeZone defaultTimeZone;
820 820
821 821 static final String GMT_ID = "GMT";
822 822 private static final int GMT_ID_LENGTH = 3;
823 823
824 824 // a static TimeZone we can reference if no AppContext is in place
825 825 private static TimeZone mainAppContextDefault;
826 826
827 827 /**
828 828 * Parses a custom time zone identifier and returns a corresponding zone.
829 829 * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
830 830 *
831 831 * @param id a string of the <a href="#CustomID">custom ID form</a>.
832 832 * @return a newly created TimeZone with the given offset and
833 833 * no daylight saving time, or null if the id cannot be parsed.
834 834 */
835 835 private static final TimeZone parseCustomTimeZone(String id) {
836 836 int length;
837 837
838 838 // Error if the length of id isn't long enough or id doesn't
839 839 // start with "GMT".
840 840 if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||
841 841 id.indexOf(GMT_ID) != 0) {
842 842 return null;
843 843 }
844 844
845 845 ZoneInfo zi;
846 846
847 847 // First, we try to find it in the cache with the given
848 848 // id. Even the id is not normalized, the returned ZoneInfo
849 849 // should have its normalized id.
850 850 zi = ZoneInfoFile.getZoneInfo(id);
851 851 if (zi != null) {
852 852 return zi;
853 853 }
854 854
855 855 int index = GMT_ID_LENGTH;
856 856 boolean negative = false;
857 857 char c = id.charAt(index++);
858 858 if (c == '-') {
859 859 negative = true;
860 860 } else if (c != '+') {
861 861 return null;
862 862 }
863 863
864 864 int hours = 0;
865 865 int num = 0;
866 866 int countDelim = 0;
867 867 int len = 0;
868 868 while (index < length) {
869 869 c = id.charAt(index++);
870 870 if (c == ':') {
871 871 if (countDelim > 0) {
872 872 return null;
873 873 }
874 874 if (len > 2) {
875 875 return null;
876 876 }
877 877 hours = num;
878 878 countDelim++;
879 879 num = 0;
880 880 len = 0;
881 881 continue;
882 882 }
883 883 if (c < '0' || c > '9') {
884 884 return null;
885 885 }
886 886 num = num * 10 + (c - '0');
887 887 len++;
888 888 }
889 889 if (index != length) {
890 890 return null;
891 891 }
892 892 if (countDelim == 0) {
893 893 if (len <= 2) {
894 894 hours = num;
895 895 num = 0;
896 896 } else {
897 897 hours = num / 100;
898 898 num %= 100;
899 899 }
900 900 } else {
901 901 if (len != 2) {
902 902 return null;
903 903 }
904 904 }
905 905 if (hours > 23 || num > 59) {
906 906 return null;
907 907 }
908 908 int gmtOffset = (hours * 60 + num) * 60 * 1000;
909 909
910 910 if (gmtOffset == 0) {
911 911 zi = ZoneInfoFile.getZoneInfo(GMT_ID);
912 912 if (negative) {
913 913 zi.setID("GMT-00:00");
914 914 } else {
915 915 zi.setID("GMT+00:00");
916 916 }
917 917 } else {
918 918 zi = ZoneInfoFile.getCustomTimeZone(id, negative ? -gmtOffset : gmtOffset);
919 919 }
920 920 return zi;
921 921 }
922 922 }
↓ open down ↓ |
506 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX