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