| /* |
| * Copyright (C) 1996-2014, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| */ |
| |
| package com.ibm.icu.util; |
| |
| import java.io.IOException; |
| import java.util.Date; |
| |
| import com.ibm.icu.impl.Grego; |
| |
| /** |
| * {@icuenhanced java.util.SimpleTimeZone}.{@icu _usage_} |
| * |
| * <p><code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code> |
| * that represents a time zone for use with a Gregorian calendar. This |
| * class does not handle historical changes. |
| * |
| * <p>Use a negative value for <code>dayOfWeekInMonth</code> to indicate that |
| * <code>SimpleTimeZone</code> should count from the end of the month backwards. For |
| * example, if Daylight Savings Time starts or ends at the last Sunday in a month, use |
| * <code>dayOfWeekInMonth = -1</code> along with <code>dayOfWeek = Calendar.SUNDAY</code> |
| * to specify the rule. |
| * |
| * @see Calendar |
| * @see GregorianCalendar |
| * @see TimeZone |
| * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu |
| * @stable ICU 2.0 |
| */ |
| public class SimpleTimeZone extends BasicTimeZone { |
| private static final long serialVersionUID = -7034676239311322769L; |
| |
| /** |
| * Constant for a mode of start or end time specified as local wall time. |
| * @stable ICU 3.8 |
| */ |
| public static final int WALL_TIME = 0; |
| |
| /** |
| * Constant for a mode of start or end time specified as local standard time. |
| * @stable ICU 3.8 |
| */ |
| public static final int STANDARD_TIME = 1; |
| |
| /** |
| * Constant for a mode of start or end time specified as UTC. |
| * @stable ICU 3.8 |
| */ |
| public static final int UTC_TIME = 2; |
| |
| /** |
| * Constructs a SimpleTimeZone with the given base time zone offset from GMT |
| * and time zone ID. Timezone IDs can be obtained from |
| * TimeZone.getAvailableIDs. Normally you should use TimeZone.getDefault to |
| * construct a TimeZone. |
| * |
| * @param rawOffset The given base time zone offset to GMT. |
| * @param ID The time zone ID which is obtained from |
| * TimeZone.getAvailableIDs. |
| * @stable ICU 2.0 |
| */ |
| public SimpleTimeZone(int rawOffset, String ID) { |
| super(ID); |
| construct(rawOffset, 0, 0, 0, |
| 0, WALL_TIME, |
| 0, 0, 0, |
| 0, WALL_TIME, |
| Grego.MILLIS_PER_HOUR); |
| } |
| |
| /** |
| * Constructs a SimpleTimeZone with the given base time zone offset from |
| * GMT, time zone ID, time to start and end the daylight time. Timezone IDs |
| * can be obtained from TimeZone.getAvailableIDs. Normally you should use |
| * TimeZone.getDefault to create a TimeZone. For a time zone that does not |
| * use daylight saving time, do not use this constructor; instead you should |
| * use SimpleTimeZone(rawOffset, ID). |
| * |
| * By default, this constructor specifies day-of-week-in-month rules. That |
| * is, if the startDay is 1, and the startDayOfWeek is SUNDAY, then this |
| * indicates the first Sunday in the startMonth. A startDay of -1 likewise |
| * indicates the last Sunday. However, by using negative or zero values for |
| * certain parameters, other types of rules can be specified. |
| * |
| * Day of month. To specify an exact day of the month, such as March 1, set |
| * startDayOfWeek to zero. |
| * |
| * Day of week after day of month. To specify the first day of the week |
| * occurring on or after an exact day of the month, make the day of the week |
| * negative. For example, if startDay is 5 and startDayOfWeek is -MONDAY, |
| * this indicates the first Monday on or after the 5th day of the |
| * startMonth. |
| * |
| * Day of week before day of month. To specify the last day of the week |
| * occurring on or before an exact day of the month, make the day of the |
| * week and the day of the month negative. For example, if startDay is -21 |
| * and startDayOfWeek is -WEDNESDAY, this indicates the last Wednesday on or |
| * before the 21st of the startMonth. |
| * |
| * The above examples refer to the startMonth, startDay, and startDayOfWeek; |
| * the same applies for the endMonth, endDay, and endDayOfWeek. |
| * |
| * @param rawOffset The given base time zone offset to GMT. |
| * @param ID The time zone ID which is obtained from |
| * TimeZone.getAvailableIDs. |
| * @param startMonth The daylight savings starting month. Month is |
| * 0-based. eg, 0 for January. |
| * @param startDay The daylight savings starting |
| * day-of-week-in-month. Please see the member |
| * description for an example. |
| * @param startDayOfWeek The daylight savings starting day-of-week. Please |
| * see the member description for an example. |
| * @param startTime The daylight savings starting time in local wall |
| * time, which is standard time in this case. Please see the |
| * member description for an example. |
| * @param endMonth The daylight savings ending month. Month is |
| * 0-based. eg, 0 for January. |
| * @param endDay The daylight savings ending day-of-week-in-month. |
| * Please see the member description for an example. |
| * @param endDayOfWeek The daylight savings ending day-of-week. Please |
| * see the member description for an example. |
| * @param endTime The daylight savings ending time in local wall time, |
| * which is daylight time in this case. Please see the |
| * member description for an example. |
| * @throws IllegalArgumentException the month, day, dayOfWeek, or time |
| * parameters are out of range for the start or end rule |
| * @stable ICU 2.0 |
| */ |
| public SimpleTimeZone(int rawOffset, String ID, |
| int startMonth, int startDay, int startDayOfWeek, int startTime, |
| int endMonth, int endDay, int endDayOfWeek, int endTime) { |
| super(ID); |
| construct(rawOffset, |
| startMonth, startDay, startDayOfWeek, |
| startTime, WALL_TIME, |
| endMonth, endDay, endDayOfWeek, |
| endTime, WALL_TIME, |
| Grego.MILLIS_PER_HOUR); |
| } |
| |
| /** |
| * Constructs a SimpleTimeZone with the given base time zone offset from |
| * GMT, time zone ID, time and its mode to start and end the daylight time. |
| * The mode specifies either {@link #WALL_TIME} or {@link #STANDARD_TIME} |
| * or {@link #UTC_TIME}. |
| * |
| * @param rawOffset The given base time zone offset to GMT. |
| * @param ID The time zone ID which is obtained from |
| * TimeZone.getAvailableIDs. |
| * @param startMonth The daylight savings starting month. Month is |
| * 0-based. eg, 0 for January. |
| * @param startDay The daylight savings starting |
| * day-of-week-in-month. Please see the member |
| * description for an example. |
| * @param startDayOfWeek The daylight savings starting day-of-week. Please |
| * see the member description for an example. |
| * @param startTime The daylight savings starting time in local wall |
| * time, which is standard time in this case. Please see the |
| * member description for an example. |
| * @param startTimeMode The mode of the start time specified by startTime. |
| * @param endMonth The daylight savings ending month. Month is |
| * 0-based. eg, 0 for January. |
| * @param endDay The daylight savings ending day-of-week-in-month. |
| * Please see the member description for an example. |
| * @param endDayOfWeek The daylight savings ending day-of-week. Please |
| * see the member description for an example. |
| * @param endTime The daylight savings ending time in local wall time, |
| * which is daylight time in this case. Please see the |
| * member description for an example. |
| * @param endTimeMode The mode of the end time specified by endTime. |
| * @param dstSavings The amount of time in ms saved during DST. |
| * @throws IllegalArgumentException the month, day, dayOfWeek, or time |
| * parameters are out of range for the start or end rule |
| * @stable ICU 3.8 |
| */ |
| public SimpleTimeZone(int rawOffset, String ID, |
| int startMonth, int startDay, |
| int startDayOfWeek, int startTime, |
| int startTimeMode, |
| int endMonth, int endDay, |
| int endDayOfWeek, int endTime, |
| int endTimeMode,int dstSavings){ |
| super(ID); |
| construct(rawOffset, |
| startMonth, startDay, startDayOfWeek, |
| startTime, startTimeMode, |
| endMonth, endDay, endDayOfWeek, |
| endTime, endTimeMode, |
| dstSavings); |
| } |
| |
| /** |
| * Constructor. This constructor is identical to the 10-argument |
| * constructor, but also takes a dstSavings parameter. |
| * @param rawOffset The given base time zone offset to GMT. |
| * @param ID The time zone ID which is obtained from |
| * TimeZone.getAvailableIDs. |
| * @param startMonth The daylight savings starting month. Month is |
| * 0-based. eg, 0 for January. |
| * @param startDay The daylight savings starting |
| * day-of-week-in-month. Please see the member |
| * description for an example. |
| * @param startDayOfWeek The daylight savings starting day-of-week. Please |
| * see the member description for an example. |
| * @param startTime The daylight savings starting time in local wall |
| * time, which is standard time in this case. Please see the |
| * member description for an example. |
| * @param endMonth The daylight savings ending month. Month is |
| * 0-based. eg, 0 for January. |
| * @param endDay The daylight savings ending day-of-week-in-month. |
| * Please see the member description for an example. |
| * @param endDayOfWeek The daylight savings ending day-of-week. Please |
| * see the member description for an example. |
| * @param endTime The daylight savings ending time in local wall time, |
| * which is daylight time in this case. Please see the |
| * member description for an example. |
| * @param dstSavings The amount of time in ms saved during DST. |
| * @throws IllegalArgumentException the month, day, dayOfWeek, or time |
| * parameters are out of range for the start or end rule |
| * @stable ICU 2.0 |
| */ |
| public SimpleTimeZone(int rawOffset, String ID, |
| int startMonth, int startDay, int startDayOfWeek, int startTime, |
| int endMonth, int endDay, int endDayOfWeek, int endTime, |
| int dstSavings) { |
| super(ID); |
| construct(rawOffset, |
| startMonth, startDay, startDayOfWeek, |
| startTime, WALL_TIME, |
| endMonth, endDay, endDayOfWeek, |
| endTime, WALL_TIME, |
| dstSavings); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @stable ICU 3.8 |
| */ |
| @Override |
| public void setID(String ID) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| super.setID(ID); |
| transitionRulesInitialized = false; |
| } |
| |
| /** |
| * Overrides TimeZone |
| * Sets the base time zone offset to GMT. |
| * This is the offset to add "to" UTC to get local time. |
| * @param offsetMillis the raw offset of the time zone |
| * @stable ICU 2.0 |
| */ |
| @Override |
| public void setRawOffset(int offsetMillis) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| |
| raw = offsetMillis; |
| transitionRulesInitialized = false; |
| } |
| |
| /** |
| * Overrides TimeZone |
| * Gets the GMT offset for this time zone. |
| * @return the raw offset |
| * @stable ICU 2.0 |
| */ |
| @Override |
| public int getRawOffset() { |
| return raw; |
| } |
| |
| /** |
| * Sets the daylight savings starting year. |
| * |
| * @param year The daylight savings starting year. |
| * @stable ICU 2.0 |
| */ |
| public void setStartYear(int year) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| |
| getSTZInfo().sy = year; |
| this.startYear = year; |
| transitionRulesInitialized = false; |
| } |
| |
| /** |
| * Sets the daylight savings starting rule. For example, Daylight Savings |
| * Time starts at the second Sunday in March, at 2 AM in standard time. |
| * Therefore, you can set the start rule by calling: |
| * setStartRule(Calendar.MARCH, 2, Calendar.SUNDAY, 2*60*60*1000); |
| * |
| * @param month The daylight savings starting month. Month is |
| * 0-based. eg, 0 for January. |
| * @param dayOfWeekInMonth The daylight savings starting |
| * day-of-week-in-month. Please see the member |
| * description for an example. |
| * @param dayOfWeek The daylight savings starting day-of-week. |
| * Please see the member description for an |
| * example. |
| * @param time The daylight savings starting time in local wall |
| * time, which is standard time in this case. Please see |
| * the member description for an example. |
| * @throws IllegalArgumentException the month, dayOfWeekInMonth, |
| * dayOfWeek, or time parameters are out of range |
| * @stable ICU 2.0 |
| */ |
| public void setStartRule(int month, int dayOfWeekInMonth, int dayOfWeek, |
| int time) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| |
| getSTZInfo().setStart(month, dayOfWeekInMonth, dayOfWeek, time, -1, false); |
| setStartRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME); |
| } |
| |
| /** |
| * Sets the daylight savings starting rule. For example, in the U.S., Daylight Savings |
| * Time starts at the second Sunday in March, at 2 AM in standard time. |
| * Therefore, you can set the start rule by calling: |
| * <code>setStartRule(Calendar.MARCH, 2, Calendar.SUNDAY, 2*60*60*1000);</code> |
| * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calculate |
| * the exact starting date. Their exact meaning depend on their respective signs, |
| * allowing various types of rules to be constructed, as follows:<ul> |
| * <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the |
| * day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday |
| * of the month). |
| * <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify |
| * the day of week in the month counting backward from the end of the month. |
| * (e.g., (-1, MONDAY) is the last Monday in the month) |
| * <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth |
| * specifies the day of the month, regardless of what day of the week it is. |
| * (e.g., (10, 0) is the tenth day of the month) |
| * <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth |
| * specifies the day of the month counting backward from the end of the |
| * month, regardless of what day of the week it is (e.g., (-2, 0) is the |
| * next-to-last day of the month). |
| * <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the |
| * first specified day of the week on or after the specfied day of the month. |
| * (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month |
| * [or the 15th itself if the 15th is a Sunday].) |
| * <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the |
| * last specified day of the week on or before the specified day of the month. |
| * (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month |
| * [or the 20th itself if the 20th is a Tuesday].)</ul> |
| * @param month the daylight savings starting month. Month is 0-based. |
| * eg, 0 for January. |
| * @param dayOfWeekInMonth the daylight savings starting |
| * day-of-week-in-month. Please see the member description for an example. |
| * @param dayOfWeek the daylight savings starting day-of-week. Please see |
| * the member description for an example. |
| * @param time the daylight savings starting time. Please see the member |
| * description for an example. |
| */ |
| private void setStartRule(int month, int dayOfWeekInMonth, int dayOfWeek, int time, int mode) { |
| assert (!isFrozen()); |
| |
| startMonth = month; |
| startDay = dayOfWeekInMonth; |
| startDayOfWeek = dayOfWeek; |
| startTime = time; |
| startTimeMode = mode; |
| decodeStartRule(); |
| |
| transitionRulesInitialized = false; |
| } |
| |
| /** |
| * Sets the DST start rule to a fixed date within a month. |
| * |
| * @param month The month in which this rule occurs (0-based). |
| * @param dayOfMonth The date in that month (1-based). |
| * @param time The time of that day (number of millis after midnight) |
| * when DST takes effect in local wall time, which is |
| * standard time in this case. |
| * @throws IllegalArgumentException the month, |
| * dayOfMonth, or time parameters are out of range |
| * @stable ICU 2.0 |
| */ |
| public void setStartRule(int month, int dayOfMonth, int time) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| |
| getSTZInfo().setStart(month, -1, -1, time, dayOfMonth, false); |
| setStartRule(month, dayOfMonth, 0, time, WALL_TIME); |
| } |
| |
| /** |
| * Sets the DST start rule to a weekday before or after a give date within |
| * a month, e.g., the first Monday on or after the 8th. |
| * |
| * @param month The month in which this rule occurs (0-based). |
| * @param dayOfMonth A date within that month (1-based). |
| * @param dayOfWeek The day of the week on which this rule occurs. |
| * @param time The time of that day (number of millis after midnight) |
| * when DST takes effect in local wall time, which is |
| * standard time in this case. |
| * @param after If true, this rule selects the first dayOfWeek on |
| * or after dayOfMonth. If false, this rule selects |
| * the last dayOfWeek on or before dayOfMonth. |
| * @throws IllegalArgumentException the month, dayOfMonth, |
| * dayOfWeek, or time parameters are out of range |
| * @stable ICU 2.0 |
| */ |
| public void setStartRule(int month, int dayOfMonth, int dayOfWeek, int time, boolean after) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| |
| getSTZInfo().setStart(month, -1, dayOfWeek, time, dayOfMonth, after); |
| setStartRule(month, after ? dayOfMonth : -dayOfMonth, |
| -dayOfWeek, time, WALL_TIME); |
| } |
| |
| /** |
| * Sets the daylight savings ending rule. For example, if Daylight Savings Time |
| * ends at the last (-1) Sunday in October, at 2 AM in standard time, |
| * you can set the end rule by calling: |
| * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code> |
| * |
| * @param month The daylight savings ending month. Month is |
| * 0-based. eg, 0 for January. |
| * @param dayOfWeekInMonth The daylight savings ending |
| * day-of-week-in-month. Please see the member |
| * description for an example. |
| * @param dayOfWeek The daylight savings ending day-of-week. Please |
| * see the member description for an example. |
| * @param time The daylight savings ending time in local wall time, |
| * which is daylight time in this case. Please see the |
| * member description for an example. |
| * @throws IllegalArgumentException the month, dayOfWeekInMonth, |
| * dayOfWeek, or time parameters are out of range |
| * @stable ICU 2.0 |
| */ |
| public void setEndRule(int month, int dayOfWeekInMonth, int dayOfWeek, int time) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| |
| getSTZInfo().setEnd(month, dayOfWeekInMonth, dayOfWeek, time, -1, false); |
| setEndRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME); |
| } |
| |
| /** |
| * Sets the DST end rule to a fixed date within a month. |
| * |
| * @param month The month in which this rule occurs (0-based). |
| * @param dayOfMonth The date in that month (1-based). |
| * @param time The time of that day (number of millis after midnight) |
| * when DST ends in local wall time, which is daylight |
| * time in this case. |
| * @throws IllegalArgumentException the month, |
| * dayOfMonth, or time parameters are out of range |
| * @stable ICU 2.0 |
| */ |
| public void setEndRule(int month, int dayOfMonth, int time) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| |
| getSTZInfo().setEnd(month, -1, -1, time, dayOfMonth, false); |
| setEndRule(month, dayOfMonth, WALL_TIME, time); |
| } |
| |
| /** |
| * Sets the DST end rule to a weekday before or after a give date within |
| * a month, e.g., the first Monday on or after the 8th. |
| * |
| * @param month The month in which this rule occurs (0-based). |
| * @param dayOfMonth A date within that month (1-based). |
| * @param dayOfWeek The day of the week on which this rule occurs. |
| * @param time The time of that day (number of millis after midnight) |
| * when DST ends in local wall time, which is daylight |
| * time in this case. |
| * @param after If true, this rule selects the first dayOfWeek on |
| * or after dayOfMonth. If false, this rule selects |
| * the last dayOfWeek on or before dayOfMonth. |
| * @throws IllegalArgumentException the month, dayOfMonth, |
| * dayOfWeek, or time parameters are out of range |
| * @stable ICU 2.0 |
| */ |
| public void setEndRule(int month, int dayOfMonth, int dayOfWeek, int time, boolean after) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| |
| getSTZInfo().setEnd(month, -1, dayOfWeek, time, dayOfMonth, after); |
| setEndRule(month, dayOfMonth, dayOfWeek, time, WALL_TIME, after); |
| } |
| |
| private void setEndRule(int month, int dayOfMonth, int dayOfWeek, |
| int time, int mode, boolean after){ |
| assert (!isFrozen()); |
| setEndRule(month, after ? dayOfMonth : -dayOfMonth, -dayOfWeek, time, mode); |
| } |
| |
| /** |
| * Sets the daylight savings ending rule. For example, in the U.S., Daylight |
| * Savings Time ends at the first Sunday in November, at 2 AM in standard time. |
| * Therefore, you can set the end rule by calling: |
| * setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2*60*60*1000); |
| * Various other types of rules can be specified by manipulating the dayOfWeek |
| * and dayOfWeekInMonth parameters. For complete details, see the documentation |
| * for setStartRule(). |
| * @param month the daylight savings ending month. Month is 0-based. |
| * eg, 0 for January. |
| * @param dayOfWeekInMonth the daylight savings ending |
| * day-of-week-in-month. See setStartRule() for a complete explanation. |
| * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule() |
| * for a complete explanation. |
| * @param time the daylight savings ending time. Please see the member |
| * description for an example. |
| */ |
| private void setEndRule(int month, int dayOfWeekInMonth, int dayOfWeek, int time, int mode){ |
| assert (!isFrozen()); |
| |
| endMonth = month; |
| endDay = dayOfWeekInMonth; |
| endDayOfWeek = dayOfWeek; |
| endTime = time; |
| endTimeMode = mode; |
| decodeEndRule(); |
| |
| transitionRulesInitialized = false; |
| } |
| |
| /** |
| * Sets the amount of time in ms that the clock is advanced during DST. |
| * @param millisSavedDuringDST the number of milliseconds the time is |
| * advanced with respect to standard time when the daylight savings rules |
| * are in effect. A positive number, typically one hour (3600000). |
| * @stable ICU 2.0 |
| */ |
| public void setDSTSavings(int millisSavedDuringDST) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen SimpleTimeZone instance."); |
| } |
| |
| if (millisSavedDuringDST <= 0) { |
| throw new IllegalArgumentException(); |
| } |
| dst = millisSavedDuringDST; |
| |
| transitionRulesInitialized = false; |
| } |
| |
| /** |
| * Returns the amount of time in ms that the clock is advanced during DST. |
| * @return the number of milliseconds the time is |
| * advanced with respect to standard time when the daylight savings rules |
| * are in effect. A positive number, typically one hour (3600000). |
| * @stable ICU 2.0 |
| */ |
| @Override |
| public int getDSTSavings() { |
| return dst; |
| } |
| |
| /** |
| * Returns the java.util.SimpleTimeZone that this class wraps. |
| * |
| java.util.SimpleTimeZone unwrapSTZ() { |
| return (java.util.SimpleTimeZone) unwrap(); |
| } |
| */ |
| |
| // on JDK 1.4 and later, can't deserialize a SimpleTimeZone as a SimpleTimeZone... |
| private void readObject(java.io.ObjectInputStream in) throws IOException, |
| ClassNotFoundException { |
| in.defaultReadObject(); |
| /* |
| String id = getID(); |
| if (id!=null && !(zone instanceof java.util.SimpleTimeZone && zone.getID().equals(id))) { |
| // System.out.println("*** readjust " + zone.getClass().getName() + |
| // " " + zone.getID() + " ***"); |
| java.util.SimpleTimeZone stz = |
| new java.util.SimpleTimeZone(raw, id); |
| if (dst != 0) { |
| stz.setDSTSavings(dst); |
| // if it is 0, then there shouldn't be start/end rules and the default |
| // behavior should be no dst |
| } |
| |
| if (xinfo != null) { |
| xinfo.applyTo(stz); |
| } |
| zoneJDK = stz; |
| } |
| */ |
| /* set all instance variables in this object |
| * to the values in zone |
| */ |
| if (xinfo != null) { |
| xinfo.applyTo(this); |
| } |
| } |
| |
| /** |
| * Returns a string representation of this object. |
| * @return a string representation of this object |
| * @stable ICU 3.6 |
| */ |
| @Override |
| public String toString() { |
| return "SimpleTimeZone: " + getID(); |
| } |
| |
| private STZInfo getSTZInfo() { |
| if (xinfo == null) { |
| xinfo = new STZInfo(); |
| } |
| return xinfo; |
| } |
| |
| // Use only for decodeStartRule() and decodeEndRule() where the year is not |
| // available. Set February to 29 days to accomodate rules with that date |
| // and day-of-week-on-or-before-that-date mode (DOW_LE_DOM_MODE). |
| // The compareToRule() method adjusts to February 28 in non-leap years. |
| // |
| // For actual getOffset() calculations, use TimeZone::monthLength() and |
| // TimeZone::previousMonthLength() which take leap years into account. |
| // We handle leap years assuming always |
| // Gregorian, since we know they didn't have daylight time when |
| // Gregorian calendar started. |
| private final static byte staticMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31}; |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 2.0 |
| */ |
| @Override |
| public int getOffset(int era, int year, int month, int day, |
| int dayOfWeek, int millis) |
| { |
| // Check the month before calling Grego.monthLength(). This |
| // duplicates the test that occurs in the 7-argument getOffset(), |
| // however, this is unavoidable. We don't mind because this method, in |
| // fact, should not be called; internal code should always call the |
| // 7-argument getOffset(), and outside code should use Calendar.get(int |
| // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of |
| // this method because it's public API. - liu 8/10/98 |
| if(month < Calendar.JANUARY || month > Calendar.DECEMBER) { |
| throw new IllegalArgumentException(); |
| } |
| |
| return getOffset(era, year, month, day, dayOfWeek, millis, Grego.monthLength(year, month)); |
| } |
| |
| /** |
| * @internal |
| * @deprecated This API is ICU internal only. |
| */ |
| @Deprecated |
| public int getOffset(int era, int year, int month, int day, |
| int dayOfWeek, int millis, |
| int monthLength) { |
| // Check the month before calling Grego.monthLength(). This |
| // duplicates a test that occurs in the 9-argument getOffset(), |
| // however, this is unavoidable. We don't mind because this method, in |
| // fact, should not be called; internal code should always call the |
| // 9-argument getOffset(), and outside code should use Calendar.get(int |
| // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of |
| // this method because it's public API. - liu 8/10/98 |
| if(month < Calendar.JANUARY || month > Calendar.DECEMBER) { |
| throw new IllegalArgumentException(); |
| } |
| |
| return getOffset(era, year, month, day, dayOfWeek, millis, |
| Grego.monthLength(year, month), Grego.previousMonthLength(year, month)); |
| } |
| |
| private int getOffset(int era, int year, int month, int day, |
| int dayOfWeek, int millis, |
| int monthLength, int prevMonthLength ){ |
| |
| if (true) { |
| /* Use this parameter checking code for normal operation. Only one |
| * of these two blocks should actually get compiled into the class |
| * file. */ |
| if ((era != GregorianCalendar.AD && era != GregorianCalendar.BC) |
| || month < Calendar.JANUARY |
| || month > Calendar.DECEMBER |
| || day < 1 |
| || day > monthLength |
| || dayOfWeek < Calendar.SUNDAY |
| || dayOfWeek > Calendar.SATURDAY |
| || millis < 0 |
| || millis >= Grego.MILLIS_PER_DAY |
| || monthLength < 28 |
| || monthLength > 31 |
| || prevMonthLength < 28 |
| || prevMonthLength > 31) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| //Eclipse stated the following is "dead code" |
| /*else { |
| // This parameter checking code is better for debugging, but |
| // overkill for normal operation. Only one of these two blocks |
| // should actually get compiled into the class file. |
| if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) { |
| throw new IllegalArgumentException("Illegal era " + era); |
| } |
| if (month < Calendar.JANUARY |
| || month > Calendar.DECEMBER) { |
| throw new IllegalArgumentException("Illegal month " + month); |
| } |
| if (day < 1 |
| || day > monthLength) { |
| throw new IllegalArgumentException("Illegal day " + day+" max month len: "+monthLength); |
| } |
| if (dayOfWeek < Calendar.SUNDAY |
| || dayOfWeek > Calendar.SATURDAY) { |
| throw new IllegalArgumentException("Illegal day of week " + dayOfWeek); |
| } |
| if (millis < 0 |
| || millis >= Grego.MILLIS_PER_DAY) { |
| throw new IllegalArgumentException("Illegal millis " + millis); |
| } |
| if (monthLength < 28 |
| || monthLength > 31) { |
| throw new IllegalArgumentException("Illegal month length " + monthLength); |
| } |
| if (prevMonthLength < 28 |
| || prevMonthLength > 31) { |
| throw new IllegalArgumentException("Illegal previous month length " + prevMonthLength); |
| } |
| }*/ |
| |
| int result = raw; |
| |
| // Bail out if we are before the onset of daylight savings time |
| if (!useDaylight || year < startYear || era != GregorianCalendar.AD) return result; |
| |
| // Check for southern hemisphere. We assume that the start and end |
| // month are different. |
| boolean southern = (startMonth > endMonth); |
| |
| // Compare the date to the starting and ending rules.+1 = date>rule, -1 |
| // = date<rule, 0 = date==rule. |
| int startCompare = compareToRule(month, monthLength, prevMonthLength, |
| day, dayOfWeek, millis, |
| startTimeMode == UTC_TIME ? -raw : 0, |
| startMode, startMonth, startDayOfWeek, |
| startDay, startTime); |
| int endCompare = 0; |
| |
| /* We don't always have to compute endCompare. For many instances, |
| * startCompare is enough to determine if we are in DST or not. In the |
| * northern hemisphere, if we are before the start rule, we can't have |
| * DST. In the southern hemisphere, if we are after the start rule, we |
| * must have DST. This is reflected in the way the next if statement |
| * (not the one immediately following) short circuits. */ |
| if (southern != (startCompare >= 0)) { |
| /* For the ending rule comparison, we add the dstSavings to the millis |
| * passed in to convert them from standard to wall time. We then must |
| * normalize the millis to the range 0..millisPerDay-1. */ |
| endCompare = compareToRule(month, monthLength, prevMonthLength, |
| day, dayOfWeek, millis, |
| endTimeMode == WALL_TIME ? dst : |
| (endTimeMode == UTC_TIME ? -raw : 0), |
| endMode, endMonth, endDayOfWeek, |
| endDay, endTime); |
| } |
| |
| // Check for both the northern and southern hemisphere cases. We |
| // assume that in the northern hemisphere, the start rule is before the |
| // end rule within the calendar year, and vice versa for the southern |
| // hemisphere. |
| if ((!southern && (startCompare >= 0 && endCompare < 0)) || |
| (southern && (startCompare >= 0 || endCompare < 0))) |
| result += dst; |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * @internal |
| * @deprecated This API is ICU internal only. |
| */ |
| @Deprecated |
| public void getOffsetFromLocal(long date, |
| int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) { |
| offsets[0] = getRawOffset(); |
| int fields[] = new int[6]; |
| Grego.timeToFields(date, fields); |
| offsets[1] = getOffset(GregorianCalendar.AD, |
| fields[0], fields[1], fields[2], |
| fields[3], fields[5]) - offsets[0]; |
| |
| boolean recalc = false; |
| |
| // Now, we need some adjustment |
| if (offsets[1] > 0) { |
| if ((nonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD |
| || (nonExistingTimeOpt & STD_DST_MASK) != LOCAL_DST |
| && (nonExistingTimeOpt & FORMER_LATTER_MASK) != LOCAL_LATTER) { |
| date -= getDSTSavings(); |
| recalc = true; |
| } |
| } else { |
| if ((duplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST |
| || (duplicatedTimeOpt & STD_DST_MASK) != LOCAL_STD |
| && (duplicatedTimeOpt & FORMER_LATTER_MASK) == LOCAL_FORMER) { |
| date -= getDSTSavings(); |
| recalc = true; |
| } |
| } |
| |
| if (recalc) { |
| Grego.timeToFields(date, fields); |
| offsets[1] = getOffset(GregorianCalendar.AD, |
| fields[0], fields[1], fields[2], |
| fields[3], fields[5]) - offsets[0]; |
| } |
| } |
| |
| private static final int |
| DOM_MODE = 1, |
| DOW_IN_MONTH_MODE=2, |
| DOW_GE_DOM_MODE=3, |
| DOW_LE_DOM_MODE=4; |
| |
| /** |
| * Compare a given date in the year to a rule. Return 1, 0, or -1, depending |
| * on whether the date is after, equal to, or before the rule date. The |
| * millis are compared directly against the ruleMillis, so any |
| * standard-daylight adjustments must be handled by the caller. |
| * |
| * @return 1 if the date is after the rule date, -1 if the date is before |
| * the rule date, or 0 if the date is equal to the rule date. |
| */ |
| private int compareToRule(int month, int monthLen, int prevMonthLen, |
| int dayOfMonth, |
| int dayOfWeek, int millis, int millisDelta, |
| int ruleMode, int ruleMonth, int ruleDayOfWeek, |
| int ruleDay, int ruleMillis) |
| { |
| // Make adjustments for startTimeMode and endTimeMode |
| |
| millis += millisDelta; |
| |
| while (millis >= Grego.MILLIS_PER_DAY) { |
| millis -= Grego.MILLIS_PER_DAY; |
| ++dayOfMonth; |
| dayOfWeek = 1 + (dayOfWeek % 7); // dayOfWeek is one-based |
| if (dayOfMonth > monthLen) { |
| dayOfMonth = 1; |
| /* When incrementing the month, it is desirable to overflow |
| * from DECEMBER to DECEMBER+1, since we use the result to |
| * compare against a real month. Wraparound of the value |
| * leads to bug 4173604. */ |
| ++month; |
| } |
| } |
| /* |
| * For some reasons, Sun Java 6 on Solaris/Linux has a problem with |
| * the while loop below (at least Java 6 up to build 1.6.0_02-b08). |
| * It looks the JRE messes up the variable 'millis' while executing |
| * the code in the while block. The problem is not reproduced with |
| * JVM option -Xint, that is, it is likely a bug of the HotSpot |
| * adaptive compiler. Moving 'millis += Grego.MILLIS_PER_DAY' |
| * to the end of this while block seems to resolve the problem. |
| * See ticket#5887 about the problem in detail. |
| */ |
| while (millis < 0) { |
| //millis += Grego.MILLIS_PER_DAY; |
| --dayOfMonth; |
| dayOfWeek = 1 + ((dayOfWeek+5) % 7); // dayOfWeek is one-based |
| if (dayOfMonth < 1) { |
| dayOfMonth = prevMonthLen; |
| --month; |
| } |
| millis += Grego.MILLIS_PER_DAY; |
| } |
| |
| if (month < ruleMonth) return -1; |
| else if (month > ruleMonth) return 1; |
| |
| int ruleDayOfMonth = 0; |
| |
| // Adjust the ruleDay to the monthLen, for non-leap year February 29 rule days. |
| if (ruleDay > monthLen) { |
| ruleDay = monthLen; |
| } |
| |
| switch (ruleMode) |
| { |
| case DOM_MODE: |
| ruleDayOfMonth = ruleDay; |
| break; |
| case DOW_IN_MONTH_MODE: |
| // In this case ruleDay is the day-of-week-in-month |
| if (ruleDay > 0) |
| ruleDayOfMonth = 1 + (ruleDay - 1) * 7 + |
| (7 + ruleDayOfWeek - (dayOfWeek - dayOfMonth + 1)) % 7; |
| else // Assume ruleDay < 0 here |
| { |
| ruleDayOfMonth = monthLen + (ruleDay + 1) * 7 - |
| (7 + (dayOfWeek + monthLen - dayOfMonth) - ruleDayOfWeek) % 7; |
| } |
| break; |
| case DOW_GE_DOM_MODE: |
| ruleDayOfMonth = ruleDay + |
| (49 + ruleDayOfWeek - ruleDay - dayOfWeek + dayOfMonth) % 7; |
| break; |
| case DOW_LE_DOM_MODE: |
| ruleDayOfMonth = ruleDay - |
| (49 - ruleDayOfWeek + ruleDay + dayOfWeek - dayOfMonth) % 7; |
| // Note at this point ruleDayOfMonth may be <1, although it will |
| // be >=1 for well-formed rules. |
| break; |
| } |
| |
| if (dayOfMonth < ruleDayOfMonth) return -1; |
| else if (dayOfMonth > ruleDayOfMonth) return 1; |
| |
| if (millis < ruleMillis){ |
| return -1; |
| }else if (millis > ruleMillis){ |
| return 1; |
| }else{ |
| return 0; |
| } |
| } |
| |
| // data needed for streaming mutated SimpleTimeZones in JDK14 |
| private int raw;// the TimeZone's raw GMT offset |
| private int dst = 3600000; |
| private STZInfo xinfo = null; |
| private int startMonth, startDay, startDayOfWeek; // the month, day, DOW, and time DST starts |
| private int startTime; |
| private int startTimeMode, endTimeMode; // Mode for startTime, endTime; see TimeMode |
| private int endMonth, endDay, endDayOfWeek; // the month, day, DOW, and time DST ends |
| private int endTime; |
| private int startYear; // the year these DST rules took effect |
| private boolean useDaylight; // flag indicating whether this TimeZone uses DST |
| private int startMode, endMode; // flags indicating what kind of rules the DST rules are |
| |
| /** |
| * Overrides TimeZone |
| * Queries if this time zone uses Daylight Saving Time. |
| * @stable ICU 2.0 |
| */ |
| @Override |
| public boolean useDaylightTime(){ |
| return useDaylight; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 49 |
| */ |
| public boolean observesDaylightTime() { |
| return useDaylight; |
| } |
| |
| /** |
| * Overrides TimeZone |
| * Queries if the give date is in Daylight Saving Time. |
| * @stable ICU 2.0 |
| */ |
| @Override |
| public boolean inDaylightTime(Date date){ |
| GregorianCalendar gc = new GregorianCalendar(this); |
| gc.setTime(date); |
| return gc.inDaylightTime(); |
| } |
| |
| /** |
| * Internal construction method. |
| */ |
| private void construct(int _raw, |
| int _startMonth, |
| int _startDay, |
| int _startDayOfWeek, |
| int _startTime, |
| int _startTimeMode, |
| int _endMonth, |
| int _endDay, |
| int _endDayOfWeek, |
| int _endTime, |
| int _endTimeMode, |
| int _dst) { |
| raw = _raw; |
| startMonth = _startMonth; |
| startDay = _startDay; |
| startDayOfWeek = _startDayOfWeek; |
| startTime = _startTime; |
| startTimeMode = _startTimeMode; |
| endMonth = _endMonth; |
| endDay = _endDay; |
| endDayOfWeek = _endDayOfWeek; |
| endTime = _endTime; |
| endTimeMode = _endTimeMode; |
| dst = _dst; |
| startYear = 0; |
| startMode = DOM_MODE; |
| endMode = DOM_MODE; |
| |
| decodeRules(); |
| |
| if (_dst <= 0) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| private void decodeRules(){ |
| decodeStartRule(); |
| decodeEndRule(); |
| } |
| |
| /** |
| * Decode the start rule and validate the parameters. The parameters are |
| * expected to be in encoded form, which represents the various rule modes |
| * by negating or zeroing certain values. Representation formats are: |
| * <p> |
| * <pre> |
| * DOW_IN_MONTH DOM DOW>=DOM DOW<=DOM no DST |
| * ------------ ----- -------- -------- ---------- |
| * month 0..11 same same same don't care |
| * day -5..5 1..31 1..31 -1..-31 0 |
| * dayOfWeek 1..7 0 -1..-7 -1..-7 don't care |
| * time 0..ONEDAY same same same don't care |
| * </pre> |
| * The range for month does not include UNDECIMBER since this class is |
| * really specific to GregorianCalendar, which does not use that month. |
| * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the |
| * end rule is an exclusive limit point. That is, the range of times that |
| * are in DST include those >= the start and < the end. For this reason, |
| * it should be possible to specify an end of ONEDAY in order to include the |
| * entire day. Although this is equivalent to time 0 of the following day, |
| * it's not always possible to specify that, for example, on December 31. |
| * While arguably the start range should still be 0..ONEDAY-1, we keep |
| * the start and end ranges the same for consistency. |
| */ |
| private void decodeStartRule() { |
| useDaylight = (startDay != 0) && (endDay != 0); |
| if (useDaylight && dst == 0) { |
| dst = Grego.MILLIS_PER_DAY; |
| } |
| if (startDay != 0) { |
| if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) { |
| throw new IllegalArgumentException(); |
| } |
| if (startTime < 0 || startTime > Grego.MILLIS_PER_DAY || |
| startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) { |
| throw new IllegalArgumentException(); |
| } |
| if (startDayOfWeek == 0) { |
| startMode = DOM_MODE; |
| } else { |
| if (startDayOfWeek > 0) { |
| startMode = DOW_IN_MONTH_MODE; |
| } else { |
| startDayOfWeek = -startDayOfWeek; |
| if (startDay > 0) { |
| startMode = DOW_GE_DOM_MODE; |
| } else { |
| startDay = -startDay; |
| startMode = DOW_LE_DOM_MODE; |
| } |
| } |
| if (startDayOfWeek > Calendar.SATURDAY) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if (startMode == DOW_IN_MONTH_MODE) { |
| if (startDay < -5 || startDay > 5) { |
| throw new IllegalArgumentException(); |
| } |
| } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| } |
| |
| /** |
| * Decode the end rule and validate the parameters. This method is exactly |
| * analogous to decodeStartRule(). |
| * @see #decodeStartRule |
| */ |
| private void decodeEndRule() { |
| useDaylight = (startDay != 0) && (endDay != 0); |
| if (useDaylight && dst == 0) { |
| dst = Grego.MILLIS_PER_DAY; |
| } |
| if (endDay != 0) { |
| if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) { |
| throw new IllegalArgumentException(); |
| } |
| if (endTime < 0 || endTime > Grego.MILLIS_PER_DAY || |
| endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) { |
| throw new IllegalArgumentException(); |
| } |
| if (endDayOfWeek == 0) { |
| endMode = DOM_MODE; |
| } else { |
| if (endDayOfWeek > 0) { |
| endMode = DOW_IN_MONTH_MODE; |
| } else { |
| endDayOfWeek = -endDayOfWeek; |
| if (endDay > 0) { |
| endMode = DOW_GE_DOM_MODE; |
| } else { |
| endDay = -endDay; |
| endMode = DOW_LE_DOM_MODE; |
| } |
| } |
| if (endDayOfWeek > Calendar.SATURDAY) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if (endMode == DOW_IN_MONTH_MODE) { |
| if (endDay < -5 || endDay > 5) { |
| throw new IllegalArgumentException(); |
| } |
| } else if (endDay<1 || endDay > staticMonthLength[endMonth]) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| } |
| |
| /** |
| * Overrides equals. |
| * @return true if obj is a SimpleTimeZone equivalent to this |
| * @stable ICU 3.6 |
| */ |
| @Override |
| public boolean equals(Object obj){ |
| if (this == obj) return true; |
| if (obj == null || getClass() != obj.getClass()) return false; |
| SimpleTimeZone that = (SimpleTimeZone) obj; |
| return raw == that.raw && |
| useDaylight == that.useDaylight && |
| idEquals(getID(),that.getID()) && |
| (!useDaylight |
| // Only check rules if using DST |
| || (dst == that.dst && |
| startMode == that.startMode && |
| startMonth == that.startMonth && |
| startDay == that.startDay && |
| startDayOfWeek == that.startDayOfWeek && |
| startTime == that.startTime && |
| startTimeMode == that.startTimeMode && |
| endMode == that.endMode && |
| endMonth == that.endMonth && |
| endDay == that.endDay && |
| endDayOfWeek == that.endDayOfWeek && |
| endTime == that.endTime && |
| endTimeMode == that.endTimeMode && |
| startYear == that.startYear )); |
| |
| } |
| private boolean idEquals(String id1, String id2){ |
| if(id1==null && id2==null){ |
| return true; |
| } |
| if(id1!=null && id2!=null){ |
| return id1.equals(id2); |
| } |
| return false; |
| } |
| |
| /** |
| * Overrides hashCode. |
| * @stable ICU 3.6 |
| */ |
| @Override |
| public int hashCode(){ |
| int ret = super.hashCode() |
| + raw ^ (raw >>> 8) |
| + (useDaylight ? 0 : 1); |
| if(!useDaylight){ |
| ret += dst ^ (dst >>> 10) + |
| startMode ^ (startMode>>>11) + |
| startMonth ^ (startMonth>>>12) + |
| startDay ^ (startDay>>>13) + |
| startDayOfWeek ^ (startDayOfWeek>>>14) + |
| startTime ^ (startTime>>>15) + |
| startTimeMode ^ (startTimeMode>>>16) + |
| endMode ^ (endMode>>>17) + |
| endMonth ^ (endMonth>>>18) + |
| endDay ^ (endDay>>>19) + |
| endDayOfWeek ^ (endDayOfWeek>>>20) + |
| endTime ^ (endTime>>>21) + |
| endTimeMode ^ (endTimeMode>>>22) + |
| startYear ^ (startYear>>>23); |
| } |
| return ret; |
| } |
| |
| /** |
| * Overrides clone. |
| * @stable ICU 3.6 |
| */ |
| @Override |
| public Object clone() { |
| if (isFrozen()) { |
| return this; |
| } |
| return cloneAsThawed(); |
| } |
| |
| /** |
| * Returns true if this zone has the same rules and offset as another zone. |
| * @param othr the TimeZone object to be compared with |
| * @return true if the given zone has the same rules and offset as this one |
| * @stable ICU 2.0 |
| */ |
| @Override |
| public boolean hasSameRules(TimeZone othr) { |
| if (this == othr) { |
| return true; |
| } |
| if(!(othr instanceof SimpleTimeZone)){ |
| return false; |
| } |
| SimpleTimeZone other = (SimpleTimeZone)othr; |
| return other != null && |
| raw == other.raw && |
| useDaylight == other.useDaylight && |
| (!useDaylight |
| // Only check rules if using DST |
| || (dst == other.dst && |
| startMode == other.startMode && |
| startMonth == other.startMonth && |
| startDay == other.startDay && |
| startDayOfWeek == other.startDayOfWeek && |
| startTime == other.startTime && |
| startTimeMode == other.startTimeMode && |
| endMode == other.endMode && |
| endMonth == other.endMonth && |
| endDay == other.endDay && |
| endDayOfWeek == other.endDayOfWeek && |
| endTime == other.endTime && |
| endTimeMode == other.endTimeMode && |
| startYear == other.startYear)); |
| } |
| |
| // BasicTimeZone methods |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 3.8 |
| */ |
| @Override |
| public TimeZoneTransition getNextTransition(long base, boolean inclusive) { |
| if (!useDaylight) { |
| return null; |
| } |
| |
| initTransitionRules(); |
| long firstTransitionTime = firstTransition.getTime(); |
| if (base < firstTransitionTime || (inclusive && base == firstTransitionTime)) { |
| return firstTransition; |
| } |
| Date stdDate = stdRule.getNextStart(base, dstRule.getRawOffset(), dstRule.getDSTSavings(), |
| inclusive); |
| Date dstDate = dstRule.getNextStart(base, stdRule.getRawOffset(), stdRule.getDSTSavings(), |
| inclusive); |
| if (stdDate != null && (dstDate == null || stdDate.before(dstDate))) { |
| return new TimeZoneTransition(stdDate.getTime(), dstRule, stdRule); |
| } |
| if (dstDate != null && (stdDate == null || dstDate.before(stdDate))) { |
| return new TimeZoneTransition(dstDate.getTime(), stdRule, dstRule); |
| } |
| return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 3.8 |
| */ |
| @Override |
| public TimeZoneTransition getPreviousTransition(long base, boolean inclusive) { |
| if (!useDaylight) { |
| return null; |
| } |
| |
| initTransitionRules(); |
| long firstTransitionTime = firstTransition.getTime(); |
| if (base < firstTransitionTime || (!inclusive && base == firstTransitionTime)) { |
| return null; |
| } |
| Date stdDate = stdRule.getPreviousStart(base, dstRule.getRawOffset(), |
| dstRule.getDSTSavings(), inclusive); |
| Date dstDate = dstRule.getPreviousStart(base, stdRule.getRawOffset(), |
| stdRule.getDSTSavings(), inclusive); |
| if (stdDate != null && (dstDate == null || stdDate.after(dstDate))) { |
| return new TimeZoneTransition(stdDate.getTime(), dstRule, stdRule); |
| } |
| if (dstDate != null && (stdDate == null || dstDate.after(stdDate))) { |
| return new TimeZoneTransition(dstDate.getTime(), stdRule, dstRule); |
| } |
| return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 3.8 |
| */ |
| @Override |
| public TimeZoneRule[] getTimeZoneRules() { |
| initTransitionRules(); |
| |
| int size = useDaylight ? 3 : 1; |
| TimeZoneRule[] rules = new TimeZoneRule[size]; |
| rules[0] = initialRule; |
| if (useDaylight) { |
| rules[1] = stdRule; |
| rules[2] = dstRule; |
| } |
| return rules; |
| } |
| |
| private transient boolean transitionRulesInitialized; |
| private transient InitialTimeZoneRule initialRule; |
| private transient TimeZoneTransition firstTransition; |
| private transient AnnualTimeZoneRule stdRule; |
| private transient AnnualTimeZoneRule dstRule; |
| |
| private synchronized void initTransitionRules() { |
| if (transitionRulesInitialized) { |
| return; |
| } |
| if (useDaylight) { |
| DateTimeRule dtRule = null; |
| int timeRuleType; |
| long firstStdStart, firstDstStart; |
| |
| // Create a TimeZoneRule for daylight saving time |
| timeRuleType = (startTimeMode == STANDARD_TIME) ? DateTimeRule.STANDARD_TIME : |
| ((startTimeMode == UTC_TIME) ? DateTimeRule.UTC_TIME : DateTimeRule.WALL_TIME); |
| switch (startMode) { |
| case DOM_MODE: |
| dtRule = new DateTimeRule(startMonth, startDay, startTime, timeRuleType); |
| break; |
| case DOW_IN_MONTH_MODE: |
| dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, startTime, |
| timeRuleType); |
| break; |
| case DOW_GE_DOM_MODE: |
| dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, true, startTime, |
| timeRuleType); |
| break; |
| case DOW_LE_DOM_MODE: |
| dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, false, startTime, |
| timeRuleType); |
| break; |
| } |
| // For now, use ID + "(DST)" as the name |
| dstRule = new AnnualTimeZoneRule(getID() + "(DST)", getRawOffset(), getDSTSavings(), |
| dtRule, startYear, AnnualTimeZoneRule.MAX_YEAR); |
| |
| // Calculate the first DST start time |
| firstDstStart = dstRule.getFirstStart(getRawOffset(), 0).getTime(); |
| |
| // Create a TimeZoneRule for standard time |
| timeRuleType = (endTimeMode == STANDARD_TIME) ? DateTimeRule.STANDARD_TIME : |
| ((endTimeMode == UTC_TIME) ? DateTimeRule.UTC_TIME : DateTimeRule.WALL_TIME); |
| switch (endMode) { |
| case DOM_MODE: |
| dtRule = new DateTimeRule(endMonth, endDay, endTime, timeRuleType); |
| break; |
| case DOW_IN_MONTH_MODE: |
| dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, endTime, timeRuleType); |
| break; |
| case DOW_GE_DOM_MODE: |
| dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, true, endTime, |
| timeRuleType); |
| break; |
| case DOW_LE_DOM_MODE: |
| dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, false, endTime, |
| timeRuleType); |
| break; |
| } |
| // For now, use ID + "(STD)" as the name |
| stdRule = new AnnualTimeZoneRule(getID() + "(STD)", getRawOffset(), 0, |
| dtRule, startYear, AnnualTimeZoneRule.MAX_YEAR); |
| |
| // Calculate the first STD start time |
| firstStdStart = stdRule.getFirstStart(getRawOffset(), dstRule.getDSTSavings()).getTime(); |
| |
| // Create a TimeZoneRule for initial time |
| if (firstStdStart < firstDstStart) { |
| initialRule = new InitialTimeZoneRule(getID() + "(DST)", getRawOffset(), |
| dstRule.getDSTSavings()); |
| firstTransition = new TimeZoneTransition(firstStdStart, initialRule, stdRule); |
| } else { |
| initialRule = new InitialTimeZoneRule(getID() + "(STD)", getRawOffset(), 0); |
| firstTransition = new TimeZoneTransition(firstDstStart, initialRule, dstRule); |
| } |
| |
| } else { |
| // Create a TimeZoneRule for initial time |
| initialRule = new InitialTimeZoneRule(getID(), getRawOffset(), 0); |
| } |
| transitionRulesInitialized = true; |
| } |
| |
| // Freezable stuffs |
| private volatile transient boolean isFrozen = false; |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 49 |
| */ |
| public boolean isFrozen() { |
| return isFrozen; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 49 |
| */ |
| public TimeZone freeze() { |
| isFrozen = true; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 49 |
| */ |
| public TimeZone cloneAsThawed() { |
| SimpleTimeZone tz = (SimpleTimeZone)super.cloneAsThawed(); |
| tz.isFrozen = false; |
| return tz; |
| } |
| } |