1d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes/*
2d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * Copyright (C) 2007 The Android Open Source Project
3d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes *
4d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * you may not use this file except in compliance with the License.
6d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * You may obtain a copy of the License at
7d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes *
8d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes *
10d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * Unless required by applicable law or agreed to in writing, software
11d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * See the License for the specific language governing permissions and
14d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * limitations under the License.
15d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes */
16d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
17d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughesimport java.io.IOException;
18d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughesimport java.util.Arrays;
19d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughesimport java.util.Date;
20d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughesimport java.util.TimeZone;
21d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
22d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes/**
23d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * Copied from ZoneInfo and ZoneInfoDB in dalvik.
24d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes * {@hide}
25d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes */
26d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughespublic class ZoneInfo extends TimeZone {
27d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
28d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private static final long MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
29d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private static final long MILLISECONDS_PER_400_YEARS =
30d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        MILLISECONDS_PER_DAY * (400 * 365 + 100 - 3);
31d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
32d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private static final long UNIX_OFFSET = 62167219200000L;
33d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
34d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private static final int[] NORMAL = new int[] {
35d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
36d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    };
37d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
38d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private static final int[] LEAP = new int[] {
39d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335,
40d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    };
41d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
42d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private static String nullName(byte[] data, int where, int off) {
43d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (off < 0)
44d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            return null;
45d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
46d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int end = where + off;
47d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        while (end < data.length && data[end] != '\0')
48d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            end++;
49d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
50d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return new String(data, where + off, end - (where + off));
51d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
52d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
53d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    public static ZoneInfo make(String name, byte[] data) {
54d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int ntransition = read4(data, 32);
55d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int ngmtoff = read4(data, 36);
56d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int base = 44;
57d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
58d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int[] transitions = new int[ntransition];
59d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        for (int i = 0; i < ntransition; i++)
60d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            transitions[i] = read4(data, base + 4 * i);
61d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        base += 4 * ntransition;
62d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
63d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        byte[] type = new byte[ntransition];
64d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        for (int i = 0; i < ntransition; i++)
65d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            type[i] = data[base + i];
66d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        base += ntransition;
67d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
68d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int[] gmtoff = new int[ngmtoff];
69d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        byte[] isdst = new byte[ngmtoff];
70d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        byte[] abbrev = new byte[ngmtoff];
71d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        for (int i = 0; i < ngmtoff; i++) {
72d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            gmtoff[i] = read4(data, base + 6 * i);
73d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            isdst[i] = data[base + 6 * i + 4];
74d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            abbrev[i] = data[base + 6 * i + 5];
75d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
76d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
77d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        base += 6 * ngmtoff;
78d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
79d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return new ZoneInfo(name, transitions, type, gmtoff, isdst, abbrev, data, base);
80d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
81d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
82d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private static int read4(byte[] data, int off) {
83d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return ((data[off    ] & 0xFF) << 24) |
84d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes               ((data[off + 1] & 0xFF) << 16) |
85d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes               ((data[off + 2] & 0xFF) <<  8) |
86d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes               ((data[off + 3] & 0xFF) <<  0);
87d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
88d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
89d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    /*package*/ ZoneInfo(String name, int[] transitions, byte[] type,
90d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                     int[] gmtoff, byte[] isdst, byte[] abbrev,
91d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                     byte[] data, int abbrevoff) {
92d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        mTransitions = transitions;
93d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        mTypes = type;
94d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        mGmtOffs = gmtoff;
95d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        mIsDsts = isdst;
96d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        mUseDst = false;
97d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        setID(name);
98d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
99d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        // Find the latest GMT and non-GMT offsets for their abbreviations
100d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
101d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int lastdst;
102d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        for (lastdst = mTransitions.length - 1; lastdst >= 0; lastdst--) {
103d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            if (mIsDsts[mTypes[lastdst] & 0xFF] != 0)
104d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                break;
105d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
106d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
107d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int laststd;
108d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        for (laststd = mTransitions.length - 1; laststd >= 0; laststd--) {
109d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            if (mIsDsts[mTypes[laststd] & 0xFF] == 0)
110d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                break;
111d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
112d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
113d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (lastdst >= 0) {
114d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            mDaylightName = nullName(data, abbrevoff,
115d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                                     abbrev[mTypes[lastdst] & 0xFF]);
116d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
117d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (laststd >= 0) {
118d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            mStandardName = nullName(data, abbrevoff,
119d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                                     abbrev[mTypes[laststd] & 0xFF]);
120d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
121d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
122d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        // Use the latest non-DST offset if any as the raw offset
123d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
124d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (laststd < 0) {
125d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            laststd = 0;
126d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
127d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
128d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (laststd >= mTypes.length) {
129d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            mRawOffset = mGmtOffs[0];
130d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        } else {
131d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            mRawOffset = mGmtOffs[mTypes[laststd] & 0xFF];
132d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
133d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
134d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        // Subtract the raw offset from all offsets so it can be changed
135d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        // and affect them too.
136d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        // Find whether there exist any observances of DST.
137d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
138d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        for (int i = 0; i < mGmtOffs.length; i++) {
139d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            mGmtOffs[i] -= mRawOffset;
140d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
141d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            if (mIsDsts[i] != 0) {
142d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                mUseDst = true;
143d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            }
144d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
145d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
146d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        mRawOffset *= 1000;
147d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
148d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
149d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    @Override
150d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    public int getOffset(@SuppressWarnings("unused") int era,
151d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int year, int month, int day,
152d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        @SuppressWarnings("unused") int dayOfWeek,
153d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int millis) {
154d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        // XXX This assumes Gregorian always; Calendar switches from
155d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        // Julian to Gregorian in 1582.  What calendar system are the
156d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        // arguments supposed to come from?
157d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
158d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        long calc = (year / 400) * MILLISECONDS_PER_400_YEARS;
159d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        year %= 400;
160d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
161d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        calc += year * (365 * MILLISECONDS_PER_DAY);
162d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        calc += ((year + 3) / 4) * MILLISECONDS_PER_DAY;
163d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
164d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (year > 0)
165d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            calc -= ((year - 1) / 100) * MILLISECONDS_PER_DAY;
166d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
167d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        boolean isLeap = (year == 0 || (year % 4 == 0 && year % 100 != 0));
168d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int[] mlen = isLeap ? LEAP : NORMAL;
169d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
170d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        calc += mlen[month] * MILLISECONDS_PER_DAY;
171d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        calc += (day - 1) * MILLISECONDS_PER_DAY;
172d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        calc += millis;
173d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
174d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        calc -= mRawOffset;
175d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        calc -= UNIX_OFFSET;
176d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
177d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return getOffset(calc);
178d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
179d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
180d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    @Override
181d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    public int getOffset(long when) {
182d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int unix = (int) (when / 1000);
183d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int trans = Arrays.binarySearch(mTransitions, unix);
184d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
185d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (trans == ~0) {
186d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            return mGmtOffs[0] * 1000 + mRawOffset;
187d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
188d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (trans < 0) {
189d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            trans = ~trans - 1;
190d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
191d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
192d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return mGmtOffs[mTypes[trans] & 0xFF] * 1000 + mRawOffset;
193d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
194d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
195d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    @Override
196d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    public int getRawOffset() {
197d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return mRawOffset;
198d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
199d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
200d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    @Override
201d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    public void setRawOffset(int off) {
202d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        mRawOffset = off;
203d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
204d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
205d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    @Override
206d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    public boolean inDaylightTime(Date when) {
207d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int unix = (int) (when.getTime() / 1000);
208d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int trans = Arrays.binarySearch(mTransitions, unix);
209d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
210d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (trans == ~0) {
211d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            return mIsDsts[0] != 0;
212d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
213d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (trans < 0) {
214d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            trans = ~trans - 1;
215d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
216d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
217d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return mIsDsts[mTypes[trans] & 0xFF] != 0;
218d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
219d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
220d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    @Override
221d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    public boolean useDaylightTime() {
222d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return mUseDst;
223d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
224d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
225d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private int mRawOffset;
226d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private int[] mTransitions;
227d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private int[] mGmtOffs;
228d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private byte[] mTypes;
229d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private byte[] mIsDsts;
230d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private boolean mUseDst;
231d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private String mDaylightName;
232d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    private String mStandardName;
233d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
234d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    @Override
235d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    public boolean equals(Object obj) {
236d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (this == obj) {
237d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes            return true;
238d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
239d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        if (!(obj instanceof ZoneInfo)) {
240d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes           return false;
241d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        }
242d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        ZoneInfo other = (ZoneInfo) obj;
243d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return mUseDst == other.mUseDst
244d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                && (mDaylightName == null ? other.mDaylightName == null :
245d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                        mDaylightName.equals(other.mDaylightName))
246d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                && (mStandardName == null ? other.mStandardName == null :
247d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                        mStandardName.equals(other.mStandardName))
248d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                && mRawOffset == other.mRawOffset
249d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                // Arrays.equals returns true if both arrays are null
250d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                && Arrays.equals(mGmtOffs, other.mGmtOffs)
251d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                && Arrays.equals(mIsDsts, other.mIsDsts)
252d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                && Arrays.equals(mTypes, other.mTypes)
253d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                && Arrays.equals(mTransitions, other.mTransitions);
254d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
255d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes
256d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    @Override
257d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    public int hashCode() {
258d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        final int prime = 31;
259d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        int result = 1;
260d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        result = prime * result + ((mDaylightName == null) ? 0 :
261d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                mDaylightName.hashCode());
262d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        result = prime * result + Arrays.hashCode(mGmtOffs);
263d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        result = prime * result + Arrays.hashCode(mIsDsts);
264d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        result = prime * result + mRawOffset;
265d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        result = prime * result + ((mStandardName == null) ? 0 :
266d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes                mStandardName.hashCode());
267d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        result = prime * result + Arrays.hashCode(mTransitions);
268d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        result = prime * result + Arrays.hashCode(mTypes);
269d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        result = prime * result + (mUseDst ? 1231 : 1237);
270d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes        return result;
271d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes    }
272d40e63ee47e4a7f072a9d9a20e09c26f0090b02cElliott Hughes}
273