Save This Page
Home » openjdk-7 » java » util » [javadoc | source]
    1   /*
    2    * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   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   /*
   27    * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
   28    * (C) Copyright IBM Corp. 1996 - All Rights Reserved
   29    *
   30    *   The original version of this source code and documentation is copyrighted
   31    * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   32    * materials are provided under terms of a License Agreement between Taligent
   33    * and Sun. This technology is protected by multiple US and International
   34    * patents. This notice and attribution to Taligent may not be removed.
   35    *   Taligent is a registered trademark of Taligent, Inc.
   36    *
   37    */
   38   
   39   package java.util;
   40   
   41   import java.io.ObjectInputStream;
   42   import java.io.ObjectOutputStream;
   43   import java.io.IOException;
   44   import sun.util.calendar.CalendarSystem;
   45   import sun.util.calendar.CalendarUtils;
   46   import sun.util.calendar.BaseCalendar;
   47   import sun.util.calendar.Gregorian;
   48   
   49   /**
   50    * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
   51    * that represents a time zone for use with a Gregorian calendar.
   52    * The class holds an offset from GMT, called <em>raw offset</em>, and start
   53    * and end rules for a daylight saving time schedule.  Since it only holds
   54    * single values for each, it cannot handle historical changes in the offset
   55    * from GMT and the daylight saving schedule, except that the {@link
   56    * #setStartYear setStartYear} method can specify the year when the daylight
   57    * saving time schedule starts in effect.
   58    * <p>
   59    * To construct a <code>SimpleTimeZone</code> with a daylight saving time
   60    * schedule, the schedule can be described with a set of rules,
   61    * <em>start-rule</em> and <em>end-rule</em>. A day when daylight saving time
   62    * starts or ends is specified by a combination of <em>month</em>,
   63    * <em>day-of-month</em>, and <em>day-of-week</em> values. The <em>month</em>
   64    * value is represented by a Calendar {@link Calendar#MONTH MONTH} field
   65    * value, such as {@link Calendar#MARCH}. The <em>day-of-week</em> value is
   66    * represented by a Calendar {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value,
   67    * such as {@link Calendar#SUNDAY SUNDAY}. The meanings of value combinations
   68    * are as follows.
   69    *
   70    * <ul>
   71    * <li><b>Exact day of month</b><br>
   72    * To specify an exact day of month, set the <em>month</em> and
   73    * <em>day-of-month</em> to an exact value, and <em>day-of-week</em> to zero. For
   74    * example, to specify March 1, set the <em>month</em> to {@link Calendar#MARCH
   75    * MARCH}, <em>day-of-month</em> to 1, and <em>day-of-week</em> to 0.</li>
   76    *
   77    * <li><b>Day of week on or after day of month</b><br>
   78    * To specify a day of week on or after an exact day of month, set the
   79    * <em>month</em> to an exact month value, <em>day-of-month</em> to the day on
   80    * or after which the rule is applied, and <em>day-of-week</em> to a negative {@link
   81    * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the
   82    * second Sunday of April, set <em>month</em> to {@link Calendar#APRIL APRIL},
   83    * <em>day-of-month</em> to 8, and <em>day-of-week</em> to <code>-</code>{@link
   84    * Calendar#SUNDAY SUNDAY}.</li>
   85    *
   86    * <li><b>Day of week on or before day of month</b><br>
   87    * To specify a day of the week on or before an exact day of the month, set
   88    * <em>day-of-month</em> and <em>day-of-week</em> to a negative value. For
   89    * example, to specify the last Wednesday on or before the 21st of March, set
   90    * <em>month</em> to {@link Calendar#MARCH MARCH}, <em>day-of-month</em> is -21
   91    * and <em>day-of-week</em> is <code>-</code>{@link Calendar#WEDNESDAY WEDNESDAY}. </li>
   92    *
   93    * <li><b>Last day-of-week of month</b><br>
   94    * To specify, the last day-of-week of the month, set <em>day-of-week</em> to a
   95    * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value and <em>day-of-month</em> to
   96    * -1. For example, to specify the last Sunday of October, set <em>month</em>
   97    * to {@link Calendar#OCTOBER OCTOBER}, <em>day-of-week</em> to {@link
   98    * Calendar#SUNDAY SUNDAY} and <em>day-of-month</em> to -1.  </li>
   99    *
  100    * </ul>
  101    * The time of the day at which daylight saving time starts or ends is
  102    * specified by a millisecond value within the day. There are three kinds of
  103    * <em>mode</em>s to specify the time: {@link #WALL_TIME}, {@link
  104    * #STANDARD_TIME} and {@link #UTC_TIME}. For example, if daylight
  105    * saving time ends
  106    * at 2:00 am in the wall clock time, it can be specified by 7200000
  107    * milliseconds in the {@link #WALL_TIME} mode. In this case, the wall clock time
  108    * for an <em>end-rule</em> means the same thing as the daylight time.
  109    * <p>
  110    * The following are examples of parameters for constructing time zone objects.
  111    * <pre><code>
  112    *      // Base GMT offset: -8:00
  113    *      // DST starts:      at 2:00am in standard time
  114    *      //                  on the first Sunday in April
  115    *      // DST ends:        at 2:00am in daylight time
  116    *      //                  on the last Sunday in October
  117    *      // Save:            1 hour
  118    *      SimpleTimeZone(-28800000,
  119    *                     "America/Los_Angeles",
  120    *                     Calendar.APRIL, 1, -Calendar.SUNDAY,
  121    *                     7200000,
  122    *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
  123    *                     7200000,
  124    *                     3600000)
  125    *
  126    *      // Base GMT offset: +1:00
  127    *      // DST starts:      at 1:00am in UTC time
  128    *      //                  on the last Sunday in March
  129    *      // DST ends:        at 1:00am in UTC time
  130    *      //                  on the last Sunday in October
  131    *      // Save:            1 hour
  132    *      SimpleTimeZone(3600000,
  133    *                     "Europe/Paris",
  134    *                     Calendar.MARCH, -1, Calendar.SUNDAY,
  135    *                     3600000, SimpleTimeZone.UTC_TIME,
  136    *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
  137    *                     3600000, SimpleTimeZone.UTC_TIME,
  138    *                     3600000)
  139    * </code></pre>
  140    * These parameter rules are also applicable to the set rule methods, such as
  141    * <code>setStartRule</code>.
  142    *
  143    * @since 1.1
  144    * @see      Calendar
  145    * @see      GregorianCalendar
  146    * @see      TimeZone
  147    * @author   David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
  148    */
  149   
  150   public class SimpleTimeZone extends TimeZone {
  151       /**
  152        * Constructs a SimpleTimeZone with the given base time zone offset from GMT
  153        * and time zone ID with no daylight saving time schedule.
  154        *
  155        * @param rawOffset  The base time zone offset in milliseconds to GMT.
  156        * @param ID         The time zone name that is given to this instance.
  157        */
  158       public SimpleTimeZone(int rawOffset, String ID)
  159       {
  160           this.rawOffset = rawOffset;
  161           setID (ID);
  162           dstSavings = millisPerHour; // In case user sets rules later
  163       }
  164   
  165       /**
  166        * Constructs a SimpleTimeZone with the given base time zone offset from
  167        * GMT, time zone ID, and rules for starting and ending the daylight
  168        * time.
  169        * Both <code>startTime</code> and <code>endTime</code> are specified to be
  170        * represented in the wall clock time. The amount of daylight saving is
  171        * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is
  172        * equivalent to:
  173        * <pre><code>
  174        *     SimpleTimeZone(rawOffset,
  175        *                    ID,
  176        *                    startMonth,
  177        *                    startDay,
  178        *                    startDayOfWeek,
  179        *                    startTime,
  180        *                    SimpleTimeZone.{@link #WALL_TIME},
  181        *                    endMonth,
  182        *                    endDay,
  183        *                    endDayOfWeek,
  184        *                    endTime,
  185        *                    SimpleTimeZone.{@link #WALL_TIME},
  186        *                    3600000)
  187        * </code></pre>
  188        *
  189        * @param rawOffset       The given base time zone offset from GMT.
  190        * @param ID              The time zone ID which is given to this object.
  191        * @param startMonth      The daylight saving time starting month. Month is
  192        *                        a {@link Calendar#MONTH MONTH} field value (0-based. e.g., 0
  193        *                        for January).
  194        * @param startDay        The day of the month on which the daylight saving time starts.
  195        *                        See the class description for the special cases of this parameter.
  196        * @param startDayOfWeek  The daylight saving time starting day-of-week.
  197        *                        See the class description for the special cases of this parameter.
  198        * @param startTime       The daylight saving time starting time in local wall clock
  199        *                        time (in milliseconds within the day), which is local
  200        *                        standard time in this case.
  201        * @param endMonth        The daylight saving time ending month. Month is
  202        *                        a {@link Calendar#MONTH MONTH} field
  203        *                        value (0-based. e.g., 9 for October).
  204        * @param endDay          The day of the month on which the daylight saving time ends.
  205        *                        See the class description for the special cases of this parameter.
  206        * @param endDayOfWeek    The daylight saving time ending day-of-week.
  207        *                        See the class description for the special cases of this parameter.
  208        * @param endTime         The daylight saving ending time in local wall clock time,
  209        *                        (in milliseconds within the day) which is local daylight
  210        *                        time in this case.
  211        * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
  212        * parameters are out of range for the start or end rule
  213        */
  214       public SimpleTimeZone(int rawOffset, String ID,
  215                             int startMonth, int startDay, int startDayOfWeek, int startTime,
  216                             int endMonth, int endDay, int endDayOfWeek, int endTime)
  217       {
  218           this(rawOffset, ID,
  219                startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
  220                endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
  221                millisPerHour);
  222       }
  223   
  224       /**
  225        * Constructs a SimpleTimeZone with the given base time zone offset from
  226        * GMT, time zone ID, and rules for starting and ending the daylight
  227        * time.
  228        * Both <code>startTime</code> and <code>endTime</code> are assumed to be
  229        * represented in the wall clock time. This constructor is equivalent to:
  230        * <pre><code>
  231        *     SimpleTimeZone(rawOffset,
  232        *                    ID,
  233        *                    startMonth,
  234        *                    startDay,
  235        *                    startDayOfWeek,
  236        *                    startTime,
  237        *                    SimpleTimeZone.{@link #WALL_TIME},
  238        *                    endMonth,
  239        *                    endDay,
  240        *                    endDayOfWeek,
  241        *                    endTime,
  242        *                    SimpleTimeZone.{@link #WALL_TIME},
  243        *                    dstSavings)
  244        * </code></pre>
  245        *
  246        * @param rawOffset       The given base time zone offset from GMT.
  247        * @param ID              The time zone ID which is given to this object.
  248        * @param startMonth      The daylight saving time starting month. Month is
  249        *                        a {@link Calendar#MONTH MONTH} field
  250        *                        value (0-based. e.g., 0 for January).
  251        * @param startDay        The day of the month on which the daylight saving time starts.
  252        *                        See the class description for the special cases of this parameter.
  253        * @param startDayOfWeek  The daylight saving time starting day-of-week.
  254        *                        See the class description for the special cases of this parameter.
  255        * @param startTime       The daylight saving time starting time in local wall clock
  256        *                        time, which is local standard time in this case.
  257        * @param endMonth        The daylight saving time ending month. Month is
  258        *                        a {@link Calendar#MONTH MONTH} field
  259        *                        value (0-based. e.g., 9 for October).
  260        * @param endDay          The day of the month on which the daylight saving time ends.
  261        *                        See the class description for the special cases of this parameter.
  262        * @param endDayOfWeek    The daylight saving time ending day-of-week.
  263        *                        See the class description for the special cases of this parameter.
  264        * @param endTime         The daylight saving ending time in local wall clock time,
  265        *                        which is local daylight time in this case.
  266        * @param dstSavings      The amount of time in milliseconds saved during
  267        *                        daylight saving time.
  268        * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
  269        * parameters are out of range for the start or end rule
  270        * @since 1.2
  271        */
  272       public SimpleTimeZone(int rawOffset, String ID,
  273                             int startMonth, int startDay, int startDayOfWeek, int startTime,
  274                             int endMonth, int endDay, int endDayOfWeek, int endTime,
  275                             int dstSavings)
  276       {
  277           this(rawOffset, ID,
  278                startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
  279                endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
  280                dstSavings);
  281       }
  282   
  283       /**
  284        * Constructs a SimpleTimeZone with the given base time zone offset from
  285        * GMT, time zone ID, and rules for starting and ending the daylight
  286        * time.
  287        * This constructor takes the full set of the start and end rules
  288        * parameters, including modes of <code>startTime</code> and
  289        * <code>endTime</code>. The mode specifies either {@link #WALL_TIME wall
  290        * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
  291        * time}.
  292        *
  293        * @param rawOffset       The given base time zone offset from GMT.
  294        * @param ID              The time zone ID which is given to this object.
  295        * @param startMonth      The daylight saving time starting month. Month is
  296        *                        a {@link Calendar#MONTH MONTH} field
  297        *                        value (0-based. e.g., 0 for January).
  298        * @param startDay        The day of the month on which the daylight saving time starts.
  299        *                        See the class description for the special cases of this parameter.
  300        * @param startDayOfWeek  The daylight saving time starting day-of-week.
  301        *                        See the class description for the special cases of this parameter.
  302        * @param startTime       The daylight saving time starting time in the time mode
  303        *                        specified by <code>startTimeMode</code>.
  304        * @param startTimeMode   The mode of the start time specified by startTime.
  305        * @param endMonth        The daylight saving time ending month. Month is
  306        *                        a {@link Calendar#MONTH MONTH} field
  307        *                        value (0-based. e.g., 9 for October).
  308        * @param endDay          The day of the month on which the daylight saving time ends.
  309        *                        See the class description for the special cases of this parameter.
  310        * @param endDayOfWeek    The daylight saving time ending day-of-week.
  311        *                        See the class description for the special cases of this parameter.
  312        * @param endTime         The daylight saving ending time in time time mode
  313        *                        specified by <code>endTimeMode</code>.
  314        * @param endTimeMode     The mode of the end time specified by endTime
  315        * @param dstSavings      The amount of time in milliseconds saved during
  316        *                        daylight saving time.
  317        *
  318        * @exception IllegalArgumentException if the month, day, dayOfWeek, time more, or
  319        * time parameters are out of range for the start or end rule, or if a time mode
  320        * value is invalid.
  321        *
  322        * @see #WALL_TIME
  323        * @see #STANDARD_TIME
  324        * @see #UTC_TIME
  325        *
  326        * @since 1.4
  327        */
  328       public SimpleTimeZone(int rawOffset, String ID,
  329                             int startMonth, int startDay, int startDayOfWeek,
  330                             int startTime, int startTimeMode,
  331                             int endMonth, int endDay, int endDayOfWeek,
  332                             int endTime, int endTimeMode,
  333                             int dstSavings) {
  334   
  335           setID(ID);
  336           this.rawOffset      = rawOffset;
  337           this.startMonth     = startMonth;
  338           this.startDay       = startDay;
  339           this.startDayOfWeek = startDayOfWeek;
  340           this.startTime      = startTime;
  341           this.startTimeMode  = startTimeMode;
  342           this.endMonth       = endMonth;
  343           this.endDay         = endDay;
  344           this.endDayOfWeek   = endDayOfWeek;
  345           this.endTime        = endTime;
  346           this.endTimeMode    = endTimeMode;
  347           this.dstSavings     = dstSavings;
  348   
  349           // this.useDaylight is set by decodeRules
  350           decodeRules();
  351           if (dstSavings <= 0) {
  352               throw new IllegalArgumentException("Illegal daylight saving value: " + dstSavings);
  353           }
  354       }
  355   
  356       /**
  357        * Sets the daylight saving time starting year.
  358        *
  359        * @param year  The daylight saving starting year.
  360        */
  361       public void setStartYear(int year)
  362       {
  363           startYear = year;
  364           invalidateCache();
  365       }
  366   
  367       /**
  368        * Sets the daylight saving time start rule. For example, if daylight saving
  369        * time starts on the first Sunday in April at 2 am in local wall clock
  370        * time, you can set the start rule by calling:
  371        * <pre><code>setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);</code></pre>
  372        *
  373        * @param startMonth      The daylight saving time starting month. Month is
  374        *                        a {@link Calendar#MONTH MONTH} field
  375        *                        value (0-based. e.g., 0 for January).
  376        * @param startDay        The day of the month on which the daylight saving time starts.
  377        *                        See the class description for the special cases of this parameter.
  378        * @param startDayOfWeek  The daylight saving time starting day-of-week.
  379        *                        See the class description for the special cases of this parameter.
  380        * @param startTime       The daylight saving time starting time in local wall clock
  381        *                        time, which is local standard time in this case.
  382        * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
  383        * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
  384        */
  385       public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime)
  386       {
  387           this.startMonth = startMonth;
  388           this.startDay = startDay;
  389           this.startDayOfWeek = startDayOfWeek;
  390           this.startTime = startTime;
  391           startTimeMode = WALL_TIME;
  392           decodeStartRule();
  393           invalidateCache();
  394       }
  395   
  396       /**
  397        * Sets the daylight saving time start rule to a fixed date within a month.
  398        * This method is equivalent to:
  399        * <pre><code>setStartRule(startMonth, startDay, 0, startTime)</code></pre>
  400        *
  401        * @param startMonth      The daylight saving time starting month. Month is
  402        *                        a {@link Calendar#MONTH MONTH} field
  403        *                        value (0-based. e.g., 0 for January).
  404        * @param startDay        The day of the month on which the daylight saving time starts.
  405        * @param startTime       The daylight saving time starting time in local wall clock
  406        *                        time, which is local standard time in this case.
  407        *                        See the class description for the special cases of this parameter.
  408        * @exception IllegalArgumentException if the <code>startMonth</code>,
  409        * <code>startDayOfMonth</code>, or <code>startTime</code> parameters are out of range
  410        * @since 1.2
  411        */
  412       public void setStartRule(int startMonth, int startDay, int startTime) {
  413           setStartRule(startMonth, startDay, 0, startTime);
  414       }
  415   
  416       /**
  417        * Sets the daylight saving time start rule to a weekday before or after the given date within
  418        * a month, e.g., the first Monday on or after the 8th.
  419        *
  420        * @param startMonth      The daylight saving time starting month. Month is
  421        *                        a {@link Calendar#MONTH MONTH} field
  422        *                        value (0-based. e.g., 0 for January).
  423        * @param startDay        The day of the month on which the daylight saving time starts.
  424        * @param startDayOfWeek  The daylight saving time starting day-of-week.
  425        * @param startTime       The daylight saving time starting time in local wall clock
  426        *                        time, which is local standard time in this case.
  427        * @param after           If true, this rule selects the first <code>dayOfWeek</code> on or
  428        *                        <em>after</em> <code>dayOfMonth</code>.  If false, this rule
  429        *                        selects the last <code>dayOfWeek</code> on or <em>before</em>
  430        *                        <code>dayOfMonth</code>.
  431        * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
  432        * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
  433        * @since 1.2
  434        */
  435       public void setStartRule(int startMonth, int startDay, int startDayOfWeek,
  436                                int startTime, boolean after)
  437       {
  438           // TODO: this method doesn't check the initial values of dayOfMonth or dayOfWeek.
  439           if (after) {
  440               setStartRule(startMonth, startDay, -startDayOfWeek, startTime);
  441           } else {
  442               setStartRule(startMonth, -startDay, -startDayOfWeek, startTime);
  443           }
  444       }
  445   
  446       /**
  447        * Sets the daylight saving time end rule. For example, if daylight saving time
  448        * ends on the last Sunday in October at 2 am in wall clock time,
  449        * you can set the end rule by calling:
  450        * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>
  451        *
  452        * @param endMonth        The daylight saving time ending month. Month is
  453        *                        a {@link Calendar#MONTH MONTH} field
  454        *                        value (0-based. e.g., 9 for October).
  455        * @param endDay          The day of the month on which the daylight saving time ends.
  456        *                        See the class description for the special cases of this parameter.
  457        * @param endDayOfWeek    The daylight saving time ending day-of-week.
  458        *                        See the class description for the special cases of this parameter.
  459        * @param endTime         The daylight saving ending time in local wall clock time,
  460        *                        (in milliseconds within the day) which is local daylight
  461        *                        time in this case.
  462        * @exception IllegalArgumentException if the <code>endMonth</code>, <code>endDay</code>,
  463        * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
  464        */
  465       public void setEndRule(int endMonth, int endDay, int endDayOfWeek,
  466                              int endTime)
  467       {
  468           this.endMonth = endMonth;
  469           this.endDay = endDay;
  470           this.endDayOfWeek = endDayOfWeek;
  471           this.endTime = endTime;
  472           this.endTimeMode = WALL_TIME;
  473           decodeEndRule();
  474           invalidateCache();
  475       }
  476   
  477       /**
  478        * Sets the daylight saving time end rule to a fixed date within a month.
  479        * This method is equivalent to:
  480        * <pre><code>setEndRule(endMonth, endDay, 0, endTime)</code></pre>
  481        *
  482        * @param endMonth        The daylight saving time ending month. Month is
  483        *                        a {@link Calendar#MONTH MONTH} field
  484        *                        value (0-based. e.g., 9 for October).
  485        * @param endDay          The day of the month on which the daylight saving time ends.
  486        * @param endTime         The daylight saving ending time in local wall clock time,
  487        *                        (in milliseconds within the day) which is local daylight
  488        *                        time in this case.
  489        * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
  490        * or <code>endTime</code> parameters are out of range
  491        * @since 1.2
  492        */
  493       public void setEndRule(int endMonth, int endDay, int endTime)
  494       {
  495           setEndRule(endMonth, endDay, 0, endTime);
  496       }
  497   
  498       /**
  499        * Sets the daylight saving time end rule to a weekday before or after the given date within
  500        * a month, e.g., the first Monday on or after the 8th.
  501        *
  502        * @param endMonth        The daylight saving time ending month. Month is
  503        *                        a {@link Calendar#MONTH MONTH} field
  504        *                        value (0-based. e.g., 9 for October).
  505        * @param endDay          The day of the month on which the daylight saving time ends.
  506        * @param endDayOfWeek    The daylight saving time ending day-of-week.
  507        * @param endTime         The daylight saving ending time in local wall clock time,
  508        *                        (in milliseconds within the day) which is local daylight
  509        *                        time in this case.
  510        * @param after           If true, this rule selects the first <code>endDayOfWeek</code> on
  511        *                        or <em>after</em> <code>endDay</code>.  If false, this rule
  512        *                        selects the last <code>endDayOfWeek</code> on or before
  513        *                        <code>endDay</code> of the month.
  514        * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
  515        * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
  516        * @since 1.2
  517        */
  518       public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after)
  519       {
  520           if (after) {
  521               setEndRule(endMonth, endDay, -endDayOfWeek, endTime);
  522           } else {
  523               setEndRule(endMonth, -endDay, -endDayOfWeek, endTime);
  524           }
  525       }
  526   
  527       /**
  528        * Returns the offset of this time zone from UTC at the given
  529        * time. If daylight saving time is in effect at the given time,
  530        * the offset value is adjusted with the amount of daylight
  531        * saving.
  532        *
  533        * @param date the time at which the time zone offset is found
  534        * @return the amount of time in milliseconds to add to UTC to get
  535        * local time.
  536        * @since 1.4
  537        */
  538       public int getOffset(long date) {
  539           return getOffsets(date, null);
  540       }
  541   
  542       /**
  543        * @see TimeZone#getOffsets
  544        */
  545       int getOffsets(long date, int[] offsets) {
  546           int offset = rawOffset;
  547   
  548         computeOffset:
  549           if (useDaylight) {
  550               synchronized (this) {
  551                   if (cacheStart != 0) {
  552                       if (date >= cacheStart && date < cacheEnd) {
  553                           offset += dstSavings;
  554                           break computeOffset;
  555                       }
  556                   }
  557               }
  558               BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
  559                   gcal : (BaseCalendar) CalendarSystem.forName("julian");
  560               BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
  561               // Get the year in local time
  562               cal.getCalendarDate(date + rawOffset, cdate);
  563               int year = cdate.getNormalizedYear();
  564               if (year >= startYear) {
  565                   // Clear time elements for the transition calculations
  566                   cdate.setTimeOfDay(0, 0, 0, 0);
  567                   offset = getOffset(cal, cdate, year, date);
  568               }
  569           }
  570   
  571           if (offsets != null) {
  572               offsets[0] = rawOffset;
  573               offsets[1] = offset - rawOffset;
  574           }
  575           return offset;
  576       }
  577   
  578      /**
  579        * Returns the difference in milliseconds between local time and
  580        * UTC, taking into account both the raw offset and the effect of
  581        * daylight saving, for the specified date and time.  This method
  582        * assumes that the start and end month are distinct.  It also
  583        * uses a default {@link GregorianCalendar} object as its
  584        * underlying calendar, such as for determining leap years.  Do
  585        * not use the result of this method with a calendar other than a
  586        * default <code>GregorianCalendar</code>.
  587        *
  588        * <p><em>Note:  In general, clients should use
  589        * <code>Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)</code>
  590        * instead of calling this method.</em>
  591        *
  592        * @param era       The era of the given date.
  593        * @param year      The year in the given date.
  594        * @param month     The month in the given date. Month is 0-based. e.g.,
  595        *                  0 for January.
  596        * @param day       The day-in-month of the given date.
  597        * @param dayOfWeek The day-of-week of the given date.
  598        * @param millis    The milliseconds in day in <em>standard</em> local time.
  599        * @return          The milliseconds to add to UTC to get local time.
  600        * @exception       IllegalArgumentException the <code>era</code>,
  601        *                  <code>month</code>, <code>day</code>, <code>dayOfWeek</code>,
  602        *                  or <code>millis</code> parameters are out of range
  603        */
  604       public int getOffset(int era, int year, int month, int day, int dayOfWeek,
  605                            int millis)
  606       {
  607           if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
  608               throw new IllegalArgumentException("Illegal era " + era);
  609           }
  610   
  611           int y = year;
  612           if (era == GregorianCalendar.BC) {
  613               // adjust y with the GregorianCalendar-style year numbering.
  614               y = 1 - y;
  615           }
  616   
  617           // If the year isn't representable with the 64-bit long
  618           // integer in milliseconds, convert the year to an
  619           // equivalent year. This is required to pass some JCK test cases
  620           // which are actually useless though because the specified years
  621           // can't be supported by the Java time system.
  622           if (y >= 292278994) {
  623               y = 2800 + y % 2800;
  624           } else if (y <= -292269054) {
  625               // y %= 28 also produces an equivalent year, but positive
  626               // year numbers would be convenient to use the UNIX cal
  627               // command.
  628               y = (int) CalendarUtils.mod((long) y, 28);
  629           }
  630   
  631           // convert year to its 1-based month value
  632           int m = month + 1;
  633   
  634           // First, calculate time as a Gregorian date.
  635           BaseCalendar cal = gcal;
  636           BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
  637           cdate.setDate(y, m, day);
  638           long time = cal.getTime(cdate); // normalize cdate
  639           time += millis - rawOffset; // UTC time
  640   
  641           // If the time value represents a time before the default
  642           // Gregorian cutover, recalculate time using the Julian
  643           // calendar system. For the Julian calendar system, the
  644           // normalized year numbering is ..., -2 (BCE 2), -1 (BCE 1),
  645           // 1, 2 ... which is different from the GregorianCalendar
  646           // style year numbering (..., -1, 0 (BCE 1), 1, 2, ...).
  647           if (time < GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER) {
  648               cal = (BaseCalendar) CalendarSystem.forName("julian");
  649               cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
  650               cdate.setNormalizedDate(y, m, day);
  651               time = cal.getTime(cdate) + millis - rawOffset;
  652           }
  653   
  654           if ((cdate.getNormalizedYear() != y)
  655               || (cdate.getMonth() != m)
  656               || (cdate.getDayOfMonth() != day)
  657               // The validation should be cdate.getDayOfWeek() ==
  658               // dayOfWeek. However, we don't check dayOfWeek for
  659               // compatibility.
  660               || (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
  661               || (millis < 0 || millis >= (24*60*60*1000))) {
  662               throw new IllegalArgumentException();
  663           }
  664   
  665           if (!useDaylight || year < startYear || era != GregorianCalendar.CE) {
  666               return rawOffset;
  667           }
  668   
  669           return getOffset(cal, cdate, y, time);
  670       }
  671   
  672       private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) {
  673           synchronized (this) {
  674               if (cacheStart != 0) {
  675                   if (time >= cacheStart && time < cacheEnd) {
  676                       return rawOffset + dstSavings;
  677                   }
  678                   if (year == cacheYear) {
  679                       return rawOffset;
  680                   }
  681               }
  682           }
  683   
  684           long start = getStart(cal, cdate, year);
  685           long end = getEnd(cal, cdate, year);
  686           int offset = rawOffset;
  687           if (start <= end) {
  688               if (time >= start && time < end) {
  689                   offset += dstSavings;
  690               }
  691               synchronized (this) {
  692                   cacheYear = year;
  693                   cacheStart = start;
  694                   cacheEnd = end;
  695               }
  696           } else {
  697               if (time < end) {
  698                   // TODO: support Gregorian cutover. The previous year
  699                   // may be in the other calendar system.
  700                   start = getStart(cal, cdate, year - 1);
  701                   if (time >= start) {
  702                       offset += dstSavings;
  703                   }
  704               } else if (time >= start) {
  705                   // TODO: support Gregorian cutover. The next year
  706                   // may be in the other calendar system.
  707                   end = getEnd(cal, cdate, year + 1);
  708                   if (time < end) {
  709                       offset += dstSavings;
  710                   }
  711               }
  712               if (start <= end) {
  713                   synchronized (this) {
  714                       // The start and end transitions are in multiple years.
  715                       cacheYear = (long) startYear - 1;
  716                       cacheStart = start;
  717                       cacheEnd = end;
  718                   }
  719               }
  720           }
  721           return offset;
  722       }
  723   
  724       private long getStart(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
  725           int time = startTime;
  726           if (startTimeMode != UTC_TIME) {
  727               time -= rawOffset;
  728           }
  729           return getTransition(cal, cdate, startMode, year, startMonth, startDay,
  730                                startDayOfWeek, time);
  731       }
  732   
  733       private long getEnd(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
  734           int time = endTime;
  735           if (endTimeMode != UTC_TIME) {
  736               time -= rawOffset;
  737           }
  738           if (endTimeMode == WALL_TIME) {
  739               time -= dstSavings;
  740           }
  741           return getTransition(cal, cdate, endMode, year, endMonth, endDay,
  742                                           endDayOfWeek, time);
  743       }
  744   
  745       private long getTransition(BaseCalendar cal, BaseCalendar.Date cdate,
  746                                  int mode, int year, int month, int dayOfMonth,
  747                                  int dayOfWeek, int timeOfDay) {
  748           cdate.setNormalizedYear(year);
  749           cdate.setMonth(month + 1);
  750           switch (mode) {
  751           case DOM_MODE:
  752               cdate.setDayOfMonth(dayOfMonth);
  753               break;
  754   
  755           case DOW_IN_MONTH_MODE:
  756               cdate.setDayOfMonth(1);
  757               if (dayOfMonth < 0) {
  758                   cdate.setDayOfMonth(cal.getMonthLength(cdate));
  759               }
  760               cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
  761               break;
  762   
  763           case DOW_GE_DOM_MODE:
  764               cdate.setDayOfMonth(dayOfMonth);
  765               cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
  766               break;
  767   
  768           case DOW_LE_DOM_MODE:
  769               cdate.setDayOfMonth(dayOfMonth);
  770               cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
  771               break;
  772           }
  773           return cal.getTime(cdate) + timeOfDay;
  774       }
  775   
  776       /**
  777        * Gets the GMT offset for this time zone.
  778        * @return the GMT offset value in milliseconds
  779        * @see #setRawOffset
  780        */
  781       public int getRawOffset()
  782       {
  783           // The given date will be taken into account while
  784           // we have the historical time zone data in place.
  785           return rawOffset;
  786       }
  787   
  788       /**
  789        * Sets the base time zone offset to GMT.
  790        * This is the offset to add to UTC to get local time.
  791        * @see #getRawOffset
  792        */
  793       public void setRawOffset(int offsetMillis)
  794       {
  795           this.rawOffset = offsetMillis;
  796       }
  797   
  798       /**
  799        * Sets the amount of time in milliseconds that the clock is advanced
  800        * during daylight saving time.
  801        * @param millisSavedDuringDST the number of milliseconds the time is
  802        * advanced with respect to standard time when the daylight saving time rules
  803        * are in effect. A positive number, typically one hour (3600000).
  804        * @see #getDSTSavings
  805        * @since 1.2
  806        */
  807       public void setDSTSavings(int millisSavedDuringDST) {
  808           if (millisSavedDuringDST <= 0) {
  809               throw new IllegalArgumentException("Illegal daylight saving value: "
  810                                                  + millisSavedDuringDST);
  811           }
  812           dstSavings = millisSavedDuringDST;
  813       }
  814   
  815       /**
  816        * Returns the amount of time in milliseconds that the clock is
  817        * advanced during daylight saving time.
  818        *
  819        * @return the number of milliseconds the time is advanced with
  820        * respect to standard time when the daylight saving rules are in
  821        * effect, or 0 (zero) if this time zone doesn't observe daylight
  822        * saving time.
  823        *
  824        * @see #setDSTSavings
  825        * @since 1.2
  826        */
  827       public int getDSTSavings() {
  828           return useDaylight ? dstSavings : 0;
  829       }
  830   
  831       /**
  832        * Queries if this time zone uses daylight saving time.
  833        * @return true if this time zone uses daylight saving time;
  834        * false otherwise.
  835        */
  836       public boolean useDaylightTime()
  837       {
  838           return useDaylight;
  839       }
  840   
  841       /**
  842        * Returns {@code true} if this {@code SimpleTimeZone} observes
  843        * Daylight Saving Time. This method is equivalent to {@link
  844        * #useDaylightTime()}.
  845        *
  846        * @return {@code true} if this {@code SimpleTimeZone} observes
  847        * Daylight Saving Time; {@code false} otherwise.
  848        * @since 1.7
  849        */
  850       @Override
  851       public boolean observesDaylightTime() {
  852           return useDaylightTime();
  853       }
  854   
  855       /**
  856        * Queries if the given date is in daylight saving time.
  857        * @return true if daylight saving time is in effective at the
  858        * given date; false otherwise.
  859        */
  860       public boolean inDaylightTime(Date date)
  861       {
  862           return (getOffset(date.getTime()) != rawOffset);
  863       }
  864   
  865       /**
  866        * Returns a clone of this <code>SimpleTimeZone</code> instance.
  867        * @return a clone of this instance.
  868        */
  869       public Object clone()
  870       {
  871           return super.clone();
  872       }
  873   
  874       /**
  875        * Generates the hash code for the SimpleDateFormat object.
  876        * @return the hash code for this object
  877        */
  878       public synchronized int hashCode()
  879       {
  880           return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
  881               endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
  882       }
  883   
  884       /**
  885        * Compares the equality of two <code>SimpleTimeZone</code> objects.
  886        *
  887        * @param obj  The <code>SimpleTimeZone</code> object to be compared with.
  888        * @return     True if the given <code>obj</code> is the same as this
  889        *             <code>SimpleTimeZone</code> object; false otherwise.
  890        */
  891       public boolean equals(Object obj)
  892       {
  893           if (this == obj) {
  894               return true;
  895           }
  896           if (!(obj instanceof SimpleTimeZone)) {
  897               return false;
  898           }
  899   
  900           SimpleTimeZone that = (SimpleTimeZone) obj;
  901   
  902           return getID().equals(that.getID()) &&
  903               hasSameRules(that);
  904       }
  905   
  906       /**
  907        * Returns <code>true</code> if this zone has the same rules and offset as another zone.
  908        * @param other the TimeZone object to be compared with
  909        * @return <code>true</code> if the given zone is a SimpleTimeZone and has the
  910        * same rules and offset as this one
  911        * @since 1.2
  912        */
  913       public boolean hasSameRules(TimeZone other) {
  914           if (this == other) {
  915               return true;
  916           }
  917           if (!(other instanceof SimpleTimeZone)) {
  918               return false;
  919           }
  920           SimpleTimeZone that = (SimpleTimeZone) other;
  921           return rawOffset == that.rawOffset &&
  922               useDaylight == that.useDaylight &&
  923               (!useDaylight
  924                // Only check rules if using DST
  925                || (dstSavings == that.dstSavings &&
  926                    startMode == that.startMode &&
  927                    startMonth == that.startMonth &&
  928                    startDay == that.startDay &&
  929                    startDayOfWeek == that.startDayOfWeek &&
  930                    startTime == that.startTime &&
  931                    startTimeMode == that.startTimeMode &&
  932                    endMode == that.endMode &&
  933                    endMonth == that.endMonth &&
  934                    endDay == that.endDay &&
  935                    endDayOfWeek == that.endDayOfWeek &&
  936                    endTime == that.endTime &&
  937                    endTimeMode == that.endTimeMode &&
  938                    startYear == that.startYear));
  939       }
  940   
  941       /**
  942        * Returns a string representation of this time zone.
  943        * @return a string representation of this time zone.
  944        */
  945       public String toString() {
  946           return getClass().getName() +
  947               "[id=" + getID() +
  948               ",offset=" + rawOffset +
  949               ",dstSavings=" + dstSavings +
  950               ",useDaylight=" + useDaylight +
  951               ",startYear=" + startYear +
  952               ",startMode=" + startMode +
  953               ",startMonth=" + startMonth +
  954               ",startDay=" + startDay +
  955               ",startDayOfWeek=" + startDayOfWeek +
  956               ",startTime=" + startTime +
  957               ",startTimeMode=" + startTimeMode +
  958               ",endMode=" + endMode +
  959               ",endMonth=" + endMonth +
  960               ",endDay=" + endDay +
  961               ",endDayOfWeek=" + endDayOfWeek +
  962               ",endTime=" + endTime +
  963               ",endTimeMode=" + endTimeMode + ']';
  964       }
  965   
  966       // =======================privates===============================
  967   
  968       /**
  969        * The month in which daylight saving time starts.  This value must be
  970        * between <code>Calendar.JANUARY</code> and
  971        * <code>Calendar.DECEMBER</code> inclusive.  This value must not equal
  972        * <code>endMonth</code>.
  973        * <p>If <code>useDaylight</code> is false, this value is ignored.
  974        * @serial
  975        */
  976       private int startMonth;
  977   
  978       /**
  979        * This field has two possible interpretations:
  980        * <dl>
  981        * <dt><code>startMode == DOW_IN_MONTH</code></dt>
  982        * <dd>
  983        * <code>startDay</code> indicates the day of the month of
  984        * <code>startMonth</code> on which daylight
  985        * saving time starts, from 1 to 28, 30, or 31, depending on the
  986        * <code>startMonth</code>.
  987        * </dd>
  988        * <dt><code>startMode != DOW_IN_MONTH</code></dt>
  989        * <dd>
  990        * <code>startDay</code> indicates which <code>startDayOfWeek</code> in the
  991        * month <code>startMonth</code> daylight
  992        * saving time starts on.  For example, a value of +1 and a
  993        * <code>startDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
  994        * first Sunday of <code>startMonth</code>.  Likewise, +2 would indicate the
  995        * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
  996        * </dd>
  997        * </dl>
  998        * <p>If <code>useDaylight</code> is false, this value is ignored.
  999        * @serial
 1000        */
 1001       private int startDay;
 1002   
 1003       /**
 1004        * The day of the week on which daylight saving time starts.  This value
 1005        * must be between <code>Calendar.SUNDAY</code> and
 1006        * <code>Calendar.SATURDAY</code> inclusive.
 1007        * <p>If <code>useDaylight</code> is false or
 1008        * <code>startMode == DAY_OF_MONTH</code>, this value is ignored.
 1009        * @serial
 1010        */
 1011       private int startDayOfWeek;
 1012   
 1013       /**
 1014        * The time in milliseconds after midnight at which daylight saving
 1015        * time starts.  This value is expressed as wall time, standard time,
 1016        * or UTC time, depending on the setting of <code>startTimeMode</code>.
 1017        * <p>If <code>useDaylight</code> is false, this value is ignored.
 1018        * @serial
 1019        */
 1020       private int startTime;
 1021   
 1022       /**
 1023        * The format of startTime, either WALL_TIME, STANDARD_TIME, or UTC_TIME.
 1024        * @serial
 1025        * @since 1.3
 1026        */
 1027       private int startTimeMode;
 1028   
 1029       /**
 1030        * The month in which daylight saving time ends.  This value must be
 1031        * between <code>Calendar.JANUARY</code> and
 1032        * <code>Calendar.UNDECIMBER</code>.  This value must not equal
 1033        * <code>startMonth</code>.
 1034        * <p>If <code>useDaylight</code> is false, this value is ignored.
 1035        * @serial
 1036        */
 1037       private int endMonth;
 1038   
 1039       /**
 1040        * This field has two possible interpretations:
 1041        * <dl>
 1042        * <dt><code>endMode == DOW_IN_MONTH</code></dt>
 1043        * <dd>
 1044        * <code>endDay</code> indicates the day of the month of
 1045        * <code>endMonth</code> on which daylight
 1046        * saving time ends, from 1 to 28, 30, or 31, depending on the
 1047        * <code>endMonth</code>.
 1048        * </dd>
 1049        * <dt><code>endMode != DOW_IN_MONTH</code></dt>
 1050        * <dd>
 1051        * <code>endDay</code> indicates which <code>endDayOfWeek</code> in th
 1052        * month <code>endMonth</code> daylight
 1053        * saving time ends on.  For example, a value of +1 and a
 1054        * <code>endDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
 1055        * first Sunday of <code>endMonth</code>.  Likewise, +2 would indicate the
 1056        * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
 1057        * </dd>
 1058        * </dl>
 1059        * <p>If <code>useDaylight</code> is false, this value is ignored.
 1060        * @serial
 1061        */
 1062       private int endDay;
 1063   
 1064       /**
 1065        * The day of the week on which daylight saving time ends.  This value
 1066        * must be between <code>Calendar.SUNDAY</code> and
 1067        * <code>Calendar.SATURDAY</code> inclusive.
 1068        * <p>If <code>useDaylight</code> is false or
 1069        * <code>endMode == DAY_OF_MONTH</code>, this value is ignored.
 1070        * @serial
 1071        */
 1072       private int endDayOfWeek;
 1073   
 1074       /**
 1075        * The time in milliseconds after midnight at which daylight saving
 1076        * time ends.  This value is expressed as wall time, standard time,
 1077        * or UTC time, depending on the setting of <code>endTimeMode</code>.
 1078        * <p>If <code>useDaylight</code> is false, this value is ignored.
 1079        * @serial
 1080        */
 1081       private int endTime;
 1082   
 1083       /**
 1084        * The format of endTime, either <code>WALL_TIME</code>,
 1085        * <code>STANDARD_TIME</code>, or <code>UTC_TIME</code>.
 1086        * @serial
 1087        * @since 1.3
 1088        */
 1089       private int endTimeMode;
 1090   
 1091       /**
 1092        * The year in which daylight saving time is first observed.  This is an {@link GregorianCalendar#AD AD}
 1093        * value.  If this value is less than 1 then daylight saving time is observed
 1094        * for all <code>AD</code> years.
 1095        * <p>If <code>useDaylight</code> is false, this value is ignored.
 1096        * @serial
 1097        */
 1098       private int startYear;
 1099   
 1100       /**
 1101        * The offset in milliseconds between this zone and GMT.  Negative offsets
 1102        * are to the west of Greenwich.  To obtain local <em>standard</em> time,
 1103        * add the offset to GMT time.  To obtain local wall time it may also be
 1104        * necessary to add <code>dstSavings</code>.
 1105        * @serial
 1106        */
 1107       private int rawOffset;
 1108   
 1109       /**
 1110        * A boolean value which is true if and only if this zone uses daylight
 1111        * saving time.  If this value is false, several other fields are ignored.
 1112        * @serial
 1113        */
 1114       private boolean useDaylight=false; // indicate if this time zone uses DST
 1115   
 1116       private static final int millisPerHour = 60*60*1000;
 1117       private static final int millisPerDay  = 24*millisPerHour;
 1118   
 1119       /**
 1120        * This field was serialized in JDK 1.1, so we have to keep it that way
 1121        * to maintain serialization compatibility. However, there's no need to
 1122        * recreate the array each time we create a new time zone.
 1123        * @serial An array of bytes containing the values {31, 28, 31, 30, 31, 30,
 1124        * 31, 31, 30, 31, 30, 31}.  This is ignored as of the Java 2 platform v1.2, however, it must
 1125        * be streamed out for compatibility with JDK 1.1.
 1126        */
 1127       private final byte monthLength[] = staticMonthLength;
 1128       private final static byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31};
 1129       private final static byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
 1130   
 1131       /**
 1132        * Variables specifying the mode of the start rule.  Takes the following
 1133        * values:
 1134        * <dl>
 1135        * <dt><code>DOM_MODE</code></dt>
 1136        * <dd>
 1137        * Exact day of week; e.g., March 1.
 1138        * </dd>
 1139        * <dt><code>DOW_IN_MONTH_MODE</code></dt>
 1140        * <dd>
 1141        * Day of week in month; e.g., last Sunday in March.
 1142        * </dd>
 1143        * <dt><code>DOW_GE_DOM_MODE</code></dt>
 1144        * <dd>
 1145        * Day of week after day of month; e.g., Sunday on or after March 15.
 1146        * </dd>
 1147        * <dt><code>DOW_LE_DOM_MODE</code></dt>
 1148        * <dd>
 1149        * Day of week before day of month; e.g., Sunday on or before March 15.
 1150        * </dd>
 1151        * </dl>
 1152        * The setting of this field affects the interpretation of the
 1153        * <code>startDay</code> field.
 1154        * <p>If <code>useDaylight</code> is false, this value is ignored.
 1155        * @serial
 1156        * @since 1.1.4
 1157        */
 1158       private int startMode;
 1159   
 1160       /**
 1161        * Variables specifying the mode of the end rule.  Takes the following
 1162        * values:
 1163        * <dl>
 1164        * <dt><code>DOM_MODE</code></dt>
 1165        * <dd>
 1166        * Exact day of week; e.g., March 1.
 1167        * </dd>
 1168        * <dt><code>DOW_IN_MONTH_MODE</code></dt>
 1169        * <dd>
 1170        * Day of week in month; e.g., last Sunday in March.
 1171        * </dd>
 1172        * <dt><code>DOW_GE_DOM_MODE</code></dt>
 1173        * <dd>
 1174        * Day of week after day of month; e.g., Sunday on or after March 15.
 1175        * </dd>
 1176        * <dt><code>DOW_LE_DOM_MODE</code></dt>
 1177        * <dd>
 1178        * Day of week before day of month; e.g., Sunday on or before March 15.
 1179        * </dd>
 1180        * </dl>
 1181        * The setting of this field affects the interpretation of the
 1182        * <code>endDay</code> field.
 1183        * <p>If <code>useDaylight</code> is false, this value is ignored.
 1184        * @serial
 1185        * @since 1.1.4
 1186        */
 1187       private int endMode;
 1188   
 1189       /**
 1190        * A positive value indicating the amount of time saved during DST in
 1191        * milliseconds.
 1192        * Typically one hour (3600000); sometimes 30 minutes (1800000).
 1193        * <p>If <code>useDaylight</code> is false, this value is ignored.
 1194        * @serial
 1195        * @since 1.1.4
 1196        */
 1197       private int dstSavings;
 1198   
 1199       private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
 1200   
 1201       /**
 1202        * Cache values representing a single period of daylight saving
 1203        * time. When the cache values are valid, cacheStart is the start
 1204        * time (inclusive) of daylight saving time and cacheEnd is the
 1205        * end time (exclusive).
 1206        *
 1207        * cacheYear has a year value if both cacheStart and cacheEnd are
 1208        * in the same year. cacheYear is set to startYear - 1 if
 1209        * cacheStart and cacheEnd are in different years. cacheStart is 0
 1210        * if the cache values are void. cacheYear is a long to support
 1211        * Integer.MIN_VALUE - 1 (JCK requirement).
 1212        */
 1213       private transient long cacheYear;
 1214       private transient long cacheStart;
 1215       private transient long cacheEnd;
 1216   
 1217       /**
 1218        * Constants specifying values of startMode and endMode.
 1219        */
 1220       private static final int DOM_MODE          = 1; // Exact day of month, "Mar 1"
 1221       private static final int DOW_IN_MONTH_MODE = 2; // Day of week in month, "lastSun"
 1222       private static final int DOW_GE_DOM_MODE   = 3; // Day of week after day of month, "Sun>=15"
 1223       private static final int DOW_LE_DOM_MODE   = 4; // Day of week before day of month, "Sun<=21"
 1224   
 1225       /**
 1226        * Constant for a mode of start or end time specified as wall clock
 1227        * time.  Wall clock time is standard time for the onset rule, and
 1228        * daylight time for the end rule.
 1229        * @since 1.4
 1230        */
 1231       public static final int WALL_TIME = 0; // Zero for backward compatibility
 1232   
 1233       /**
 1234        * Constant for a mode of start or end time specified as standard time.
 1235        * @since 1.4
 1236        */
 1237       public static final int STANDARD_TIME = 1;
 1238   
 1239       /**
 1240        * Constant for a mode of start or end time specified as UTC. European
 1241        * Union rules are specified as UTC time, for example.
 1242        * @since 1.4
 1243        */
 1244       public static final int UTC_TIME = 2;
 1245   
 1246       // Proclaim compatibility with 1.1
 1247       static final long serialVersionUID = -403250971215465050L;
 1248   
 1249       // the internal serial version which says which version was written
 1250       // - 0 (default) for version up to JDK 1.1.3
 1251       // - 1 for version from JDK 1.1.4, which includes 3 new fields
 1252       // - 2 for JDK 1.3, which includes 2 new fields
 1253       static final int currentSerialVersion = 2;
 1254   
 1255       /**
 1256        * The version of the serialized data on the stream.  Possible values:
 1257        * <dl>
 1258        * <dt><b>0</b> or not present on stream</dt>
 1259        * <dd>
 1260        * JDK 1.1.3 or earlier.
 1261        * </dd>
 1262        * <dt><b>1</b></dt>
 1263        * <dd>
 1264        * JDK 1.1.4 or later.  Includes three new fields: <code>startMode</code>,
 1265        * <code>endMode</code>, and <code>dstSavings</code>.
 1266        * </dd>
 1267        * <dt><b>2</b></dt>
 1268        * <dd>
 1269        * JDK 1.3 or later.  Includes two new fields: <code>startTimeMode</code>
 1270        * and <code>endTimeMode</code>.
 1271        * </dd>
 1272        * </dl>
 1273        * When streaming out this class, the most recent format
 1274        * and the highest allowable <code>serialVersionOnStream</code>
 1275        * is written.
 1276        * @serial
 1277        * @since 1.1.4
 1278        */
 1279       private int serialVersionOnStream = currentSerialVersion;
 1280   
 1281       synchronized private void invalidateCache() {
 1282           cacheYear = startYear - 1;
 1283           cacheStart = cacheEnd = 0;
 1284       }
 1285   
 1286       //----------------------------------------------------------------------
 1287       // Rule representation
 1288       //
 1289       // We represent the following flavors of rules:
 1290       //       5        the fifth of the month
 1291       //       lastSun  the last Sunday in the month
 1292       //       lastMon  the last Monday in the month
 1293       //       Sun>=8   first Sunday on or after the eighth
 1294       //       Sun<=25  last Sunday on or before the 25th
 1295       // This is further complicated by the fact that we need to remain
 1296       // backward compatible with the 1.1 FCS.  Finally, we need to minimize
 1297       // API changes.  In order to satisfy these requirements, we support
 1298       // three representation systems, and we translate between them.
 1299       //
 1300       // INTERNAL REPRESENTATION
 1301       // This is the format SimpleTimeZone objects take after construction or
 1302       // streaming in is complete.  Rules are represented directly, using an
 1303       // unencoded format.  We will discuss the start rule only below; the end
 1304       // rule is analogous.
 1305       //   startMode      Takes on enumerated values DAY_OF_MONTH,
 1306       //                  DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
 1307       //   startDay       The day of the month, or for DOW_IN_MONTH mode, a
 1308       //                  value indicating which DOW, such as +1 for first,
 1309       //                  +2 for second, -1 for last, etc.
 1310       //   startDayOfWeek The day of the week.  Ignored for DAY_OF_MONTH.
 1311       //
 1312       // ENCODED REPRESENTATION
 1313       // This is the format accepted by the constructor and by setStartRule()
 1314       // and setEndRule().  It uses various combinations of positive, negative,
 1315       // and zero values to encode the different rules.  This representation
 1316       // allows us to specify all the different rule flavors without altering
 1317       // the API.
 1318       //   MODE              startMonth    startDay    startDayOfWeek
 1319       //   DOW_IN_MONTH_MODE >=0           !=0         >0
 1320       //   DOM_MODE          >=0           >0          ==0
 1321       //   DOW_GE_DOM_MODE   >=0           >0          <0
 1322       //   DOW_LE_DOM_MODE   >=0           <0          <0
 1323       //   (no DST)          don't care    ==0         don't care
 1324       //
 1325       // STREAMED REPRESENTATION
 1326       // We must retain binary compatibility with the 1.1 FCS.  The 1.1 code only
 1327       // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
 1328       // flag useDaylight.  When we stream an object out, we translate into an
 1329       // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
 1330       // and used by 1.1 code.  Following that, we write out the full
 1331       // representation separately so that contemporary code can recognize and
 1332       // parse it.  The full representation is written in a "packed" format,
 1333       // consisting of a version number, a length, and an array of bytes.  Future
 1334       // versions of this class may specify different versions.  If they wish to
 1335       // include additional data, they should do so by storing them after the
 1336       // packed representation below.
 1337       //----------------------------------------------------------------------
 1338   
 1339       /**
 1340        * Given a set of encoded rules in startDay and startDayOfMonth, decode
 1341        * them and set the startMode appropriately.  Do the same for endDay and
 1342        * endDayOfMonth.  Upon entry, the day of week variables may be zero or
 1343        * negative, in order to indicate special modes.  The day of month
 1344        * variables may also be negative.  Upon exit, the mode variables will be
 1345        * set, and the day of week and day of month variables will be positive.
 1346        * This method also recognizes a startDay or endDay of zero as indicating
 1347        * no DST.
 1348        */
 1349       private void decodeRules()
 1350       {
 1351           decodeStartRule();
 1352           decodeEndRule();
 1353       }
 1354   
 1355       /**
 1356        * Decode the start rule and validate the parameters.  The parameters are
 1357        * expected to be in encoded form, which represents the various rule modes
 1358        * by negating or zeroing certain values.  Representation formats are:
 1359        * <p>
 1360        * <pre>
 1361        *            DOW_IN_MONTH  DOM    DOW>=DOM  DOW<=DOM  no DST
 1362        *            ------------  -----  --------  --------  ----------
 1363        * month       0..11        same    same      same     don't care
 1364        * day        -5..5         1..31   1..31    -1..-31   0
 1365        * dayOfWeek   1..7         0      -1..-7    -1..-7    don't care
 1366        * time        0..ONEDAY    same    same      same     don't care
 1367        * </pre>
 1368        * The range for month does not include UNDECIMBER since this class is
 1369        * really specific to GregorianCalendar, which does not use that month.
 1370        * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
 1371        * end rule is an exclusive limit point.  That is, the range of times that
 1372        * are in DST include those >= the start and < the end.  For this reason,
 1373        * it should be possible to specify an end of ONEDAY in order to include the
 1374        * entire day.  Although this is equivalent to time 0 of the following day,
 1375        * it's not always possible to specify that, for example, on December 31.
 1376        * While arguably the start range should still be 0..ONEDAY-1, we keep
 1377        * the start and end ranges the same for consistency.
 1378        */
 1379       private void decodeStartRule() {
 1380           useDaylight = (startDay != 0) && (endDay != 0);
 1381           if (startDay != 0) {
 1382               if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
 1383                   throw new IllegalArgumentException(
 1384                           "Illegal start month " + startMonth);
 1385               }
 1386               if (startTime < 0 || startTime > millisPerDay) {
 1387                   throw new IllegalArgumentException(
 1388                           "Illegal start time " + startTime);
 1389               }
 1390               if (startDayOfWeek == 0) {
 1391                   startMode = DOM_MODE;
 1392               } else {
 1393                   if (startDayOfWeek > 0) {
 1394                       startMode = DOW_IN_MONTH_MODE;
 1395                   } else {
 1396                       startDayOfWeek = -startDayOfWeek;
 1397                       if (startDay > 0) {
 1398                           startMode = DOW_GE_DOM_MODE;
 1399                       } else {
 1400                           startDay = -startDay;
 1401                           startMode = DOW_LE_DOM_MODE;
 1402                       }
 1403                   }
 1404                   if (startDayOfWeek > Calendar.SATURDAY) {
 1405                       throw new IllegalArgumentException(
 1406                              "Illegal start day of week " + startDayOfWeek);
 1407                   }
 1408               }
 1409               if (startMode == DOW_IN_MONTH_MODE) {
 1410                   if (startDay < -5 || startDay > 5) {
 1411                       throw new IllegalArgumentException(
 1412                               "Illegal start day of week in month " + startDay);
 1413                   }
 1414               } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
 1415                   throw new IllegalArgumentException(
 1416                           "Illegal start day " + startDay);
 1417               }
 1418           }
 1419       }
 1420   
 1421       /**
 1422        * Decode the end rule and validate the parameters.  This method is exactly
 1423        * analogous to decodeStartRule().
 1424        * @see decodeStartRule
 1425        */
 1426       private void decodeEndRule() {
 1427           useDaylight = (startDay != 0) && (endDay != 0);
 1428           if (endDay != 0) {
 1429               if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
 1430                   throw new IllegalArgumentException(
 1431                           "Illegal end month " + endMonth);
 1432               }
 1433               if (endTime < 0 || endTime > millisPerDay) {
 1434                   throw new IllegalArgumentException(
 1435                           "Illegal end time " + endTime);
 1436               }
 1437               if (endDayOfWeek == 0) {
 1438                   endMode = DOM_MODE;
 1439               } else {
 1440                   if (endDayOfWeek > 0) {
 1441                       endMode = DOW_IN_MONTH_MODE;
 1442                   } else {
 1443                       endDayOfWeek = -endDayOfWeek;
 1444                       if (endDay > 0) {
 1445                           endMode = DOW_GE_DOM_MODE;
 1446                       } else {
 1447                           endDay = -endDay;
 1448                           endMode = DOW_LE_DOM_MODE;
 1449                       }
 1450                   }
 1451                   if (endDayOfWeek > Calendar.SATURDAY) {
 1452                       throw new IllegalArgumentException(
 1453                              "Illegal end day of week " + endDayOfWeek);
 1454                   }
 1455               }
 1456               if (endMode == DOW_IN_MONTH_MODE) {
 1457                   if (endDay < -5 || endDay > 5) {
 1458                       throw new IllegalArgumentException(
 1459                               "Illegal end day of week in month " + endDay);
 1460                   }
 1461               } else if (endDay < 1 || endDay > staticMonthLength[endMonth]) {
 1462                   throw new IllegalArgumentException(
 1463                           "Illegal end day " + endDay);
 1464               }
 1465           }
 1466       }
 1467   
 1468       /**
 1469        * Make rules compatible to 1.1 FCS code.  Since 1.1 FCS code only understands
 1470        * day-of-week-in-month rules, we must modify other modes of rules to their
 1471        * approximate equivalent in 1.1 FCS terms.  This method is used when streaming
 1472        * out objects of this class.  After it is called, the rules will be modified,
 1473        * with a possible loss of information.  startMode and endMode will NOT be
 1474        * altered, even though semantically they should be set to DOW_IN_MONTH_MODE,
 1475        * since the rule modification is only intended to be temporary.
 1476        */
 1477       private void makeRulesCompatible()
 1478       {
 1479           switch (startMode) {
 1480           case DOM_MODE:
 1481               startDay = 1 + (startDay / 7);
 1482               startDayOfWeek = Calendar.SUNDAY;
 1483               break;
 1484   
 1485           case DOW_GE_DOM_MODE:
 1486               // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
 1487               // that is, Sun>=1 == firstSun.
 1488               if (startDay != 1) {
 1489                   startDay = 1 + (startDay / 7);
 1490               }
 1491               break;
 1492   
 1493           case DOW_LE_DOM_MODE:
 1494               if (startDay >= 30) {
 1495                   startDay = -1;
 1496               } else {
 1497                   startDay = 1 + (startDay / 7);
 1498               }
 1499               break;
 1500           }
 1501   
 1502           switch (endMode) {
 1503           case DOM_MODE:
 1504               endDay = 1 + (endDay / 7);
 1505               endDayOfWeek = Calendar.SUNDAY;
 1506               break;
 1507   
 1508           case DOW_GE_DOM_MODE:
 1509               // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
 1510               // that is, Sun>=1 == firstSun.
 1511               if (endDay != 1) {
 1512                   endDay = 1 + (endDay / 7);
 1513               }
 1514               break;
 1515   
 1516           case DOW_LE_DOM_MODE:
 1517               if (endDay >= 30) {
 1518                   endDay = -1;
 1519               } else {
 1520                   endDay = 1 + (endDay / 7);
 1521               }
 1522               break;
 1523           }
 1524   
 1525           /*
 1526            * Adjust the start and end times to wall time.  This works perfectly
 1527            * well unless it pushes into the next or previous day.  If that
 1528            * happens, we attempt to adjust the day rule somewhat crudely.  The day
 1529            * rules have been forced into DOW_IN_MONTH mode already, so we change
 1530            * the day of week to move forward or back by a day.  It's possible to
 1531            * make a more refined adjustment of the original rules first, but in
 1532            * most cases this extra effort will go to waste once we adjust the day
 1533            * rules anyway.
 1534            */
 1535           switch (startTimeMode) {
 1536           case UTC_TIME:
 1537               startTime += rawOffset;
 1538               break;
 1539           }
 1540           while (startTime < 0) {
 1541               startTime += millisPerDay;
 1542               startDayOfWeek = 1 + ((startDayOfWeek+5) % 7); // Back 1 day
 1543           }
 1544           while (startTime >= millisPerDay) {
 1545               startTime -= millisPerDay;
 1546               startDayOfWeek = 1 + (startDayOfWeek % 7); // Forward 1 day
 1547           }
 1548   
 1549           switch (endTimeMode) {
 1550           case UTC_TIME:
 1551               endTime += rawOffset + dstSavings;
 1552               break;
 1553           case STANDARD_TIME:
 1554               endTime += dstSavings;
 1555           }
 1556           while (endTime < 0) {
 1557               endTime += millisPerDay;
 1558               endDayOfWeek = 1 + ((endDayOfWeek+5) % 7); // Back 1 day
 1559           }
 1560           while (endTime >= millisPerDay) {
 1561               endTime -= millisPerDay;
 1562               endDayOfWeek = 1 + (endDayOfWeek % 7); // Forward 1 day
 1563           }
 1564       }
 1565   
 1566       /**
 1567        * Pack the start and end rules into an array of bytes.  Only pack
 1568        * data which is not preserved by makeRulesCompatible.
 1569        */
 1570       private byte[] packRules()
 1571       {
 1572           byte[] rules = new byte[6];
 1573           rules[0] = (byte)startDay;
 1574           rules[1] = (byte)startDayOfWeek;
 1575           rules[2] = (byte)endDay;
 1576           rules[3] = (byte)endDayOfWeek;
 1577   
 1578           // As of serial version 2, include time modes
 1579           rules[4] = (byte)startTimeMode;
 1580           rules[5] = (byte)endTimeMode;
 1581   
 1582           return rules;
 1583       }
 1584   
 1585       /**
 1586        * Given an array of bytes produced by packRules, interpret them
 1587        * as the start and end rules.
 1588        */
 1589       private void unpackRules(byte[] rules)
 1590       {
 1591           startDay       = rules[0];
 1592           startDayOfWeek = rules[1];
 1593           endDay         = rules[2];
 1594           endDayOfWeek   = rules[3];
 1595   
 1596           // As of serial version 2, include time modes
 1597           if (rules.length >= 6) {
 1598               startTimeMode = rules[4];
 1599               endTimeMode   = rules[5];
 1600           }
 1601       }
 1602   
 1603       /**
 1604        * Pack the start and end times into an array of bytes.  This is required
 1605        * as of serial version 2.
 1606        */
 1607       private int[] packTimes() {
 1608           int[] times = new int[2];
 1609           times[0] = startTime;
 1610           times[1] = endTime;
 1611           return times;
 1612       }
 1613   
 1614       /**
 1615        * Unpack the start and end times from an array of bytes.  This is required
 1616        * as of serial version 2.
 1617        */
 1618       private void unpackTimes(int[] times) {
 1619           startTime = times[0];
 1620           endTime = times[1];
 1621       }
 1622   
 1623       /**
 1624        * Save the state of this object to a stream (i.e., serialize it).
 1625        *
 1626        * @serialData We write out two formats, a JDK 1.1 compatible format, using
 1627        * <code>DOW_IN_MONTH_MODE</code> rules, in the required section, followed
 1628        * by the full rules, in packed format, in the optional section.  The
 1629        * optional section will be ignored by JDK 1.1 code upon stream in.
 1630        * <p> Contents of the optional section: The length of a byte array is
 1631        * emitted (int); this is 4 as of this release. The byte array of the given
 1632        * length is emitted. The contents of the byte array are the true values of
 1633        * the fields <code>startDay</code>, <code>startDayOfWeek</code>,
 1634        * <code>endDay</code>, and <code>endDayOfWeek</code>.  The values of these
 1635        * fields in the required section are approximate values suited to the rule
 1636        * mode <code>DOW_IN_MONTH_MODE</code>, which is the only mode recognized by
 1637        * JDK 1.1.
 1638        */
 1639       private void writeObject(ObjectOutputStream stream)
 1640            throws IOException
 1641       {
 1642           // Construct a binary rule
 1643           byte[] rules = packRules();
 1644           int[] times = packTimes();
 1645   
 1646           // Convert to 1.1 FCS rules.  This step may cause us to lose information.
 1647           makeRulesCompatible();
 1648   
 1649           // Write out the 1.1 FCS rules
 1650           stream.defaultWriteObject();
 1651   
 1652           // Write out the binary rules in the optional data area of the stream.
 1653           stream.writeInt(rules.length);
 1654           stream.write(rules);
 1655           stream.writeObject(times);
 1656   
 1657           // Recover the original rules.  This recovers the information lost
 1658           // by makeRulesCompatible.
 1659           unpackRules(rules);
 1660           unpackTimes(times);
 1661       }
 1662   
 1663       /**
 1664        * Reconstitute this object from a stream (i.e., deserialize it).
 1665        *
 1666        * We handle both JDK 1.1
 1667        * binary formats and full formats with a packed byte array.
 1668        */
 1669       private void readObject(ObjectInputStream stream)
 1670            throws IOException, ClassNotFoundException
 1671       {
 1672           stream.defaultReadObject();
 1673   
 1674           if (serialVersionOnStream < 1) {
 1675               // Fix a bug in the 1.1 SimpleTimeZone code -- namely,
 1676               // startDayOfWeek and endDayOfWeek were usually uninitialized.  We can't do
 1677               // too much, so we assume SUNDAY, which actually works most of the time.
 1678               if (startDayOfWeek == 0) {
 1679                   startDayOfWeek = Calendar.SUNDAY;
 1680               }
 1681               if (endDayOfWeek == 0) {
 1682                   endDayOfWeek = Calendar.SUNDAY;
 1683               }
 1684   
 1685               // The variables dstSavings, startMode, and endMode are post-1.1, so they
 1686               // won't be present if we're reading from a 1.1 stream.  Fix them up.
 1687               startMode = endMode = DOW_IN_MONTH_MODE;
 1688               dstSavings = millisPerHour;
 1689           } else {
 1690               // For 1.1.4, in addition to the 3 new instance variables, we also
 1691               // store the actual rules (which have not be made compatible with 1.1)
 1692               // in the optional area.  Read them in here and parse them.
 1693               int length = stream.readInt();
 1694               byte[] rules = new byte[length];
 1695               stream.readFully(rules);
 1696               unpackRules(rules);
 1697           }
 1698   
 1699           if (serialVersionOnStream >= 2) {
 1700               int[] times = (int[]) stream.readObject();
 1701               unpackTimes(times);
 1702           }
 1703   
 1704           serialVersionOnStream = currentSerialVersion;
 1705       }
 1706   }

Save This Page
Home » openjdk-7 » java » util » [javadoc | source]