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