]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/util/BasicTimeZone.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / util / BasicTimeZone.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 2007-2010, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 package com.ibm.icu.util;\r
8 \r
9 import java.util.BitSet;\r
10 import java.util.Date;\r
11 import java.util.LinkedList;\r
12 import java.util.List;\r
13 \r
14 import com.ibm.icu.impl.Grego;\r
15 \r
16 /**\r
17  * {@icu} BasicTimeZone extends <code>TimeZone</code> with additional methods to access\r
18  * time zone transitions and rules.  All ICU <code>TimeZone</code> concrete subclasses\r
19  * extend this class. APIs added to <code>java.util.TimeZone</code> by\r
20  * <code>BasicTimeZone</code> are annotated with <strong>'<font\r
21  * style="color:red">[icu]</font>'</strong>.\r
22  *\r
23  * @see com.ibm.icu.util.TimeZoneRule\r
24  * @see com.ibm.icu.util.TimeZoneTransition\r
25  *\r
26  * @stable ICU 3.8\r
27  */\r
28 public abstract class BasicTimeZone extends TimeZone {\r
29 \r
30     private static final long serialVersionUID = -3204278532246180932L;\r
31 \r
32     private static final long MILLIS_PER_YEAR = 365*24*60*60*1000L;\r
33 \r
34     /**\r
35      * {@icu} Returns the first time zone transition after the base time.\r
36      *\r
37      * @param base      The base time.\r
38      * @param inclusive Whether the base time is inclusive or not.\r
39      *\r
40      * @return  A <code>Date</code> holding the first time zone transition time\r
41      *          after the given base time, or null if no time zone transitions\r
42      *          are available after the base time.\r
43      *\r
44      * @stable ICU 3.8\r
45      */\r
46     public abstract TimeZoneTransition getNextTransition(long base, boolean inclusive);\r
47 \r
48     /**\r
49      * {@icu} Returns the last time zone transition before the base time.\r
50      *\r
51      * @param base      The base time.\r
52      * @param inclusive Whether the base time is inclusive or not.\r
53      *\r
54      * @return  A <code>Date</code> holding the last time zone transition time\r
55      *          before the given base time, or null if no time zone transitions\r
56      *          are available before the base time.\r
57      *\r
58      * @stable ICU 3.8\r
59      */\r
60     public abstract TimeZoneTransition getPreviousTransition(long base, boolean inclusive);\r
61 \r
62     /**\r
63      * {@icu} Checks if the time zone has equivalent transitions in the time range.\r
64      * This method returns true when all of transition times, from/to standard\r
65      * offsets and DST savings used by this time zone match the other in the\r
66      * time range.\r
67      *\r
68      * @param tz    The instance of <code>TimeZone</code>\r
69      * @param start The start time of the evaluated time range (inclusive)\r
70      * @param end   The end time of the evaluated time range (inclusive)\r
71      *\r
72      * @return true if the other time zone has the equivalent transitions in the\r
73      * time range.  When tz is not a <code>BasicTimeZone</code>, this method\r
74      * returns false.\r
75      *\r
76      * @stable ICU 3.8\r
77      */\r
78     public boolean hasEquivalentTransitions(TimeZone tz, long start, long end) {\r
79         return hasEquivalentTransitions(tz, start, end, false);\r
80     }\r
81 \r
82     /**\r
83      * {@icu} Checks if the time zone has equivalent transitions in the time range.\r
84      * This method returns true when all of transition times, from/to standard\r
85      * offsets and DST savings used by this time zone match the other in the\r
86      * time range.\r
87      *\r
88      * @param tz    The instance of <code>TimeZone</code>\r
89      * @param start The start time of the evaluated time range (inclusive)\r
90      * @param end   The end time of the evaluated time range (inclusive)\r
91      * @param ignoreDstAmount When true, any transitions with only daylight saving amount\r
92      * changes will be ignored, except either of them is zero. For example, a transition\r
93      * from rawoffset 3:00/dstsavings 1:00 to rawoffset 2:00/dstsavings 2:00 is excluded\r
94      * from the comparison, but a transtion from rawoffset 2:00/dstsavings 1:00 to\r
95      * rawoffset 3:00/dstsavings 0:00 is included.\r
96      *\r
97      * @return true if the other time zone has the equivalent transitions in the\r
98      * time range.  When tz is not a <code>BasicTimeZone</code>, this method\r
99      * returns false.\r
100      *\r
101      * @stable ICU 3.8\r
102      */\r
103     public boolean hasEquivalentTransitions(TimeZone tz, long start, long end, \r
104                                             boolean ignoreDstAmount) {\r
105         if (hasSameRules(tz)) {\r
106             return true;\r
107         }\r
108         if (!(tz instanceof BasicTimeZone)) {\r
109             return false;\r
110         }\r
111 \r
112         // Check the offsets at the start time\r
113         int[] offsets1 = new int[2];\r
114         int[] offsets2 = new int[2];\r
115 \r
116         getOffset(start, false, offsets1);\r
117         tz.getOffset(start, false, offsets2);\r
118 \r
119         if (ignoreDstAmount) {\r
120             if ((offsets1[0] + offsets1[1] != offsets2[0] + offsets2[1])\r
121                 || (offsets1[1] != 0 && offsets2[1] == 0)\r
122                 || (offsets1[1] == 0 && offsets2[1] != 0)) {\r
123                 return false;\r
124             }\r
125         } else {\r
126             if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) {\r
127                 return false;\r
128             }\r
129         }\r
130 \r
131         // Check transitions in the range\r
132         long time = start;\r
133         while (true) {\r
134             TimeZoneTransition tr1 = getNextTransition(time, false);\r
135             TimeZoneTransition tr2 = ((BasicTimeZone)tz).getNextTransition(time, false);\r
136 \r
137             if (ignoreDstAmount) {\r
138                 // Skip a transition which only differ the amount of DST savings\r
139                 if (tr1 != null\r
140                         && (tr1.getFrom().getRawOffset() + tr1.getFrom().getDSTSavings()\r
141                                 == tr1.getTo().getRawOffset() + tr1.getTo().getDSTSavings())\r
142                         && (tr1.getFrom().getDSTSavings() != 0 && tr1.getTo().getDSTSavings() != 0)) {\r
143                     tr1 = getNextTransition(tr1.getTime(), false);\r
144                 }\r
145                 if (tr2 != null\r
146                         && (tr2.getFrom().getRawOffset() + tr2.getFrom().getDSTSavings()\r
147                                 == tr2.getTo().getRawOffset() + tr2.getTo().getDSTSavings())\r
148                         && (tr2.getFrom().getDSTSavings() != 0 && tr2.getTo().getDSTSavings() != 0)) {\r
149                     tr2 = getNextTransition(tr2.getTime(), false);\r
150                 }\r
151             }\r
152 \r
153             boolean inRange1 = false;\r
154             boolean inRange2 = false;\r
155             if (tr1 != null) {\r
156                 if (tr1.getTime() <= end) {\r
157                     inRange1 = true;\r
158                 }\r
159             }\r
160             if (tr2 != null) {\r
161                 if (tr2.getTime() <= end) {\r
162                     inRange2 = true;\r
163                 }\r
164             }\r
165             if (!inRange1 && !inRange2) {\r
166                 // No more transition in the range\r
167                 break;\r
168             }\r
169             if (!inRange1 || !inRange2) {\r
170                 return false;\r
171             }\r
172             if (tr1.getTime() != tr2.getTime()) {\r
173                 return false;\r
174             }\r
175             if (ignoreDstAmount) {\r
176                 if (tr1.getTo().getRawOffset() + tr1.getTo().getDSTSavings()\r
177                             != tr2.getTo().getRawOffset() + tr2.getTo().getDSTSavings()\r
178                         || tr1.getTo().getDSTSavings() != 0 &&  tr2.getTo().getDSTSavings() == 0\r
179                         || tr1.getTo().getDSTSavings() == 0 &&  tr2.getTo().getDSTSavings() != 0) {\r
180                     return false;\r
181                 }\r
182             } else {\r
183                 if (tr1.getTo().getRawOffset() != tr2.getTo().getRawOffset() ||\r
184                     tr1.getTo().getDSTSavings() != tr2.getTo().getDSTSavings()) {\r
185                     return false;\r
186                 }\r
187             }\r
188             time = tr1.getTime();\r
189         }\r
190         return true;\r
191     }\r
192 \r
193     /**\r
194      * {@icu} Returns the array of <code>TimeZoneRule</code> which represents the rule\r
195      * of this time zone object.  The first element in the result array will\r
196      * be the <code>InitialTimeZoneRule</code> instance for the initial rule.\r
197      * The rest will be either <code>AnnualTimeZoneRule</code> or\r
198      * <code>TimeArrayTimeZoneRule</code> instances representing transitions.\r
199      *\r
200      * @return  The array of <code>TimeZoneRule</code> which represents this\r
201      *          time zone.\r
202      *\r
203      * @stable ICU 3.8\r
204      */\r
205     public abstract TimeZoneRule[] getTimeZoneRules();\r
206 \r
207     /**\r
208      * {@icu} Returns the array of <code>TimeZoneRule</code> which represents the rule\r
209      * of this time zone object since the specified start time.  The first\r
210      * element in the result array will be the <code>InitialTimeZoneRule</code>\r
211      * instance for the initial rule.  The rest will be either\r
212      * <code>AnnualTimeZoneRule</code> or <code>TimeArrayTimeZoneRule</code>\r
213      * instances representing transitions.\r
214      *\r
215      * @param start The start time (inclusive).\r
216      * @return  The array of <code>TimeZoneRule</code> which represents this\r
217      *          time zone since the start time.\r
218      *\r
219      * @stable ICU 3.8\r
220      */\r
221     public TimeZoneRule[] getTimeZoneRules(long start) {\r
222         TimeZoneRule[] all = getTimeZoneRules();\r
223         TimeZoneTransition tzt = getPreviousTransition(start, true);\r
224         if (tzt == null) {\r
225             // No need to filter out rules only applicable to time before the start\r
226             return all;\r
227         }\r
228 \r
229         BitSet isProcessed = new BitSet(all.length);\r
230         List<TimeZoneRule> filteredRules = new LinkedList<TimeZoneRule>();\r
231 \r
232         // Create initial rule\r
233         TimeZoneRule initial = new InitialTimeZoneRule(tzt.getTo().getName(),\r
234                 tzt.getTo().getRawOffset(), tzt.getTo().getDSTSavings());\r
235         filteredRules.add(initial);\r
236         isProcessed.set(0);\r
237 \r
238         // Mark rules which does not need to be processed\r
239         for (int i = 1; i < all.length; i++) {\r
240             Date d = all[i].getNextStart(start, initial.getRawOffset(),\r
241                     initial.getDSTSavings(), false);\r
242             if (d == null) {\r
243                 isProcessed.set(i);\r
244             }\r
245         }\r
246 \r
247         long time = start;\r
248         boolean bFinalStd = false, bFinalDst = false;\r
249         while(!bFinalStd || !bFinalDst) {\r
250             tzt = getNextTransition(time, false);\r
251             if (tzt == null) {\r
252                 break;\r
253             }\r
254             time = tzt.getTime();\r
255 \r
256             TimeZoneRule toRule = tzt.getTo();\r
257             int ruleIdx = 1;\r
258             for (; ruleIdx < all.length; ruleIdx++) {\r
259                 if (all[ruleIdx].equals(toRule)) {\r
260                     break;\r
261                 }\r
262             }\r
263             if (ruleIdx >= all.length) {\r
264                 throw new IllegalStateException("The rule was not found");\r
265             }\r
266             if (isProcessed.get(ruleIdx)) {\r
267                 continue;\r
268             }\r
269             if (toRule instanceof TimeArrayTimeZoneRule) {\r
270                 TimeArrayTimeZoneRule tar = (TimeArrayTimeZoneRule)toRule;\r
271 \r
272                 // Get the previous raw offset and DST savings before the very first start time\r
273                 long t = start;\r
274                 while(true) {\r
275                     tzt = getNextTransition(t, false);\r
276                     if (tzt == null) {\r
277                         break;\r
278                     }\r
279                     if (tzt.getTo().equals(tar)) {\r
280                         break;\r
281                     }\r
282                     t = tzt.getTime();\r
283                 }\r
284                 if (tzt != null) {\r
285                     // Check if the entire start times to be added\r
286                     Date firstStart = tar.getFirstStart(tzt.getFrom().getRawOffset(),\r
287                             tzt.getFrom().getDSTSavings());\r
288                     if (firstStart.getTime() > start) {\r
289                         // Just add the rule as is\r
290                         filteredRules.add(tar);\r
291                     } else {\r
292                         // Collect transitions after the start time\r
293                         long[] times = tar.getStartTimes();\r
294                         int timeType = tar.getTimeType();\r
295                         int idx;\r
296                         for (idx = 0; idx < times.length; idx++) {\r
297                             t = times[idx];\r
298                             if (timeType == DateTimeRule.STANDARD_TIME) {\r
299                                 t -= tzt.getFrom().getRawOffset();\r
300                             }\r
301                             if (timeType == DateTimeRule.WALL_TIME) {\r
302                                 t -= tzt.getFrom().getDSTSavings();\r
303                             }\r
304                             if (t > start) {\r
305                                 break;\r
306                             }\r
307                         }\r
308                         int asize = times.length - idx;\r
309                         if (asize > 0) {\r
310                             long[] newtimes = new long[asize];\r
311                             System.arraycopy(times, idx, newtimes, 0, asize);\r
312                             TimeArrayTimeZoneRule newtar = new TimeArrayTimeZoneRule(\r
313                                     tar.getName(), tar.getRawOffset(), tar.getDSTSavings(),\r
314                                     newtimes, tar.getTimeType());\r
315                             filteredRules.add(newtar);\r
316                         }\r
317                     }\r
318                 }\r
319             } else if (toRule instanceof AnnualTimeZoneRule) {\r
320                 AnnualTimeZoneRule ar = (AnnualTimeZoneRule)toRule;\r
321                 Date firstStart = ar.getFirstStart(tzt.getFrom().getRawOffset(),\r
322                         tzt.getFrom().getDSTSavings());\r
323                 if (firstStart.getTime() == tzt.getTime()) {\r
324                     // Just add the rule as is\r
325                     filteredRules.add(ar);\r
326                 } else {\r
327                     // Calculate the transition year\r
328                     int[] dfields = new int[6];\r
329                     Grego.timeToFields(tzt.getTime(), dfields);\r
330                     // Recreate the rule\r
331                     AnnualTimeZoneRule newar = new AnnualTimeZoneRule(ar.getName(),\r
332                             ar.getRawOffset(), ar.getDSTSavings(),\r
333                             ar.getRule(), dfields[0], ar.getEndYear());\r
334                     filteredRules.add(newar);\r
335                 }\r
336                 // Check if this is a final rule\r
337                 if (ar.getEndYear() == AnnualTimeZoneRule.MAX_YEAR) {\r
338                     // After both final standard and dst rule are processed,\r
339                     // exit this while loop.\r
340                     if (ar.getDSTSavings() == 0) {\r
341                         bFinalStd = true;\r
342                     } else {\r
343                         bFinalDst = true;\r
344                     }\r
345                 }\r
346             }\r
347             isProcessed.set(ruleIdx);\r
348         }\r
349         TimeZoneRule[] rules = filteredRules.toArray(new TimeZoneRule[filteredRules.size()]);\r
350         return rules;\r
351     }\r
352 \r
353     /**\r
354      * {@icu} Returns the array of <code>TimeZoneRule</code> which represents the rule of\r
355      * this time zone object near the specified date.  Some applications are not\r
356      * capable to handle historic time zone rule changes.  Also some applications\r
357      * can only handle certain type of rule definitions.  This method returns\r
358      * either a single <code>InitialTimeZoneRule</code> if this time zone does not\r
359      * have any daylight saving time within 1 year from the specified time, or a\r
360      * pair of <code>AnnualTimeZoneRule</code> whose rule type is\r
361      * <code>DateTimeRule.DOW</code> for date and <code>DateTimeRule.WALL_TIME</code>\r
362      * for time with a single <code>InitialTimeZoneRule</code> representing the\r
363      * initial time, when this time zone observes daylight saving time near the\r
364      * specified date.  Thus, the result may be only valid for dates around the\r
365      * specified date.\r
366      *\r
367      * @param date The date to be used for <code>TimeZoneRule</code> extraction.\r
368      * @return The array of <code>TimeZoneRule</code>, either a single\r
369      * <code>InitialTimeZoneRule</code> object, or a pair of <code>AnnualTimeZoneRule</code>\r
370      * with a single <code>InitialTimeZoneRule</code>.  The first element in the\r
371      * array is always a <code>InitialTimeZoneRule</code>.\r
372      *\r
373      * @stable ICU 3.8\r
374      */\r
375     public TimeZoneRule[] getSimpleTimeZoneRulesNear(long date) {\r
376         AnnualTimeZoneRule[] annualRules = null;\r
377         TimeZoneRule initialRule = null;\r
378         // Get the next transition\r
379         TimeZoneTransition tr = getNextTransition(date, false);\r
380         if (tr != null) {\r
381             String initialName = tr.getFrom().getName();\r
382             int initialRaw = tr.getFrom().getRawOffset();\r
383             int initialDst = tr.getFrom().getDSTSavings();\r
384 \r
385             // Check if the next transition is either DST->STD or STD->DST and\r
386             // within roughly 1 year from the specified date\r
387             long nextTransitionTime = tr.getTime();\r
388             if (((tr.getFrom().getDSTSavings() == 0 && tr.getTo().getDSTSavings() != 0)\r
389                     || (tr.getFrom().getDSTSavings() != 0 && tr.getTo().getDSTSavings() == 0))\r
390                         && date + MILLIS_PER_YEAR > nextTransitionTime) {\r
391                 annualRules = new AnnualTimeZoneRule[2];\r
392                 // Get local wall time for the transition time\r
393                 int dtfields[] = Grego.timeToFields(nextTransitionTime\r
394                         + tr.getFrom().getRawOffset() + tr.getFrom().getDSTSavings(), null);\r
395                 int weekInMonth = Grego.getDayOfWeekInMonth(dtfields[0], dtfields[1], dtfields[2]);\r
396                 // Create DOW rule\r
397                 DateTimeRule dtr = new DateTimeRule(dtfields[1], weekInMonth, dtfields[3],\r
398                         dtfields[5], DateTimeRule.WALL_TIME);\r
399 \r
400                 AnnualTimeZoneRule secondRule = null;\r
401 \r
402                 // Note:  SimpleTimeZone does not support raw offset change.\r
403                 // So we always use raw offset of the given time for the rule,\r
404                 // even raw offset is changed.  This will result that the result\r
405                 // zone to return wrong offset after the transition.\r
406                 // When we encounter such case, we do not inspect next next\r
407                 // transition for another rule.\r
408                 annualRules[0] = new AnnualTimeZoneRule(tr.getTo().getName(),\r
409                         initialRaw, tr.getTo().getDSTSavings(),\r
410                         dtr, dtfields[0], AnnualTimeZoneRule.MAX_YEAR);\r
411 \r
412                 if (tr.getTo().getRawOffset() == initialRaw) {\r
413 \r
414                     // Get the next next transition\r
415                     tr = getNextTransition(nextTransitionTime, false);\r
416                     if (tr != null) {\r
417                         // Check if the next next transition is either DST->STD or STD->DST\r
418                         // and within roughly 1 year from the next transition\r
419                         if (((tr.getFrom().getDSTSavings() == 0 && tr.getTo().getDSTSavings() != 0)\r
420                                 || (tr.getFrom().getDSTSavings() != 0 \r
421                                     && tr.getTo().getDSTSavings() == 0))\r
422                             && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) {\r
423                             // Generate another DOW rule\r
424                             dtfields = Grego.timeToFields(tr.getTime()\r
425                                     + tr.getFrom().getRawOffset() + tr.getFrom().getDSTSavings(), \r
426                                                           dtfields);\r
427                             weekInMonth = Grego.getDayOfWeekInMonth(dtfields[0], dtfields[1], \r
428                                                                     dtfields[2]);\r
429                             dtr = new DateTimeRule(dtfields[1], weekInMonth, dtfields[3], \r
430                                                    dtfields[5], DateTimeRule.WALL_TIME);\r
431                             secondRule = new AnnualTimeZoneRule(tr.getTo().getName(),\r
432                                     tr.getTo().getRawOffset(), tr.getTo().getDSTSavings(),\r
433                                     dtr, dtfields[0] - 1, AnnualTimeZoneRule.MAX_YEAR);\r
434                             // Make sure this rule can be applied to the specified date\r
435                             Date d = secondRule.getPreviousStart(date, tr.getFrom().getRawOffset(),\r
436                                     tr.getFrom().getDSTSavings(), true);\r
437                             if (d != null && d.getTime() <= date\r
438                                     && initialRaw == tr.getTo().getRawOffset()\r
439                                     && initialDst == tr.getTo().getDSTSavings()) {\r
440                                 // We can use this rule as the second transition rule\r
441                                 annualRules[1] = secondRule;\r
442                             }\r
443                         }\r
444                     }\r
445                 }\r
446 \r
447                 if (annualRules[1] == null) {\r
448                     // Try previous transition\r
449                     tr = getPreviousTransition(date, true);\r
450                     if (tr != null) {\r
451                         // Check if the previous transition is either DST->STD or STD->DST.\r
452                         // The actual transition time does not matter here.\r
453                         if ((tr.getFrom().getDSTSavings() == 0 && tr.getTo().getDSTSavings() != 0)\r
454                                 || (tr.getFrom().getDSTSavings() != 0\r
455                                     && tr.getTo().getDSTSavings() == 0)) {\r
456                             // Generate another DOW rule\r
457                             dtfields = Grego.timeToFields(tr.getTime()\r
458                                     + tr.getFrom().getRawOffset() + tr.getFrom().getDSTSavings(), \r
459                                                           dtfields);\r
460                             weekInMonth = Grego.getDayOfWeekInMonth(dtfields[0], dtfields[1], \r
461                                                                     dtfields[2]);\r
462                             dtr = new DateTimeRule(dtfields[1], weekInMonth, dtfields[3], \r
463                                                    dtfields[5], DateTimeRule.WALL_TIME);\r
464 \r
465                             // second rule raw/dst offsets should match raw/dst offsets\r
466                             // at the given time\r
467                             secondRule = new AnnualTimeZoneRule(\r
468                                 tr.getTo().getName(), initialRaw, initialDst, dtr, \r
469                                 annualRules[0].getStartYear() - 1, AnnualTimeZoneRule.MAX_YEAR);\r
470 \r
471                             // Check if this rule start after the first rule after the\r
472                             // specified date\r
473                             Date d = secondRule.getNextStart(date, tr.getFrom().getRawOffset(), \r
474                                                              tr.getFrom().getDSTSavings(), false);\r
475                             if (d.getTime() > nextTransitionTime) {\r
476                                 // We can use this rule as the second transition rule\r
477                                 annualRules[1] = secondRule;\r
478                             }\r
479                         }\r
480                     }\r
481                 }\r
482                 if (annualRules[1] == null) {\r
483                     // Cannot generate a good pair of AnnualTimeZoneRule\r
484                     annualRules = null;\r
485                 } else {\r
486                     // The initial rule should represent the rule before the previous transition\r
487                     initialName = annualRules[0].getName();\r
488                     initialRaw = annualRules[0].getRawOffset();\r
489                     initialDst = annualRules[0].getDSTSavings();\r
490                 }\r
491             }\r
492             initialRule = new InitialTimeZoneRule(initialName, initialRaw, initialDst);\r
493         } else {\r
494             // Try the previous one\r
495             tr = getPreviousTransition(date, true);\r
496             if (tr != null) {\r
497                 initialRule = new InitialTimeZoneRule(tr.getTo().getName(),\r
498                         tr.getTo().getRawOffset(), tr.getTo().getDSTSavings());\r
499             } else {\r
500                 // No transitions in the past.  Just use the current offsets\r
501                 int[] offsets = new int[2];\r
502                 getOffset(date, false, offsets);\r
503                 initialRule = new InitialTimeZoneRule(getID(), offsets[0], offsets[1]);\r
504             }\r
505         }\r
506 \r
507         TimeZoneRule[] result = null;\r
508         if (annualRules == null) {\r
509             result = new TimeZoneRule[1];\r
510             result[0] = initialRule;\r
511         } else {\r
512             result = new TimeZoneRule[3];\r
513             result[0] = initialRule;\r
514             result[1] = annualRules[0];\r
515             result[2] = annualRules[1];\r
516         }\r
517 \r
518         return result;\r
519     }\r
520 \r
521     /**\r
522      * {@icu} The time type option for standard time used by\r
523      * {@link #getOffsetFromLocal(long, int, int, int[])}\r
524      * @internal\r
525      * @deprecated This API is ICU internal only.\r
526      */\r
527     public static final int LOCAL_STD = 0x01;\r
528 \r
529     /**\r
530      * {@icu} The time type option for daylight saving time used by\r
531      * {@link #getOffsetFromLocal(long, int, int, int[])}\r
532      * @internal\r
533      * @deprecated This API is ICU internal only.\r
534      */\r
535     public static final int LOCAL_DST = 0x03;\r
536 \r
537     /**\r
538      * {@icu} The option designate former time to be used by\r
539      * {@link #getOffsetFromLocal(long, int, int, int[])}\r
540      * @internal\r
541      * @deprecated This API is ICU internal only.\r
542      */\r
543     public static final int LOCAL_FORMER = 0x04;\r
544 \r
545     /**\r
546      * {@icu} The option designate latter time to be used by\r
547      * {@link #getOffsetFromLocal(long, int, int, int[])}\r
548      * @internal\r
549      * @deprecated This API is ICU internal only.\r
550      */\r
551     public static final int LOCAL_LATTER = 0x0C;\r
552 \r
553     /**\r
554      * {@icu} The bit mask for the time type option used by\r
555      * {@link #getOffsetFromLocal(long, int, int, int[])}\r
556      * @internal\r
557      * @deprecated This API is ICU internal only.\r
558      */\r
559     protected static final int STD_DST_MASK = 0x03;\r
560 \r
561     /**\r
562      * {@icu} The bit mask for the former/latter option used by\r
563      * {@link #getOffsetFromLocal(long, int, int, int[])}\r
564      * @internal\r
565      * @deprecated This API is ICU internal only.\r
566      */\r
567     protected static final int FORMER_LATTER_MASK = 0x0C;\r
568 \r
569     /**\r
570      * {@icu} Returns time zone offsets from local wall time.\r
571      * @internal\r
572      * @deprecated This API is ICU internal only.\r
573      */\r
574     public void getOffsetFromLocal(long date,\r
575             int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) {\r
576         throw new IllegalStateException("Not implemented");\r
577     }\r
578 \r
579     /**\r
580      * Protected no arg constructor.\r
581      * @stable ICU 3.8\r
582      */\r
583     protected BasicTimeZone() {\r
584     }\r
585 }\r