src/share/classes/sun/util/calendar/ZoneInfo.java

Print this page




  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.util.calendar;
  27 
  28 import java.io.IOException;
  29 import java.io.ObjectInputStream;
  30 import java.lang.ref.SoftReference;
  31 import java.security.AccessController;
  32 import java.util.ArrayList;

  33 import java.util.Date;
  34 import java.util.List;
  35 import java.util.Locale;
  36 import java.util.Map;

  37 import java.util.SimpleTimeZone;
  38 import java.util.TimeZone;
  39 
  40 /**
  41  * <code>ZoneInfo</code> is an implementation subclass of {@link
  42  * java.util.TimeZone TimeZone} that represents GMT offsets and
  43  * daylight saving time transitions of a time zone.
  44  * <p>
  45  * The daylight saving time transitions are described in the {@link
  46  * #transitions transitions} table consisting of a chronological
  47  * sequence of transitions of GMT offset and/or daylight saving time
  48  * changes. Since all transitions are represented in UTC, in theory,
  49  * <code>ZoneInfo</code> can be used with any calendar systems except
  50  * for the {@link #getOffset(int,int,int,int,int,int) getOffset}
  51  * method that takes Gregorian calendar date fields.
  52  * <p>
  53  * This table covers transitions from 1900 until 2037 (as of version
  54  * 1.4), Before 1900, it assumes that there was no daylight saving
  55  * time and the <code>getOffset</code> methods always return the
  56  * {@link #getRawOffset} value. No Local Mean Time is supported. If a


  61  * <p>
  62  * The date items, transitions, GMT offset(s), etc. are read from a database
  63  * file. See {@link ZoneInfoFile} for details.
  64  * @see java.util.SimpleTimeZone
  65  * @since 1.4
  66  */
  67 
  68 public class ZoneInfo extends TimeZone {
  69 
  70     private static final int UTC_TIME = 0;
  71     private static final int STANDARD_TIME = 1;
  72     private static final int WALL_TIME = 2;
  73 
  74     private static final long OFFSET_MASK = 0x0fL;
  75     private static final long DST_MASK = 0xf0L;
  76     private static final int DST_NSHIFT = 4;
  77     // this bit field is reserved for abbreviation support
  78     private static final long ABBR_MASK = 0xf00L;
  79     private static final int TRANSITION_NSHIFT = 12;
  80 
  81     // Flag for supporting JDK backward compatible IDs, such as "EST".
  82     static final boolean USE_OLDMAPPING;
  83     static {
  84       String oldmapping = AccessController.doPrivileged(
  85           new sun.security.action.GetPropertyAction("sun.timezone.ids.oldmapping", "false")).toLowerCase(Locale.ROOT);
  86       USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true"));
  87     }
  88 
  89     // IDs having conflicting data between Olson and JDK 1.1
  90     static final String[] conflictingIDs = {
  91         "EST", "MST", "HST"
  92     };
  93 
  94     private static final CalendarSystem gcal = CalendarSystem.getGregorianCalendar();
  95 
  96     /**
  97      * The raw GMT offset in milliseconds between this zone and GMT.
  98      * Negative offsets are to the west of Greenwich.  To obtain local
  99      * <em>standard</em> time, add the offset to GMT time.
 100      * @serial
 101      */
 102     private int rawOffset;
 103 
 104     /**
 105      * Difference in milliseconds from the original GMT offset in case
 106      * the raw offset value has been modified by calling {@link
 107      * #setRawOffset}. The initial value is 0.
 108      * @serial
 109      */
 110     private int rawOffsetDiff = 0;
 111 
 112     /**
 113      * A CRC32 value of all pairs of transition time (in milliseconds


 555      * Returns a string representation of this time zone.
 556      * @return the string
 557      */
 558     public String toString() {
 559         return getClass().getName() +
 560             "[id=\"" + getID() + "\"" +
 561             ",offset=" + getLastRawOffset() +
 562             ",dstSavings=" + dstSavings +
 563             ",useDaylight=" + useDaylightTime() +
 564             ",transitions=" + ((transitions != null) ? transitions.length : 0) +
 565             ",lastRule=" + (lastRule == null ? getLastRuleInstance() : lastRule) +
 566             "]";
 567     }
 568 
 569     /**
 570      * Gets all available IDs supported in the Java run-time.
 571      *
 572      * @return an array of time zone IDs.
 573      */
 574     public static String[] getAvailableIDs() {
 575         List<String> idList = ZoneInfoFile.getZoneIDs();
 576         List<String> excluded = ZoneInfoFile.getExcludedZones();
 577         if (excluded != null) {
 578             // List all zones from the idList and excluded lists
 579             List<String> list = new ArrayList<>(idList.size() + excluded.size());
 580             list.addAll(idList);
 581             list.addAll(excluded);
 582             idList = list;
 583         }
 584         String[] ids = new String[idList.size()];
 585         return idList.toArray(ids);
 586     }
 587 
 588     /**
 589      * Gets all available IDs that have the same value as the
 590      * specified raw GMT offset.
 591      *
 592      * @param rawOffset the GMT offset in milliseconds. This
 593      * value should not include any daylight saving time.
 594      *
 595      * @return an array of time zone IDs.
 596      */
 597     public static String[] getAvailableIDs(int rawOffset) {
 598         String[] result;
 599         List<String> matched = new ArrayList<>();
 600         List<String> IDs = ZoneInfoFile.getZoneIDs();
 601         int[] rawOffsets = ZoneInfoFile.getRawOffsets();
 602 
 603     loop:
 604         for (int index = 0; index < rawOffsets.length; index++) {
 605             if (rawOffsets[index] == rawOffset) {
 606                 byte[] indices = ZoneInfoFile.getRawOffsetIndices();
 607                 for (int i = 0; i < indices.length; i++) {
 608                     if (indices[i] == index) {
 609                         matched.add(IDs.get(i++));
 610                         while (i < indices.length && indices[i] == index) {
 611                             matched.add(IDs.get(i++));
 612                         }
 613                         break loop;
 614                     }
 615                 }
 616             }
 617         }
 618 
 619         // We need to add any zones from the excluded zone list that
 620         // currently have the same GMT offset as the specified
 621         // rawOffset. The zones returned by this method may not be
 622         // correct as of return to the caller if any GMT offset
 623         // transition is happening during this GMT offset checking...
 624         List<String> excluded = ZoneInfoFile.getExcludedZones();
 625         if (excluded != null) {
 626             for (String id : excluded) {
 627                 TimeZone zi = getTimeZone(id);
 628                 if (zi != null && zi.getRawOffset() == rawOffset) {
 629                     matched.add(id);
 630                 }
 631             }
 632         }
 633 
 634         result = new String[matched.size()];
 635         matched.toArray(result);
 636         return result;
 637     }
 638 
 639     /**
 640      * Gets the ZoneInfo for the given ID.
 641      *
 642      * @param ID the ID for a ZoneInfo. See TimeZone for detail.
 643      *
 644      * @return the specified ZoneInfo object, or null if there is no
 645      * time zone of the ID.
 646      */
 647     public static TimeZone getTimeZone(String ID) {
 648         String givenID = null;
 649 
 650         /*
 651          * If old JDK compatibility is specified, get the old alias
 652          * name.
 653          */
 654         if (USE_OLDMAPPING) {
 655             String compatibleID = TzIDOldMapping.MAP.get(ID);
 656             if (compatibleID != null) {
 657                 givenID = ID;
 658                 ID = compatibleID;
 659             }
 660         }
 661 
 662         ZoneInfo zi = ZoneInfoFile.getZoneInfo(ID);
 663         if (zi == null) {
 664             // if we can't create an object for the ID, try aliases.
 665             try {
 666                 Map<String, String> map = getAliasTable();
 667                 String alias = ID;
 668                 while ((alias = map.get(alias)) != null) {
 669                     zi = ZoneInfoFile.getZoneInfo(alias);
 670                     if (zi != null) {
 671                         zi.setID(ID);
 672                         zi = ZoneInfoFile.addToCache(ID, zi);
 673                         zi = (ZoneInfo) zi.clone();
 674                         break;
 675                     }
 676                 }
 677             } catch (Exception e) {
 678                 // ignore exceptions
 679             }
 680         }
 681 
 682         if (givenID != null && zi != null) {
 683             zi.setID(givenID);
 684         }
 685         return zi;
 686     }
 687 
 688     private transient SimpleTimeZone lastRule;
 689 
 690     /**
 691      * Returns a SimpleTimeZone object representing the last GMT
 692      * offset and DST schedule or null if this time zone doesn't
 693      * observe DST.
 694      */
 695     private synchronized SimpleTimeZone getLastRule() {
 696         if (lastRule == null) {
 697             lastRule = getLastRuleInstance();
 698         }
 699         return lastRule;
 700     }
 701 
 702     /**
 703      * Returns a SimpleTimeZone object that represents the last
 704      * known daylight saving time rules.
 705      *


 794         }
 795         if (!(other instanceof ZoneInfo)) {
 796             if (getRawOffset() != other.getRawOffset()) {
 797                 return false;
 798             }
 799             // if both have the same raw offset and neither observes
 800             // DST, they have the same rule.
 801             if ((transitions == null)
 802                 && (useDaylightTime() == false)
 803                 && (other.useDaylightTime() == false)) {
 804                 return true;
 805             }
 806             return false;
 807         }
 808         if (getLastRawOffset() != ((ZoneInfo)other).getLastRawOffset()) {
 809             return false;
 810         }
 811         return (checksum == ((ZoneInfo)other).checksum);
 812     }
 813 
 814     private static SoftReference<Map<String, String>> aliasTable;
 815 
 816     static Map<String, String> getCachedAliasTable() {
 817         Map<String, String> aliases = null;
 818 
 819         SoftReference<Map<String, String>> cache = aliasTable;
 820         if (cache != null) {
 821             aliases = cache.get();
 822         }
 823         return aliases;
 824     }
 825 
 826     /**
 827      * Returns a Map from alias time zone IDs to their standard
 828      * time zone IDs.
 829      *
 830      * @return the Map that holds the mappings from alias time zone IDs
 831      *    to their standard time zone IDs, or null if
 832      *    <code>ZoneInfoMappings</code> file is not available.
 833      */
 834      public synchronized static Map<String, String> getAliasTable() {
 835          Map<String, String> aliases = getCachedAliasTable();
 836          if (aliases == null) {
 837              aliases = ZoneInfoFile.getZoneAliases();
 838              if (aliases != null) {
 839                  if (!USE_OLDMAPPING) {
 840                      // Remove the conflicting IDs from the alias table.
 841                      for (String key : conflictingIDs) {
 842                          aliases.remove(key);
 843                      }
 844                  }
 845                  aliasTable = new SoftReference<Map<String, String>>(aliases);
 846              }
 847          }
 848          return aliases;
 849      }
 850 
 851     private void readObject(ObjectInputStream stream)
 852             throws IOException, ClassNotFoundException {
 853         stream.defaultReadObject();
 854         // We don't know how this object from 1.4.x or earlier has
 855         // been mutated. So it should always be marked as `dirty'.
 856         dirty = true;
 857     }
 858 }


  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.util.calendar;
  27 
  28 import java.io.IOException;
  29 import java.io.ObjectInputStream;
  30 import java.lang.ref.SoftReference;
  31 import java.security.AccessController;
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.Date;
  35 import java.util.List;
  36 import java.util.Locale;
  37 import java.util.Map;
  38 import java.util.Set;
  39 import java.util.SimpleTimeZone;
  40 import java.util.TimeZone;
  41 
  42 /**
  43  * <code>ZoneInfo</code> is an implementation subclass of {@link
  44  * java.util.TimeZone TimeZone} that represents GMT offsets and
  45  * daylight saving time transitions of a time zone.
  46  * <p>
  47  * The daylight saving time transitions are described in the {@link
  48  * #transitions transitions} table consisting of a chronological
  49  * sequence of transitions of GMT offset and/or daylight saving time
  50  * changes. Since all transitions are represented in UTC, in theory,
  51  * <code>ZoneInfo</code> can be used with any calendar systems except
  52  * for the {@link #getOffset(int,int,int,int,int,int) getOffset}
  53  * method that takes Gregorian calendar date fields.
  54  * <p>
  55  * This table covers transitions from 1900 until 2037 (as of version
  56  * 1.4), Before 1900, it assumes that there was no daylight saving
  57  * time and the <code>getOffset</code> methods always return the
  58  * {@link #getRawOffset} value. No Local Mean Time is supported. If a


  63  * <p>
  64  * The date items, transitions, GMT offset(s), etc. are read from a database
  65  * file. See {@link ZoneInfoFile} for details.
  66  * @see java.util.SimpleTimeZone
  67  * @since 1.4
  68  */
  69 
  70 public class ZoneInfo extends TimeZone {
  71 
  72     private static final int UTC_TIME = 0;
  73     private static final int STANDARD_TIME = 1;
  74     private static final int WALL_TIME = 2;
  75 
  76     private static final long OFFSET_MASK = 0x0fL;
  77     private static final long DST_MASK = 0xf0L;
  78     private static final int DST_NSHIFT = 4;
  79     // this bit field is reserved for abbreviation support
  80     private static final long ABBR_MASK = 0xf00L;
  81     private static final int TRANSITION_NSHIFT = 12;
  82 













  83     private static final CalendarSystem gcal = CalendarSystem.getGregorianCalendar();
  84 
  85     /**
  86      * The raw GMT offset in milliseconds between this zone and GMT.
  87      * Negative offsets are to the west of Greenwich.  To obtain local
  88      * <em>standard</em> time, add the offset to GMT time.
  89      * @serial
  90      */
  91     private int rawOffset;
  92 
  93     /**
  94      * Difference in milliseconds from the original GMT offset in case
  95      * the raw offset value has been modified by calling {@link
  96      * #setRawOffset}. The initial value is 0.
  97      * @serial
  98      */
  99     private int rawOffsetDiff = 0;
 100 
 101     /**
 102      * A CRC32 value of all pairs of transition time (in milliseconds


 544      * Returns a string representation of this time zone.
 545      * @return the string
 546      */
 547     public String toString() {
 548         return getClass().getName() +
 549             "[id=\"" + getID() + "\"" +
 550             ",offset=" + getLastRawOffset() +
 551             ",dstSavings=" + dstSavings +
 552             ",useDaylight=" + useDaylightTime() +
 553             ",transitions=" + ((transitions != null) ? transitions.length : 0) +
 554             ",lastRule=" + (lastRule == null ? getLastRuleInstance() : lastRule) +
 555             "]";
 556     }
 557 
 558     /**
 559      * Gets all available IDs supported in the Java run-time.
 560      *
 561      * @return an array of time zone IDs.
 562      */
 563     public static String[] getAvailableIDs() {
 564         Set<String> idSet = ZoneInfoFile.getZoneIds();
 565         return idSet.toArray(new String[idSet.size()]);









 566     }
 567 
 568     /**
 569      * Gets all available IDs that have the same value as the
 570      * specified raw GMT offset.
 571      *
 572      * @param rawOffset the GMT offset in milliseconds. This
 573      * value should not include any daylight saving time.
 574      *
 575      * @return an array of time zone IDs.
 576      */
 577     public static String[] getAvailableIDs(int rawOffset) {
 578         return ZoneInfoFile.getZoneIds(rawOffset);






































 579     }
 580 
 581     /**
 582      * Gets the ZoneInfo for the given ID.
 583      *
 584      * @param ID the ID for a ZoneInfo. See TimeZone for detail.
 585      *
 586      * @return the specified ZoneInfo object, or null if there is no
 587      * time zone of the ID.
 588      */
 589     public static TimeZone getTimeZone(String ID) {
 590         return ZoneInfoFile.getZoneInfo(ID);





































 591     }
 592 
 593     private transient SimpleTimeZone lastRule;
 594 
 595     /**
 596      * Returns a SimpleTimeZone object representing the last GMT
 597      * offset and DST schedule or null if this time zone doesn't
 598      * observe DST.
 599      */
 600     private synchronized SimpleTimeZone getLastRule() {
 601         if (lastRule == null) {
 602             lastRule = getLastRuleInstance();
 603         }
 604         return lastRule;
 605     }
 606 
 607     /**
 608      * Returns a SimpleTimeZone object that represents the last
 609      * known daylight saving time rules.
 610      *


 699         }
 700         if (!(other instanceof ZoneInfo)) {
 701             if (getRawOffset() != other.getRawOffset()) {
 702                 return false;
 703             }
 704             // if both have the same raw offset and neither observes
 705             // DST, they have the same rule.
 706             if ((transitions == null)
 707                 && (useDaylightTime() == false)
 708                 && (other.useDaylightTime() == false)) {
 709                 return true;
 710             }
 711             return false;
 712         }
 713         if (getLastRawOffset() != ((ZoneInfo)other).getLastRawOffset()) {
 714             return false;
 715         }
 716         return (checksum == ((ZoneInfo)other).checksum);
 717     }
 718 












 719     /**
 720      * Returns a Map from alias time zone IDs to their standard
 721      * time zone IDs.
 722      *
 723      * @return the Map that holds the mappings from alias time zone IDs
 724      *    to their standard time zone IDs, or null if
 725      *    <code>ZoneInfoMappings</code> file is not available.
 726      */
 727     public static Map<String, String> getAliasTable() {
 728          return ZoneInfoFile.getAliasMap();













 729     }
 730 
 731     private void readObject(ObjectInputStream stream)
 732             throws IOException, ClassNotFoundException {
 733         stream.defaultReadObject();
 734         // We don't know how this object from 1.4.x or earlier has
 735         // been mutated. So it should always be marked as `dirty'.
 736         dirty = true;
 737     }
 738 }