| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // BEGIN android-note |
| // This implementation is based on an old version of Apache Harmony. The current |
| // Harmony uses ICU4J, which makes it much simpler. We should consider updating |
| // this implementation to leverage ICU4JNI. |
| // END android-note |
| |
| package java.util; |
| |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.ObjectStreamField; |
| |
| /** |
| * {@code SimpleTimeZone} is a concrete subclass of {@code TimeZone} |
| * 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} to indicate that |
| * {@code SimpleTimeZone} should count from the end of the month |
| * backwards. For example, Daylight Savings Time ends at the last |
| * (dayOfWeekInMonth = -1) Sunday in October, at 2 AM in standard time. |
| * |
| * @see Calendar |
| * @see GregorianCalendar |
| * @see TimeZone |
| */ |
| public class SimpleTimeZone extends TimeZone { |
| |
| private static final long serialVersionUID = -403250971215465050L; |
| |
| // BEGIN android-removed |
| // private static com.ibm.icu.util.TimeZone getICUTimeZone(final String name){ |
| // return AccessController.doPrivileged(new PrivilegedAction<com.ibm.icu.util.TimeZone>(){ |
| // public com.ibm.icu.util.TimeZone run() { |
| // return com.ibm.icu.util.TimeZone.getTimeZone(name); |
| // } |
| // }); |
| // } |
| // END android-removed |
| |
| private int rawOffset; |
| |
| private int startYear, startMonth, startDay, startDayOfWeek, startTime; |
| |
| private int endMonth, endDay, endDayOfWeek, endTime; |
| |
| private int startMode, endMode; |
| |
| private static final int DOM_MODE = 1, DOW_IN_MONTH_MODE = 2, |
| DOW_GE_DOM_MODE = 3, DOW_LE_DOM_MODE = 4; |
| |
| /** |
| * The constant for representing a start or end time in GMT time mode. |
| */ |
| public static final int UTC_TIME = 2; |
| |
| /** |
| * The constant for representing a start or end time in standard local time mode, |
| * based on timezone's raw offset from GMT; does not include Daylight |
| * savings. |
| */ |
| public static final int STANDARD_TIME = 1; |
| |
| /** |
| * The constant for representing a start or end time in local wall clock time |
| * mode, based on timezone's adjusted offset from GMT; includes |
| * Daylight savings. |
| */ |
| public static final int WALL_TIME = 0; |
| |
| private boolean useDaylight; |
| |
| private int dstSavings = 3600000; |
| |
| // BEGIN android-removed |
| // private final transient com.ibm.icu.util.TimeZone icuTZ; |
| // |
| // private final transient boolean isSimple; |
| // END android-removed |
| |
| /** |
| * Constructs a {@code SimpleTimeZone} with the given base time zone offset from GMT |
| * and time zone ID. Timezone IDs can be obtained from |
| * {@code TimeZone.getAvailableIDs}. Normally you should use {@code TimeZone.getDefault} to |
| * construct a {@code TimeZone}. |
| * |
| * @param offset |
| * the given base time zone offset to GMT. |
| * @param name |
| * the time zone ID which is obtained from |
| * {@code TimeZone.getAvailableIDs}. |
| */ |
| public SimpleTimeZone(int offset, final String name) { |
| setID(name); |
| rawOffset = offset; |
| // BEGIN android-removed |
| // icuTZ = getICUTimeZone(name); |
| // if (icuTZ instanceof com.ibm.icu.util.SimpleTimeZone) { |
| // isSimple = true; |
| // icuTZ.setRawOffset(offset); |
| // } else { |
| // isSimple = false; |
| // } |
| // useDaylight = icuTZ.useDaylightTime(); |
| // END android-removed |
| } |
| |
| /** |
| * Constructs a {@code SimpleTimeZone} with the given base time zone offset from GMT, |
| * time zone ID, and times to start and end the daylight savings time. Timezone IDs can |
| * be obtained from {@code TimeZone.getAvailableIDs}. Normally you should use |
| * {@code TimeZone.getDefault} to create a {@code TimeZone}. For a time zone that does not |
| * use daylight saving time, do not use this constructor; instead you should |
| * use {@code SimpleTimeZone(rawOffset, ID)}. |
| * <p> |
| * By default, this constructor specifies day-of-week-in-month rules. That |
| * is, if the {@code startDay} is 1, and the {@code startDayOfWeek} is {@code SUNDAY}, then this |
| * indicates the first Sunday in the {@code startMonth}. A {@code 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. |
| * <p> |
| * Day of month: To specify an exact day of the month, such as March 1, set |
| * {@code startDayOfWeek} to zero. |
| * <p> |
| * 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 {@code startDay} is 5 and {@code startDayOfWeek} is {@code -MONDAY}, |
| * this indicates the first Monday on or after the 5th day of the |
| * {@code startMonth}. |
| * <p> |
| * 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 {@code startDay} is {@code -21} |
| * and {@code startDayOfWeek} is {@code -WEDNESDAY}, this indicates the last Wednesday on or |
| * before the 21st of the {@code startMonth}. |
| * <p> |
| * The above examples refer to the {@code startMonth}, {@code startDay}, and {@code startDayOfWeek}; |
| * the same applies for the {@code endMonth}, {@code endDay}, and {@code endDayOfWeek}. |
| * <p> |
| * The daylight savings time difference is set to the default value: one hour. |
| * |
| * @param offset |
| * the given base time zone offset to GMT. |
| * @param name |
| * the time zone ID which is obtained from |
| * {@code TimeZone.getAvailableIDs}. |
| * @param startMonth |
| * the daylight savings starting month. The month indexing 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. The month indexing 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 |
| * if the month, day, dayOfWeek, or time parameters are out of |
| * range for the start or end rule. |
| */ |
| public SimpleTimeZone(int offset, String name, int startMonth, |
| int startDay, int startDayOfWeek, int startTime, int endMonth, |
| int endDay, int endDayOfWeek, int endTime) { |
| this(offset, name, startMonth, startDay, startDayOfWeek, startTime, |
| endMonth, endDay, endDayOfWeek, endTime, 3600000); |
| } |
| |
| /** |
| * Constructs a {@code SimpleTimeZone} with the given base time zone offset from GMT, |
| * time zone ID, times to start and end the daylight savings time, and |
| * the daylight savings time difference in milliseconds. |
| * |
| * @param offset |
| * the given base time zone offset to GMT. |
| * @param name |
| * the time zone ID which is obtained from |
| * {@code 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 description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. |
| * @param startDayOfWeek |
| * the daylight savings starting day-of-week. Please see the |
| * description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. |
| * @param startTime |
| * The daylight savings starting time in local wall time, which |
| * is standard time in this case. Please see the description of |
| * {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} 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 description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. |
| * @param endDayOfWeek |
| * the daylight savings ending day-of-week. Please see the description of |
| * {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. |
| * @param endTime |
| * the daylight savings ending time in local wall time, which is |
| * daylight time in this case. Please see the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} |
| * for an example. |
| * @param daylightSavings |
| * the daylight savings time difference in milliseconds. |
| * @throws IllegalArgumentException |
| * if the month, day, dayOfWeek, or time parameters are out of |
| * range for the start or end rule. |
| */ |
| public SimpleTimeZone(int offset, String name, int startMonth, |
| int startDay, int startDayOfWeek, int startTime, int endMonth, |
| int endDay, int endDayOfWeek, int endTime, int daylightSavings) { |
| // BEGIN android-changed |
| // icuTZ = getICUTimeZone(name); |
| // if (icuTZ instanceof com.ibm.icu.util.SimpleTimeZone) { |
| // isSimple = true; |
| // com.ibm.icu.util.SimpleTimeZone tz = (com.ibm.icu.util.SimpleTimeZone)icuTZ; |
| // tz.setRawOffset(offset); |
| // tz.setStartRule(startMonth, startDay, startDayOfWeek, startTime); |
| // tz.setEndRule(endMonth, endDay, endDayOfWeek, endTime); |
| // tz.setDSTSavings(daylightSavings); |
| // } else { |
| // isSimple = false; |
| // } |
| // setID(name); |
| // rawOffset = offset; |
| this(offset, name); |
| // END android-changed |
| if (daylightSavings <= 0) { |
| throw new IllegalArgumentException("Invalid daylightSavings: " + daylightSavings); |
| } |
| dstSavings = daylightSavings; |
| |
| setStartRule(startMonth, startDay, startDayOfWeek, startTime); |
| setEndRule(endMonth, endDay, endDayOfWeek, endTime); |
| |
| // BEGIN android-removed |
| // useDaylight = daylightSavings > 0 || icuTZ.useDaylightTime(); |
| // END android-removed |
| } |
| |
| /** |
| * Construct a {@code SimpleTimeZone} with the given base time zone offset from GMT, |
| * time zone ID, times to start and end the daylight savings time including a |
| * mode specifier, the daylight savings time difference in milliseconds. |
| * The mode specifies either {@link #WALL_TIME}, {@link #STANDARD_TIME}, or |
| * {@link #UTC_TIME}. |
| * |
| * @param offset |
| * the given base time zone offset to GMT. |
| * @param name |
| * the time zone ID which is obtained from |
| * {@code TimeZone.getAvailableIDs}. |
| * @param startMonth |
| * the daylight savings starting month. The month indexing is 0-based. eg, 0 |
| * for January. |
| * @param startDay |
| * the daylight savings starting day-of-week-in-month. Please see |
| * the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. |
| * @param startDayOfWeek |
| * the daylight savings starting day-of-week. Please see the |
| * description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. |
| * @param startTime |
| * the time of day in milliseconds on which daylight savings |
| * time starts, based on the {@code startTimeMode}. |
| * @param startTimeMode |
| * the mode (UTC, standard, or wall time) of the start time |
| * value. |
| * @param endDay |
| * the day of the week on which daylight savings time ends. |
| * @param endMonth |
| * the daylight savings ending month. The month indexing is 0-based. eg, 0 for |
| * January. |
| * @param endDayOfWeek |
| * the daylight savings ending day-of-week. Please see the description of |
| * {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. |
| * @param endTime |
| * the time of day in milliseconds on which daylight savings |
| * time ends, based on the {@code endTimeMode}. |
| * @param endTimeMode |
| * the mode (UTC, standard, or wall time) of the end time value. |
| * @param daylightSavings |
| * the daylight savings time difference in milliseconds. |
| * @throws IllegalArgumentException |
| * if the month, day, dayOfWeek, or time parameters are out of |
| * range for the start or end rule. |
| */ |
| public SimpleTimeZone(int offset, String name, int startMonth, |
| int startDay, int startDayOfWeek, int startTime, int startTimeMode, |
| int endMonth, int endDay, int endDayOfWeek, int endTime, |
| int endTimeMode, int daylightSavings) { |
| |
| this(offset, name, startMonth, startDay, startDayOfWeek, startTime, |
| endMonth, endDay, endDayOfWeek, endTime, daylightSavings); |
| startMode = startTimeMode; |
| endMode = endTimeMode; |
| } |
| |
| /** |
| * Returns a new {@code SimpleTimeZone} with the same ID, {@code rawOffset} and daylight |
| * savings time rules as this SimpleTimeZone. |
| * |
| * @return a shallow copy of this {@code SimpleTimeZone}. |
| * @see java.lang.Cloneable |
| */ |
| @Override |
| public Object clone() { |
| SimpleTimeZone zone = (SimpleTimeZone) super.clone(); |
| return zone; |
| } |
| |
| /** |
| * Compares the specified object to this {@code SimpleTimeZone} and returns whether they |
| * are equal. The object must be an instance of {@code SimpleTimeZone} and have the |
| * same internal data. |
| * |
| * @param object |
| * the object to compare with this object. |
| * @return {@code true} if the specified object is equal to this |
| * {@code SimpleTimeZone}, {@code false} otherwise. |
| * @see #hashCode |
| */ |
| @Override |
| public boolean equals(Object object) { |
| if (!(object instanceof SimpleTimeZone)) { |
| return false; |
| } |
| SimpleTimeZone tz = (SimpleTimeZone) object; |
| return getID().equals(tz.getID()) |
| && rawOffset == tz.rawOffset |
| && useDaylight == tz.useDaylight |
| && (!useDaylight || (startYear == tz.startYear |
| && startMonth == tz.startMonth |
| && startDay == tz.startDay && startMode == tz.startMode |
| && startDayOfWeek == tz.startDayOfWeek |
| && startTime == tz.startTime && endMonth == tz.endMonth |
| && endDay == tz.endDay |
| && endDayOfWeek == tz.endDayOfWeek |
| && endTime == tz.endTime && endMode == tz.endMode && dstSavings == tz.dstSavings)); |
| } |
| |
| @Override |
| public int getDSTSavings() { |
| if (!useDaylight) { |
| return 0; |
| } |
| return dstSavings; |
| } |
| |
| @Override |
| public int getOffset(int era, int year, int month, int day, int dayOfWeek, int time) { |
| if (era != GregorianCalendar.BC && era != GregorianCalendar.AD) { |
| throw new IllegalArgumentException("Invalid era: " + era); |
| } |
| checkRange(month, dayOfWeek, time); |
| if (month != Calendar.FEBRUARY || day != 29 || !isLeapYear(year)) { |
| checkDay(month, day); |
| } |
| |
| // BEGIN android-changed |
| // return icuTZ.getOffset(era, year, month, day, dayOfWeek, time); |
| if (!useDaylightTime() || era != GregorianCalendar.AD || year < startYear) { |
| return rawOffset; |
| } |
| if (endMonth < startMonth) { |
| if (month > endMonth && month < startMonth) { |
| return rawOffset; |
| } |
| } else { |
| if (month < startMonth || month > endMonth) { |
| return rawOffset; |
| } |
| } |
| |
| int ruleDay = 0, daysInMonth, firstDayOfMonth = mod7(dayOfWeek - day); |
| if (month == startMonth) { |
| switch (startMode) { |
| case DOM_MODE: |
| ruleDay = startDay; |
| break; |
| case DOW_IN_MONTH_MODE: |
| if (startDay >= 0) { |
| ruleDay = mod7(startDayOfWeek - firstDayOfMonth) + 1 |
| + (startDay - 1) * 7; |
| } else { |
| daysInMonth = GregorianCalendar.DaysInMonth[startMonth]; |
| if (startMonth == Calendar.FEBRUARY && isLeapYear( |
| year)) { |
| daysInMonth += 1; |
| } |
| ruleDay = daysInMonth |
| + 1 |
| + mod7(startDayOfWeek |
| - (firstDayOfMonth + daysInMonth)) |
| + startDay * 7; |
| } |
| break; |
| case DOW_GE_DOM_MODE: |
| ruleDay = startDay |
| + mod7(startDayOfWeek |
| - (firstDayOfMonth + startDay - 1)); |
| break; |
| case DOW_LE_DOM_MODE: |
| ruleDay = startDay |
| + mod7(startDayOfWeek |
| - (firstDayOfMonth + startDay - 1)); |
| if (ruleDay != startDay) { |
| ruleDay -= 7; |
| } |
| break; |
| } |
| if (ruleDay > day || ruleDay == day && time < startTime) { |
| return rawOffset; |
| } |
| } |
| |
| int ruleTime = endTime - dstSavings; |
| int nextMonth = (month + 1) % 12; |
| if (month == endMonth || (ruleTime < 0 && nextMonth == endMonth)) { |
| switch (endMode) { |
| case DOM_MODE: |
| ruleDay = endDay; |
| break; |
| case DOW_IN_MONTH_MODE: |
| if (endDay >= 0) { |
| ruleDay = mod7(endDayOfWeek - firstDayOfMonth) + 1 |
| + (endDay - 1) * 7; |
| } else { |
| daysInMonth = GregorianCalendar.DaysInMonth[endMonth]; |
| if (endMonth == Calendar.FEBRUARY && isLeapYear(year)) { |
| daysInMonth++; |
| } |
| ruleDay = daysInMonth |
| + 1 |
| + mod7(endDayOfWeek |
| - (firstDayOfMonth + daysInMonth)) + endDay |
| * 7; |
| } |
| break; |
| case DOW_GE_DOM_MODE: |
| ruleDay = endDay |
| + mod7( |
| endDayOfWeek - (firstDayOfMonth + endDay - 1)); |
| break; |
| case DOW_LE_DOM_MODE: |
| ruleDay = endDay |
| + mod7( |
| endDayOfWeek - (firstDayOfMonth + endDay - 1)); |
| if (ruleDay != endDay) { |
| ruleDay -= 7; |
| } |
| break; |
| } |
| |
| int ruleMonth = endMonth; |
| if (ruleTime < 0) { |
| int changeDays = 1 - (ruleTime / 86400000); |
| ruleTime = (ruleTime % 86400000) + 86400000; |
| ruleDay -= changeDays; |
| if (ruleDay <= 0) { |
| if (--ruleMonth < Calendar.JANUARY) { |
| ruleMonth = Calendar.DECEMBER; |
| } |
| ruleDay += GregorianCalendar.DaysInMonth[ruleMonth]; |
| if (ruleMonth == Calendar.FEBRUARY && isLeapYear(year)) { |
| ruleDay++; |
| } |
| } |
| } |
| |
| if (month == ruleMonth) { |
| if (ruleDay < day || ruleDay == day && time >= ruleTime) { |
| return rawOffset; |
| } |
| } else if (nextMonth != ruleMonth) { |
| return rawOffset; |
| } |
| } |
| return rawOffset + dstSavings; |
| // END android-changed |
| } |
| |
| @Override |
| public int getOffset(long time) { |
| // BEGIN android-changed: simplified variant of the ICU4J code. |
| if (!useDaylightTime()) { |
| return rawOffset; |
| } |
| int[] fields = Grego.timeToFields(time + rawOffset, null); |
| return getOffset(GregorianCalendar.AD, fields[0], fields[1], fields[2], |
| fields[3], fields[5]); |
| // END android-changed |
| } |
| |
| @Override |
| public int getRawOffset() { |
| return rawOffset; |
| } |
| |
| /** |
| * Returns an integer hash code for the receiver. Objects which are equal |
| * return the same value for this method. |
| * |
| * @return the receiver's hash. |
| * @see #equals |
| */ |
| @Override |
| public synchronized int hashCode() { |
| int hashCode = getID().hashCode() + rawOffset; |
| if (useDaylight) { |
| hashCode += startYear + startMonth + startDay + startDayOfWeek |
| + startTime + startMode + endMonth + endDay + endDayOfWeek |
| + endTime + endMode + dstSavings; |
| } |
| return hashCode; |
| } |
| |
| @Override |
| public boolean hasSameRules(TimeZone zone) { |
| if (!(zone instanceof SimpleTimeZone)) { |
| return false; |
| } |
| SimpleTimeZone tz = (SimpleTimeZone) zone; |
| if (useDaylight != tz.useDaylight) { |
| return false; |
| } |
| if (!useDaylight) { |
| return rawOffset == tz.rawOffset; |
| } |
| return rawOffset == tz.rawOffset && dstSavings == tz.dstSavings |
| && startYear == tz.startYear && startMonth == tz.startMonth |
| && startDay == tz.startDay && startMode == tz.startMode |
| && startDayOfWeek == tz.startDayOfWeek |
| && startTime == tz.startTime && endMonth == tz.endMonth |
| && endDay == tz.endDay && endDayOfWeek == tz.endDayOfWeek |
| && endTime == tz.endTime && endMode == tz.endMode; |
| } |
| |
| @Override |
| public boolean inDaylightTime(Date time) { |
| // BEGIN android-changed: reuse getOffset. |
| return useDaylightTime() && getOffset(time.getTime()) != rawOffset; |
| // END android-changed |
| } |
| |
| private boolean isLeapYear(int year) { |
| if (year > 1582) { |
| return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); |
| } |
| return year % 4 == 0; |
| } |
| |
| // BEGIN android-added |
| private int mod7(int num1) { |
| int rem = num1 % 7; |
| return (num1 < 0 && rem < 0) ? 7 + rem : rem; |
| } |
| // END android-added |
| |
| /** |
| * Sets the daylight savings offset in milliseconds for this {@code SimpleTimeZone}. |
| * |
| * @param milliseconds |
| * the daylight savings offset in milliseconds. |
| */ |
| public void setDSTSavings(int milliseconds) { |
| if (milliseconds > 0) { |
| dstSavings = milliseconds; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| private void checkRange(int month, int dayOfWeek, int time) { |
| if (month < Calendar.JANUARY || month > Calendar.DECEMBER) { |
| throw new IllegalArgumentException("Invalid month: " + month); |
| } |
| if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) { |
| throw new IllegalArgumentException("Invalid day of week: " + dayOfWeek); |
| } |
| if (time < 0 || time >= 24 * 3600000) { |
| throw new IllegalArgumentException("Invalid time: " + time); |
| } |
| } |
| |
| private void checkDay(int month, int day) { |
| if (day <= 0 || day > GregorianCalendar.DaysInMonth[month]) { |
| throw new IllegalArgumentException("Invalid day of month: " + day); |
| } |
| } |
| |
| private void setEndMode() { |
| if (endDayOfWeek == 0) { |
| endMode = DOM_MODE; |
| } else if (endDayOfWeek < 0) { |
| endDayOfWeek = -endDayOfWeek; |
| if (endDay < 0) { |
| endDay = -endDay; |
| endMode = DOW_LE_DOM_MODE; |
| } else { |
| endMode = DOW_GE_DOM_MODE; |
| } |
| } else { |
| endMode = DOW_IN_MONTH_MODE; |
| } |
| useDaylight = startDay != 0 && endDay != 0; |
| if (endDay != 0) { |
| checkRange(endMonth, endMode == DOM_MODE ? 1 : endDayOfWeek, |
| endTime); |
| if (endMode != DOW_IN_MONTH_MODE) { |
| checkDay(endMonth, endDay); |
| } else { |
| if (endDay < -5 || endDay > 5) { |
| throw new IllegalArgumentException("Day of week in month: " + endDay); |
| } |
| } |
| } |
| if (endMode != DOM_MODE) { |
| endDayOfWeek--; |
| } |
| } |
| |
| /** |
| * Sets the rule which specifies the end of daylight savings time. |
| * |
| * @param month |
| * the {@code Calendar} month in which daylight savings time ends. |
| * @param dayOfMonth |
| * the {@code Calendar} day of the month on which daylight savings time |
| * ends. |
| * @param time |
| * the time of day in milliseconds standard time on which |
| * daylight savings time ends. |
| */ |
| public void setEndRule(int month, int dayOfMonth, int time) { |
| endMonth = month; |
| endDay = dayOfMonth; |
| endDayOfWeek = 0; // Initialize this value for hasSameRules() |
| endTime = time; |
| setEndMode(); |
| // BEGIN android-removed |
| // if (isSimple) { |
| // ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, |
| // dayOfMonth, time); |
| // } |
| // END android-removed |
| } |
| |
| /** |
| * Sets the rule which specifies the end of daylight savings time. |
| * |
| * @param month |
| * the {@code Calendar} month in which daylight savings time ends. |
| * @param day |
| * the occurrence of the day of the week on which daylight |
| * savings time ends. |
| * @param dayOfWeek |
| * the {@code Calendar} day of the week on which daylight savings time |
| * ends. |
| * @param time |
| * the time of day in milliseconds standard time on which |
| * daylight savings time ends. |
| */ |
| public void setEndRule(int month, int day, int dayOfWeek, int time) { |
| endMonth = month; |
| endDay = day; |
| endDayOfWeek = dayOfWeek; |
| endTime = time; |
| setEndMode(); |
| // BEGIN android-removed |
| // if (isSimple) { |
| // ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, |
| // dayOfWeek, time); |
| // } |
| // END android-removed |
| } |
| |
| /** |
| * Sets the rule which specifies the end of daylight savings time. |
| * |
| * @param month |
| * the {@code Calendar} month in which daylight savings time ends. |
| * @param day |
| * the {@code Calendar} day of the month. |
| * @param dayOfWeek |
| * the {@code Calendar} day of the week on which daylight savings time |
| * ends. |
| * @param time |
| * the time of day in milliseconds on which daylight savings time |
| * ends. |
| * @param after |
| * selects the day after or before the day of month. |
| */ |
| public void setEndRule(int month, int day, int dayOfWeek, int time, |
| boolean after) { |
| endMonth = month; |
| endDay = after ? day : -day; |
| endDayOfWeek = -dayOfWeek; |
| endTime = time; |
| setEndMode(); |
| // BEGIN android-removed |
| // if (isSimple) { |
| // ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, |
| // dayOfWeek, time, after); |
| // } |
| // END android-removed |
| } |
| |
| /** |
| * Sets the offset for standard time from GMT for this {@code SimpleTimeZone}. |
| * |
| * @param offset |
| * the offset from GMT of standard time in milliseconds. |
| */ |
| @Override |
| public void setRawOffset(int offset) { |
| rawOffset = offset; |
| // BEGIN android-removed |
| // icuTZ.setRawOffset(offset); |
| // END android-removed |
| } |
| |
| private void setStartMode() { |
| if (startDayOfWeek == 0) { |
| startMode = DOM_MODE; |
| } else if (startDayOfWeek < 0) { |
| startDayOfWeek = -startDayOfWeek; |
| if (startDay < 0) { |
| startDay = -startDay; |
| startMode = DOW_LE_DOM_MODE; |
| } else { |
| startMode = DOW_GE_DOM_MODE; |
| } |
| } else { |
| startMode = DOW_IN_MONTH_MODE; |
| } |
| useDaylight = startDay != 0 && endDay != 0; |
| if (startDay != 0) { |
| checkRange(startMonth, startMode == DOM_MODE ? 1 : startDayOfWeek, |
| startTime); |
| if (startMode != DOW_IN_MONTH_MODE) { |
| checkDay(startMonth, startDay); |
| } else { |
| if (startDay < -5 || startDay > 5) { |
| throw new IllegalArgumentException("Day of week in month: " + startDay); |
| } |
| } |
| } |
| if (startMode != DOM_MODE) { |
| startDayOfWeek--; |
| } |
| } |
| |
| /** |
| * Sets the rule which specifies the start of daylight savings time. |
| * |
| * @param month |
| * the {@code Calendar} month in which daylight savings time starts. |
| * @param dayOfMonth |
| * the {@code Calendar} day of the month on which daylight savings time |
| * starts. |
| * @param time |
| * the time of day in milliseconds on which daylight savings time |
| * starts. |
| */ |
| public void setStartRule(int month, int dayOfMonth, int time) { |
| startMonth = month; |
| startDay = dayOfMonth; |
| startDayOfWeek = 0; // Initialize this value for hasSameRules() |
| startTime = time; |
| setStartMode(); |
| // BEGIN android-removed |
| // if (isSimple) { |
| // ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, |
| // dayOfMonth, time); |
| // } |
| // END android-removed |
| } |
| |
| /** |
| * Sets the rule which specifies the start of daylight savings time. |
| * |
| * @param month |
| * the {@code Calendar} month in which daylight savings time starts. |
| * @param day |
| * the occurrence of the day of the week on which daylight |
| * savings time starts. |
| * @param dayOfWeek |
| * the {@code Calendar} day of the week on which daylight savings time |
| * starts. |
| * @param time |
| * the time of day in milliseconds on which daylight savings time |
| * starts. |
| */ |
| public void setStartRule(int month, int day, int dayOfWeek, int time) { |
| startMonth = month; |
| startDay = day; |
| startDayOfWeek = dayOfWeek; |
| startTime = time; |
| setStartMode(); |
| // BEGIN android-removed |
| // if (isSimple) { |
| // ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, |
| // dayOfWeek, time); |
| // } |
| // END android-removed |
| } |
| |
| /** |
| * Sets the rule which specifies the start of daylight savings time. |
| * |
| * @param month |
| * the {@code Calendar} month in which daylight savings time starts. |
| * @param day |
| * the {@code Calendar} day of the month. |
| * @param dayOfWeek |
| * the {@code Calendar} day of the week on which daylight savings time |
| * starts. |
| * @param time |
| * the time of day in milliseconds on which daylight savings time |
| * starts. |
| * @param after |
| * selects the day after or before the day of month. |
| */ |
| public void setStartRule(int month, int day, int dayOfWeek, int time, |
| boolean after) { |
| startMonth = month; |
| startDay = after ? day : -day; |
| startDayOfWeek = -dayOfWeek; |
| startTime = time; |
| setStartMode(); |
| // BEGIN android-removed |
| // if (isSimple) { |
| // ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, |
| // dayOfWeek, time, after); |
| // } |
| // END android-removed |
| } |
| |
| /** |
| * Sets the starting year for daylight savings time in this {@code SimpleTimeZone}. |
| * Years before this start year will always be in standard time. |
| * |
| * @param year |
| * the starting year. |
| */ |
| public void setStartYear(int year) { |
| startYear = year; |
| useDaylight = true; |
| } |
| |
| /** |
| * Returns the string representation of this {@code SimpleTimeZone}. |
| * |
| * @return the string representation of this {@code SimpleTimeZone}. |
| */ |
| @Override |
| public String toString() { |
| return getClass().getName() |
| + "[id=" |
| + getID() |
| + ",offset=" |
| + rawOffset |
| + ",dstSavings=" |
| + dstSavings |
| + ",useDaylight=" |
| + useDaylight |
| + ",startYear=" |
| + startYear |
| + ",startMode=" |
| + startMode |
| + ",startMonth=" |
| + startMonth |
| + ",startDay=" |
| + startDay |
| + ",startDayOfWeek=" |
| + (useDaylight && (startMode != DOM_MODE) ? startDayOfWeek + 1 |
| : 0) + ",startTime=" + startTime + ",endMode=" |
| + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay |
| + ",endDayOfWeek=" |
| + (useDaylight && (endMode != DOM_MODE) ? endDayOfWeek + 1 : 0) |
| + ",endTime=" + endTime + "]"; |
| } |
| |
| @Override |
| public boolean useDaylightTime() { |
| return useDaylight; |
| } |
| |
| private static final ObjectStreamField[] serialPersistentFields = { |
| new ObjectStreamField("dstSavings", Integer.TYPE), |
| new ObjectStreamField("endDay", Integer.TYPE), |
| new ObjectStreamField("endDayOfWeek", Integer.TYPE), |
| new ObjectStreamField("endMode", Integer.TYPE), |
| new ObjectStreamField("endMonth", Integer.TYPE), |
| new ObjectStreamField("endTime", Integer.TYPE), |
| new ObjectStreamField("monthLength", byte[].class), |
| new ObjectStreamField("rawOffset", Integer.TYPE), |
| new ObjectStreamField("serialVersionOnStream", Integer.TYPE), |
| new ObjectStreamField("startDay", Integer.TYPE), |
| new ObjectStreamField("startDayOfWeek", Integer.TYPE), |
| new ObjectStreamField("startMode", Integer.TYPE), |
| new ObjectStreamField("startMonth", Integer.TYPE), |
| new ObjectStreamField("startTime", Integer.TYPE), |
| new ObjectStreamField("startYear", Integer.TYPE), |
| new ObjectStreamField("useDaylight", Boolean.TYPE), }; |
| |
| private void writeObject(ObjectOutputStream stream) throws IOException { |
| int sEndDay = endDay, sEndDayOfWeek = endDayOfWeek + 1, sStartDay = startDay, sStartDayOfWeek = startDayOfWeek + 1; |
| if (useDaylight |
| && (startMode != DOW_IN_MONTH_MODE || endMode != DOW_IN_MONTH_MODE)) { |
| Calendar cal = new GregorianCalendar(this); |
| if (endMode != DOW_IN_MONTH_MODE) { |
| cal.set(Calendar.MONTH, endMonth); |
| cal.set(Calendar.DATE, endDay); |
| sEndDay = cal.get(Calendar.DAY_OF_WEEK_IN_MONTH); |
| if (endMode == DOM_MODE) { |
| sEndDayOfWeek = cal.getFirstDayOfWeek(); |
| } |
| } |
| if (startMode != DOW_IN_MONTH_MODE) { |
| cal.set(Calendar.MONTH, startMonth); |
| cal.set(Calendar.DATE, startDay); |
| sStartDay = cal.get(Calendar.DAY_OF_WEEK_IN_MONTH); |
| if (startMode == DOM_MODE) { |
| sStartDayOfWeek = cal.getFirstDayOfWeek(); |
| } |
| } |
| } |
| ObjectOutputStream.PutField fields = stream.putFields(); |
| fields.put("dstSavings", dstSavings); |
| fields.put("endDay", sEndDay); |
| fields.put("endDayOfWeek", sEndDayOfWeek); |
| fields.put("endMode", endMode); |
| fields.put("endMonth", endMonth); |
| fields.put("endTime", endTime); |
| fields.put("monthLength", GregorianCalendar.DaysInMonth); |
| fields.put("rawOffset", rawOffset); |
| fields.put("serialVersionOnStream", 1); |
| fields.put("startDay", sStartDay); |
| fields.put("startDayOfWeek", sStartDayOfWeek); |
| fields.put("startMode", startMode); |
| fields.put("startMonth", startMonth); |
| fields.put("startTime", startTime); |
| fields.put("startYear", startYear); |
| fields.put("useDaylight", useDaylight); |
| stream.writeFields(); |
| stream.writeInt(4); |
| byte[] values = new byte[4]; |
| values[0] = (byte) startDay; |
| values[1] = (byte) (startMode == DOM_MODE ? 0 : startDayOfWeek + 1); |
| values[2] = (byte) endDay; |
| values[3] = (byte) (endMode == DOM_MODE ? 0 : endDayOfWeek + 1); |
| stream.write(values); |
| } |
| |
| private void readObject(ObjectInputStream stream) throws IOException, |
| ClassNotFoundException { |
| ObjectInputStream.GetField fields = stream.readFields(); |
| rawOffset = fields.get("rawOffset", 0); |
| useDaylight = fields.get("useDaylight", false); |
| if (useDaylight) { |
| endMonth = fields.get("endMonth", 0); |
| endTime = fields.get("endTime", 0); |
| startMonth = fields.get("startMonth", 0); |
| startTime = fields.get("startTime", 0); |
| startYear = fields.get("startYear", 0); |
| } |
| if (fields.get("serialVersionOnStream", 0) == 0) { |
| if (useDaylight) { |
| startMode = endMode = DOW_IN_MONTH_MODE; |
| endDay = fields.get("endDay", 0); |
| endDayOfWeek = fields.get("endDayOfWeek", 0) - 1; |
| startDay = fields.get("startDay", 0); |
| startDayOfWeek = fields.get("startDayOfWeek", 0) - 1; |
| } |
| } else { |
| dstSavings = fields.get("dstSavings", 0); |
| if (useDaylight) { |
| endMode = fields.get("endMode", 0); |
| startMode = fields.get("startMode", 0); |
| int length = stream.readInt(); |
| byte[] values = new byte[length]; |
| stream.readFully(values); |
| if (length >= 4) { |
| startDay = values[0]; |
| startDayOfWeek = values[1]; |
| if (startMode != DOM_MODE) { |
| startDayOfWeek--; |
| } |
| endDay = values[2]; |
| endDayOfWeek = values[3]; |
| if (endMode != DOM_MODE) { |
| endDayOfWeek--; |
| } |
| } |
| } |
| } |
| } |
| |
| } |