summaryrefslogtreecommitdiffstats
path: root/luni/src/main/java/java/util/SimpleTimeZone.java
diff options
context:
space:
mode:
Diffstat (limited to 'luni/src/main/java/java/util/SimpleTimeZone.java')
-rw-r--r--luni/src/main/java/java/util/SimpleTimeZone.java986
1 files changed, 986 insertions, 0 deletions
diff --git a/luni/src/main/java/java/util/SimpleTimeZone.java b/luni/src/main/java/java/util/SimpleTimeZone.java
new file mode 100644
index 0000000..18d076f
--- /dev/null
+++ b/luni/src/main/java/java/util/SimpleTimeZone.java
@@ -0,0 +1,986 @@
+/*
+ * 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.
+ */
+/**
+*******************************************************************************
+* Copyright (C) 1996-2008, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+
+import org.apache.harmony.luni.util.Msg;
+
+// BEGIN android-note
+// The class javadoc and some of the method descriptions are copied from ICU4J
+// source files. Changes have been made to the copied descriptions.
+// The icu license header was added to this file.
+// END android-note
+/**
+ * {@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
+ * @since Android 1.0
+ */
+public class SimpleTimeZone extends TimeZone {
+
+ private static final long serialVersionUID = -403250971215465050L;
+
+ 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.
+ *
+ * @since Android 1.0
+ */
+ 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.
+ *
+ * @since Android 1.0
+ */
+ 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.
+ *
+ * @since Android 1.0
+ */
+ public static final int WALL_TIME = 0;
+
+ private boolean useDaylight;
+
+ private GregorianCalendar daylightSavings;
+
+ private int dstSavings = 3600000;
+
+ /**
+ * 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}.
+ * @since Android 1.0
+ */
+ public SimpleTimeZone(int offset, String name) {
+ setID(name);
+ rawOffset = offset;
+ }
+
+ /**
+ * 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @exception IllegalArgumentException
+ * the month, day, dayOfWeek, or time parameters are out of
+ * range for the start or end rule.
+ * @since Android 1.0
+ */
+ public SimpleTimeZone(int offset, String name, int startMonth,
+ int startDay, int startDayOfWeek, int startTime, int endMonth,
+ int endDay, int endDayOfWeek, int endTime, int daylightSavings) {
+ this(offset, name);
+ if (daylightSavings <= 0) {
+ throw new IllegalArgumentException(Msg.getString("K00e9", daylightSavings)); //$NON-NLS-1$
+ }
+ dstSavings = daylightSavings;
+
+ setStartRule(startMonth, startDay, startDayOfWeek, startTime);
+ setEndRule(endMonth, endDay, endDayOfWeek, endTime);
+ }
+
+ /**
+ * 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.
+ * @since Android 1.0
+ */
+ 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
+ * @since Android 1.0
+ */
+ @Override
+ public Object clone() {
+ SimpleTimeZone zone = (SimpleTimeZone) super.clone();
+ if (daylightSavings != null) {
+ zone.daylightSavings = (GregorianCalendar) daylightSavings.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
+ * @since Android 1.0
+ */
+ @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(Msg.getString("K00ea", era)); //$NON-NLS-1$
+ }
+ checkRange(month, dayOfWeek, time);
+ if (month != Calendar.FEBRUARY || day != 29 || !isLeapYear(year)) {
+ checkDay(month, day);
+ }
+
+ 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;
+ }
+
+ @Override
+ public int getOffset(long time) {
+ if (!useDaylightTime()) {
+ return rawOffset;
+ }
+ if (daylightSavings == null) {
+ daylightSavings = new GregorianCalendar(this);
+ }
+ return daylightSavings.getOffset(time + rawOffset);
+ }
+
+ @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
+ * @since Android 1.0
+ */
+ @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) {
+ // check for null pointer
+ long millis = time.getTime();
+ if (!useDaylightTime()) {
+ return false;
+ }
+ if (daylightSavings == null) {
+ daylightSavings = new GregorianCalendar(this);
+ }
+ return daylightSavings.getOffset(millis + rawOffset) != rawOffset;
+ }
+
+ private boolean isLeapYear(int year) {
+ if (year > 1582) {
+ return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
+ }
+ return year % 4 == 0;
+ }
+
+ private int mod7(int num1) {
+ int rem = num1 % 7;
+ return (num1 < 0 && rem < 0) ? 7 + rem : rem;
+ }
+
+ /**
+ * Sets the daylight savings offset in milliseconds for this {@code SimpleTimeZone}.
+ *
+ * @param milliseconds
+ * the daylight savings offset in milliseconds.
+ * @since Android 1.0
+ */
+ 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(Msg.getString("K00e5", month)); //$NON-NLS-1$
+ }
+ if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) {
+ throw new IllegalArgumentException(Msg.getString("K00e7", dayOfWeek)); //$NON-NLS-1$
+ }
+ if (time < 0 || time >= 24 * 3600000) {
+ throw new IllegalArgumentException(Msg.getString("K00e8", time)); //$NON-NLS-1$
+ }
+ }
+
+ private void checkDay(int month, int day) {
+ if (day <= 0 || day > GregorianCalendar.DaysInMonth[month]) {
+ throw new IllegalArgumentException(Msg.getString("K00e6", day)); //$NON-NLS-1$
+ }
+ }
+
+ 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(Msg.getString("K00f8", endDay)); //$NON-NLS-1$
+ }
+ }
+ }
+ 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.
+ * @since Android 1.0
+ */
+ public void setEndRule(int month, int dayOfMonth, int time) {
+ endMonth = month;
+ endDay = dayOfMonth;
+ endDayOfWeek = 0; // Initialize this value for hasSameRules()
+ endTime = time;
+ setEndMode();
+ }
+
+ /**
+ * 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.
+ * @since Android 1.0
+ */
+ public void setEndRule(int month, int day, int dayOfWeek, int time) {
+ endMonth = month;
+ endDay = day;
+ endDayOfWeek = dayOfWeek;
+ endTime = time;
+ setEndMode();
+ }
+
+ /**
+ * 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.
+ * @since Android 1.0
+ */
+ public void setEndRule(int month, int day, int dayOfWeek, int time,
+ boolean after) {
+ endMonth = month;
+ endDay = after ? day : -day;
+ endDayOfWeek = -dayOfWeek;
+ endTime = time;
+ setEndMode();
+ }
+
+ /**
+ * Sets the offset for standard time from GMT for this {@code SimpleTimeZone}.
+ *
+ * @param offset
+ * the offset from GMT of standard time in milliseconds.
+ * @since Android 1.0
+ */
+ @Override
+ public void setRawOffset(int offset) {
+ rawOffset = offset;
+ }
+
+ 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(Msg.getString("K00f8", startDay)); //$NON-NLS-1$
+ }
+ }
+ }
+ 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.
+ * @since Android 1.0
+ */
+ public void setStartRule(int month, int dayOfMonth, int time) {
+ startMonth = month;
+ startDay = dayOfMonth;
+ startDayOfWeek = 0; // Initialize this value for hasSameRules()
+ startTime = time;
+ setStartMode();
+ }
+
+ /**
+ * 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.
+ * @since Android 1.0
+ */
+ public void setStartRule(int month, int day, int dayOfWeek, int time) {
+ startMonth = month;
+ startDay = day;
+ startDayOfWeek = dayOfWeek;
+ startTime = time;
+ setStartMode();
+ }
+
+ /**
+ * 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.
+ * @since Android 1.0
+ */
+ public void setStartRule(int month, int day, int dayOfWeek, int time,
+ boolean after) {
+ startMonth = month;
+ startDay = after ? day : -day;
+ startDayOfWeek = -dayOfWeek;
+ startTime = time;
+ setStartMode();
+ }
+
+ /**
+ * 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.
+ * @since Android 1.0
+ */
+ 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}.
+ * @since Android 1.0
+ */
+ @Override
+ public String toString() {
+ return getClass().getName()
+ + "[id=" //$NON-NLS-1$
+ + getID()
+ + ",offset=" //$NON-NLS-1$
+ + rawOffset
+ + ",dstSavings=" //$NON-NLS-1$
+ + dstSavings
+ + ",useDaylight=" //$NON-NLS-1$
+ + useDaylight
+ + ",startYear=" //$NON-NLS-1$
+ + startYear
+ + ",startMode=" //$NON-NLS-1$
+ + startMode
+ + ",startMonth=" //$NON-NLS-1$
+ + startMonth
+ + ",startDay=" //$NON-NLS-1$
+ + startDay
+ + ",startDayOfWeek=" //$NON-NLS-1$
+ + (useDaylight && (startMode != DOM_MODE) ? startDayOfWeek + 1
+ : 0) + ",startTime=" + startTime + ",endMode=" //$NON-NLS-1$ //$NON-NLS-2$
+ + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay //$NON-NLS-1$ //$NON-NLS-2$
+ + ",endDayOfWeek=" //$NON-NLS-1$
+ + (useDaylight && (endMode != DOM_MODE) ? endDayOfWeek + 1 : 0)
+ + ",endTime=" + endTime + "]"; //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ @Override
+ public boolean useDaylightTime() {
+ return useDaylight;
+ }
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("dstSavings", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("endDay", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("endDayOfWeek", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("endMode", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("endMonth", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("endTime", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("monthLength", byte[].class), //$NON-NLS-1$
+ new ObjectStreamField("rawOffset", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("serialVersionOnStream", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("startDay", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("startDayOfWeek", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("startMode", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("startMonth", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("startTime", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("startYear", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("useDaylight", Boolean.TYPE), }; //$NON-NLS-1$
+
+ 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); //$NON-NLS-1$
+ fields.put("endDay", sEndDay); //$NON-NLS-1$
+ fields.put("endDayOfWeek", sEndDayOfWeek); //$NON-NLS-1$
+ fields.put("endMode", endMode); //$NON-NLS-1$
+ fields.put("endMonth", endMonth); //$NON-NLS-1$
+ fields.put("endTime", endTime); //$NON-NLS-1$
+ fields.put("monthLength", GregorianCalendar.DaysInMonth); //$NON-NLS-1$
+ fields.put("rawOffset", rawOffset); //$NON-NLS-1$
+ fields.put("serialVersionOnStream", 1); //$NON-NLS-1$
+ fields.put("startDay", sStartDay); //$NON-NLS-1$
+ fields.put("startDayOfWeek", sStartDayOfWeek); //$NON-NLS-1$
+ fields.put("startMode", startMode); //$NON-NLS-1$
+ fields.put("startMonth", startMonth); //$NON-NLS-1$
+ fields.put("startTime", startTime); //$NON-NLS-1$
+ fields.put("startYear", startYear); //$NON-NLS-1$
+ fields.put("useDaylight", useDaylight); //$NON-NLS-1$
+ 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); //$NON-NLS-1$
+ useDaylight = fields.get("useDaylight", false); //$NON-NLS-1$
+ if (useDaylight) {
+ endMonth = fields.get("endMonth", 0); //$NON-NLS-1$
+ endTime = fields.get("endTime", 0); //$NON-NLS-1$
+ startMonth = fields.get("startMonth", 0); //$NON-NLS-1$
+ startTime = fields.get("startTime", 0); //$NON-NLS-1$
+ startYear = fields.get("startYear", 0); //$NON-NLS-1$
+ }
+ if (fields.get("serialVersionOnStream", 0) == 0) { //$NON-NLS-1$
+ if (useDaylight) {
+ startMode = endMode = DOW_IN_MONTH_MODE;
+ endDay = fields.get("endDay", 0); //$NON-NLS-1$
+ endDayOfWeek = fields.get("endDayOfWeek", 0) - 1; //$NON-NLS-1$
+ startDay = fields.get("startDay", 0); //$NON-NLS-1$
+ startDayOfWeek = fields.get("startDayOfWeek", 0) - 1; //$NON-NLS-1$
+ }
+ } else {
+ dstSavings = fields.get("dstSavings", 0); //$NON-NLS-1$
+ if (useDaylight) {
+ endMode = fields.get("endMode", 0); //$NON-NLS-1$
+ startMode = fields.get("startMode", 0); //$NON-NLS-1$
+ 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--;
+ }
+ }
+ }
+ }
+ }
+
+}