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