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; 219630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.os.SystemClock; 22eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkeyimport android.text.format.DateUtils; 23eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkey 24eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkeyimport com.android.internal.util.XmlUtils; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 301ebccf531d1049853b3b0630035434619682c016Dianne Hackbornimport java.io.PrintWriter; 31a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Savilleimport java.util.ArrayList; 3226e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Savilleimport java.util.Calendar; 33a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Savilleimport java.util.Collection; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Date; 35eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkeyimport java.util.TimeZone; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 37eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkeyimport libcore.util.ZoneInfoDB; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A class containing utility methods related to time zones. 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class TimeUtils { 43a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson /** @hide */ public TimeUtils() {} 44a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville private static final boolean DBG = false; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "TimeUtils"; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 47a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville /** Cached results of getTineZones */ 48a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville private static final Object sLastLockObj = new Object(); 49a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville private static ArrayList<TimeZone> sLastZones = null; 50a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville private static String sLastCountry = null; 51a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 52a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville /** Cached results of getTimeZonesWithUniqueOffsets */ 53a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville private static final Object sLastUniqueLockObj = new Object(); 54a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville private static ArrayList<TimeZone> sLastUniqueZoneOffsets = null; 55a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville private static String sLastUniqueCountry = null; 56a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 57a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Tries to return a time zone that would have had the specified offset 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and DST value at the specified moment in the specified country. 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns null if no suitable zone could be found. 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) { 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TimeZone best = null; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Resources r = Resources.getSystem(); 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country); 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Date d = new Date(when); 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TimeZone current = TimeZone.getDefault(); 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String currentName = current.getID(); 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int currentOffset = current.getOffset(when); 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean currentDst = current.inDaylightTime(d); 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 75a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville for (TimeZone tz : getTimeZones(country)) { 76a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // If the current time zone is from the right country 77a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // and meets the other known properties, keep it 78a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // instead of changing to another one. 79a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 80a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (tz.getID().equals(currentName)) { 81a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (currentOffset == offset && currentDst == dst) { 82a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville return current; 83a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 84a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 85a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 86a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // Otherwise, take the first zone from the right 87a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // country that has the correct current offset and DST. 88a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // (Keep iterating instead of returning in case we 89a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // haven't encountered the current time zone yet.) 90a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 91a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (best == null) { 92a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (tz.getOffset(when) == offset && 93a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville tz.inDaylightTime(d) == dst) { 94a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville best = tz; 95a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 96a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 97a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 98a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 99a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville return best; 100a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 101a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 102a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville /** 103a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * Return list of unique time zones for the country. Do not modify 104a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * 105a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * @param country to find 106a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * @return list of unique time zones, maybe empty but never null. Do not modify. 107a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * @hide 108a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville */ 109a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville public static ArrayList<TimeZone> getTimeZonesWithUniqueOffsets(String country) { 110a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville synchronized(sLastUniqueLockObj) { 111a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if ((country != null) && country.equals(sLastUniqueCountry)) { 112a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (DBG) { 113a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville Log.d(TAG, "getTimeZonesWithUniqueOffsets(" + 114a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville country + "): return cached version"); 115a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 116a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville return sLastUniqueZoneOffsets; 117a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 118a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 119a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 120a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville Collection<TimeZone> zones = getTimeZones(country); 121a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville ArrayList<TimeZone> uniqueTimeZones = new ArrayList<TimeZone>(); 122a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville for (TimeZone zone : zones) { 123a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // See if we already have this offset, 124a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // Using slow but space efficient and these are small. 125a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville boolean found = false; 126a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville for (int i = 0; i < uniqueTimeZones.size(); i++) { 127a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (uniqueTimeZones.get(i).getRawOffset() == zone.getRawOffset()) { 128a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville found = true; 129a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville break; 130a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 131a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 132a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (found == false) { 133a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (DBG) { 134a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville Log.d(TAG, "getTimeZonesWithUniqueOffsets: add unique offset=" + 135a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville zone.getRawOffset() + " zone.getID=" + zone.getID()); 136a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 137a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville uniqueTimeZones.add(zone); 138a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 139a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 140a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 141a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville synchronized(sLastUniqueLockObj) { 142a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // Cache the last result 143a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville sLastUniqueZoneOffsets = uniqueTimeZones; 144a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville sLastUniqueCountry = country; 145a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 146a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville return sLastUniqueZoneOffsets; 147a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 148a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 149a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 150a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville /** 151a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * Returns the time zones for the country, which is the code 152a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * attribute of the timezone element in time_zones_by_country.xml. Do not modify. 153a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * 154a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * @param country is a two character country code. 155a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * @return TimeZone list, maybe empty but never null. Do not modify. 156a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville * @hide 157a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville */ 158a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville public static ArrayList<TimeZone> getTimeZones(String country) { 159a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville synchronized (sLastLockObj) { 160a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if ((country != null) && country.equals(sLastCountry)) { 161a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (DBG) Log.d(TAG, "getTimeZones(" + country + "): return cached version"); 162a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville return sLastZones; 163a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 164a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 165a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 166a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville ArrayList<TimeZone> tzs = new ArrayList<TimeZone>(); 167a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 168a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (country == null) { 169a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (DBG) Log.d(TAG, "getTimeZones(null): return empty list"); 170a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville return tzs; 171a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 172a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 173a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville Resources r = Resources.getSystem(); 174a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country); 175a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project XmlUtils.beginDocument(parser, "timezones"); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (true) { 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project XmlUtils.nextElement(parser); 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String element = parser.getName(); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (element == null || !(element.equals("timezone"))) { 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String code = parser.getAttributeValue(null, "code"); 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (country.equals(code)) { 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (parser.next() == XmlPullParser.TEXT) { 191a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville String zoneIdString = parser.getText(); 192a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville TimeZone tz = TimeZone.getTimeZone(zoneIdString); 193a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (tz.getID().startsWith("GMT") == false) { 194a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // tz.getID doesn't start not "GMT" so its valid 195a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville tzs.add(tz); 196a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville if (DBG) { 197a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville Log.d(TAG, "getTimeZone('" + country + "'): found tz.getID==" 198a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville + ((tz != null) ? tz.getID() : "<no tz>")); 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (XmlPullParserException e) { 205a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville Log.e(TAG, "Got xml parser exception getTimeZone('" + country + "'): e=", e); 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 207a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville Log.e(TAG, "Got IO exception getTimeZone('" + country + "'): e=", e); 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parser.close(); 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 212a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville synchronized(sLastLockObj) { 213a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville // Cache the last result; 214a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville sLastZones = tzs; 215a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville sLastCountry = country; 216a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville return sLastZones; 217a27421a306c49fbe9b3823b30f7ab1cd58b28854Wink Saville } 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns a String indicating the version of the time zone database currently 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in use. The format of the string is dependent on the underlying time zone 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * database implementation, but will typically contain the year in which the database 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * was updated plus a letter from a to z indicating changes made within that year. 225a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson * 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Time zone database updates should be expected to occur periodically due to 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * political and legal changes that cannot be anticipated in advance. Therefore, 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when computing the UTC time for a future event, applications should be aware that 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the results may differ following a time zone database update. This method allows 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * applications to detect that a database change has occurred, and to recalculate any 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cached times accordingly. 232a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson * 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>The time zone database may be assumed to change only when the device runtime 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is restarted. Therefore, it is not necessary to re-query the database version 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * during the lifetime of an activity. 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static String getTimeZoneDatabaseVersion() { 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ZoneInfoDB.getVersion(); 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2401ebccf531d1049853b3b0630035434619682c016Dianne Hackborn 241b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn /** @hide Field length that can hold 999 days of time */ 242b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn public static final int HUNDRED_DAY_FIELD_LEN = 19; 243a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 2441ebccf531d1049853b3b0630035434619682c016Dianne Hackborn private static final int SECONDS_PER_MINUTE = 60; 2451ebccf531d1049853b3b0630035434619682c016Dianne Hackborn private static final int SECONDS_PER_HOUR = 60 * 60; 2461ebccf531d1049853b3b0630035434619682c016Dianne Hackborn private static final int SECONDS_PER_DAY = 24 * 60 * 60; 2471ebccf531d1049853b3b0630035434619682c016Dianne Hackborn 248b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn private static final Object sFormatSync = new Object(); 249b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5]; 250a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 251eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkey private static final long LARGEST_DURATION = (1000 * DateUtils.DAY_IN_MILLIS) - 1; 252eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkey 253b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn static private int accumField(int amt, int suffix, boolean always, int zeropad) { 254b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn if (amt > 99 || (always && zeropad >= 3)) { 255b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn return 3+suffix; 2561ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 257b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn if (amt > 9 || (always && zeropad >= 2)) { 258b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn return 2+suffix; 2591ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 260b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn if (always || amt > 0) { 261b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn return 1+suffix; 2621ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 263b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn return 0; 264b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 265a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 266b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn static private int printField(char[] formatStr, int amt, char suffix, int pos, 267b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn boolean always, int zeropad) { 268b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn if (always || amt > 0) { 269901b3796fd0954cc4b01bf95dbcbd88d87414e84Bjorn Bringert final int startPos = pos; 270b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn if ((always && zeropad >= 3) || amt > 99) { 271b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn int dig = amt/100; 272b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatStr[pos] = (char)(dig + '0'); 273b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos++; 274b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn amt -= (dig*100); 275b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 276901b3796fd0954cc4b01bf95dbcbd88d87414e84Bjorn Bringert if ((always && zeropad >= 2) || amt > 9 || startPos != pos) { 277b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn int dig = amt/10; 278b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatStr[pos] = (char)(dig + '0'); 279b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos++; 280b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn amt -= (dig*10); 281b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 282b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatStr[pos] = (char)(amt + '0'); 283b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos++; 284b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatStr[pos] = suffix; 285b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos++; 2861ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 287b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn return pos; 2881ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 289a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 290b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn private static int formatDurationLocked(long duration, int fieldLen) { 291b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn if (sFormatStr.length < fieldLen) { 292b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn sFormatStr = new char[fieldLen]; 293b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 294a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 295b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn char[] formatStr = sFormatStr; 296a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 2971ebccf531d1049853b3b0630035434619682c016Dianne Hackborn if (duration == 0) { 298b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn int pos = 0; 299b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn fieldLen -= 1; 300b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn while (pos < fieldLen) { 30147f13e7c52b260858bab42217d2101741ea8bc46Jozef BABJAK formatStr[pos++] = ' '; 302b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 303b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatStr[pos] = '0'; 304b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn return pos+1; 3051ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 306a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 307b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn char prefix; 3081ebccf531d1049853b3b0630035434619682c016Dianne Hackborn if (duration > 0) { 309b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn prefix = '+'; 3101ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } else { 311b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn prefix = '-'; 3121ebccf531d1049853b3b0630035434619682c016Dianne Hackborn duration = -duration; 3131ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 3141ebccf531d1049853b3b0630035434619682c016Dianne Hackborn 315eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkey if (duration > LARGEST_DURATION) { 316eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkey duration = LARGEST_DURATION; 317eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkey } 318eaaf396169abdbd213565cacb37dc0c9c391b365Jeff Sharkey 3191ebccf531d1049853b3b0630035434619682c016Dianne Hackborn int millis = (int)(duration%1000); 3201ebccf531d1049853b3b0630035434619682c016Dianne Hackborn int seconds = (int) Math.floor(duration / 1000); 3211ebccf531d1049853b3b0630035434619682c016Dianne Hackborn int days = 0, hours = 0, minutes = 0; 3221ebccf531d1049853b3b0630035434619682c016Dianne Hackborn 3231ebccf531d1049853b3b0630035434619682c016Dianne Hackborn if (seconds > SECONDS_PER_DAY) { 3241ebccf531d1049853b3b0630035434619682c016Dianne Hackborn days = seconds / SECONDS_PER_DAY; 3251ebccf531d1049853b3b0630035434619682c016Dianne Hackborn seconds -= days * SECONDS_PER_DAY; 3261ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 3271ebccf531d1049853b3b0630035434619682c016Dianne Hackborn if (seconds > SECONDS_PER_HOUR) { 3281ebccf531d1049853b3b0630035434619682c016Dianne Hackborn hours = seconds / SECONDS_PER_HOUR; 3291ebccf531d1049853b3b0630035434619682c016Dianne Hackborn seconds -= hours * SECONDS_PER_HOUR; 3301ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 3311ebccf531d1049853b3b0630035434619682c016Dianne Hackborn if (seconds > SECONDS_PER_MINUTE) { 3321ebccf531d1049853b3b0630035434619682c016Dianne Hackborn minutes = seconds / SECONDS_PER_MINUTE; 3331ebccf531d1049853b3b0630035434619682c016Dianne Hackborn seconds -= minutes * SECONDS_PER_MINUTE; 3341ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 3351ebccf531d1049853b3b0630035434619682c016Dianne Hackborn 336b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn int pos = 0; 337a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 338b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn if (fieldLen != 0) { 339b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn int myLen = accumField(days, 1, false, 0); 340b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn myLen += accumField(hours, 1, myLen > 0, 2); 341b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn myLen += accumField(minutes, 1, myLen > 0, 2); 342b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn myLen += accumField(seconds, 1, myLen > 0, 2); 343b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn myLen += accumField(millis, 2, true, myLen > 0 ? 3 : 0) + 1; 344b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn while (myLen < fieldLen) { 345b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatStr[pos] = ' '; 346b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos++; 347b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn myLen++; 348b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 3491ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 350a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 351b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatStr[pos] = prefix; 352b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos++; 353a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 354b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn int start = pos; 355b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn boolean zeropad = fieldLen != 0; 356b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos = printField(formatStr, days, 'd', pos, false, 0); 357b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos = printField(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0); 358b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos = printField(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0); 359b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos = printField(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0); 360b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pos = printField(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0); 361b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatStr[pos] = 's'; 362b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn return pos + 1; 363b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 364a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 365b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn /** @hide Just for debugging; not internationalized. */ 366b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn public static void formatDuration(long duration, StringBuilder builder) { 367b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn synchronized (sFormatSync) { 368b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn int len = formatDurationLocked(duration, 0); 369b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn builder.append(sFormatStr, 0, len); 3701ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 3711ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 3721ebccf531d1049853b3b0630035434619682c016Dianne Hackborn 373b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn /** @hide Just for debugging; not internationalized. */ 374b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn public static void formatDuration(long duration, PrintWriter pw, int fieldLen) { 375b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn synchronized (sFormatSync) { 376b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn int len = formatDurationLocked(duration, fieldLen); 377b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn pw.print(new String(sFormatStr, 0, len)); 378b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 379b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 3801ebccf531d1049853b3b0630035434619682c016Dianne Hackborn 3811ebccf531d1049853b3b0630035434619682c016Dianne Hackborn /** @hide Just for debugging; not internationalized. */ 382b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn public static void formatDuration(long duration, PrintWriter pw) { 383b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatDuration(duration, pw, 0); 384b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn } 385a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson 386b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn /** @hide Just for debugging; not internationalized. */ 3871ebccf531d1049853b3b0630035434619682c016Dianne Hackborn public static void formatDuration(long time, long now, PrintWriter pw) { 3881ebccf531d1049853b3b0630035434619682c016Dianne Hackborn if (time == 0) { 3891ebccf531d1049853b3b0630035434619682c016Dianne Hackborn pw.print("--"); 3901ebccf531d1049853b3b0630035434619682c016Dianne Hackborn return; 3911ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 392b5e3165129a5871cf679a67d9e9323ffad3d4902Dianne Hackborn formatDuration(time-now, pw, 0); 3931ebccf531d1049853b3b0630035434619682c016Dianne Hackborn } 39426e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville 3959630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown /** @hide Just for debugging; not internationalized. */ 3969630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown public static String formatUptime(long time) { 3979630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown final long diff = time - SystemClock.uptimeMillis(); 3989630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown if (diff > 0) { 3999630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown return time + " (in " + diff + " ms)"; 4009630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 4019630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown if (diff < 0) { 4029630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown return time + " (" + -diff + " ms ago)"; 4039630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 4049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown return time + " (now)"; 4059630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 4069630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 40726e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville /** 40826e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville * Convert a System.currentTimeMillis() value to a time of day value like 40926e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville * that printed in logs. MM-DD HH:MM:SS.MMM 41026e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville * 41126e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville * @param millis since the epoch (1/1/1970) 41226e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville * @return String representation of the time. 41326e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville * @hide 41426e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville */ 41526e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville public static String logTimeOfDay(long millis) { 41626e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville Calendar c = Calendar.getInstance(); 41726e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville if (millis >= 0) { 41826e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville c.setTimeInMillis(millis); 41926e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c); 42026e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville } else { 42126e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville return Long.toString(millis); 42226e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville } 42326e1a02ba3183aba2ba262c6f60602e10dd792e3Wink Saville } 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 425