TimeUtils.java revision 26e1a02ba3183aba2ba262c6f60602e10dd792e3
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.util;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.XmlResourceParser;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2208065b9f09ead8895d97b2971622af8c179e1768Brian Carlstromimport libcore.util.ZoneInfoDB;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
271ebccf531d1049853b3b0630035434619682c016Dianne Hackbornimport java.io.PrintWriter;
28a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Savilleimport java.util.ArrayList;
2926e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Savilleimport java.util.Calendar;
30a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Savilleimport java.util.Collection;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.TimeZone;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Date;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
342269d1572e5fcfb725ea55f5764d8c3280d69f6dDianne Hackbornimport com.android.internal.util.XmlUtils;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A class containing utility methods related to time zones.
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class TimeUtils {
40a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson    /** @hide */ public TimeUtils() {}
41a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    private static final boolean DBG = false;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "TimeUtils";
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
44a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    /** Cached results of getTineZones */
45a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    private static final Object sLastLockObj = new Object();
46a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    private static ArrayList<TimeZone> sLastZones = null;
47a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    private static String sLastCountry = null;
48a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
49a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    /** Cached results of getTimeZonesWithUniqueOffsets */
50a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    private static final Object sLastUniqueLockObj = new Object();
51a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    private static ArrayList<TimeZone> sLastUniqueZoneOffsets = null;
52a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    private static String sLastUniqueCountry = null;
53a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
54a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Tries to return a time zone that would have had the specified offset
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and DST value at the specified moment in the specified country.
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if no suitable zone could be found.
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) {
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TimeZone best = null;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Resources r = Resources.getSystem();
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country);
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Date d = new Date(when);
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TimeZone current = TimeZone.getDefault();
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String currentName = current.getID();
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int currentOffset = current.getOffset(when);
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean currentDst = current.inDaylightTime(d);
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
72a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        for (TimeZone tz : getTimeZones(country)) {
73a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // If the current time zone is from the right country
74a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // and meets the other known properties, keep it
75a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // instead of changing to another one.
76a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
77a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            if (tz.getID().equals(currentName)) {
78a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                if (currentOffset == offset && currentDst == dst) {
79a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                    return current;
80a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                }
81a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            }
82a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
83a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // Otherwise, take the first zone from the right
84a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // country that has the correct current offset and DST.
85a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // (Keep iterating instead of returning in case we
86a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // haven't encountered the current time zone yet.)
87a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
88a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            if (best == null) {
89a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                if (tz.getOffset(when) == offset &&
90a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                    tz.inDaylightTime(d) == dst) {
91a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                    best = tz;
92a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                }
93a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            }
94a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        }
95a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
96a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        return best;
97a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    }
98a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
99a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    /**
100a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     * Return list of unique time zones for the country. Do not modify
101a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     *
102a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     * @param country to find
103a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     * @return list of unique time zones, maybe empty but never null. Do not modify.
104a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     * @hide
105a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     */
106a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    public static ArrayList<TimeZone> getTimeZonesWithUniqueOffsets(String country) {
107a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        synchronized(sLastUniqueLockObj) {
108a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            if ((country != null) && country.equals(sLastUniqueCountry)) {
109a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                if (DBG) {
110a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                    Log.d(TAG, "getTimeZonesWithUniqueOffsets(" +
111a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                            country + "): return cached version");
112a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                }
113a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                return sLastUniqueZoneOffsets;
114a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            }
115a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        }
116a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
117a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        Collection<TimeZone> zones = getTimeZones(country);
118a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        ArrayList<TimeZone> uniqueTimeZones = new ArrayList<TimeZone>();
119a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        for (TimeZone zone : zones) {
120a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // See if we already have this offset,
121a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // Using slow but space efficient and these are small.
122a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            boolean found = false;
123a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            for (int i = 0; i < uniqueTimeZones.size(); i++) {
124a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                if (uniqueTimeZones.get(i).getRawOffset() == zone.getRawOffset()) {
125a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                    found = true;
126a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                    break;
127a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                }
128a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            }
129a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            if (found == false) {
130a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                if (DBG) {
131a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                    Log.d(TAG, "getTimeZonesWithUniqueOffsets: add unique offset=" +
132a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                            zone.getRawOffset() + " zone.getID=" + zone.getID());
133a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                }
134a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                uniqueTimeZones.add(zone);
135a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            }
136a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        }
137a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
138a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        synchronized(sLastUniqueLockObj) {
139a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // Cache the last result
140a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            sLastUniqueZoneOffsets = uniqueTimeZones;
141a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            sLastUniqueCountry = country;
142a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
143a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            return sLastUniqueZoneOffsets;
144a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        }
145a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    }
146a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
147a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    /**
148a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     * Returns the time zones for the country, which is the code
149a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     * attribute of the timezone element in time_zones_by_country.xml. Do not modify.
150a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     *
151a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     * @param country is a two character country code.
152a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     * @return TimeZone list, maybe empty but never null. Do not modify.
153a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     * @hide
154a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville     */
155a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville    public static ArrayList<TimeZone> getTimeZones(String country) {
156a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        synchronized (sLastLockObj) {
157a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            if ((country != null) && country.equals(sLastCountry)) {
158a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                if (DBG) Log.d(TAG, "getTimeZones(" + country + "): return cached version");
159a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                return sLastZones;
160a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            }
161a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        }
162a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
163a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        ArrayList<TimeZone> tzs = new ArrayList<TimeZone>();
164a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
165a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        if (country == null) {
166a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            if (DBG) Log.d(TAG, "getTimeZones(null): return empty list");
167a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            return tzs;
168a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        }
169a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
170a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        Resources r = Resources.getSystem();
171a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country);
172a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            XmlUtils.beginDocument(parser, "timezones");
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (true) {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                XmlUtils.nextElement(parser);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String element = parser.getName();
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (element == null || !(element.equals("timezone"))) {
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String code = parser.getAttributeValue(null, "code");
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (country.equals(code)) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (parser.next() == XmlPullParser.TEXT) {
188a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                        String zoneIdString = parser.getText();
189a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                        TimeZone tz = TimeZone.getTimeZone(zoneIdString);
190a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                        if (tz.getID().startsWith("GMT") == false) {
191a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                            // tz.getID doesn't start not "GMT" so its valid
192a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                            tzs.add(tz);
193a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                            if (DBG) {
194a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                                Log.d(TAG, "getTimeZone('" + country + "'): found tz.getID=="
195a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville                                    + ((tz != null) ? tz.getID() : "<no tz>"));
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (XmlPullParserException e) {
202a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            Log.e(TAG, "Got xml parser exception getTimeZone('" + country + "'): e=", e);
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
204a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            Log.e(TAG, "Got IO exception getTimeZone('" + country + "'): e=", e);
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            parser.close();
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
209a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        synchronized(sLastLockObj) {
210a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            // Cache the last result;
211a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            sLastZones = tzs;
212a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            sLastCountry = country;
213a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville            return sLastZones;
214a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville        }
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns a String indicating the version of the time zone database currently
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in use.  The format of the string is dependent on the underlying time zone
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * database implementation, but will typically contain the year in which the database
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * was updated plus a letter from a to z indicating changes made within that year.
222a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson     *
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Time zone database updates should be expected to occur periodically due to
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * political and legal changes that cannot be anticipated in advance.  Therefore,
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * when computing the UTC time for a future event, applications should be aware that
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the results may differ following a time zone database update.  This method allows
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * applications to detect that a database change has occurred, and to recalculate any
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * cached times accordingly.
229a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson     *
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>The time zone database may be assumed to change only when the device runtime
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is restarted.  Therefore, it is not necessary to re-query the database version
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * during the lifetime of an activity.
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String getTimeZoneDatabaseVersion() {
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ZoneInfoDB.getVersion();
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2371ebccf531d1049853b3b0630035434619682c016Dianne Hackborn
238b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    /** @hide Field length that can hold 999 days of time */
239b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    public static final int HUNDRED_DAY_FIELD_LEN = 19;
240a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
2411ebccf531d1049853b3b0630035434619682c016Dianne Hackborn    private static final int SECONDS_PER_MINUTE = 60;
2421ebccf531d1049853b3b0630035434619682c016Dianne Hackborn    private static final int SECONDS_PER_HOUR = 60 * 60;
2431ebccf531d1049853b3b0630035434619682c016Dianne Hackborn    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
2441ebccf531d1049853b3b0630035434619682c016Dianne Hackborn
245b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    private static final Object sFormatSync = new Object();
246b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5];
247a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
248b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    static private int accumField(int amt, int suffix, boolean always, int zeropad) {
249b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        if (amt > 99 || (always && zeropad >= 3)) {
250b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            return 3+suffix;
2511ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
252b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        if (amt > 9 || (always && zeropad >= 2)) {
253b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            return 2+suffix;
2541ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
255b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        if (always || amt > 0) {
256b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            return 1+suffix;
2571ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
258b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        return 0;
259b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    }
260a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
261b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    static private int printField(char[] formatStr, int amt, char suffix, int pos,
262b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            boolean always, int zeropad) {
263b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        if (always || amt > 0) {
264901b3796fd0954cc4b01bf95dbcbd88d87414e84Bjorn Bringert            final int startPos = pos;
265b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            if ((always && zeropad >= 3) || amt > 99) {
266b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                int dig = amt/100;
267b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                formatStr[pos] = (char)(dig + '0');
268b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                pos++;
269b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                amt -= (dig*100);
270b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            }
271901b3796fd0954cc4b01bf95dbcbd88d87414e84Bjorn Bringert            if ((always && zeropad >= 2) || amt > 9 || startPos != pos) {
272b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                int dig = amt/10;
273b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                formatStr[pos] = (char)(dig + '0');
274b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                pos++;
275b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                amt -= (dig*10);
276b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            }
277b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            formatStr[pos] = (char)(amt + '0');
278b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            pos++;
279b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            formatStr[pos] = suffix;
280b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            pos++;
2811ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
282b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        return pos;
2831ebccf531d1049853b3b0630035434619682c016Dianne Hackborn    }
284a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
285b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    private static int formatDurationLocked(long duration, int fieldLen) {
286b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        if (sFormatStr.length < fieldLen) {
287b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            sFormatStr = new char[fieldLen];
288b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        }
289a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
290b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        char[] formatStr = sFormatStr;
291a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
2921ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        if (duration == 0) {
293b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            int pos = 0;
294b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            fieldLen -= 1;
295b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            while (pos < fieldLen) {
29647f13e7c52b260858bab42217d2101741ea8bc46Jozef BABJAK                formatStr[pos++] = ' ';
297b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            }
298b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            formatStr[pos] = '0';
299b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            return pos+1;
3001ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
301a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
302b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        char prefix;
3031ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        if (duration > 0) {
304b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            prefix = '+';
3051ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        } else {
306b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            prefix = '-';
3071ebccf531d1049853b3b0630035434619682c016Dianne Hackborn            duration = -duration;
3081ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
3091ebccf531d1049853b3b0630035434619682c016Dianne Hackborn
3101ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        int millis = (int)(duration%1000);
3111ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        int seconds = (int) Math.floor(duration / 1000);
3121ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        int days = 0, hours = 0, minutes = 0;
3131ebccf531d1049853b3b0630035434619682c016Dianne Hackborn
3141ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        if (seconds > SECONDS_PER_DAY) {
3151ebccf531d1049853b3b0630035434619682c016Dianne Hackborn            days = seconds / SECONDS_PER_DAY;
3161ebccf531d1049853b3b0630035434619682c016Dianne Hackborn            seconds -= days * SECONDS_PER_DAY;
3171ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
3181ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        if (seconds > SECONDS_PER_HOUR) {
3191ebccf531d1049853b3b0630035434619682c016Dianne Hackborn            hours = seconds / SECONDS_PER_HOUR;
3201ebccf531d1049853b3b0630035434619682c016Dianne Hackborn            seconds -= hours * SECONDS_PER_HOUR;
3211ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
3221ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        if (seconds > SECONDS_PER_MINUTE) {
3231ebccf531d1049853b3b0630035434619682c016Dianne Hackborn            minutes = seconds / SECONDS_PER_MINUTE;
3241ebccf531d1049853b3b0630035434619682c016Dianne Hackborn            seconds -= minutes * SECONDS_PER_MINUTE;
3251ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
3261ebccf531d1049853b3b0630035434619682c016Dianne Hackborn
327b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        int pos = 0;
328a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
329b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        if (fieldLen != 0) {
330b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            int myLen = accumField(days, 1, false, 0);
331b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            myLen += accumField(hours, 1, myLen > 0, 2);
332b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            myLen += accumField(minutes, 1, myLen > 0, 2);
333b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            myLen += accumField(seconds, 1, myLen > 0, 2);
334b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            myLen += accumField(millis, 2, true, myLen > 0 ? 3 : 0) + 1;
335b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            while (myLen < fieldLen) {
336b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                formatStr[pos] = ' ';
337b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                pos++;
338b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn                myLen++;
339b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            }
3401ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
341a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
342b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        formatStr[pos] = prefix;
343b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        pos++;
344a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
345b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        int start = pos;
346b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        boolean zeropad = fieldLen != 0;
347b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        pos = printField(formatStr, days, 'd', pos, false, 0);
348b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        pos = printField(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0);
349b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        pos = printField(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0);
350b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        pos = printField(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0);
351b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        pos = printField(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0);
352b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        formatStr[pos] = 's';
353b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        return pos + 1;
354b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    }
355a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
356b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    /** @hide Just for debugging; not internationalized. */
357b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    public static void formatDuration(long duration, StringBuilder builder) {
358b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        synchronized (sFormatSync) {
359b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            int len = formatDurationLocked(duration, 0);
360b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            builder.append(sFormatStr, 0, len);
3611ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
3621ebccf531d1049853b3b0630035434619682c016Dianne Hackborn    }
3631ebccf531d1049853b3b0630035434619682c016Dianne Hackborn
364b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    /** @hide Just for debugging; not internationalized. */
365b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    public static void formatDuration(long duration, PrintWriter pw, int fieldLen) {
366b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        synchronized (sFormatSync) {
367b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            int len = formatDurationLocked(duration, fieldLen);
368b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn            pw.print(new String(sFormatStr, 0, len));
369b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        }
370b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    }
3711ebccf531d1049853b3b0630035434619682c016Dianne Hackborn
3721ebccf531d1049853b3b0630035434619682c016Dianne Hackborn    /** @hide Just for debugging; not internationalized. */
373b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    public static void formatDuration(long duration, PrintWriter pw) {
374b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        formatDuration(duration, pw, 0);
375b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    }
376a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
377b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn    /** @hide Just for debugging; not internationalized. */
3781ebccf531d1049853b3b0630035434619682c016Dianne Hackborn    public static void formatDuration(long time, long now, PrintWriter pw) {
3791ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        if (time == 0) {
3801ebccf531d1049853b3b0630035434619682c016Dianne Hackborn            pw.print("--");
3811ebccf531d1049853b3b0630035434619682c016Dianne Hackborn            return;
3821ebccf531d1049853b3b0630035434619682c016Dianne Hackborn        }
383b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn        formatDuration(time-now, pw, 0);
3841ebccf531d1049853b3b0630035434619682c016Dianne Hackborn    }
38526e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville
38626e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville    /**
38726e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville     * Convert a System.currentTimeMillis() value to a time of day value like
38826e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville     * that printed in logs. MM-DD HH:MM:SS.MMM
38926e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville     *
39026e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville     * @param millis since the epoch (1/1/1970)
39126e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville     * @return String representation of the time.
39226e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville     * @hide
39326e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville     */
39426e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville    public static String logTimeOfDay(long millis) {
39526e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville        Calendar c = Calendar.getInstance();
39626e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville        if (millis >= 0) {
39726e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville            c.setTimeInMillis(millis);
39826e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville            return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c);
39926e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville        } else {
40026e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville            return Long.toString(millis);
40126e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville        }
40226e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville    }
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
404