You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1450 lines
60 KiB
1450 lines
60 KiB
// © 2016 and later: Unicode, Inc. and others. |
|
// License & terms of use: http://www.unicode.org/copyright.html#License |
|
/* |
|
* Copyright (C) 1996-2016, International Business Machines |
|
* Corporation and others. All Rights Reserved. |
|
*/ |
|
|
|
package com.fr.third.ibm.icu.util; |
|
|
|
import java.io.IOException; |
|
import java.util.Date; |
|
|
|
import com.fr.third.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 Deborah 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. Typically one hour (+3600000). The amount could be negative, |
|
* but not 0. |
|
* @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. Typically one hour (3600000). The amount could be negative, |
|
* but not 0. |
|
* @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. |
|
*/ |
|
@Override |
|
@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 |
|
*/ |
|
@Override |
|
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 |
|
*/ |
|
@Override |
|
public boolean isFrozen() { |
|
return isFrozen; |
|
} |
|
|
|
/** |
|
* {@inheritDoc} |
|
* @stable ICU 49 |
|
*/ |
|
@Override |
|
public TimeZone freeze() { |
|
isFrozen = true; |
|
return this; |
|
} |
|
|
|
/** |
|
* {@inheritDoc} |
|
* @stable ICU 49 |
|
*/ |
|
@Override |
|
public TimeZone cloneAsThawed() { |
|
SimpleTimeZone tz = (SimpleTimeZone)super.cloneAsThawed(); |
|
tz.isFrozen = false; |
|
return tz; |
|
} |
|
}
|
|
|