]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/util/SimpleTimeZone.java
go
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / util / SimpleTimeZone.java
1  /*\r
2 *   Copyright (C) 1996-2009, International Business Machines\r
3 *   Corporation and others.  All Rights Reserved.\r
4 */\r
5 \r
6 package com.ibm.icu.util;\r
7 \r
8 import java.io.IOException;\r
9 import java.util.Date;\r
10 \r
11 import com.ibm.icu.impl.Grego;\r
12 \r
13 /**\r
14  * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>\r
15  * that represents a time zone for use with a Gregorian calendar. This\r
16  * class does not handle historical changes.\r
17  *\r
18  * <P>\r
19  * Use a negative value for <code>dayOfWeekInMonth</code> to indicate that\r
20  * <code>SimpleTimeZone</code> should count from the end of the month backwards.\r
21  * For example, if Daylight Savings Time starts or ends at the last Sunday in a month,\r
22  * use <code>dayOfWeekInMonth = -1</code> along with <code>dayOfWeek = Calendar.SUNDAY</code>\r
23  * to specify the rule.\r
24  *\r
25  * @see      Calendar\r
26  * @see      GregorianCalendar\r
27  * @see      TimeZone\r
28  * @author   David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu\r
29  * @stable ICU 2.0\r
30  */\r
31 public class SimpleTimeZone extends BasicTimeZone {\r
32     private static final long serialVersionUID = -7034676239311322769L;\r
33 \r
34     /**\r
35      * Constant for a mode of start or end time specified as local wall time.\r
36      * @stable ICU 3.8\r
37      */\r
38     public static final int WALL_TIME = 0;\r
39 \r
40     /**\r
41      * Constant for a mode of start or end time specified as local standard time.\r
42      * @stable ICU 3.8\r
43      */\r
44     public static final int STANDARD_TIME = 1;\r
45 \r
46     /**\r
47      * Constant for a mode of start or end time specified as UTC.\r
48      * @stable ICU 3.8\r
49      */\r
50     public static final int UTC_TIME = 2;\r
51 \r
52     /**\r
53      * Constructs a SimpleTimeZone with the given base time zone offset from GMT\r
54      * and time zone ID. Timezone IDs can be obtained from\r
55      * TimeZone.getAvailableIDs. Normally you should use TimeZone.getDefault to\r
56      * construct a TimeZone.\r
57      *\r
58      * @param rawOffset  The given base time zone offset to GMT.\r
59      * @param ID         The time zone ID which is obtained from\r
60      *                   TimeZone.getAvailableIDs.\r
61      * @stable ICU 2.0\r
62      */\r
63     public SimpleTimeZone(int rawOffset, String ID) {\r
64         construct(rawOffset, 0, 0, 0,\r
65                 0, WALL_TIME,\r
66                 0, 0, 0,\r
67                 0, WALL_TIME,\r
68                 Grego.MILLIS_PER_HOUR);\r
69         super.setID(ID);\r
70     }\r
71 \r
72     /**\r
73      * Construct a SimpleTimeZone with the given base time zone offset from\r
74      * GMT, time zone ID, time to start and end the daylight time. Timezone IDs\r
75      * can be obtained from TimeZone.getAvailableIDs. Normally you should use\r
76      * TimeZone.getDefault to create a TimeZone. For a time zone that does not\r
77      * use daylight saving time, do not use this constructor; instead you should\r
78      * use SimpleTimeZone(rawOffset, ID).\r
79      *\r
80      * By default, this constructor specifies day-of-week-in-month rules. That\r
81      * is, if the startDay is 1, and the startDayOfWeek is SUNDAY, then this\r
82      * indicates the first Sunday in the startMonth. A startDay of -1 likewise\r
83      * indicates the last Sunday. However, by using negative or zero values for\r
84      * certain parameters, other types of rules can be specified.\r
85      *\r
86      * Day of month. To specify an exact day of the month, such as March 1, set\r
87      * startDayOfWeek to zero.\r
88      *\r
89      * Day of week after day of month. To specify the first day of the week\r
90      * occurring on or after an exact day of the month, make the day of the week\r
91      * negative. For example, if startDay is 5 and startDayOfWeek is -MONDAY,\r
92      * this indicates the first Monday on or after the 5th day of the\r
93      * startMonth.\r
94      *\r
95      * Day of week before day of month. To specify the last day of the week\r
96      * occurring on or before an exact day of the month, make the day of the\r
97      * week and the day of the month negative. For example, if startDay is -21\r
98      * and startDayOfWeek is -WEDNESDAY, this indicates the last Wednesday on or\r
99      * before the 21st of the startMonth.\r
100      *\r
101      * The above examples refer to the startMonth, startDay, and startDayOfWeek;\r
102      * the same applies for the endMonth, endDay, and endDayOfWeek.\r
103      *\r
104      * @param rawOffset       The given base time zone offset to GMT.\r
105      * @param ID              The time zone ID which is obtained from\r
106      *                        TimeZone.getAvailableIDs.\r
107      * @param startMonth      The daylight savings starting month. Month is\r
108      *                        0-based. eg, 0 for January.\r
109      * @param startDay        The daylight savings starting\r
110      *                        day-of-week-in-month. Please see the member\r
111      *                        description for an example.\r
112      * @param startDayOfWeek  The daylight savings starting day-of-week. Please\r
113      *                        see the member description for an example.\r
114      * @param startTime       The daylight savings starting time in local wall\r
115      *                        time, which is standard time in this case. Please see the\r
116      *                        member description for an example.\r
117      * @param endMonth        The daylight savings ending month. Month is\r
118      *                        0-based. eg, 0 for January.\r
119      * @param endDay          The daylight savings ending day-of-week-in-month.\r
120      *                        Please see the member description for an example.\r
121      * @param endDayOfWeek    The daylight savings ending day-of-week. Please\r
122      *                        see the member description for an example.\r
123      * @param endTime         The daylight savings ending time in local wall time,\r
124      *                        which is daylight time in this case. Please see the\r
125      *                        member description for an example.\r
126      * @exception IllegalArgumentException the month, day, dayOfWeek, or time\r
127      * parameters are out of range for the start or end rule\r
128      * @stable ICU 2.0\r
129      */\r
130     public SimpleTimeZone(int rawOffset, String ID,\r
131                           int startMonth, int startDay, int startDayOfWeek, int startTime,\r
132                           int endMonth, int endDay, int endDayOfWeek, int endTime) {\r
133         construct(rawOffset,\r
134                 startMonth, startDay, startDayOfWeek,\r
135                 startTime, WALL_TIME,\r
136                 endMonth, endDay, endDayOfWeek,\r
137                 endTime, WALL_TIME,\r
138                 Grego.MILLIS_PER_HOUR);\r
139         super.setID(ID);\r
140     }\r
141 \r
142     /**\r
143      * Construct a SimpleTimeZone with the given base time zone offset from\r
144      * GMT, time zone ID, time and its mode to start and end the daylight time.\r
145      * The mode specifies either {@link #WALL_TIME} or {@link #STANDARD_TIME}\r
146      * or {@link #UTC_TIME}.\r
147      * \r
148      * @param rawOffset       The given base time zone offset to GMT.\r
149      * @param ID              The time zone ID which is obtained from\r
150      *                        TimeZone.getAvailableIDs.\r
151      * @param startMonth      The daylight savings starting month. Month is\r
152      *                        0-based. eg, 0 for January.\r
153      * @param startDay        The daylight savings starting\r
154      *                        day-of-week-in-month. Please see the member\r
155      *                        description for an example.\r
156      * @param startDayOfWeek  The daylight savings starting day-of-week. Please\r
157      *                        see the member description for an example.\r
158      * @param startTime       The daylight savings starting time in local wall\r
159      *                        time, which is standard time in this case. Please see the\r
160      *                        member description for an example.\r
161      * @param startTimeMode   The mode of the start time specified by startTime.\r
162      * @param endMonth        The daylight savings ending month. Month is\r
163      *                        0-based. eg, 0 for January.\r
164      * @param endDay          The daylight savings ending day-of-week-in-month.\r
165      *                        Please see the member description for an example.\r
166      * @param endDayOfWeek    The daylight savings ending day-of-week. Please\r
167      *                        see the member description for an example.\r
168      * @param endTime         The daylight savings ending time in local wall time,\r
169      *                        which is daylight time in this case. Please see the\r
170      *                        member description for an example.\r
171      * @param endTimeMode     The mode of the end time specified by endTime.\r
172      * @param dstSavings      The amount of time in ms saved during DST.\r
173      * @exception IllegalArgumentException the month, day, dayOfWeek, or time\r
174      * parameters are out of range for the start or end rule\r
175      * @stable ICU 3.8\r
176      */\r
177     public SimpleTimeZone(int rawOffset,  String ID,\r
178                           int startMonth, int startDay,\r
179                           int startDayOfWeek, int startTime,\r
180                           int startTimeMode,\r
181                           int endMonth, int endDay,\r
182                           int endDayOfWeek, int endTime,\r
183                           int endTimeMode,int dstSavings){\r
184         construct(rawOffset,\r
185                   startMonth, startDay, startDayOfWeek,\r
186                   startTime, startTimeMode,\r
187                   endMonth, endDay, endDayOfWeek,\r
188                   endTime, endTimeMode,\r
189                   dstSavings);\r
190         super.setID(ID);\r
191     }\r
192 \r
193     /**\r
194      * Constructor.  This constructor is identical to the 10-argument\r
195      * constructor, but also takes a dstSavings parameter.\r
196      * @param rawOffset       The given base time zone offset to GMT.\r
197      * @param ID              The time zone ID which is obtained from\r
198      *                        TimeZone.getAvailableIDs.\r
199      * @param startMonth      The daylight savings starting month. Month is\r
200      *                        0-based. eg, 0 for January.\r
201      * @param startDay        The daylight savings starting\r
202      *                        day-of-week-in-month. Please see the member\r
203      *                        description for an example.\r
204      * @param startDayOfWeek  The daylight savings starting day-of-week. Please\r
205      *                        see the member description for an example.\r
206      * @param startTime       The daylight savings starting time in local wall\r
207      *                        time, which is standard time in this case. Please see the\r
208      *                        member description for an example.\r
209      * @param endMonth        The daylight savings ending month. Month is\r
210      *                        0-based. eg, 0 for January.\r
211      * @param endDay          The daylight savings ending day-of-week-in-month.\r
212      *                        Please see the member description for an example.\r
213      * @param endDayOfWeek    The daylight savings ending day-of-week. Please\r
214      *                        see the member description for an example.\r
215      * @param endTime         The daylight savings ending time in local wall time,\r
216      *                        which is daylight time in this case. Please see the\r
217      *                        member description for an example.\r
218      * @param dstSavings      The amount of time in ms saved during DST.\r
219      * @exception IllegalArgumentException the month, day, dayOfWeek, or time\r
220      * parameters are out of range for the start or end rule\r
221      * @stable ICU 2.0\r
222      */\r
223     public SimpleTimeZone(int rawOffset, String ID,\r
224                           int startMonth, int startDay, int startDayOfWeek, int startTime,\r
225                           int endMonth, int endDay, int endDayOfWeek, int endTime,\r
226                           int dstSavings) {\r
227         construct(rawOffset,\r
228                 startMonth, startDay, startDayOfWeek,\r
229                 startTime, WALL_TIME,\r
230                 endMonth, endDay, endDayOfWeek,\r
231                 endTime, WALL_TIME,\r
232                 dstSavings); \r
233         super.setID(ID);\r
234     }\r
235     \r
236 \r
237     /**\r
238      * {@inheritDoc}\r
239      * \r
240      * @stable ICU 3.8\r
241      */\r
242     public void setID(String ID) {\r
243         super.setID(ID);\r
244 \r
245         transitionRulesInitialized = false;\r
246     }\r
247 \r
248     /**\r
249      * Overrides TimeZone\r
250      * Sets the base time zone offset to GMT.\r
251      * This is the offset to add "to" UTC to get local time.\r
252      * @param offsetMillis the raw offset of the time zone\r
253      * @stable ICU 2.0\r
254      */\r
255     public void setRawOffset(int offsetMillis) {\r
256         raw = offsetMillis;\r
257 \r
258         transitionRulesInitialized = false;\r
259     }\r
260   \r
261     /**\r
262      * Overrides TimeZone\r
263      * Gets the GMT offset for this time zone.\r
264      * @return the raw offset\r
265      * @stable ICU 2.0\r
266      */\r
267     public int getRawOffset() {\r
268         return raw;\r
269     }\r
270 \r
271     /**\r
272      * Sets the daylight savings starting year.\r
273      *\r
274      * @param year  The daylight savings starting year.\r
275      * @stable ICU 2.0\r
276      */\r
277     public void setStartYear(int year) {\r
278         //unwrapSTZ().setStartYear(year);\r
279 \r
280         getSTZInfo().sy = year;\r
281         this.startYear = year;\r
282 \r
283         transitionRulesInitialized = false;\r
284     }\r
285 \r
286     /**\r
287      * Sets the daylight savings starting rule. For example, Daylight Savings\r
288      * Time starts at the second Sunday in March, at 2 AM in standard time.\r
289      * Therefore, you can set the start rule by calling:\r
290      * setStartRule(Calendar.MARCH, 2, Calendar.SUNDAY, 2*60*60*1000);\r
291      *\r
292      * @param month             The daylight savings starting month. Month is\r
293      *                          0-based. eg, 0 for January.\r
294      * @param dayOfWeekInMonth  The daylight savings starting\r
295      *                          day-of-week-in-month. Please see the member\r
296      *                          description for an example.\r
297      * @param dayOfWeek         The daylight savings starting day-of-week.\r
298      *                          Please see the member description for an\r
299      *                          example.\r
300      * @param time              The daylight savings starting time in local wall\r
301      *                          time, which is standard time in this case. Please see\r
302      *                          the member description for an example.\r
303      * @exception IllegalArgumentException the month, dayOfWeekInMonth,\r
304      * dayOfWeek, or time parameters are out of range\r
305      * @stable ICU 2.0\r
306      */\r
307     public void setStartRule(int month, int dayOfWeekInMonth, int dayOfWeek,\r
308                              int time) {\r
309         getSTZInfo().setStart(month, dayOfWeekInMonth, dayOfWeek, time, -1, false);\r
310         setStartRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME);\r
311     }\r
312     /**\r
313      * Sets the daylight savings starting rule. For example, in the U.S., Daylight Savings\r
314      * Time starts at the second Sunday in March, at 2 AM in standard time.\r
315      * Therefore, you can set the start rule by calling:\r
316      * setStartRule(Calendar.MARCH, 2, Calendar.SUNDAY, 2*60*60*1000);\r
317      * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calculate\r
318      * the exact starting date.  Their exact meaning depend on their respective signs,\r
319      * allowing various types of rules to be constructed, as follows:<ul>\r
320      *   <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the\r
321      *       day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday\r
322      *       of the month).\r
323      *   <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify\r
324      *       the day of week in the month counting backward from the end of the month.\r
325      *       (e.g., (-1, MONDAY) is the last Monday in the month)\r
326      *   <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth\r
327      *       specifies the day of the month, regardless of what day of the week it is.\r
328      *       (e.g., (10, 0) is the tenth day of the month)\r
329      *   <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth\r
330      *       specifies the day of the month counting backward from the end of the\r
331      *       month, regardless of what day of the week it is (e.g., (-2, 0) is the\r
332      *       next-to-last day of the month).\r
333      *   <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the\r
334      *       first specified day of the week on or after the specfied day of the month.\r
335      *       (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month\r
336      *       [or the 15th itself if the 15th is a Sunday].)\r
337      *   <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the\r
338      *       last specified day of the week on or before the specified day of the month.\r
339      *       (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month\r
340      *       [or the 20th itself if the 20th is a Tuesday].)</ul>\r
341      * @param month the daylight savings starting month. Month is 0-based.\r
342      * eg, 0 for January.\r
343      * @param dayOfWeekInMonth the daylight savings starting\r
344      * day-of-week-in-month. Please see the member description for an example.\r
345      * @param dayOfWeek the daylight savings starting day-of-week. Please see\r
346      * the member description for an example.\r
347      * @param time the daylight savings starting time. Please see the member\r
348      * description for an example.\r
349      */\r
350      \r
351     private void setStartRule(int month, int dayOfWeekInMonth, int dayOfWeek, int time, int mode)\r
352     {\r
353         startMonth     =  month;\r
354         startDay       = dayOfWeekInMonth;\r
355         startDayOfWeek = dayOfWeek;\r
356         startTime      = time;\r
357         startTimeMode  = mode;\r
358         decodeStartRule();\r
359 \r
360         transitionRulesInitialized = false;\r
361     }\r
362     /**\r
363      * Sets the DST start rule to a fixed date within a month.\r
364      *\r
365      * @param month         The month in which this rule occurs (0-based).\r
366      * @param dayOfMonth    The date in that month (1-based).\r
367      * @param time          The time of that day (number of millis after midnight)\r
368      *                      when DST takes effect in local wall time, which is\r
369      *                      standard time in this case.\r
370      * @exception IllegalArgumentException the month,\r
371      * dayOfMonth, or time parameters are out of range\r
372      * @stable ICU 2.0\r
373      */\r
374     public void setStartRule(int month, int dayOfMonth, int time) {\r
375        // unwrapSTZ().setStartRule(month, dayOfMonth, time);\r
376 \r
377         getSTZInfo().setStart(month, -1, -1, time, dayOfMonth, false);\r
378         setStartRule(month, dayOfMonth, 0, time, WALL_TIME);\r
379     }\r
380 \r
381     /**\r
382      * Sets the DST start rule to a weekday before or after a give date within\r
383      * a month, e.g., the first Monday on or after the 8th.\r
384      *\r
385      * @param month         The month in which this rule occurs (0-based).\r
386      * @param dayOfMonth    A date within that month (1-based).\r
387      * @param dayOfWeek     The day of the week on which this rule occurs.\r
388      * @param time          The time of that day (number of millis after midnight)\r
389      *                      when DST takes effect in local wall time, which is\r
390      *                      standard time in this case.\r
391      * @param after         If true, this rule selects the first dayOfWeek on\r
392      *                      or after dayOfMonth.  If false, this rule selects\r
393      *                      the last dayOfWeek on or before dayOfMonth.\r
394      * @exception IllegalArgumentException the month, dayOfMonth,\r
395      * dayOfWeek, or time parameters are out of range\r
396      * @stable ICU 2.0\r
397      */\r
398     public void setStartRule(int month, int dayOfMonth, int dayOfWeek, int time, boolean after) {\r
399         getSTZInfo().setStart(month, -1, dayOfWeek, time, dayOfMonth, after);\r
400         setStartRule(month, after ? dayOfMonth : -dayOfMonth,\r
401                 -dayOfWeek, time, WALL_TIME);\r
402     }\r
403 \r
404     /**\r
405      * Sets the daylight savings ending rule. For example, if Daylight Savings Time\r
406      * ends at the last (-1) Sunday in October, at 2 AM in standard time,\r
407      * you can set the end rule by calling:\r
408      * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>\r
409      *\r
410      * @param month             The daylight savings ending month. Month is\r
411      *                          0-based. eg, 0 for January.\r
412      * @param dayOfWeekInMonth  The daylight savings ending\r
413      *                          day-of-week-in-month. Please see the member\r
414      *                          description for an example.\r
415      * @param dayOfWeek         The daylight savings ending day-of-week. Please\r
416      *                          see the member description for an example.\r
417      * @param time              The daylight savings ending time in local wall time,\r
418      *                          which is daylight time in this case. Please see the\r
419      *                          member description for an example.\r
420      * @exception IllegalArgumentException the month, dayOfWeekInMonth,\r
421      * dayOfWeek, or time parameters are out of range\r
422      * @stable ICU 2.0\r
423      */\r
424     public void setEndRule(int month, int dayOfWeekInMonth, int dayOfWeek, int time) {\r
425         getSTZInfo().setEnd(month, dayOfWeekInMonth, dayOfWeek, time, -1, false);\r
426         setEndRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME);        \r
427     }\r
428 \r
429     /**\r
430      * Sets the DST end rule to a fixed date within a month.\r
431      *\r
432      * @param month         The month in which this rule occurs (0-based).\r
433      * @param dayOfMonth    The date in that month (1-based).\r
434      * @param time          The time of that day (number of millis after midnight)\r
435      *                      when DST ends in local wall time, which is daylight\r
436      *                      time in this case.\r
437      * @exception IllegalArgumentException the month,\r
438      * dayOfMonth, or time parameters are out of range\r
439      * @stable ICU 2.0\r
440      */\r
441     public void setEndRule(int month, int dayOfMonth, int time) {\r
442         getSTZInfo().setEnd(month, -1, -1, time, dayOfMonth, false);\r
443         setEndRule(month, dayOfMonth, WALL_TIME, time);\r
444     }\r
445 \r
446     /**\r
447      * Sets the DST end rule to a weekday before or after a give date within\r
448      * a month, e.g., the first Monday on or after the 8th.\r
449      *\r
450      * @param month         The month in which this rule occurs (0-based).\r
451      * @param dayOfMonth    A date within that month (1-based).\r
452      * @param dayOfWeek     The day of the week on which this rule occurs.\r
453      * @param time          The time of that day (number of millis after midnight)\r
454      *                      when DST ends in local wall time, which is daylight\r
455      *                      time in this case.\r
456      * @param after         If true, this rule selects the first dayOfWeek on\r
457      *                      or after dayOfMonth.  If false, this rule selects\r
458      *                      the last dayOfWeek on or before dayOfMonth.\r
459      * @exception IllegalArgumentException the month, dayOfMonth,\r
460      * dayOfWeek, or time parameters are out of range\r
461      * @stable ICU 2.0\r
462      */\r
463     public void setEndRule(int month, int dayOfMonth, int dayOfWeek, int time, boolean after) {\r
464         getSTZInfo().setEnd(month, -1, dayOfWeek, time, dayOfMonth, after);\r
465         setEndRule(month, dayOfMonth, dayOfWeek, time, WALL_TIME, after);\r
466     }\r
467     private void setEndRule(int month, int dayOfMonth, int dayOfWeek, \r
468                                                 int time, int mode, boolean after){\r
469         setEndRule(month, after ? dayOfMonth : -dayOfMonth, -dayOfWeek, time, mode);\r
470     }\r
471     /**\r
472      * Sets the daylight savings ending rule. For example, in the U.S., Daylight\r
473      * Savings Time ends at the first Sunday in November, at 2 AM in standard time.\r
474      * Therefore, you can set the end rule by calling:\r
475      * setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2*60*60*1000);\r
476      * Various other types of rules can be specified by manipulating the dayOfWeek\r
477      * and dayOfWeekInMonth parameters.  For complete details, see the documentation\r
478      * for setStartRule().\r
479      * @param month the daylight savings ending month. Month is 0-based.\r
480      * eg, 0 for January.\r
481      * @param dayOfWeekInMonth the daylight savings ending\r
482      * day-of-week-in-month. See setStartRule() for a complete explanation.\r
483      * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule()\r
484      * for a complete explanation.\r
485      * @param time the daylight savings ending time. Please see the member\r
486      * description for an example.\r
487      */\r
488     private void setEndRule(int month, int dayOfWeekInMonth, int dayOfWeek, int time, int mode){\r
489         endMonth     = month;\r
490         endDay       = dayOfWeekInMonth;\r
491         endDayOfWeek = dayOfWeek;\r
492         endTime      = time;\r
493         endTimeMode  = mode;\r
494         decodeEndRule();\r
495 \r
496         transitionRulesInitialized = false;\r
497     }\r
498     /**\r
499      * Sets the amount of time in ms that the clock is advanced during DST.\r
500      * @param millisSavedDuringDST the number of milliseconds the time is\r
501      * advanced with respect to standard time when the daylight savings rules\r
502      * are in effect. A positive number, typically one hour (3600000).\r
503      * @stable ICU 2.0\r
504      */\r
505     public void setDSTSavings(int millisSavedDuringDST) {\r
506         if (millisSavedDuringDST <= 0) {\r
507             throw new IllegalArgumentException();\r
508         }\r
509         dst = millisSavedDuringDST;\r
510 \r
511         transitionRulesInitialized = false;\r
512     }\r
513 \r
514     /**\r
515      * Returns the amount of time in ms that the clock is advanced during DST.\r
516      * @return the number of milliseconds the time is\r
517      * advanced with respect to standard time when the daylight savings rules\r
518      * are in effect. A positive number, typically one hour (3600000).\r
519      * @stable ICU 2.0\r
520      */\r
521     public int getDSTSavings() {\r
522         return dst;\r
523     }\r
524 \r
525     /**\r
526      * Returns the java.util.SimpleTimeZone that this class wraps.\r
527      *\r
528     java.util.SimpleTimeZone unwrapSTZ() {\r
529         return (java.util.SimpleTimeZone) unwrap();\r
530     }\r
531     */\r
532     // on JDK 1.4 and later, can't deserialize a SimpleTimeZone as a SimpleTimeZone...\r
533     private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {\r
534         in.defaultReadObject();\r
535         /*\r
536         String id = getID();\r
537         if (id!=null && !(zone instanceof java.util.SimpleTimeZone && zone.getID().equals(id))) {\r
538             // System.out.println("*** readjust " + zone.getClass().getName() + " " + zone.getID() + " ***");\r
539             java.util.SimpleTimeZone stz = \r
540                 new java.util.SimpleTimeZone(raw, id);\r
541             if (dst != 0) {\r
542                 stz.setDSTSavings(dst);\r
543                 // if it is 0, then there shouldn't be start/end rules and the default\r
544                 // behavior should be no dst\r
545             }\r
546 \r
547             if (xinfo != null) {\r
548                 xinfo.applyTo(stz);\r
549             }\r
550             zoneJDK = stz;\r
551         }\r
552         */\r
553         /* set all instance variables in this object\r
554          * to the values in zone \r
555          */            \r
556          if (xinfo != null) {\r
557              xinfo.applyTo(this);\r
558          }\r
559         \r
560     }\r
561     /**\r
562      * Returns a string representation of this object.\r
563      * @return  a string representation of this object\r
564      * @stable ICU 3.6\r
565      */\r
566     public String toString() {\r
567         return "SimpleTimeZone: " + getID();\r
568     }\r
569 \r
570     private STZInfo getSTZInfo() {\r
571         if (xinfo == null) {\r
572             xinfo = new STZInfo();\r
573         }\r
574         return xinfo;\r
575     }\r
576 \r
577     //  Use only for decodeStartRule() and decodeEndRule() where the year is not\r
578     //  available. Set February to 29 days to accomodate rules with that date\r
579     //  and day-of-week-on-or-before-that-date mode (DOW_LE_DOM_MODE).\r
580     //  The compareToRule() method adjusts to February 28 in non-leap years.\r
581     //\r
582     //  For actual getOffset() calculations, use TimeZone::monthLength() and\r
583     //  TimeZone::previousMonthLength() which take leap years into account.\r
584     //  We handle leap years assuming always\r
585     //  Gregorian, since we know they didn't have daylight time when\r
586     //  Gregorian calendar started.\r
587     private final static byte staticMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};\r
588 \r
589     /**\r
590      * {@inheritDoc}\r
591      * @stable ICU 2.0\r
592      */\r
593     public int getOffset(int era, int year, int month, int day,\r
594                          int dayOfWeek, int millis) \r
595     {\r
596         // Check the month before calling Grego.monthLength(). This\r
597         // duplicates the test that occurs in the 7-argument getOffset(),\r
598         // however, this is unavoidable. We don't mind because this method, in\r
599         // fact, should not be called; internal code should always call the\r
600         // 7-argument getOffset(), and outside code should use Calendar.get(int\r
601         // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of\r
602         // this method because it's public API. - liu 8/10/98\r
603         if(month < Calendar.JANUARY || month > Calendar.DECEMBER) {\r
604             throw new IllegalArgumentException();\r
605         }\r
606 \r
607         return getOffset(era, year, month, day, dayOfWeek, millis, Grego.monthLength(year, month));\r
608     }\r
609 \r
610     /**\r
611      * @internal\r
612      * @deprecated This API is ICU internal only.\r
613      */\r
614     public int getOffset(int era, int year, int month, int day,\r
615                               int dayOfWeek, int millis, \r
616                               int monthLength)  {\r
617         // Check the month before calling Grego.monthLength(). This\r
618         // duplicates a test that occurs in the 9-argument getOffset(),\r
619         // however, this is unavoidable. We don't mind because this method, in\r
620         // fact, should not be called; internal code should always call the\r
621         // 9-argument getOffset(), and outside code should use Calendar.get(int\r
622         // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of\r
623         // this method because it's public API. - liu 8/10/98\r
624         if(month < Calendar.JANUARY || month > Calendar.DECEMBER) {\r
625             throw new IllegalArgumentException();\r
626         }\r
627         \r
628         return getOffset(era, year, month, day, dayOfWeek, millis,\r
629                          Grego.monthLength(year, month), Grego.previousMonthLength(year, month));\r
630     }\r
631 \r
632     int getOffset(int era, int year, int month, int day,\r
633                   int dayOfWeek, int millis, \r
634                   int monthLength, int prevMonthLength ){\r
635 \r
636         if (true) {\r
637             /* Use this parameter checking code for normal operation.  Only one\r
638              * of these two blocks should actually get compiled into the class\r
639              * file.  */\r
640             if ((era != GregorianCalendar.AD && era != GregorianCalendar.BC)\r
641                 || month < Calendar.JANUARY\r
642                 || month > Calendar.DECEMBER\r
643                 || day < 1\r
644                 || day > monthLength\r
645                 || dayOfWeek < Calendar.SUNDAY\r
646                 || dayOfWeek > Calendar.SATURDAY\r
647                 || millis < 0\r
648                 || millis >= Grego.MILLIS_PER_DAY\r
649                 || monthLength < 28\r
650                 || monthLength > 31\r
651                 || prevMonthLength < 28\r
652                 || prevMonthLength > 31) {\r
653                 throw new IllegalArgumentException();\r
654             }\r
655         } else {\r
656             /* This parameter checking code is better for debugging, but\r
657              * overkill for normal operation.  Only one of these two blocks\r
658              * should actually get compiled into the class file.  */\r
659             if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {\r
660                 throw new IllegalArgumentException("Illegal era " + era);\r
661             }\r
662             if (month < Calendar.JANUARY\r
663                 || month > Calendar.DECEMBER) {\r
664                 throw new IllegalArgumentException("Illegal month " + month);\r
665             }\r
666             if (day < 1\r
667                 || day > monthLength) {\r
668                 throw new IllegalArgumentException("Illegal day " + day+" max month len: "+monthLength);\r
669             }\r
670             if (dayOfWeek < Calendar.SUNDAY\r
671                 || dayOfWeek > Calendar.SATURDAY) {\r
672                 throw new IllegalArgumentException("Illegal day of week " + dayOfWeek);\r
673             }\r
674             if (millis < 0\r
675                 || millis >= Grego.MILLIS_PER_DAY) {\r
676                 throw new IllegalArgumentException("Illegal millis " + millis);\r
677             }\r
678             if (monthLength < 28\r
679                 || monthLength > 31) {\r
680                 throw new IllegalArgumentException("Illegal month length " + monthLength);\r
681             }\r
682             if (prevMonthLength < 28\r
683                 || prevMonthLength > 31) {\r
684                 throw new IllegalArgumentException("Illegal previous month length " + prevMonthLength);\r
685             }\r
686         }\r
687 \r
688         int result = raw;\r
689 \r
690         // Bail out if we are before the onset of daylight savings time\r
691         if (!useDaylight || year < startYear || era != GregorianCalendar.AD) return result;\r
692 \r
693         // Check for southern hemisphere.  We assume that the start and end\r
694         // month are different.\r
695         boolean southern = (startMonth > endMonth);\r
696 \r
697         // Compare the date to the starting and ending rules.+1 = date>rule, -1\r
698         // = date<rule, 0 = date==rule.\r
699         int startCompare = compareToRule(month, monthLength, prevMonthLength,\r
700                                          day, dayOfWeek, millis,\r
701                                          startTimeMode == UTC_TIME ? -raw : 0,\r
702                                          startMode, startMonth, startDayOfWeek,\r
703                                          startDay, startTime);\r
704         int endCompare = 0;\r
705 \r
706         /* We don't always have to compute endCompare.  For many instances,\r
707          * startCompare is enough to determine if we are in DST or not.  In the\r
708          * northern hemisphere, if we are before the start rule, we can't have\r
709          * DST.  In the southern hemisphere, if we are after the start rule, we\r
710          * must have DST.  This is reflected in the way the next if statement\r
711          * (not the one immediately following) short circuits. */\r
712         if (southern != (startCompare >= 0)) {\r
713             /* For the ending rule comparison, we add the dstSavings to the millis\r
714              * passed in to convert them from standard to wall time.  We then must\r
715              * normalize the millis to the range 0..millisPerDay-1. */\r
716             endCompare = compareToRule(month, monthLength, prevMonthLength,\r
717                                        day, dayOfWeek, millis,\r
718                                        endTimeMode == WALL_TIME ? dst :\r
719                                         (endTimeMode == UTC_TIME ? -raw : 0),\r
720                                        endMode, endMonth, endDayOfWeek,\r
721                                        endDay, endTime);\r
722         }\r
723 \r
724         // Check for both the northern and southern hemisphere cases.  We\r
725         // assume that in the northern hemisphere, the start rule is before the\r
726         // end rule within the calendar year, and vice versa for the southern\r
727         // hemisphere.\r
728         if ((!southern && (startCompare >= 0 && endCompare < 0)) ||\r
729             (southern && (startCompare >= 0 || endCompare < 0)))\r
730             result += dst;\r
731 \r
732         return result;\r
733     }\r
734 \r
735     /**\r
736      * {@inheritDoc}\r
737      * @internal\r
738      * @deprecated This API is ICU internal only.\r
739      */\r
740     public void getOffsetFromLocal(long date,\r
741             int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) {\r
742         offsets[0] = getRawOffset();\r
743         int fields[] = new int[6];\r
744         Grego.timeToFields(date, fields);\r
745         offsets[1] = getOffset(GregorianCalendar.AD,\r
746               fields[0], fields[1], fields[2],\r
747               fields[3], fields[5]) - offsets[0];        \r
748 \r
749         boolean recalc = false;\r
750 \r
751         // Now, we need some adjustment\r
752         if (offsets[1] > 0) {\r
753             if ((nonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD\r
754                 || (nonExistingTimeOpt & STD_DST_MASK) != LOCAL_DST && (nonExistingTimeOpt & FORMER_LATTER_MASK) != LOCAL_LATTER) {\r
755                 date -= getDSTSavings();\r
756                 recalc = true;\r
757             }\r
758         } else {\r
759             if ((duplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST\r
760                     || (duplicatedTimeOpt & STD_DST_MASK) != LOCAL_STD && (duplicatedTimeOpt & FORMER_LATTER_MASK) == LOCAL_FORMER) {\r
761                 date -= getDSTSavings();\r
762                 recalc = true;\r
763             }\r
764         }\r
765 \r
766         if (recalc) {\r
767             Grego.timeToFields(date, fields);\r
768             offsets[1] = getOffset(GregorianCalendar.AD,\r
769                     fields[0], fields[1], fields[2],\r
770                     fields[3], fields[5]) - offsets[0];        \r
771         }\r
772     }\r
773 \r
774     private static final int\r
775         DOM_MODE = 1,\r
776         DOW_IN_MONTH_MODE=2,\r
777         DOW_GE_DOM_MODE=3,\r
778         DOW_LE_DOM_MODE=4;\r
779 \r
780     /**\r
781      * Compare a given date in the year to a rule. Return 1, 0, or -1, depending\r
782      * on whether the date is after, equal to, or before the rule date. The\r
783      * millis are compared directly against the ruleMillis, so any\r
784      * standard-daylight adjustments must be handled by the caller.\r
785      *\r
786      * @return  1 if the date is after the rule date, -1 if the date is before\r
787      *          the rule date, or 0 if the date is equal to the rule date.\r
788      */\r
789     private int compareToRule(int month, int monthLen, int prevMonthLen,\r
790                                   int dayOfMonth,\r
791                                   int dayOfWeek, int millis, int millisDelta,\r
792                                   int ruleMode, int ruleMonth, int ruleDayOfWeek,\r
793                                   int ruleDay, int ruleMillis)\r
794     {\r
795         // Make adjustments for startTimeMode and endTimeMode\r
796         \r
797         millis += millisDelta;\r
798         \r
799         while (millis >= Grego.MILLIS_PER_DAY) {\r
800             millis -= Grego.MILLIS_PER_DAY;\r
801             ++dayOfMonth;\r
802             dayOfWeek = 1 + (dayOfWeek % 7); // dayOfWeek is one-based\r
803             if (dayOfMonth > monthLen) {\r
804                 dayOfMonth = 1;\r
805                 /* When incrementing the month, it is desirable to overflow\r
806                  * from DECEMBER to DECEMBER+1, since we use the result to\r
807                  * compare against a real month. Wraparound of the value\r
808                  * leads to bug 4173604. */\r
809                 ++month;\r
810             }\r
811         }\r
812         /*\r
813          * For some reasons, Sun Java 6 on Solaris/Linux has a problem with\r
814          * the while loop below (at least Java 6 up to build 1.6.0_02-b08).\r
815          * It looks the JRE messes up the variable 'millis' while executing\r
816          * the code in the while block.  The problem is not reproduced with\r
817          * JVM option -Xint, that is, it is likely a bug of the HotSpot\r
818          * adaptive compiler.  Moving 'millis += Grego.MILLIS_PER_DAY'\r
819          * to the end of this while block seems to resolve the problem.\r
820          * See ticket#5887 about the problem in detail.\r
821          */\r
822         while (millis < 0) {\r
823             //millis += Grego.MILLIS_PER_DAY;\r
824             --dayOfMonth;\r
825             dayOfWeek = 1 + ((dayOfWeek+5) % 7); // dayOfWeek is one-based\r
826             if (dayOfMonth < 1) {\r
827                 dayOfMonth = prevMonthLen;\r
828                 --month;\r
829             }\r
830             millis += Grego.MILLIS_PER_DAY;\r
831         }\r
832         \r
833         if (month < ruleMonth) return -1;\r
834         else if (month > ruleMonth) return 1;\r
835 \r
836         int ruleDayOfMonth = 0;\r
837 \r
838         // Adjust the ruleDay to the monthLen, for non-leap year February 29 rule days.\r
839         if (ruleDay > monthLen) {\r
840             ruleDay = monthLen;\r
841         }\r
842 \r
843         switch (ruleMode)\r
844         {\r
845         case DOM_MODE:\r
846             ruleDayOfMonth = ruleDay;\r
847             break;\r
848         case DOW_IN_MONTH_MODE:\r
849             // In this case ruleDay is the day-of-week-in-month\r
850             if (ruleDay > 0)\r
851                 ruleDayOfMonth = 1 + (ruleDay - 1) * 7 +\r
852                     (7 + ruleDayOfWeek - (dayOfWeek - dayOfMonth + 1)) % 7;\r
853             else // Assume ruleDay < 0 here\r
854             {\r
855                 ruleDayOfMonth = monthLen + (ruleDay + 1) * 7 -\r
856                     (7 + (dayOfWeek + monthLen - dayOfMonth) - ruleDayOfWeek) % 7;\r
857             }\r
858             break;\r
859         case DOW_GE_DOM_MODE:\r
860             ruleDayOfMonth = ruleDay +\r
861                 (49 + ruleDayOfWeek - ruleDay - dayOfWeek + dayOfMonth) % 7;\r
862             break;\r
863         case DOW_LE_DOM_MODE:\r
864             ruleDayOfMonth = ruleDay -\r
865                 (49 - ruleDayOfWeek + ruleDay + dayOfWeek - dayOfMonth) % 7;\r
866             // Note at this point ruleDayOfMonth may be <1, although it will\r
867             // be >=1 for well-formed rules.\r
868             break;\r
869         }\r
870 \r
871         if (dayOfMonth < ruleDayOfMonth) return -1;\r
872         else if (dayOfMonth > ruleDayOfMonth) return 1;\r
873 \r
874         if (millis < ruleMillis){\r
875                 return -1;\r
876         }else if (millis > ruleMillis){\r
877                 return 1;\r
878         }else{\r
879                 return 0;\r
880         }\r
881     }\r
882 \r
883     // data needed for streaming mutated SimpleTimeZones in JDK14\r
884     private int raw;// the TimeZone's raw GMT offset \r
885     private int dst = 3600000;\r
886     private STZInfo xinfo = null;\r
887     private int startMonth, startDay, startDayOfWeek;   // the month, day, DOW, and time DST starts\r
888     private int startTime;\r
889     private int startTimeMode, endTimeMode; // Mode for startTime, endTime; see TimeMode\r
890     private int endMonth, endDay, endDayOfWeek; // the month, day, DOW, and time DST ends\r
891     private int endTime;\r
892     private int startYear;  // the year these DST rules took effect \r
893     private boolean useDaylight; // flag indicating whether this TimeZone uses DST\r
894     private int startMode, endMode;   // flags indicating what kind of rules the DST rules are\r
895     \r
896     /**\r
897      * Overrides TimeZone\r
898      * Queries if this time zone uses Daylight Saving Time.\r
899      * @stable ICU 2.0\r
900      */\r
901     public boolean useDaylightTime(){\r
902         return useDaylight;\r
903     }\r
904 \r
905     /**\r
906      * Overrides TimeZone\r
907      * Queries if the give date is in Daylight Saving Time.\r
908      * @stable ICU 2.0\r
909      */\r
910     public boolean inDaylightTime(Date date){\r
911         GregorianCalendar gc = new GregorianCalendar(this);\r
912         gc.setTime(date);\r
913         return gc.inDaylightTime();\r
914     }\r
915 \r
916     /**\r
917      * Internal construction method.\r
918      */\r
919     private void construct(int _raw,\r
920                            int _startMonth,\r
921                            int _startDay,\r
922                            int _startDayOfWeek,\r
923                            int _startTime,\r
924                            int _startTimeMode,\r
925                            int _endMonth,\r
926                            int _endDay,\r
927                            int _endDayOfWeek,\r
928                            int _endTime,\r
929                            int _endTimeMode,\r
930                            int _dst) {\r
931         raw            = _raw;\r
932         startMonth     = _startMonth;\r
933         startDay       = _startDay;\r
934         startDayOfWeek = _startDayOfWeek;\r
935         startTime      = _startTime;\r
936         startTimeMode  = _startTimeMode;\r
937         endMonth       = _endMonth;\r
938         endDay         = _endDay;\r
939         endDayOfWeek   = _endDayOfWeek;\r
940         endTime        = _endTime;\r
941         endTimeMode    = _endTimeMode;\r
942         dst            = _dst;\r
943         startYear      = 0;\r
944         startMode      = DOM_MODE;\r
945         endMode        = DOM_MODE;\r
946 \r
947         decodeRules();\r
948 \r
949         if (_dst <= 0) {\r
950             throw new IllegalArgumentException();\r
951         }\r
952     }\r
953     private void decodeRules(){\r
954         decodeStartRule();\r
955         decodeEndRule();\r
956     }\r
957 \r
958     /**\r
959      * Decode the start rule and validate the parameters.  The parameters are\r
960      * expected to be in encoded form, which represents the various rule modes\r
961      * by negating or zeroing certain values.  Representation formats are:\r
962      * <p>\r
963      * <pre>\r
964      *            DOW_IN_MONTH  DOM    DOW>=DOM  DOW<=DOM  no DST\r
965      *            ------------  -----  --------  --------  ----------\r
966      * month       0..11        same    same      same     don't care\r
967      * day        -5..5         1..31   1..31    -1..-31   0\r
968      * dayOfWeek   1..7         0      -1..-7    -1..-7    don't care\r
969      * time        0..ONEDAY    same    same      same     don't care\r
970      * </pre>\r
971      * The range for month does not include UNDECIMBER since this class is\r
972      * really specific to GregorianCalendar, which does not use that month.\r
973      * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the\r
974      * end rule is an exclusive limit point.  That is, the range of times that\r
975      * are in DST include those >= the start and < the end.  For this reason,\r
976      * it should be possible to specify an end of ONEDAY in order to include the\r
977      * entire day.  Although this is equivalent to time 0 of the following day,\r
978      * it's not always possible to specify that, for example, on December 31.\r
979      * While arguably the start range should still be 0..ONEDAY-1, we keep\r
980      * the start and end ranges the same for consistency.\r
981      */\r
982     private void decodeStartRule() {\r
983 \r
984         useDaylight = (boolean)((startDay != 0) && (endDay != 0) ? true : false  );\r
985         if (useDaylight && dst == 0) {\r
986             dst = Grego.MILLIS_PER_DAY;\r
987         }\r
988         if (startDay != 0) {\r
989             if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {\r
990                 throw new IllegalArgumentException();\r
991             }\r
992             if (startTime < 0 || startTime > Grego.MILLIS_PER_DAY ||\r
993                 startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) {\r
994                 throw new IllegalArgumentException();\r
995             }\r
996             if (startDayOfWeek == 0) {\r
997                 startMode = DOM_MODE;\r
998             } else {\r
999                 if (startDayOfWeek > 0) {\r
1000                     startMode = DOW_IN_MONTH_MODE;\r
1001                 } else {\r
1002                     startDayOfWeek = (int)-startDayOfWeek;\r
1003                     if (startDay > 0) {\r
1004                         startMode = DOW_GE_DOM_MODE;\r
1005                     } else {\r
1006                         startDay = (int)-startDay;\r
1007                         startMode = DOW_LE_DOM_MODE;\r
1008                     }\r
1009                 }\r
1010                 if (startDayOfWeek > Calendar.SATURDAY) {\r
1011                     throw new IllegalArgumentException();\r
1012                 }\r
1013             }\r
1014             if (startMode == DOW_IN_MONTH_MODE) {\r
1015                 if (startDay < -5 || startDay > 5) {\r
1016                     throw new IllegalArgumentException();\r
1017                 }\r
1018             } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {\r
1019                 throw new IllegalArgumentException();\r
1020             }\r
1021         }\r
1022     }\r
1023 \r
1024     /**\r
1025      * Decode the end rule and validate the parameters.  This method is exactly\r
1026      * analogous to decodeStartRule().\r
1027      * @see #decodeStartRule\r
1028      */\r
1029     private void decodeEndRule() {\r
1030         useDaylight = (boolean)((startDay != 0) && (endDay != 0) ? true : false);\r
1031         if (useDaylight && dst == 0) {\r
1032             dst = Grego.MILLIS_PER_DAY;\r
1033         }\r
1034         if (endDay != 0) {\r
1035             if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {\r
1036                 throw new IllegalArgumentException();\r
1037             }\r
1038             if (endTime < 0 || endTime > Grego.MILLIS_PER_DAY ||\r
1039                 endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) {\r
1040                 throw new IllegalArgumentException();\r
1041             }\r
1042             if (endDayOfWeek == 0) {\r
1043                 endMode = DOM_MODE;\r
1044             } else {\r
1045                 if (endDayOfWeek > 0) {\r
1046                     endMode = DOW_IN_MONTH_MODE;\r
1047                 } else {\r
1048                     endDayOfWeek = (int)-endDayOfWeek;\r
1049                     if (endDay > 0) {\r
1050                         endMode = DOW_GE_DOM_MODE;\r
1051                     } else {\r
1052                         endDay = (int)-endDay;\r
1053                         endMode = DOW_LE_DOM_MODE;\r
1054                     }\r
1055                 }\r
1056                 if (endDayOfWeek > Calendar.SATURDAY) {\r
1057                     throw new IllegalArgumentException();\r
1058                 }\r
1059             }\r
1060             if (endMode == DOW_IN_MONTH_MODE) {\r
1061                 if (endDay < -5 || endDay > 5) {\r
1062                     throw new IllegalArgumentException();\r
1063                 }\r
1064             } else if (endDay<1 || endDay > staticMonthLength[endMonth]) {\r
1065                 throw new IllegalArgumentException();\r
1066             }\r
1067         }\r
1068     }\r
1069 \r
1070     /**\r
1071      * Return true if obj is a SimpleTimeZone equivalent to this.\r
1072      * @return true if obj is a SimpleTimeZone equivalent to this\r
1073      * @stable ICU 3.6\r
1074      */\r
1075     public boolean equals(Object obj){\r
1076         if (this == obj) return true;\r
1077         if (obj == null || getClass() != obj.getClass()) return false;\r
1078         SimpleTimeZone that = (SimpleTimeZone) obj;\r
1079         return raw     == that.raw &&\r
1080             useDaylight     == that.useDaylight &&\r
1081             idEquals(getID(),that.getID()) &&\r
1082             (!useDaylight\r
1083              // Only check rules if using DST\r
1084              || (dst            == that.dst &&\r
1085                  startMode      == that.startMode &&\r
1086                  startMonth     == that.startMonth &&\r
1087                  startDay       == that.startDay &&\r
1088                  startDayOfWeek == that.startDayOfWeek &&\r
1089                  startTime      == that.startTime &&\r
1090                  startTimeMode  == that.startTimeMode &&\r
1091                  endMode        == that.endMode &&\r
1092                  endMonth       == that.endMonth &&\r
1093                  endDay         == that.endDay &&\r
1094                  endDayOfWeek   == that.endDayOfWeek &&\r
1095                  endTime        == that.endTime &&\r
1096                  endTimeMode    == that.endTimeMode &&\r
1097                  startYear      == that.startYear ));\r
1098 \r
1099     }\r
1100     private boolean idEquals(String id1, String id2){\r
1101         if(id1==null && id2==null){\r
1102             return true;\r
1103         }\r
1104         if(id1!=null && id2!=null){\r
1105             return id1.equals(id2);\r
1106         }\r
1107         return false;\r
1108     }\r
1109 \r
1110     /**\r
1111      * Return the hash code.\r
1112      * @return the hash code\r
1113      * @stable ICU 3.6\r
1114      */\r
1115     public int hashCode(){\r
1116         int ret = (int)( super.hashCode() +\r
1117                                          raw ^ (raw>>>8) +\r
1118                                          (useDaylight?0:1));\r
1119         if(!useDaylight){\r
1120                 ret += (int)(dst ^ (dst>>>10) +\r
1121                                 startMode ^ (startMode>>>11) +\r
1122                                 startMonth ^ (startMonth>>>12) +\r
1123                                 startDay ^ (startDay>>>13) +\r
1124                                 startDayOfWeek ^ (startDayOfWeek>>>14) +\r
1125                                 startTime ^ (startTime>>>15) +\r
1126                                 startTimeMode ^ (startTimeMode>>>16) +\r
1127                                 endMode ^ (endMode>>>17) +\r
1128                                 endMonth ^ (endMonth>>>18) +\r
1129                                 endDay ^ (endDay>>>19) +\r
1130                                 endDayOfWeek ^ (endDayOfWeek>>>20) +\r
1131                                 endTime ^ (endTime>>>21) +\r
1132                                 endTimeMode ^ (endTimeMode>>>22) +\r
1133                                 startYear ^ (startYear>>>23));\r
1134         }\r
1135                 return ret;\r
1136     }\r
1137 \r
1138     /**\r
1139      * Return a clone of this time zone.\r
1140      * @return a clone of this time zone\r
1141      * @stable ICU 3.6\r
1142      */\r
1143     public Object clone() {\r
1144         return super.clone();\r
1145     }\r
1146 \r
1147     /**\r
1148      * Return true if this zone has the same rules and offset as another zone.\r
1149      * @param othr the TimeZone object to be compared with\r
1150      * @return true if the given zone has the same rules and offset as this one\r
1151      * @stable ICU 2.0\r
1152      */\r
1153     public boolean hasSameRules(TimeZone othr) {\r
1154         if(!(othr instanceof SimpleTimeZone)){\r
1155                 return false;\r
1156         }\r
1157         SimpleTimeZone other = (SimpleTimeZone)othr;\r
1158         return other != null &&\r
1159         raw     == other.raw &&\r
1160         useDaylight     == other.useDaylight &&\r
1161         (!useDaylight\r
1162          // Only check rules if using DST\r
1163          || (dst     == other.dst &&\r
1164              startMode      == other.startMode &&\r
1165              startMonth     == other.startMonth &&\r
1166              startDay       == other.startDay &&\r
1167              startDayOfWeek == other.startDayOfWeek &&\r
1168              startTime      == other.startTime &&\r
1169              startTimeMode  == other.startTimeMode &&\r
1170              endMode        == other.endMode &&\r
1171              endMonth       == other.endMonth &&\r
1172              endDay         == other.endDay &&\r
1173              endDayOfWeek   == other.endDayOfWeek &&\r
1174              endTime        == other.endTime &&\r
1175              endTimeMode    == other.endTimeMode &&\r
1176              startYear      == other.startYear));\r
1177     }\r
1178 \r
1179     // BasicTimeZone methods\r
1180 \r
1181     /**\r
1182      * {@inheritDoc}\r
1183      * @stable ICU 3.8\r
1184      */\r
1185     public TimeZoneTransition getNextTransition(long base, boolean inclusive) {\r
1186         if (!useDaylight) {\r
1187             return null;\r
1188         }\r
1189 \r
1190         initTransitionRules();\r
1191         long firstTransitionTime = firstTransition.getTime();\r
1192         if (base < firstTransitionTime || (inclusive && base == firstTransitionTime)) {\r
1193             return firstTransition;\r
1194         }\r
1195         Date stdDate = stdRule.getNextStart(base, dstRule.getRawOffset(), dstRule.getDSTSavings(), inclusive);\r
1196         Date dstDate = dstRule.getNextStart(base, stdRule.getRawOffset(), stdRule.getDSTSavings(), inclusive);\r
1197         if (stdDate != null && (dstDate == null || stdDate.before(dstDate))) {\r
1198             return new TimeZoneTransition(stdDate.getTime(), dstRule, stdRule);\r
1199         }\r
1200         if (dstDate != null && (stdDate == null || dstDate.before(stdDate))) {\r
1201             return new TimeZoneTransition(dstDate.getTime(), stdRule, dstRule);\r
1202         }\r
1203         return null;\r
1204     }\r
1205 \r
1206     /**\r
1207      * {@inheritDoc}\r
1208      * @stable ICU 3.8\r
1209      */\r
1210     public TimeZoneTransition getPreviousTransition(long base, boolean inclusive) {\r
1211         if (!useDaylight) {\r
1212             return null;\r
1213         }\r
1214 \r
1215         initTransitionRules();\r
1216         long firstTransitionTime = firstTransition.getTime();\r
1217         if (base < firstTransitionTime || (!inclusive && base == firstTransitionTime)) {\r
1218             return null;\r
1219         }\r
1220         Date stdDate = stdRule.getPreviousStart(base, dstRule.getRawOffset(), dstRule.getDSTSavings(), inclusive);\r
1221         Date dstDate = dstRule.getPreviousStart(base, stdRule.getRawOffset(), stdRule.getDSTSavings(), inclusive);\r
1222         if (stdDate != null && (dstDate == null || stdDate.after(dstDate))) {\r
1223             return new TimeZoneTransition(stdDate.getTime(), dstRule, stdRule);\r
1224         }\r
1225         if (dstDate != null && (stdDate == null || dstDate.after(stdDate))) {\r
1226             return new TimeZoneTransition(dstDate.getTime(), stdRule, dstRule);            \r
1227         }\r
1228         return null;\r
1229     }\r
1230 \r
1231     /**\r
1232      * {@inheritDoc}\r
1233      * @stable ICU 3.8\r
1234      */\r
1235     public TimeZoneRule[] getTimeZoneRules() {\r
1236         initTransitionRules();\r
1237 \r
1238         int size = useDaylight ? 3 : 1;\r
1239         TimeZoneRule[] rules = new TimeZoneRule[size];\r
1240         rules[0] = initialRule;\r
1241         if (useDaylight) {\r
1242             rules[1] = stdRule;\r
1243             rules[2] = dstRule;\r
1244         }\r
1245         return rules;\r
1246     }\r
1247 \r
1248     private transient boolean transitionRulesInitialized;\r
1249     private transient InitialTimeZoneRule initialRule;\r
1250     private transient TimeZoneTransition firstTransition;\r
1251     private transient AnnualTimeZoneRule stdRule;\r
1252     private transient AnnualTimeZoneRule dstRule;\r
1253 \r
1254     private synchronized void initTransitionRules() {\r
1255         if (transitionRulesInitialized) {\r
1256             return;\r
1257         }\r
1258         if (useDaylight) {\r
1259             DateTimeRule dtRule = null;\r
1260             int timeRuleType;\r
1261             long firstStdStart, firstDstStart;\r
1262 \r
1263             // Create a TimeZoneRule for daylight saving time\r
1264             timeRuleType = (startTimeMode == STANDARD_TIME) ? DateTimeRule.STANDARD_TIME :\r
1265                 ((startTimeMode == UTC_TIME) ? DateTimeRule.UTC_TIME : DateTimeRule.WALL_TIME);\r
1266             switch (startMode) {\r
1267             case DOM_MODE:\r
1268              dtRule = new DateTimeRule(startMonth, startDay, startTime, timeRuleType);\r
1269              break;\r
1270             case DOW_IN_MONTH_MODE:\r
1271              dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, startTime, timeRuleType);\r
1272              break;\r
1273             case DOW_GE_DOM_MODE:\r
1274              dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, true, startTime, timeRuleType);\r
1275              break;\r
1276             case DOW_LE_DOM_MODE:\r
1277              dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, false, startTime, timeRuleType);\r
1278              break;\r
1279             }\r
1280             // For now, use ID + "(DST)" as the name\r
1281             dstRule = new AnnualTimeZoneRule(getID() + "(DST)", getRawOffset(), getDSTSavings(),\r
1282                  dtRule, startYear, AnnualTimeZoneRule.MAX_YEAR);\r
1283      \r
1284             // Calculate the first DST start time\r
1285             firstDstStart = dstRule.getFirstStart(getRawOffset(), 0).getTime();\r
1286 \r
1287             // Create a TimeZoneRule for standard time\r
1288             timeRuleType = (endTimeMode == STANDARD_TIME) ? DateTimeRule.STANDARD_TIME :\r
1289                 ((endTimeMode == UTC_TIME) ? DateTimeRule.UTC_TIME : DateTimeRule.WALL_TIME);\r
1290             switch (endMode) {\r
1291             case DOM_MODE:\r
1292                 dtRule = new DateTimeRule(endMonth, endDay, endTime, timeRuleType);\r
1293                 break;\r
1294             case DOW_IN_MONTH_MODE:\r
1295                 dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, endTime, timeRuleType);\r
1296                 break;\r
1297             case DOW_GE_DOM_MODE:\r
1298                 dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, true, endTime, timeRuleType);\r
1299                 break;\r
1300             case DOW_LE_DOM_MODE:\r
1301                 dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, false, endTime, timeRuleType);\r
1302                 break;\r
1303             }\r
1304             // For now, use ID + "(STD)" as the name\r
1305             stdRule = new AnnualTimeZoneRule(getID() + "(STD)", getRawOffset(), 0,\r
1306                     dtRule, startYear, AnnualTimeZoneRule.MAX_YEAR);\r
1307 \r
1308             // Calculate the first STD start time\r
1309             firstStdStart = stdRule.getFirstStart(getRawOffset(), dstRule.getDSTSavings()).getTime();\r
1310 \r
1311             // Create a TimeZoneRule for initial time\r
1312             if (firstStdStart < firstDstStart) {\r
1313                 initialRule = new InitialTimeZoneRule(getID() + "(DST)", getRawOffset(), dstRule.getDSTSavings());                \r
1314                 firstTransition = new TimeZoneTransition(firstStdStart, initialRule, stdRule);\r
1315             } else {\r
1316                 initialRule = new InitialTimeZoneRule(getID() + "(STD)", getRawOffset(), 0);\r
1317                 firstTransition = new TimeZoneTransition(firstDstStart, initialRule, dstRule);\r
1318             }\r
1319             \r
1320         } else {\r
1321             // Create a TimeZoneRule for initial time\r
1322             initialRule = new InitialTimeZoneRule(getID(), getRawOffset(), 0);\r
1323         }\r
1324         transitionRulesInitialized = true;\r
1325     }\r
1326 }\r
1327 \r