TimeZoneInfo.java revision b1b7080deea42aa533c3757b585cf765c6b76732
1b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan/*
2b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * Copyright (C) 2013 The Android Open Source Project
3b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *
4b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * Licensed under the Apache License, Version 2.0 (the "License");
5b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * you may not use this file except in compliance with the License.
6b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * You may obtain a copy of the License at
7b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *
8b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *      http://www.apache.org/licenses/LICENSE-2.0
9b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *
10b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * Unless required by applicable law or agreed to in writing, software
11b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * distributed under the License is distributed on an "AS IS" BASIS,
12b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * See the License for the specific language governing permissions and
14b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * limitations under the License.
15b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan */
16b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
17b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanpackage com.android.timezonepicker;
18b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
19b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.content.Context;
20b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.text.format.DateUtils;
21b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.text.format.Time;
22b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.util.Log;
23b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.util.SparseArray;
24b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
25b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.lang.reflect.Field;
26b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.text.DateFormat;
27b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.Arrays;
28b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.Date;
29b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.Formatter;
30b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.Locale;
31b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.TimeZone;
32b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
33b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanpublic class TimeZoneInfo implements Comparable<TimeZoneInfo> {
34b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final char SEPARATOR = ',';
35b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final String TAG = null;
36b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public static int NUM_OF_TRANSITIONS = 6;
37b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public static long time = System.currentTimeMillis() / 1000;
38b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public static boolean is24HourFormat;
39b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
40b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    TimeZone mTz;
41b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public String mTzId;
42b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    int mRawoffset;
43b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int[] mTransitions; // may have trailing 0's.
44b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public String mCountry;
45b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int groupId;
46b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private boolean hasDst;
47b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public String mDisplayName;
48b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private Time recycledTime = new Time();
49b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static StringBuilder mSB = new StringBuilder(50);
50b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static Formatter mFormatter = new Formatter(mSB, Locale.getDefault());
51b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
52b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public TimeZoneInfo(TimeZone tz, String country) {
53b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTz = tz;
54b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTzId = tz.getID();
55b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mCountry = country;
56b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mRawoffset = tz.getRawOffset();
57b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        hasDst = tz.useDaylightTime();
58b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
59b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        try {
60b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mTransitions = getTransitions(tz, time);
61b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } catch (NoSuchFieldException ignored) {
62b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } catch (IllegalAccessException ignored) {
63b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            ignored.printStackTrace();
64b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
65b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
66b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
67b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    SparseArray<String> mLocalTimeCache = new SparseArray<String>();
68b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    long mLocalTimeCacheReferenceTime = 0;
69b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    static private long mGmtDisplayNameUpdateTime;
70b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    static private SparseArray<String> mGmtDisplayNameCache = new SparseArray<String>();
71b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
72b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public String getLocalTime(long referenceTime) {
73b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        recycledTime.timezone = TimeZone.getDefault().getID();
74b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        recycledTime.set(referenceTime);
75b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
76b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int currYearDay = recycledTime.year * 366 + recycledTime.yearDay;
77b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
78b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        recycledTime.timezone = mTzId;
79b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        recycledTime.set(referenceTime);
80b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
81b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        String localTimeStr = null;
82b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
83b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int hourMinute = recycledTime.hour * 60 +
84b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                recycledTime.minute;
85b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
86b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (mLocalTimeCacheReferenceTime != referenceTime) {
87b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mLocalTimeCacheReferenceTime = referenceTime;
88b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mLocalTimeCache.clear();
89b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } else {
90b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            localTimeStr = mLocalTimeCache.get(hourMinute);
91b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
92b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
93b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (localTimeStr == null) {
94b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            String format = "%I:%M %p";
95b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (currYearDay != (recycledTime.year * 366 + recycledTime.yearDay)) {
96b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (is24HourFormat) {
97b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    format = "%b %d %H:%M";
98b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                } else {
99b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    format = "%b %d %I:%M %p";
100b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
101b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            } else if (is24HourFormat) {
102b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                format = "%H:%M";
103b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
104b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
105b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // format = "%Y-%m-%d %H:%M";
106b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            localTimeStr = recycledTime.format(format);
107b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mLocalTimeCache.put(hourMinute, localTimeStr);
108b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
109b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
110b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return localTimeStr;
111b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
112b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
113b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int getLocalHr(long referenceTime) {
114b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        recycledTime.timezone = TimeZone.getDefault().getID();
115b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        recycledTime.set(referenceTime);
116b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return recycledTime.hour;
117b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
118b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
119b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int getNowOffsetMillis() {
120b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mTz.getOffset(System.currentTimeMillis());
121b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
122b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
123b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    /*
124b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * The method is synchronized because there's one mSB, which is used by
125b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * mFormatter, per instance. If there are multiple callers for
126b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * getGmtDisplayName, the output may be mangled.
127b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     */
128b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public synchronized String getGmtDisplayName(Context context) {
129b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // TODO Note: The local time is shown in current time (current GMT
130b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // offset) which may be different from the time specified by
131b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // mTimeMillis
132b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
133b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        final long nowMinute = System.currentTimeMillis() / DateUtils.MINUTE_IN_MILLIS;
134b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        final long now = nowMinute * DateUtils.MINUTE_IN_MILLIS;
135b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        final int gmtOffset = mTz.getOffset(now);
136b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int cacheKey;
137b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
138b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        boolean hasFutureDST = mTz.useDaylightTime();
139b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (hasFutureDST) {
140b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            cacheKey = (int) (gmtOffset + 36 * DateUtils.HOUR_IN_MILLIS);
141b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } else {
142b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            cacheKey = (int) (gmtOffset - 36 * DateUtils.HOUR_IN_MILLIS);
143b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
144b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
145b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        String displayName = null;
146b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (mGmtDisplayNameUpdateTime != nowMinute) {
147b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mGmtDisplayNameUpdateTime = nowMinute;
148b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mGmtDisplayNameCache.clear();
149b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } else {
150b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            displayName = mGmtDisplayNameCache.get(cacheKey);
151b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
152b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
153b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (displayName == null) {
154b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mSB.setLength(0);
155b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            int flags = DateUtils.FORMAT_ABBREV_ALL;
156b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            flags |= DateUtils.FORMAT_SHOW_TIME;
157b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (TimeZoneInfo.is24HourFormat) {
158b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                flags |= DateUtils.FORMAT_24HOUR;
159b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
160b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
161b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // mFormatter writes to mSB
162b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            DateUtils.formatDateRange(context, mFormatter, now, now, flags, mTzId);
163b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mSB.append(" (GMT");
164b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
165b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (gmtOffset < 0) {
166b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                mSB.append('-');
167b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            } else {
168b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                mSB.append('+');
169b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
170b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
171b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            final int p = Math.abs(gmtOffset);
172b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mSB.append(p / DateUtils.HOUR_IN_MILLIS); // Hour
173b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
174b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            final int min = (p / 60000) % 60;
175b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (min != 0) { // Show minutes if non-zero
176b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                mSB.append(':');
177b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (min < 10) {
178b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    mSB.append('0');
179b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
180b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                mSB.append(min);
181b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
182b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mSB.append(')');
183b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
184b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (hasFutureDST) {
185b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                mSB.append(" \u2600"); // Sun symbol
186b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
187b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
188b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            displayName = mSB.toString();
189b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mGmtDisplayNameCache.put(cacheKey, displayName);
190b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
191b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return displayName;
192b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
193b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
194b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static int[] getTransitions(TimeZone tz, long time)
195b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            throws IllegalAccessException, NoSuchFieldException {
196b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        Class<?> zoneInfoClass = tz.getClass();
197b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        Field mTransitionsField = zoneInfoClass.getDeclaredField("mTransitions");
198b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTransitionsField.setAccessible(true);
199b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int[] objTransitions = (int[]) mTransitionsField.get(tz);
200b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int[] transitions = null;
201b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (objTransitions.length != 0) {
202b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            transitions = new int[NUM_OF_TRANSITIONS];
203b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            int numOfTransitions = 0;
204b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            for (int i = 0; i < objTransitions.length; ++i) {
205b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (objTransitions[i] < time) {
206b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    continue;
207b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
208b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                transitions[numOfTransitions++] = objTransitions[i];
209b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (numOfTransitions == NUM_OF_TRANSITIONS) {
210b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    break;
211b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
212b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
213b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
214b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return transitions;
215b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
216b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
217b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public boolean hasSameRules(TimeZoneInfo tzi) {
218b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // this.mTz.hasSameRules(tzi.mTz)
219b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
220b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return this.mRawoffset == tzi.mRawoffset
221b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                && Arrays.equals(this.mTransitions, tzi.mTransitions);
222b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
223b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
224b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
225b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public String toString() {
226b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        StringBuilder sb = new StringBuilder();
227b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
228b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        final String country = this.mCountry;
229b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        final TimeZone tz = this.mTz;
230b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
231b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(mTzId);
232b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
233b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(tz.getDisplayName(false /* daylightTime */, TimeZone.LONG));
234b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
235b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(tz.getDisplayName(false /* daylightTime */, TimeZone.SHORT));
236b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
237b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (tz.useDaylightTime()) {
238b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            sb.append(tz.getDisplayName(true, TimeZone.LONG));
239b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            sb.append(SEPARATOR);
240b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            sb.append(tz.getDisplayName(true, TimeZone.SHORT));
241b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } else {
242b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            sb.append(SEPARATOR);
243b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
244b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
245b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(tz.getRawOffset() / 3600000f);
246b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
247b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(tz.getDSTSavings() / 3600000f);
248b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
249b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(country);
250b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
251b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
252b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // 1-1-2013 noon GMT
253b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(getLocalTime(1357041600000L));
254b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
255b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
256b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // 3-15-2013 noon GMT
257b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(getLocalTime(1363348800000L));
258b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
259b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
260b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // 7-1-2013 noon GMT
261b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(getLocalTime(1372680000000L));
262b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
263b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
264b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // 11-01-2013 noon GMT
265b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(getLocalTime(1383307200000L));
266b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append(SEPARATOR);
267b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
268b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // if (this.mTransitions != null && this.mTransitions.length != 0) {
269b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // sb.append('"');
270b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // DateFormat df = new SimpleDateFormat("yyyy-MM-dd' 'HH:mm:ss Z",
271b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // Locale.US);
272b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // df.setTimeZone(tz);
273b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // DateFormat weekdayFormat = new SimpleDateFormat("EEEE", Locale.US);
274b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // weekdayFormat.setTimeZone(tz);
275b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // Formatter f = new Formatter(sb);
276b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // for (int i = 0; i < this.mTransitions.length; ++i) {
277b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // if (this.mTransitions[i] < time) {
278b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // continue;
279b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // }
280b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        //
281b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // String fromTime = formatTime(df, this.mTransitions[i] - 1);
282b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // String toTime = formatTime(df, this.mTransitions[i]);
283b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // f.format("%s -> %s (%d)", fromTime, toTime, this.mTransitions[i]);
284b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        //
285b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // String weekday = weekdayFormat.format(new Date(1000L *
286b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // this.mTransitions[i]));
287b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // if (!weekday.equals("Sunday")) {
288b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // f.format(" -- %s", weekday);
289b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // }
290b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // sb.append("##");
291b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // }
292b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // sb.append('"');
293b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // }
294b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // sb.append(SEPARATOR);
295b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        sb.append('\n');
296b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return sb.toString();
297b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
298b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
299b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static String formatTime(DateFormat df, int s) {
300b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        long ms = s * 1000L;
301b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return df.format(new Date(ms));
302b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
303b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
304b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    /*
305b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * Returns a negative integer if this instance is less than the other; a
306b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * positive integer if this instance is greater than the other; 0 if this
307b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * instance has the same order as the other.
308b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     */
309b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
310b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int compareTo(TimeZoneInfo other) {
311b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
312b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // TODO !!! Should compare the clock time instead of raw offset
313b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
314b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // Higher raw offset comes before i.e. if the offset is bigger, return
315b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // positive number.
316b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (this.mRawoffset != other.mRawoffset) {
317b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            return other.mRawoffset - this.mRawoffset;
318b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
319b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
320b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // TZ with DST comes first because the offset is bigger during DST
321b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // compared to a tz without DST
322b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (this.hasDst != other.hasDst) {
323b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            return this.hasDst ? -1 : 1;
324b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
325b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
326b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // By country
327b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (this.mCountry == null) {
328b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (other.mCountry != null) {
329b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                return 1;
330b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
331b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
332b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
333b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (other.mCountry == null) {
334b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            return -1;
335b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } else {
336b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            int diff = this.mCountry.compareTo(other.mCountry);
337b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
338b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (diff != 0) {
339b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                return diff;
340b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
341b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
342b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
343b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (Arrays.equals(this.mTransitions, other.mTransitions)) {
344b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            Log.e(TAG, "Not expected to be comparing tz with the same country, same offset," +
345b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    " same dst, same transitions:\n" + this.toString() + "\n" + other.toString());
346b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
347b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
348b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // Finally diff by display name
349b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return this.mTz.getDisplayName(Locale.getDefault()).compareTo(
350b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                other.mTz.getDisplayName(Locale.getDefault()));
351b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
352b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan}
353