17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /*
27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*   Copyright (C) 1996-2014, International Business Machines
37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*   Corporation and others.  All Rights Reserved.
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*/
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.util;
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.IOException;
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Date;
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.Grego;
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icuenhanced java.util.SimpleTimeZone}.{@icu _usage_}
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * that represents a time zone for use with a Gregorian calendar. This
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * class does not handle historical changes.
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Use a negative value for <code>dayOfWeekInMonth</code> to indicate that
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>SimpleTimeZone</code> should count from the end of the month backwards.  For
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * example, if Daylight Savings Time starts or ends at the last Sunday in a month, use
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>dayOfWeekInMonth = -1</code> along with <code>dayOfWeek = Calendar.SUNDAY</code>
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * to specify the rule.
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see      Calendar
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see      GregorianCalendar
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see      TimeZone
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author   David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 2.0
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class SimpleTimeZone extends BasicTimeZone {
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final long serialVersionUID = -7034676239311322769L;
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constant for a mode of start or end time specified as local wall time.
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int WALL_TIME = 0;
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constant for a mode of start or end time specified as local standard time.
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int STANDARD_TIME = 1;
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constant for a mode of start or end time specified as UTC.
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int UTC_TIME = 2;
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a SimpleTimeZone with the given base time zone offset from GMT
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * and time zone ID. Timezone IDs can be obtained from
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * TimeZone.getAvailableIDs. Normally you should use TimeZone.getDefault to
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * construct a TimeZone.
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param rawOffset  The given base time zone offset to GMT.
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ID         The time zone ID which is obtained from
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                   TimeZone.getAvailableIDs.
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleTimeZone(int rawOffset, String ID) {
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(ID);
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        construct(rawOffset, 0, 0, 0,
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                0, WALL_TIME,
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                0, 0, 0,
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                0, WALL_TIME,
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Grego.MILLIS_PER_HOUR);
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a SimpleTimeZone with the given base time zone offset from
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * GMT, time zone ID, time to start and end the daylight time. Timezone IDs
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * can be obtained from TimeZone.getAvailableIDs. Normally you should use
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * TimeZone.getDefault to create a TimeZone. For a time zone that does not
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * use daylight saving time, do not use this constructor; instead you should
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * use SimpleTimeZone(rawOffset, ID).
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * By default, this constructor specifies day-of-week-in-month rules. That
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is, if the startDay is 1, and the startDayOfWeek is SUNDAY, then this
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * indicates the first Sunday in the startMonth. A startDay of -1 likewise
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * indicates the last Sunday. However, by using negative or zero values for
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * certain parameters, other types of rules can be specified.
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Day of month. To specify an exact day of the month, such as March 1, set
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * startDayOfWeek to zero.
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Day of week after day of month. To specify the first day of the week
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * occurring on or after an exact day of the month, make the day of the week
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * negative. For example, if startDay is 5 and startDayOfWeek is -MONDAY,
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * this indicates the first Monday on or after the 5th day of the
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * startMonth.
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Day of week before day of month. To specify the last day of the week
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * occurring on or before an exact day of the month, make the day of the
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * week and the day of the month negative. For example, if startDay is -21
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * and startDayOfWeek is -WEDNESDAY, this indicates the last Wednesday on or
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * before the 21st of the startMonth.
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The above examples refer to the startMonth, startDay, and startDayOfWeek;
1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the same applies for the endMonth, endDay, and endDayOfWeek.
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param rawOffset       The given base time zone offset to GMT.
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ID              The time zone ID which is obtained from
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        TimeZone.getAvailableIDs.
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startMonth      The daylight savings starting month. Month is
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        0-based. eg, 0 for January.
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startDay        The daylight savings starting
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        day-of-week-in-month. Please see the member
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        description for an example.
1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startDayOfWeek  The daylight savings starting day-of-week. Please
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        see the member description for an example.
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startTime       The daylight savings starting time in local wall
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        time, which is standard time in this case. Please see the
1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        member description for an example.
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endMonth        The daylight savings ending month. Month is
1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        0-based. eg, 0 for January.
1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endDay          The daylight savings ending day-of-week-in-month.
1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        Please see the member description for an example.
1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endDayOfWeek    The daylight savings ending day-of-week. Please
1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        see the member description for an example.
1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endTime         The daylight savings ending time in local wall time,
1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        which is daylight time in this case. Please see the
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        member description for an example.
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException the month, day, dayOfWeek, or time
1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * parameters are out of range for the start or end rule
1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleTimeZone(int rawOffset, String ID,
1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int startMonth, int startDay, int startDayOfWeek, int startTime,
1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int endMonth, int endDay, int endDayOfWeek, int endTime) {
1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(ID);
1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        construct(rawOffset,
1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                startMonth, startDay, startDayOfWeek,
1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                startTime, WALL_TIME,
1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                endMonth, endDay, endDayOfWeek,
1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                endTime, WALL_TIME,
1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Grego.MILLIS_PER_HOUR);
1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a SimpleTimeZone with the given base time zone offset from
1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * GMT, time zone ID, time and its mode to start and end the daylight time.
1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The mode specifies either {@link #WALL_TIME} or {@link #STANDARD_TIME}
1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * or {@link #UTC_TIME}.
1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param rawOffset       The given base time zone offset to GMT.
1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ID              The time zone ID which is obtained from
1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        TimeZone.getAvailableIDs.
1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startMonth      The daylight savings starting month. Month is
1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        0-based. eg, 0 for January.
1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startDay        The daylight savings starting
1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        day-of-week-in-month. Please see the member
1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        description for an example.
1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startDayOfWeek  The daylight savings starting day-of-week. Please
1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        see the member description for an example.
1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startTime       The daylight savings starting time in local wall
1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        time, which is standard time in this case. Please see the
1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        member description for an example.
1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startTimeMode   The mode of the start time specified by startTime.
1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endMonth        The daylight savings ending month. Month is
1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        0-based. eg, 0 for January.
1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endDay          The daylight savings ending day-of-week-in-month.
1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        Please see the member description for an example.
1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endDayOfWeek    The daylight savings ending day-of-week. Please
1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        see the member description for an example.
1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endTime         The daylight savings ending time in local wall time,
1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        which is daylight time in this case. Please see the
1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        member description for an example.
1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endTimeMode     The mode of the end time specified by endTime.
1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dstSavings      The amount of time in ms saved during DST.
1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException the month, day, dayOfWeek, or time
1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * parameters are out of range for the start or end rule
1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleTimeZone(int rawOffset,  String ID,
1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int startMonth, int startDay,
1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int startDayOfWeek, int startTime,
1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int startTimeMode,
1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int endMonth, int endDay,
1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int endDayOfWeek, int endTime,
1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int endTimeMode,int dstSavings){
1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(ID);
1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        construct(rawOffset,
1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  startMonth, startDay, startDayOfWeek,
1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  startTime, startTimeMode,
1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  endMonth, endDay, endDayOfWeek,
1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  endTime, endTimeMode,
1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  dstSavings);
1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructor.  This constructor is identical to the 10-argument
1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * constructor, but also takes a dstSavings parameter.
1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param rawOffset       The given base time zone offset to GMT.
1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ID              The time zone ID which is obtained from
1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        TimeZone.getAvailableIDs.
2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startMonth      The daylight savings starting month. Month is
2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        0-based. eg, 0 for January.
2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startDay        The daylight savings starting
2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        day-of-week-in-month. Please see the member
2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        description for an example.
2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startDayOfWeek  The daylight savings starting day-of-week. Please
2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        see the member description for an example.
2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startTime       The daylight savings starting time in local wall
2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        time, which is standard time in this case. Please see the
2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        member description for an example.
2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endMonth        The daylight savings ending month. Month is
2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        0-based. eg, 0 for January.
2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endDay          The daylight savings ending day-of-week-in-month.
2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        Please see the member description for an example.
2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endDayOfWeek    The daylight savings ending day-of-week. Please
2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        see the member description for an example.
2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param endTime         The daylight savings ending time in local wall time,
2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        which is daylight time in this case. Please see the
2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                        member description for an example.
2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dstSavings      The amount of time in ms saved during DST.
2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException the month, day, dayOfWeek, or time
2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * parameters are out of range for the start or end rule
2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleTimeZone(int rawOffset, String ID,
2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int startMonth, int startDay, int startDayOfWeek, int startTime,
2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int endMonth, int endDay, int endDayOfWeek, int endTime,
2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int dstSavings) {
2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(ID);
2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        construct(rawOffset,
2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                startMonth, startDay, startDayOfWeek,
2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                startTime, WALL_TIME,
2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                endMonth, endDay, endDayOfWeek,
2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                endTime, WALL_TIME,
2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                dstSavings);
2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setID(String ID) {
2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super.setID(ID);
2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        transitionRulesInitialized = false;
2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides TimeZone
2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the base time zone offset to GMT.
2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This is the offset to add "to" UTC to get local time.
2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param offsetMillis the raw offset of the time zone
2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setRawOffset(int offsetMillis) {
2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        raw = offsetMillis;
2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        transitionRulesInitialized = false;
2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides TimeZone
2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Gets the GMT offset for this time zone.
2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the raw offset
2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getRawOffset() {
2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return raw;
2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the daylight savings starting year.
2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param year  The daylight savings starting year.
2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setStartYear(int year) {
2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        getSTZInfo().sy = year;
2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.startYear = year;
2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        transitionRulesInitialized = false;
2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the daylight savings starting rule. For example, Daylight Savings
2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Time starts at the second Sunday in March, at 2 AM in standard time.
2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Therefore, you can set the start rule by calling:
2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * setStartRule(Calendar.MARCH, 2, Calendar.SUNDAY, 2*60*60*1000);
3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month             The daylight savings starting month. Month is
3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          0-based. eg, 0 for January.
3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeekInMonth  The daylight savings starting
3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          day-of-week-in-month. Please see the member
3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          description for an example.
3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeek         The daylight savings starting day-of-week.
3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          Please see the member description for an
3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          example.
3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param time              The daylight savings starting time in local wall
3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          time, which is standard time in this case. Please see
3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          the member description for an example.
3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException the month, dayOfWeekInMonth,
3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * dayOfWeek, or time parameters are out of range
3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setStartRule(int month, int dayOfWeekInMonth, int dayOfWeek,
3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                             int time) {
3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        getSTZInfo().setStart(month, dayOfWeekInMonth, dayOfWeek, time, -1, false);
3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setStartRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME);
3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the daylight savings starting rule. For example, in the U.S., Daylight Savings
3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Time starts at the second Sunday in March, at 2 AM in standard time.
3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Therefore, you can set the start rule by calling:
3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <code>setStartRule(Calendar.MARCH, 2, Calendar.SUNDAY, 2*60*60*1000);</code>
3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calculate
3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the exact starting date.  Their exact meaning depend on their respective signs,
3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * allowing various types of rules to be constructed, as follows:<ul>
3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *   <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the
3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday
3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       of the month).
3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *   <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify
3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       the day of week in the month counting backward from the end of the month.
3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       (e.g., (-1, MONDAY) is the last Monday in the month)
3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *   <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth
3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       specifies the day of the month, regardless of what day of the week it is.
3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       (e.g., (10, 0) is the tenth day of the month)
3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *   <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth
3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       specifies the day of the month counting backward from the end of the
3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       month, regardless of what day of the week it is (e.g., (-2, 0) is the
3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       next-to-last day of the month).
3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *   <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the
3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       first specified day of the week on or after the specfied day of the month.
3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month
3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       [or the 15th itself if the 15th is a Sunday].)
3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *   <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the
3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       last specified day of the week on or before the specified day of the month.
3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month
3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *       [or the 20th itself if the 20th is a Tuesday].)</ul>
3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month the daylight savings starting month. Month is 0-based.
3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * eg, 0 for January.
3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeekInMonth the daylight savings starting
3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * day-of-week-in-month. Please see the member description for an example.
3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeek the daylight savings starting day-of-week. Please see
3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the member description for an example.
3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param time the daylight savings starting time. Please see the member
3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * description for an example.
3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void setStartRule(int month, int dayOfWeekInMonth, int dayOfWeek, int time, int mode) {
3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assert (!isFrozen());
3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startMonth     =  month;
3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startDay       = dayOfWeekInMonth;
3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startDayOfWeek = dayOfWeek;
3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startTime      = time;
3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startTimeMode  = mode;
3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        decodeStartRule();
3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        transitionRulesInitialized = false;
3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the DST start rule to a fixed date within a month.
3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month         The month in which this rule occurs (0-based).
3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfMonth    The date in that month (1-based).
3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param time          The time of that day (number of millis after midnight)
3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      when DST takes effect in local wall time, which is
3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      standard time in this case.
3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException the month,
3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * dayOfMonth, or time parameters are out of range
3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setStartRule(int month, int dayOfMonth, int time) {
3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        getSTZInfo().setStart(month, -1, -1, time, dayOfMonth, false);
3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setStartRule(month, dayOfMonth, 0, time, WALL_TIME);
3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the DST start rule to a weekday before or after a give date within
4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * a month, e.g., the first Monday on or after the 8th.
4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month         The month in which this rule occurs (0-based).
4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfMonth    A date within that month (1-based).
4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeek     The day of the week on which this rule occurs.
4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param time          The time of that day (number of millis after midnight)
4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      when DST takes effect in local wall time, which is
4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      standard time in this case.
4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param after         If true, this rule selects the first dayOfWeek on
4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      or after dayOfMonth.  If false, this rule selects
4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      the last dayOfWeek on or before dayOfMonth.
4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException the month, dayOfMonth,
4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * dayOfWeek, or time parameters are out of range
4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setStartRule(int month, int dayOfMonth, int dayOfWeek, int time, boolean after) {
4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        getSTZInfo().setStart(month, -1, dayOfWeek, time, dayOfMonth, after);
4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setStartRule(month, after ? dayOfMonth : -dayOfMonth,
4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                -dayOfWeek, time, WALL_TIME);
4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the daylight savings ending rule. For example, if Daylight Savings Time
4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * ends at the last (-1) Sunday in October, at 2 AM in standard time,
4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * you can set the end rule by calling:
4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>
4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month             The daylight savings ending month. Month is
4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          0-based. eg, 0 for January.
4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeekInMonth  The daylight savings ending
4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          day-of-week-in-month. Please see the member
4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          description for an example.
4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeek         The daylight savings ending day-of-week. Please
4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          see the member description for an example.
4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param time              The daylight savings ending time in local wall time,
4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          which is daylight time in this case. Please see the
4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          member description for an example.
4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException the month, dayOfWeekInMonth,
4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * dayOfWeek, or time parameters are out of range
4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setEndRule(int month, int dayOfWeekInMonth, int dayOfWeek, int time) {
4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        getSTZInfo().setEnd(month, dayOfWeekInMonth, dayOfWeek, time, -1, false);
4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setEndRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME);
4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the DST end rule to a fixed date within a month.
4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month         The month in which this rule occurs (0-based).
4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfMonth    The date in that month (1-based).
4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param time          The time of that day (number of millis after midnight)
4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      when DST ends in local wall time, which is daylight
4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      time in this case.
4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException the month,
4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * dayOfMonth, or time parameters are out of range
4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setEndRule(int month, int dayOfMonth, int time) {
4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        getSTZInfo().setEnd(month, -1, -1, time, dayOfMonth, false);
4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setEndRule(month, dayOfMonth, WALL_TIME, time);
4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the DST end rule to a weekday before or after a give date within
4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * a month, e.g., the first Monday on or after the 8th.
4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month         The month in which this rule occurs (0-based).
4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfMonth    A date within that month (1-based).
4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeek     The day of the week on which this rule occurs.
4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param time          The time of that day (number of millis after midnight)
4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      when DST ends in local wall time, which is daylight
4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      time in this case.
4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param after         If true, this rule selects the first dayOfWeek on
4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      or after dayOfMonth.  If false, this rule selects
4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      the last dayOfWeek on or before dayOfMonth.
4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException the month, dayOfMonth,
4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * dayOfWeek, or time parameters are out of range
4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setEndRule(int month, int dayOfMonth, int dayOfWeek, int time, boolean after) {
4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        getSTZInfo().setEnd(month, -1, dayOfWeek, time, dayOfMonth, after);
4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setEndRule(month, dayOfMonth, dayOfWeek, time, WALL_TIME, after);
4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void setEndRule(int month, int dayOfMonth, int dayOfWeek,
5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                int time, int mode, boolean after){
5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assert (!isFrozen());
5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setEndRule(month, after ? dayOfMonth : -dayOfMonth, -dayOfWeek, time, mode);
5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the daylight savings ending rule. For example, in the U.S., Daylight
5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Savings Time ends at the first Sunday in November, at 2 AM in standard time.
5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Therefore, you can set the end rule by calling:
5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2*60*60*1000);
5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Various other types of rules can be specified by manipulating the dayOfWeek
5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * and dayOfWeekInMonth parameters.  For complete details, see the documentation
5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * for setStartRule().
5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month the daylight savings ending month. Month is 0-based.
5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * eg, 0 for January.
5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeekInMonth the daylight savings ending
5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * day-of-week-in-month. See setStartRule() for a complete explanation.
5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule()
5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * for a complete explanation.
5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param time the daylight savings ending time. Please see the member
5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * description for an example.
5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void setEndRule(int month, int dayOfWeekInMonth, int dayOfWeek, int time, int mode){
5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assert (!isFrozen());
5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endMonth     = month;
5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endDay       = dayOfWeekInMonth;
5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endDayOfWeek = dayOfWeek;
5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endTime      = time;
5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endTimeMode  = mode;
5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        decodeEndRule();
5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        transitionRulesInitialized = false;
5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the amount of time in ms that the clock is advanced during DST.
5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param millisSavedDuringDST the number of milliseconds the time is
5407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * advanced with respect to standard time when the daylight savings rules
5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * are in effect. A positive number, typically one hour (3600000).
5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setDSTSavings(int millisSavedDuringDST) {
5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance.");
5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (millisSavedDuringDST <= 0) {
5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException();
5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        dst = millisSavedDuringDST;
5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        transitionRulesInitialized = false;
5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the amount of time in ms that the clock is advanced during DST.
5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the number of milliseconds the time is
5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * advanced with respect to standard time when the daylight savings rules
5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * are in effect. A positive number, typically one hour (3600000).
5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getDSTSavings() {
5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return dst;
5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the java.util.SimpleTimeZone that this class wraps.
5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    java.util.SimpleTimeZone unwrapSTZ() {
5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (java.util.SimpleTimeZone) unwrap();
5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    */
5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // on JDK 1.4 and later, can't deserialize a SimpleTimeZone as a SimpleTimeZone...
5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void readObject(java.io.ObjectInputStream in) throws IOException,
5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ClassNotFoundException {
5807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        in.defaultReadObject();
5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*
5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String id = getID();
5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (id!=null && !(zone instanceof java.util.SimpleTimeZone && zone.getID().equals(id))) {
5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // System.out.println("*** readjust " + zone.getClass().getName() +
5857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // " " + zone.getID() + " ***");
5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            java.util.SimpleTimeZone stz =
5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                new java.util.SimpleTimeZone(raw, id);
5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (dst != 0) {
5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                stz.setDSTSavings(dst);
5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // if it is 0, then there shouldn't be start/end rules and the default
5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // behavior should be no dst
5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (xinfo != null) {
5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                xinfo.applyTo(stz);
5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            zoneJDK = stz;
5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /* set all instance variables in this object
6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * to the values in zone
6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         */
6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         if (xinfo != null) {
6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             xinfo.applyTo(this);
6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         }
6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns a string representation of this object.
6107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return  a string representation of this object
6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String toString() {
6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return "SimpleTimeZone: " + getID();
6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private STZInfo getSTZInfo() {
6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (xinfo == null) {
6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            xinfo = new STZInfo();
6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return xinfo;
6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //  Use only for decodeStartRule() and decodeEndRule() where the year is not
6267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //  available. Set February to 29 days to accomodate rules with that date
6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //  and day-of-week-on-or-before-that-date mode (DOW_LE_DOM_MODE).
6287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //  The compareToRule() method adjusts to February 28 in non-leap years.
6297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //
6307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //  For actual getOffset() calculations, use TimeZone::monthLength() and
6317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //  TimeZone::previousMonthLength() which take leap years into account.
6327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //  We handle leap years assuming always
6337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //  Gregorian, since we know they didn't have daylight time when
6347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //  Gregorian calendar started.
6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private final static byte staticMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
6387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
6397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getOffset(int era, int year, int month, int day,
6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                         int dayOfWeek, int millis)
6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Check the month before calling Grego.monthLength(). This
6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // duplicates the test that occurs in the 7-argument getOffset(),
6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // however, this is unavoidable. We don't mind because this method, in
6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // fact, should not be called; internal code should always call the
6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // 7-argument getOffset(), and outside code should use Calendar.get(int
6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // this method because it's public API. - liu 8/10/98
6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(month < Calendar.JANUARY || month > Calendar.DECEMBER) {
6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException();
6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getOffset(era, year, month, day, dayOfWeek, millis, Grego.monthLength(year, month));
6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
6607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
6617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getOffset(int era, int year, int month, int day,
6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                              int dayOfWeek, int millis,
6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                              int monthLength)  {
6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Check the month before calling Grego.monthLength(). This
6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // duplicates a test that occurs in the 9-argument getOffset(),
6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // however, this is unavoidable. We don't mind because this method, in
6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // fact, should not be called; internal code should always call the
6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // 9-argument getOffset(), and outside code should use Calendar.get(int
6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // this method because it's public API. - liu 8/10/98
6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(month < Calendar.JANUARY || month > Calendar.DECEMBER) {
6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException();
6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getOffset(era, year, month, day, dayOfWeek, millis,
6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                         Grego.monthLength(year, month), Grego.previousMonthLength(year, month));
6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int getOffset(int era, int year, int month, int day,
6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  int dayOfWeek, int millis,
6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  int monthLength, int prevMonthLength ){
6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (true) {
6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            /* Use this parameter checking code for normal operation.  Only one
6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             * of these two blocks should actually get compiled into the class
6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             * file.  */
6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if ((era != GregorianCalendar.AD && era != GregorianCalendar.BC)
6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || month < Calendar.JANUARY
6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || month > Calendar.DECEMBER
6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || day < 1
6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || day > monthLength
6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || dayOfWeek < Calendar.SUNDAY
6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || dayOfWeek > Calendar.SATURDAY
6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || millis < 0
6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || millis >= Grego.MILLIS_PER_DAY
6997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || monthLength < 28
7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || monthLength > 31
7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || prevMonthLength < 28
7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || prevMonthLength > 31) {
7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException();
7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        //Eclipse stated the following is "dead code"
7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*else {
7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // This parameter checking code is better for debugging, but
7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // overkill for normal operation.  Only one of these two blocks
7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // should actually get compiled into the class file.
7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal era " + era);
7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (month < Calendar.JANUARY
7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || month > Calendar.DECEMBER) {
7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal month " + month);
7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (day < 1
7197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || day > monthLength) {
7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal day " + day+" max month len: "+monthLength);
7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (dayOfWeek < Calendar.SUNDAY
7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || dayOfWeek > Calendar.SATURDAY) {
7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal day of week " + dayOfWeek);
7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (millis < 0
7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || millis >= Grego.MILLIS_PER_DAY) {
7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal millis " + millis);
7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (monthLength < 28
7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || monthLength > 31) {
7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal month length " + monthLength);
7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (prevMonthLength < 28
7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || prevMonthLength > 31) {
7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal previous month length " + prevMonthLength);
7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }*/
7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int result = raw;
7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Bail out if we are before the onset of daylight savings time
7437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!useDaylight || year < startYear || era != GregorianCalendar.AD) return result;
7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Check for southern hemisphere.  We assume that the start and end
7467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // month are different.
7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean southern = (startMonth > endMonth);
7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Compare the date to the starting and ending rules.+1 = date>rule, -1
7507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // = date<rule, 0 = date==rule.
7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int startCompare = compareToRule(month, monthLength, prevMonthLength,
7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                         day, dayOfWeek, millis,
7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                         startTimeMode == UTC_TIME ? -raw : 0,
7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                         startMode, startMonth, startDayOfWeek,
7557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                         startDay, startTime);
7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int endCompare = 0;
7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /* We don't always have to compute endCompare.  For many instances,
7597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * startCompare is enough to determine if we are in DST or not.  In the
7607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * northern hemisphere, if we are before the start rule, we can't have
7617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * DST.  In the southern hemisphere, if we are after the start rule, we
7627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * must have DST.  This is reflected in the way the next if statement
7637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * (not the one immediately following) short circuits. */
7647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (southern != (startCompare >= 0)) {
7657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            /* For the ending rule comparison, we add the dstSavings to the millis
7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             * passed in to convert them from standard to wall time.  We then must
7677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             * normalize the millis to the range 0..millisPerDay-1. */
7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            endCompare = compareToRule(month, monthLength, prevMonthLength,
7697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                       day, dayOfWeek, millis,
7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                       endTimeMode == WALL_TIME ? dst :
7717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        (endTimeMode == UTC_TIME ? -raw : 0),
7727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                       endMode, endMonth, endDayOfWeek,
7737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                       endDay, endTime);
7747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Check for both the northern and southern hemisphere cases.  We
7777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // assume that in the northern hemisphere, the start rule is before the
7787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // end rule within the calendar year, and vice versa for the southern
7797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // hemisphere.
7807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ((!southern && (startCompare >= 0 && endCompare < 0)) ||
7817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            (southern && (startCompare >= 0 || endCompare < 0)))
7827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            result += dst;
7837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return result;
7857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
7867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
7887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
7897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
7907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
7917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
7927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
7937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void getOffsetFromLocal(long date,
7947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) {
7957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        offsets[0] = getRawOffset();
7967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int fields[] = new int[6];
7977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Grego.timeToFields(date, fields);
7987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        offsets[1] = getOffset(GregorianCalendar.AD,
7997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              fields[0], fields[1], fields[2],
8007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              fields[3], fields[5]) - offsets[0];
8017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean recalc = false;
8037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Now, we need some adjustment
8057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (offsets[1] > 0) {
8067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if ((nonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD
8077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || (nonExistingTimeOpt & STD_DST_MASK) != LOCAL_DST
8087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                && (nonExistingTimeOpt & FORMER_LATTER_MASK) != LOCAL_LATTER) {
8097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                date -= getDSTSavings();
8107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                recalc = true;
8117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
8127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
8137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if ((duplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST
8147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                || (duplicatedTimeOpt & STD_DST_MASK) != LOCAL_STD
8157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                && (duplicatedTimeOpt & FORMER_LATTER_MASK) == LOCAL_FORMER) {
8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                date -= getDSTSavings();
8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                recalc = true;
8187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
8197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
8207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (recalc) {
8227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            Grego.timeToFields(date, fields);
8237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            offsets[1] = getOffset(GregorianCalendar.AD,
8247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    fields[0], fields[1], fields[2],
8257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    fields[3], fields[5]) - offsets[0];
8267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
8287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int
8307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        DOM_MODE = 1,
8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        DOW_IN_MONTH_MODE=2,
8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        DOW_GE_DOM_MODE=3,
8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        DOW_LE_DOM_MODE=4;
8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Compare a given date in the year to a rule. Return 1, 0, or -1, depending
8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * on whether the date is after, equal to, or before the rule date. The
8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * millis are compared directly against the ruleMillis, so any
8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * standard-daylight adjustments must be handled by the caller.
8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return  1 if the date is after the rule date, -1 if the date is before
8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *          the rule date, or 0 if the date is equal to the rule date.
8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int compareToRule(int month, int monthLen, int prevMonthLen,
8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                  int dayOfMonth,
8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                  int dayOfWeek, int millis, int millisDelta,
8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                  int ruleMode, int ruleMonth, int ruleDayOfWeek,
8487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                  int ruleDay, int ruleMillis)
8497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Make adjustments for startTimeMode and endTimeMode
8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        millis += millisDelta;
8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        while (millis >= Grego.MILLIS_PER_DAY) {
8557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            millis -= Grego.MILLIS_PER_DAY;
8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ++dayOfMonth;
8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            dayOfWeek = 1 + (dayOfWeek % 7); // dayOfWeek is one-based
8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (dayOfMonth > monthLen) {
8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                dayOfMonth = 1;
8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                /* When incrementing the month, it is desirable to overflow
8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 * from DECEMBER to DECEMBER+1, since we use the result to
8627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 * compare against a real month. Wraparound of the value
8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 * leads to bug 4173604. */
8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ++month;
8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*
8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * For some reasons, Sun Java 6 on Solaris/Linux has a problem with
8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * the while loop below (at least Java 6 up to build 1.6.0_02-b08).
8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * It looks the JRE messes up the variable 'millis' while executing
8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * the code in the while block.  The problem is not reproduced with
8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * JVM option -Xint, that is, it is likely a bug of the HotSpot
8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * adaptive compiler.  Moving 'millis += Grego.MILLIS_PER_DAY'
8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * to the end of this while block seems to resolve the problem.
8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * See ticket#5887 about the problem in detail.
8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         */
8777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        while (millis < 0) {
8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            //millis += Grego.MILLIS_PER_DAY;
8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            --dayOfMonth;
8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            dayOfWeek = 1 + ((dayOfWeek+5) % 7); // dayOfWeek is one-based
8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (dayOfMonth < 1) {
8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                dayOfMonth = prevMonthLen;
8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                --month;
8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            millis += Grego.MILLIS_PER_DAY;
8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (month < ruleMonth) return -1;
8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        else if (month > ruleMonth) return 1;
8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int ruleDayOfMonth = 0;
8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Adjust the ruleDay to the monthLen, for non-leap year February 29 rule days.
8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (ruleDay > monthLen) {
8957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ruleDay = monthLen;
8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        switch (ruleMode)
8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case DOM_MODE:
9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ruleDayOfMonth = ruleDay;
9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case DOW_IN_MONTH_MODE:
9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // In this case ruleDay is the day-of-week-in-month
9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (ruleDay > 0)
9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ruleDayOfMonth = 1 + (ruleDay - 1) * 7 +
9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    (7 + ruleDayOfWeek - (dayOfWeek - dayOfMonth + 1)) % 7;
9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            else // Assume ruleDay < 0 here
9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ruleDayOfMonth = monthLen + (ruleDay + 1) * 7 -
9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    (7 + (dayOfWeek + monthLen - dayOfMonth) - ruleDayOfWeek) % 7;
9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case DOW_GE_DOM_MODE:
9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ruleDayOfMonth = ruleDay +
9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                (49 + ruleDayOfWeek - ruleDay - dayOfWeek + dayOfMonth) % 7;
9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case DOW_LE_DOM_MODE:
9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ruleDayOfMonth = ruleDay -
9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                (49 - ruleDayOfWeek + ruleDay + dayOfWeek - dayOfMonth) % 7;
9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Note at this point ruleDayOfMonth may be <1, although it will
9227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // be >=1 for well-formed rules.
9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
9247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (dayOfMonth < ruleDayOfMonth) return -1;
9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        else if (dayOfMonth > ruleDayOfMonth) return 1;
9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (millis < ruleMillis){
9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return -1;
9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }else if (millis > ruleMillis){
9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return 1;
9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }else{
9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return 0;
9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // data needed for streaming mutated SimpleTimeZones in JDK14
9397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int raw;// the TimeZone's raw GMT offset
9407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int dst = 3600000;
9417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private STZInfo xinfo = null;
9427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int startMonth, startDay, startDayOfWeek;   // the month, day, DOW, and time DST starts
9437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int startTime;
9447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int startTimeMode, endTimeMode; // Mode for startTime, endTime; see TimeMode
9457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int endMonth, endDay, endDayOfWeek; // the month, day, DOW, and time DST ends
9467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int endTime;
9477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int startYear;  // the year these DST rules took effect
9487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private boolean useDaylight; // flag indicating whether this TimeZone uses DST
9497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int startMode, endMode;   // flags indicating what kind of rules the DST rules are
9507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides TimeZone
9537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Queries if this time zone uses Daylight Saving Time.
9547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
9557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
9577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean useDaylightTime(){
9587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return useDaylight;
9597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
9637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
9647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean observesDaylightTime() {
9667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return useDaylight;
9677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides TimeZone
9717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Queries if the give date is in Daylight Saving Time.
9727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
9737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
9757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean inDaylightTime(Date date){
9767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GregorianCalendar gc = new GregorianCalendar(this);
9777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        gc.setTime(date);
9787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return gc.inDaylightTime();
9797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Internal construction method.
9837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void construct(int _raw,
9857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _startMonth,
9867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _startDay,
9877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _startDayOfWeek,
9887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _startTime,
9897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _startTimeMode,
9907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _endMonth,
9917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _endDay,
9927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _endDayOfWeek,
9937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _endTime,
9947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _endTimeMode,
9957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           int _dst) {
9967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        raw            = _raw;
9977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startMonth     = _startMonth;
9987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startDay       = _startDay;
9997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startDayOfWeek = _startDayOfWeek;
10007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startTime      = _startTime;
10017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startTimeMode  = _startTimeMode;
10027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endMonth       = _endMonth;
10037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endDay         = _endDay;
10047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endDayOfWeek   = _endDayOfWeek;
10057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endTime        = _endTime;
10067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endTimeMode    = _endTimeMode;
10077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        dst            = _dst;
10087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startYear      = 0;
10097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        startMode      = DOM_MODE;
10107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        endMode        = DOM_MODE;
10117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        decodeRules();
10137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (_dst <= 0) {
10157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException();
10167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
10177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
10187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void decodeRules(){
10197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        decodeStartRule();
10207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        decodeEndRule();
10217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
10227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
10247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Decode the start rule and validate the parameters.  The parameters are
10257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * expected to be in encoded form, which represents the various rule modes
10267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * by negating or zeroing certain values.  Representation formats are:
10277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>
10287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <pre>
10297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *            DOW_IN_MONTH  DOM    DOW>=DOM  DOW<=DOM  no DST
10307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *            ------------  -----  --------  --------  ----------
10317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * month       0..11        same    same      same     don't care
10327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * day        -5..5         1..31   1..31    -1..-31   0
10337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * dayOfWeek   1..7         0      -1..-7    -1..-7    don't care
10347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * time        0..ONEDAY    same    same      same     don't care
10357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * </pre>
10367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The range for month does not include UNDECIMBER since this class is
10377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * really specific to GregorianCalendar, which does not use that month.
10387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
10397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * end rule is an exclusive limit point.  That is, the range of times that
10407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * are in DST include those >= the start and < the end.  For this reason,
10417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * it should be possible to specify an end of ONEDAY in order to include the
10427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * entire day.  Although this is equivalent to time 0 of the following day,
10437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * it's not always possible to specify that, for example, on December 31.
10447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * While arguably the start range should still be 0..ONEDAY-1, we keep
10457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the start and end ranges the same for consistency.
10467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
10477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void decodeStartRule() {
10487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        useDaylight = (startDay != 0) && (endDay != 0);
10497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (useDaylight && dst == 0) {
10507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            dst = Grego.MILLIS_PER_DAY;
10517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
10527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (startDay != 0) {
10537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
10547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException();
10557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
10567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (startTime < 0 || startTime > Grego.MILLIS_PER_DAY ||
10577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) {
10587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException();
10597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
10607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (startDayOfWeek == 0) {
10617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                startMode = DOM_MODE;
10627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
10637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (startDayOfWeek > 0) {
10647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    startMode = DOW_IN_MONTH_MODE;
10657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
10667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    startDayOfWeek = -startDayOfWeek;
10677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (startDay > 0) {
10687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startMode = DOW_GE_DOM_MODE;
10697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
10707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startDay = -startDay;
10717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startMode = DOW_LE_DOM_MODE;
10727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
10737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
10747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (startDayOfWeek > Calendar.SATURDAY) {
10757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    throw new IllegalArgumentException();
10767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
10777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
10787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (startMode == DOW_IN_MONTH_MODE) {
10797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (startDay < -5 || startDay > 5) {
10807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    throw new IllegalArgumentException();
10817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
10827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
10837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException();
10847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
10857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
10867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
10877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
10897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Decode the end rule and validate the parameters.  This method is exactly
10907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * analogous to decodeStartRule().
10917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #decodeStartRule
10927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
10937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void decodeEndRule() {
10947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        useDaylight = (startDay != 0) && (endDay != 0);
10957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (useDaylight && dst == 0) {
10967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            dst = Grego.MILLIS_PER_DAY;
10977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
10987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (endDay != 0) {
10997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
11007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException();
11017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
11027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (endTime < 0 || endTime > Grego.MILLIS_PER_DAY ||
11037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) {
11047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException();
11057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
11067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (endDayOfWeek == 0) {
11077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                endMode = DOM_MODE;
11087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
11097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (endDayOfWeek > 0) {
11107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    endMode = DOW_IN_MONTH_MODE;
11117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
11127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    endDayOfWeek = -endDayOfWeek;
11137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (endDay > 0) {
11147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        endMode = DOW_GE_DOM_MODE;
11157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
11167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        endDay = -endDay;
11177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        endMode = DOW_LE_DOM_MODE;
11187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
11197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
11207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (endDayOfWeek > Calendar.SATURDAY) {
11217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    throw new IllegalArgumentException();
11227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
11237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
11247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (endMode == DOW_IN_MONTH_MODE) {
11257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (endDay < -5 || endDay > 5) {
11267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    throw new IllegalArgumentException();
11277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
11287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (endDay<1 || endDay > staticMonthLength[endMonth]) {
11297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException();
11307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
11317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
11327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
11337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
11357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides equals.
11367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return true if obj is a SimpleTimeZone equivalent to this
11377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
11387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
11397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
11407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean equals(Object obj){
11417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (this == obj) return true;
11427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (obj == null || getClass() != obj.getClass()) return false;
11437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        SimpleTimeZone that = (SimpleTimeZone) obj;
11447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return raw     == that.raw &&
11457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            useDaylight     == that.useDaylight &&
11467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            idEquals(getID(),that.getID()) &&
11477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            (!useDaylight
11487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             // Only check rules if using DST
11497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             || (dst            == that.dst &&
11507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 startMode      == that.startMode &&
11517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 startMonth     == that.startMonth &&
11527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 startDay       == that.startDay &&
11537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 startDayOfWeek == that.startDayOfWeek &&
11547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 startTime      == that.startTime &&
11557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 startTimeMode  == that.startTimeMode &&
11567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 endMode        == that.endMode &&
11577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 endMonth       == that.endMonth &&
11587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 endDay         == that.endDay &&
11597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 endDayOfWeek   == that.endDayOfWeek &&
11607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 endTime        == that.endTime &&
11617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 endTimeMode    == that.endTimeMode &&
11627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 startYear      == that.startYear ));
11637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
11657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private boolean idEquals(String id1, String id2){
11667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(id1==null && id2==null){
11677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return true;
11687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
11697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(id1!=null && id2!=null){
11707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return id1.equals(id2);
11717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
11727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return false;
11737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
11747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
11767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides hashCode.
11777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
11787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
11797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
11807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int hashCode(){
11817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int ret = super.hashCode()
11827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    + raw ^ (raw >>> 8)
11837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    + (useDaylight ? 0 : 1);
11847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(!useDaylight){
11857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ret += dst ^ (dst >>> 10) +
11867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startMode ^ (startMode>>>11) +
11877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startMonth ^ (startMonth>>>12) +
11887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startDay ^ (startDay>>>13) +
11897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startDayOfWeek ^ (startDayOfWeek>>>14) +
11907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startTime ^ (startTime>>>15) +
11917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startTimeMode ^ (startTimeMode>>>16) +
11927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        endMode ^ (endMode>>>17) +
11937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        endMonth ^ (endMonth>>>18) +
11947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        endDay ^ (endDay>>>19) +
11957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        endDayOfWeek ^ (endDayOfWeek>>>20) +
11967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        endTime ^ (endTime>>>21) +
11977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        endTimeMode ^ (endTimeMode>>>22) +
11987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        startYear ^ (startYear>>>23);
11997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ret;
12017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
12047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides clone.
12057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
12067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
12077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
12087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public Object clone() {
12097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isFrozen()) {
12107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return this;
12117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return cloneAsThawed();
12137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
12167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns true if this zone has the same rules and offset as another zone.
12177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param othr the TimeZone object to be compared with
12187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return true if the given zone has the same rules and offset as this one
12197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
12207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
12217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
12227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean hasSameRules(TimeZone othr) {
12237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (this == othr) {
12247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return true;
12257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(!(othr instanceof SimpleTimeZone)){
12277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return false;
12287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        SimpleTimeZone other = (SimpleTimeZone)othr;
12307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return other != null &&
12317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        raw     == other.raw &&
12327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        useDaylight     == other.useDaylight &&
12337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        (!useDaylight
12347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         // Only check rules if using DST
12357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         || (dst     == other.dst &&
12367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             startMode      == other.startMode &&
12377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             startMonth     == other.startMonth &&
12387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             startDay       == other.startDay &&
12397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             startDayOfWeek == other.startDayOfWeek &&
12407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             startTime      == other.startTime &&
12417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             startTimeMode  == other.startTimeMode &&
12427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             endMode        == other.endMode &&
12437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             endMonth       == other.endMonth &&
12447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             endDay         == other.endDay &&
12457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             endDayOfWeek   == other.endDayOfWeek &&
12467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             endTime        == other.endTime &&
12477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             endTimeMode    == other.endTimeMode &&
12487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             startYear      == other.startYear));
12497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // BasicTimeZone methods
12527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
12547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
12557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
12567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
12577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
12587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public TimeZoneTransition getNextTransition(long base, boolean inclusive) {
12597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!useDaylight) {
12607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return null;
12617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        initTransitionRules();
12647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        long firstTransitionTime = firstTransition.getTime();
12657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (base < firstTransitionTime || (inclusive && base == firstTransitionTime)) {
12667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return firstTransition;
12677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Date stdDate = stdRule.getNextStart(base, dstRule.getRawOffset(), dstRule.getDSTSavings(),
12697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                            inclusive);
12707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Date dstDate = dstRule.getNextStart(base, stdRule.getRawOffset(), stdRule.getDSTSavings(),
12717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                            inclusive);
12727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (stdDate != null && (dstDate == null || stdDate.before(dstDate))) {
12737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return new TimeZoneTransition(stdDate.getTime(), dstRule, stdRule);
12747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (dstDate != null && (stdDate == null || dstDate.before(stdDate))) {
12767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return new TimeZoneTransition(dstDate.getTime(), stdRule, dstRule);
12777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return null;
12797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
12827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
12837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
12847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
12857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
12867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public TimeZoneTransition getPreviousTransition(long base, boolean inclusive) {
12877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!useDaylight) {
12887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return null;
12897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        initTransitionRules();
12927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        long firstTransitionTime = firstTransition.getTime();
12937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (base < firstTransitionTime || (!inclusive && base == firstTransitionTime)) {
12947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return null;
12957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Date stdDate = stdRule.getPreviousStart(base, dstRule.getRawOffset(),
12977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                dstRule.getDSTSavings(), inclusive);
12987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Date dstDate = dstRule.getPreviousStart(base, stdRule.getRawOffset(),
12997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                stdRule.getDSTSavings(), inclusive);
13007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (stdDate != null && (dstDate == null || stdDate.after(dstDate))) {
13017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return new TimeZoneTransition(stdDate.getTime(), dstRule, stdRule);
13027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
13037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (dstDate != null && (stdDate == null || dstDate.after(stdDate))) {
13047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return new TimeZoneTransition(dstDate.getTime(), stdRule, dstRule);
13057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
13067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return null;
13077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
13087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
13107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
13117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
13127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
13137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
13147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public TimeZoneRule[] getTimeZoneRules() {
13157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        initTransitionRules();
13167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int size = useDaylight ? 3 : 1;
13187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        TimeZoneRule[] rules = new TimeZoneRule[size];
13197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        rules[0] = initialRule;
13207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (useDaylight) {
13217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            rules[1] = stdRule;
13227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            rules[2] = dstRule;
13237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
13247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return rules;
13257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
13267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient boolean transitionRulesInitialized;
13287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient InitialTimeZoneRule initialRule;
13297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient TimeZoneTransition firstTransition;
13307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient AnnualTimeZoneRule stdRule;
13317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient AnnualTimeZoneRule dstRule;
13327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private synchronized void initTransitionRules() {
13347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (transitionRulesInitialized) {
13357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return;
13367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
13377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (useDaylight) {
13387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            DateTimeRule dtRule = null;
13397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int timeRuleType;
13407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            long firstStdStart, firstDstStart;
13417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Create a TimeZoneRule for daylight saving time
13437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            timeRuleType = (startTimeMode == STANDARD_TIME) ? DateTimeRule.STANDARD_TIME :
13447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ((startTimeMode == UTC_TIME) ? DateTimeRule.UTC_TIME : DateTimeRule.WALL_TIME);
13457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            switch (startMode) {
13467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case DOM_MODE:
13477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             dtRule = new DateTimeRule(startMonth, startDay, startTime, timeRuleType);
13487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             break;
13497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case DOW_IN_MONTH_MODE:
13507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, startTime,
13517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                       timeRuleType);
13527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             break;
13537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case DOW_GE_DOM_MODE:
13547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, true, startTime,
13557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                       timeRuleType);
13567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             break;
13577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case DOW_LE_DOM_MODE:
13587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, false, startTime,
13597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                       timeRuleType);
13607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             break;
13617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
13627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // For now, use ID + "(DST)" as the name
13637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            dstRule = new AnnualTimeZoneRule(getID() + "(DST)", getRawOffset(), getDSTSavings(),
13647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 dtRule, startYear, AnnualTimeZoneRule.MAX_YEAR);
13657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Calculate the first DST start time
13677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            firstDstStart = dstRule.getFirstStart(getRawOffset(), 0).getTime();
13687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Create a TimeZoneRule for standard time
13707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            timeRuleType = (endTimeMode == STANDARD_TIME) ? DateTimeRule.STANDARD_TIME :
13717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ((endTimeMode == UTC_TIME) ? DateTimeRule.UTC_TIME : DateTimeRule.WALL_TIME);
13727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            switch (endMode) {
13737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case DOM_MODE:
13747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                dtRule = new DateTimeRule(endMonth, endDay, endTime, timeRuleType);
13757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
13767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case DOW_IN_MONTH_MODE:
13777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, endTime, timeRuleType);
13787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
13797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case DOW_GE_DOM_MODE:
13807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, true, endTime,
13817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                          timeRuleType);
13827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
13837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case DOW_LE_DOM_MODE:
13847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, false, endTime,
13857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                          timeRuleType);
13867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
13877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
13887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // For now, use ID + "(STD)" as the name
13897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            stdRule = new AnnualTimeZoneRule(getID() + "(STD)", getRawOffset(), 0,
13907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    dtRule, startYear, AnnualTimeZoneRule.MAX_YEAR);
13917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Calculate the first STD start time
13937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            firstStdStart = stdRule.getFirstStart(getRawOffset(), dstRule.getDSTSavings()).getTime();
13947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Create a TimeZoneRule for initial time
13967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (firstStdStart < firstDstStart) {
13977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                initialRule = new InitialTimeZoneRule(getID() + "(DST)", getRawOffset(),
13987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                      dstRule.getDSTSavings());
13997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                firstTransition = new TimeZoneTransition(firstStdStart, initialRule, stdRule);
14007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
14017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                initialRule = new InitialTimeZoneRule(getID() + "(STD)", getRawOffset(), 0);
14027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                firstTransition = new TimeZoneTransition(firstDstStart, initialRule, dstRule);
14037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
14047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
14067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Create a TimeZoneRule for initial time
14077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            initialRule = new InitialTimeZoneRule(getID(), getRawOffset(), 0);
14087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
14097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        transitionRulesInitialized = true;
14107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
14117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Freezable stuffs
14137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private volatile transient boolean isFrozen = false;
14147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
14167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
14177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
14187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
14197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean isFrozen() {
14207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return isFrozen;
14217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
14227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
14247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
14257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
14267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
14277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public TimeZone freeze() {
14287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        isFrozen = true;
14297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return this;
14307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
14317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
14337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@inheritDoc}
14347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
14357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
14367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public TimeZone cloneAsThawed() {
14377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        SimpleTimeZone tz = (SimpleTimeZone)super.cloneAsThawed();
14387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        tz.isFrozen = false;
14397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return tz;
14407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
14417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
1442