1 16 package org.joda.time; 17 18 import java.io.IOException ; 19 import java.io.ObjectInputStream ; 20 import java.io.ObjectOutputStream ; 21 import java.io.ObjectStreamException ; 22 import java.io.Serializable ; 23 import java.lang.ref.Reference ; 24 import java.lang.ref.SoftReference ; 25 import java.util.HashMap ; 26 import java.util.Locale ; 27 import java.util.Map ; 28 import java.util.Set ; 29 import java.util.TimeZone ; 30 31 import org.joda.time.chrono.BaseChronology; 32 import org.joda.time.chrono.ISOChronology; 33 import org.joda.time.field.FieldUtils; 34 import org.joda.time.format.DateTimeFormatter; 35 import org.joda.time.format.DateTimeFormatterBuilder; 36 import org.joda.time.format.FormatUtils; 37 import org.joda.time.tz.DefaultNameProvider; 38 import org.joda.time.tz.FixedDateTimeZone; 39 import org.joda.time.tz.NameProvider; 40 import org.joda.time.tz.Provider; 41 import org.joda.time.tz.UTCProvider; 42 import org.joda.time.tz.ZoneInfoProvider; 43 44 87 public abstract class DateTimeZone implements Serializable { 88 89 90 private static final long serialVersionUID = 5546345482340108586L; 91 92 93 public static final DateTimeZone UTC = new FixedDateTimeZone("UTC", "UTC", 0, 0); 94 95 96 private static Provider cProvider; 97 98 private static NameProvider cNameProvider; 99 100 private static Set cAvailableIDs; 101 102 private static DateTimeZone cDefault; 103 104 private static DateTimeFormatter cOffsetFormatter; 105 106 107 private static Map iFixedOffsetCache; 108 109 110 private static Map cZoneIdConversion; 111 112 static { 113 setProvider0(null); 114 setNameProvider0(null); 115 116 try { 117 try { 118 cDefault = forID(System.getProperty("user.timezone")); 119 } catch (RuntimeException ex) { 120 } 122 if (cDefault == null) { 123 cDefault = forTimeZone(TimeZone.getDefault()); 124 } 125 } catch (IllegalArgumentException ex) { 126 } 128 129 if (cDefault == null) { 130 cDefault = UTC; 131 } 132 } 133 134 140 public static DateTimeZone getDefault() { 141 return cDefault; 142 } 143 144 151 public static void setDefault(DateTimeZone zone) throws SecurityException { 152 SecurityManager sm = System.getSecurityManager(); 153 if (sm != null) { 154 sm.checkPermission(new JodaTimePermission("DateTimeZone.setDefault")); 155 } 156 if (zone == null) { 157 throw new IllegalArgumentException ("The datetime zone must not be null"); 158 } 159 cDefault = zone; 160 } 161 162 178 public static DateTimeZone forID(String id) { 179 if (id == null) { 180 return getDefault(); 181 } 182 if (id.equals("UTC")) { 183 return DateTimeZone.UTC; 184 } 185 DateTimeZone zone = cProvider.getZone(id); 186 if (zone != null) { 187 return zone; 188 } 189 if (id.startsWith("+") || id.startsWith("-")) { 190 int offset = parseOffset(id); 191 if (offset == 0L) { 192 return DateTimeZone.UTC; 193 } else { 194 id = printOffset(offset); 195 return fixedOffsetZone(id, offset); 196 } 197 } 198 throw new IllegalArgumentException ("The datetime zone id is not recognised: " + id); 199 } 200 201 211 public static DateTimeZone forOffsetHours(int hoursOffset) throws IllegalArgumentException { 212 return forOffsetHoursMinutes(hoursOffset, 0); 213 } 214 215 228 public static DateTimeZone forOffsetHoursMinutes(int hoursOffset, int minutesOffset) throws IllegalArgumentException { 229 if (hoursOffset == 0 && minutesOffset == 0) { 230 return DateTimeZone.UTC; 231 } 232 if (minutesOffset < 0 || minutesOffset > 59) { 233 throw new IllegalArgumentException ("Minutes out of range: " + minutesOffset); 234 } 235 int offset = 0; 236 try { 237 int hoursInMinutes = FieldUtils.safeMultiply(hoursOffset, 60); 238 if (hoursInMinutes < 0) { 239 minutesOffset = FieldUtils.safeAdd(hoursInMinutes, -minutesOffset); 240 } else { 241 minutesOffset = FieldUtils.safeAdd(hoursInMinutes, minutesOffset); 242 } 243 offset = FieldUtils.safeMultiply(minutesOffset, DateTimeConstants.MILLIS_PER_MINUTE); 244 } catch (ArithmeticException ex) { 245 throw new IllegalArgumentException ("Offset is too large"); 246 } 247 return forOffsetMillis(offset); 248 } 249 250 256 public static DateTimeZone forOffsetMillis(int millisOffset) { 257 String id = printOffset(millisOffset); 258 return fixedOffsetZone(id, millisOffset); 259 } 260 261 273 public static DateTimeZone forTimeZone(TimeZone zone) { 274 if (zone == null) { 275 return getDefault(); 276 } 277 final String id = zone.getID(); 278 if (id.equals("UTC")) { 279 return DateTimeZone.UTC; 280 } 281 282 DateTimeZone dtz = null; 284 String convId = getConvertedId(id); 285 if (convId != null) { 286 dtz = cProvider.getZone(convId); 287 } 288 if (dtz == null) { 289 dtz = cProvider.getZone(id); 290 } 291 if (dtz != null) { 292 return dtz; 293 } 294 295 if (convId == null) { 297 convId = zone.getDisplayName(); 298 if (convId.startsWith("GMT+") || convId.startsWith("GMT-")) { 299 convId = convId.substring(3); 300 int offset = parseOffset(convId); 301 if (offset == 0L) { 302 return DateTimeZone.UTC; 303 } else { 304 convId = printOffset(offset); 305 return fixedOffsetZone(convId, offset); 306 } 307 } 308 } 309 310 throw new IllegalArgumentException ("The datetime zone id is not recognised: " + id); 311 } 312 313 321 private static synchronized DateTimeZone fixedOffsetZone(String id, int offset) { 322 if (offset == 0) { 323 return DateTimeZone.UTC; 324 } 325 if (iFixedOffsetCache == null) { 326 iFixedOffsetCache = new HashMap (); 327 } 328 DateTimeZone zone; 329 Reference ref = (Reference ) iFixedOffsetCache.get(id); 330 if (ref != null) { 331 zone = (DateTimeZone) ref.get(); 332 if (zone != null) { 333 return zone; 334 } 335 } 336 zone = new FixedDateTimeZone(id, null, offset, offset); 337 iFixedOffsetCache.put(id, new SoftReference (zone)); 338 return zone; 339 } 340 341 346 public static Set getAvailableIDs() { 347 return cAvailableIDs; 348 } 349 350 359 public static Provider getProvider() { 360 return cProvider; 361 } 362 363 373 public static void setProvider(Provider provider) throws SecurityException { 374 SecurityManager sm = System.getSecurityManager(); 375 if (sm != null) { 376 sm.checkPermission(new JodaTimePermission("DateTimeZone.setProvider")); 377 } 378 setProvider0(provider); 379 } 380 381 387 private static void setProvider0(Provider provider) { 388 if (provider == null) { 389 provider = getDefaultProvider(); 390 } 391 Set ids = provider.getAvailableIDs(); 392 if (ids == null || ids.size() == 0) { 393 throw new IllegalArgumentException 394 ("The provider doesn't have any available ids"); 395 } 396 if (!ids.contains("UTC")) { 397 throw new IllegalArgumentException ("The provider doesn't support UTC"); 398 } 399 if (!UTC.equals(provider.getZone("UTC"))) { 400 throw new IllegalArgumentException ("Invalid UTC zone provided"); 401 } 402 cProvider = provider; 403 cAvailableIDs = ids; 404 } 405 406 415 private static Provider getDefaultProvider() { 416 Provider provider = null; 417 418 try { 419 String providerClass = 420 System.getProperty("org.joda.time.DateTimeZone.Provider"); 421 if (providerClass != null) { 422 try { 423 provider = (Provider) Class.forName(providerClass).newInstance(); 424 } catch (Exception ex) { 425 Thread thread = Thread.currentThread(); 426 thread.getThreadGroup().uncaughtException(thread, ex); 427 } 428 } 429 } catch (SecurityException ex) { 430 } 432 433 if (provider == null) { 434 try { 435 provider = new ZoneInfoProvider("org/joda/time/tz/data"); 436 } catch (Exception ex) { 437 Thread thread = Thread.currentThread(); 438 thread.getThreadGroup().uncaughtException(thread, ex); 439 } 440 } 441 442 if (provider == null) { 443 provider = new UTCProvider(); 444 } 445 446 return provider; 447 } 448 449 458 public static NameProvider getNameProvider() { 459 return cNameProvider; 460 } 461 462 472 public static void setNameProvider(NameProvider nameProvider) throws SecurityException { 473 SecurityManager sm = System.getSecurityManager(); 474 if (sm != null) { 475 sm.checkPermission(new JodaTimePermission("DateTimeZone.setNameProvider")); 476 } 477 setNameProvider0(nameProvider); 478 } 479 480 486 private static void setNameProvider0(NameProvider nameProvider) { 487 if (nameProvider == null) { 488 nameProvider = getDefaultNameProvider(); 489 } 490 cNameProvider = nameProvider; 491 } 492 493 501 private static NameProvider getDefaultNameProvider() { 502 NameProvider nameProvider = null; 503 try { 504 String providerClass = System.getProperty("org.joda.time.DateTimeZone.NameProvider"); 505 if (providerClass != null) { 506 try { 507 nameProvider = (NameProvider) Class.forName(providerClass).newInstance(); 508 } catch (Exception ex) { 509 Thread thread = Thread.currentThread(); 510 thread.getThreadGroup().uncaughtException(thread, ex); 511 } 512 } 513 } catch (SecurityException ex) { 514 } 516 517 if (nameProvider == null) { 518 nameProvider = new DefaultNameProvider(); 519 } 520 521 return nameProvider; 522 } 523 524 531 private static synchronized String getConvertedId(String id) { 532 Map map = cZoneIdConversion; 533 if (map == null) { 534 map = new HashMap (); 536 map.put("GMT", "UTC"); 537 map.put("MIT", "Pacific/Apia"); 538 map.put("HST", "Pacific/Honolulu"); 539 map.put("AST", "America/Anchorage"); 540 map.put("PST", "America/Los_Angeles"); 541 map.put("MST", "America/Denver"); 542 map.put("PNT", "America/Phoenix"); 543 map.put("CST", "America/Chicago"); 544 map.put("EST", "America/New_York"); 545 map.put("IET", "America/Indianapolis"); 546 map.put("PRT", "America/Puerto_Rico"); 547 map.put("CNT", "America/St_Johns"); 548 map.put("AGT", "America/Buenos_Aires"); 549 map.put("BET", "America/Sao_Paulo"); 550 map.put("WET", "Europe/London"); 551 map.put("ECT", "Europe/Paris"); 552 map.put("ART", "Africa/Cairo"); 553 map.put("CAT", "Africa/Harare"); 554 map.put("EET", "Europe/Bucharest"); 555 map.put("EAT", "Africa/Addis_Ababa"); 556 map.put("MET", "Asia/Tehran"); 557 map.put("NET", "Asia/Yerevan"); 558 map.put("PLT", "Asia/Karachi"); 559 map.put("IST", "Asia/Calcutta"); 560 map.put("BST", "Asia/Dhaka"); 561 map.put("VST", "Asia/Saigon"); 562 map.put("CTT", "Asia/Shanghai"); 563 map.put("JST", "Asia/Tokyo"); 564 map.put("ACT", "Australia/Darwin"); 565 map.put("AET", "Australia/Sydney"); 566 map.put("SST", "Pacific/Guadalcanal"); 567 map.put("NST", "Pacific/Auckland"); 568 cZoneIdConversion = map; 569 } 570 return (String ) map.get(id); 571 } 572 573 private static int parseOffset(String str) { 574 Chronology chrono; 575 if (cDefault != null) { 576 chrono = ISOChronology.getInstanceUTC(); 577 } else { 578 chrono = new BaseChronology() { 581 public DateTimeZone getZone() { 582 return null; 583 } 584 public Chronology withUTC() { 585 return this; 586 } 587 public Chronology withZone(DateTimeZone zone) { 588 return this; 589 } 590 public String toString() { 591 return getClass().getName(); 592 } 593 }; 594 } 595 596 return -(int) offsetFormatter().withChronology(chrono).parseMillis(str); 597 } 598 599 608 private static String printOffset(int offset) { 609 StringBuffer buf = new StringBuffer (); 610 if (offset >= 0) { 611 buf.append('+'); 612 } else { 613 buf.append('-'); 614 offset = -offset; 615 } 616 617 int hours = offset / DateTimeConstants.MILLIS_PER_HOUR; 618 FormatUtils.appendPaddedInteger(buf, hours, 2); 619 offset -= hours * (int) DateTimeConstants.MILLIS_PER_HOUR; 620 621 int minutes = offset / DateTimeConstants.MILLIS_PER_MINUTE; 622 buf.append(':'); 623 FormatUtils.appendPaddedInteger(buf, minutes, 2); 624 offset -= minutes * DateTimeConstants.MILLIS_PER_MINUTE; 625 if (offset == 0) { 626 return buf.toString(); 627 } 628 629 int seconds = offset / DateTimeConstants.MILLIS_PER_SECOND; 630 buf.append(':'); 631 FormatUtils.appendPaddedInteger(buf, seconds, 2); 632 offset -= seconds * DateTimeConstants.MILLIS_PER_SECOND; 633 if (offset == 0) { 634 return buf.toString(); 635 } 636 637 buf.append('.'); 638 FormatUtils.appendPaddedInteger(buf, offset, 3); 639 return buf.toString(); 640 } 641 642 647 private static synchronized DateTimeFormatter offsetFormatter() { 648 if (cOffsetFormatter == null) { 649 cOffsetFormatter = new DateTimeFormatterBuilder() 650 .appendTimeZoneOffset(null, true, 2, 4) 651 .toFormatter(); 652 } 653 return cOffsetFormatter; 654 } 655 656 659 private final String iID; 660 661 667 protected DateTimeZone(String id) { 668 if (id == null) { 669 throw new IllegalArgumentException ("Id must not be null"); 670 } 671 iID = id; 672 } 673 674 677 682 public final String getID() { 683 return iID; 684 } 685 686 693 public abstract String getNameKey(long instant); 694 695 705 public final String getShortName(long instant) { 706 return getShortName(instant, null); 707 } 708 709 720 public String getShortName(long instant, Locale locale) { 721 if (locale == null) { 722 locale = Locale.getDefault(); 723 } 724 String nameKey = getNameKey(instant); 725 if (nameKey == null) { 726 return iID; 727 } 728 String name = cNameProvider.getShortName(locale, iID, nameKey); 729 if (name != null) { 730 return name; 731 } 732 return printOffset(getOffset(instant)); 733 } 734 735 745 public final String getName(long instant) { 746 return getName(instant, null); 747 } 748 749 760 public String getName(long instant, Locale locale) { 761 if (locale == null) { 762 locale = Locale.getDefault(); 763 } 764 String nameKey = getNameKey(instant); 765 if (nameKey == null) { 766 return iID; 767 } 768 String name = cNameProvider.getName(locale, iID, nameKey); 769 if (name != null) { 770 return name; 771 } 772 return printOffset(getOffset(instant)); 773 } 774 775 781 public abstract int getOffset(long instant); 782 783 789 public final int getOffset(ReadableInstant instant) { 790 if (instant == null) { 791 return getOffset(DateTimeUtils.currentTimeMillis()); 792 } 793 return getOffset(instant.getMillis()); 794 } 795 796 803 public abstract int getStandardOffset(long instant); 804 805 822 public int getOffsetFromLocal(long instantLocal) { 823 return getOffset(instantLocal - getOffset(instantLocal)); 824 } 825 826 836 public long getMillisKeepLocal(DateTimeZone newZone, long oldInstant) { 837 if (newZone == null) { 838 newZone = DateTimeZone.getDefault(); 839 } 840 if (newZone == this) { 841 return oldInstant; 842 } 843 long instantLocal = oldInstant + getOffset(oldInstant); 844 return instantLocal - newZone.getOffsetFromLocal(instantLocal); 845 } 846 847 852 public abstract boolean isFixed(); 853 854 862 public abstract long nextTransition(long instant); 863 864 872 public abstract long previousTransition(long instant); 873 874 877 882 public java.util.TimeZone toTimeZone() { 883 return java.util.TimeZone.getTimeZone(iID); 884 } 885 886 892 public abstract boolean equals(Object object); 893 894 899 public int hashCode() { 900 return 57 + getID().hashCode(); 901 } 902 903 907 public String toString() { 908 return getID(); 909 } 910 911 917 protected Object writeReplace() throws ObjectStreamException { 918 return new Stub(iID); 919 } 920 921 924 private static final class Stub implements Serializable { 925 926 private static final long serialVersionUID = -6471952376487863581L; 927 928 private transient String iID; 929 930 934 Stub(String id) { 935 iID = id; 936 } 937 938 private void writeObject(ObjectOutputStream out) throws IOException { 939 out.writeUTF(iID); 940 } 941 942 private void readObject(ObjectInputStream in) throws IOException { 943 iID = in.readUTF(); 944 } 945 946 private Object readResolve() throws ObjectStreamException { 947 return forID(iID); 948 } 949 } 950 } 951 | Popular Tags |