diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 37d675707a84b..2b03ed6c3ae13 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -16,25 +16,17 @@ package android.util; -import android.content.res.Resources; -import android.content.res.XmlResourceParser; import android.os.SystemClock; -import android.text.format.DateUtils; -import com.android.internal.util.XmlUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; +import java.util.Collections; import java.util.Date; -import java.util.TimeZone; - +import java.util.List; +import libcore.util.TimeZoneFinder; import libcore.util.ZoneInfoDB; /** @@ -45,14 +37,9 @@ public class TimeUtils { private static final boolean DBG = false; private static final String TAG = "TimeUtils"; - /** Cached results of getTineZones */ - private static final Object sLastLockObj = new Object(); - private static ArrayList sLastZones = null; - private static String sLastCountry = null; - /** Cached results of getTimeZonesWithUniqueOffsets */ private static final Object sLastUniqueLockObj = new Object(); - private static ArrayList sLastUniqueZoneOffsets = null; + private static List sLastUniqueZoneOffsets = null; private static String sLastUniqueCountry = null; /** {@hide} */ @@ -63,50 +50,39 @@ public class TimeUtils { * and DST value at the specified moment in the specified country. * Returns null if no suitable zone could be found. */ - public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) { - TimeZone best = null; - final Date d = new Date(when); + public static java.util.TimeZone getTimeZone( + int offset, boolean dst, long when, String country) { - TimeZone current = TimeZone.getDefault(); - String currentName = current.getID(); - int currentOffset = current.getOffset(when); - boolean currentDst = current.inDaylightTime(d); - - for (TimeZone tz : getTimeZones(country)) { - // If the current time zone is from the right country - // and meets the other known properties, keep it - // instead of changing to another one. - - if (tz.getID().equals(currentName)) { - if (currentOffset == offset && currentDst == dst) { - return current; - } - } - - // Otherwise, take the first zone from the right - // country that has the correct current offset and DST. - // (Keep iterating instead of returning in case we - // haven't encountered the current time zone yet.) - - if (best == null) { - if (tz.getOffset(when) == offset && - tz.inDaylightTime(d) == dst) { - best = tz; - } - } - } - - return best; + android.icu.util.TimeZone icuTimeZone = getIcuTimeZone(offset, dst, when, country); + // We must expose a java.util.TimeZone here for API compatibility because this is a public + // API method. + return icuTimeZone != null ? java.util.TimeZone.getTimeZone(icuTimeZone.getID()) : null; } /** - * Return list of unique time zones for the country. Do not modify + * Tries to return a frozen ICU time zone that would have had the specified offset + * and DST value at the specified moment in the specified country. + * Returns null if no suitable zone could be found. + */ + private static android.icu.util.TimeZone getIcuTimeZone( + int offset, boolean dst, long when, String country) { + if (country == null) { + return null; + } + + android.icu.util.TimeZone bias = android.icu.util.TimeZone.getDefault(); + return TimeZoneFinder.getInstance() + .lookupTimeZoneByCountryAndOffset(country, offset, dst, when, bias); + } + + /** + * Returns an immutable list of unique time zone IDs for the country. * * @param country to find - * @return list of unique time zones, maybe empty but never null. Do not modify. + * @return unmodifiable list of unique time zones, maybe empty but never null. * @hide */ - public static ArrayList getTimeZonesWithUniqueOffsets(String country) { + public static List getTimeZoneIdsWithUniqueOffsets(String country) { synchronized(sLastUniqueLockObj) { if ((country != null) && country.equals(sLastUniqueCountry)) { if (DBG) { @@ -117,9 +93,9 @@ public class TimeUtils { } } - Collection zones = getTimeZones(country); - ArrayList uniqueTimeZones = new ArrayList(); - for (TimeZone zone : zones) { + Collection zones = getIcuTimeZones(country); + ArrayList uniqueTimeZones = new ArrayList<>(); + for (android.icu.util.TimeZone zone : zones) { // See if we already have this offset, // Using slow but space efficient and these are small. boolean found = false; @@ -129,7 +105,7 @@ public class TimeUtils { break; } } - if (found == false) { + if (!found) { if (DBG) { Log.d(TAG, "getTimeZonesWithUniqueOffsets: add unique offset=" + zone.getRawOffset() + " zone.getID=" + zone.getID()); @@ -140,81 +116,43 @@ public class TimeUtils { synchronized(sLastUniqueLockObj) { // Cache the last result - sLastUniqueZoneOffsets = uniqueTimeZones; + sLastUniqueZoneOffsets = extractZoneIds(uniqueTimeZones); sLastUniqueCountry = country; return sLastUniqueZoneOffsets; } } + private static List extractZoneIds(List timeZones) { + List ids = new ArrayList<>(timeZones.size()); + for (android.icu.util.TimeZone timeZone : timeZones) { + ids.add(timeZone.getID()); + } + return Collections.unmodifiableList(ids); + } + /** - * Returns the time zones for the country, which is the code - * attribute of the timezone element in time_zones_by_country.xml. Do not modify. + * Returns an immutable list of frozen ICU time zones for the country. * - * @param country is a two character country code. - * @return TimeZone list, maybe empty but never null. Do not modify. + * @param countryIso is a two character country code. + * @return TimeZone list, maybe empty but never null. * @hide */ - public static ArrayList getTimeZones(String country) { - synchronized (sLastLockObj) { - if ((country != null) && country.equals(sLastCountry)) { - if (DBG) Log.d(TAG, "getTimeZones(" + country + "): return cached version"); - return sLastZones; + private static List getIcuTimeZones(String countryIso) { + if (countryIso == null) { + if (DBG) Log.d(TAG, "getIcuTimeZones(null): return empty list"); + return Collections.emptyList(); + } + List timeZones = + TimeZoneFinder.getInstance().lookupTimeZonesByCountry(countryIso); + if (timeZones == null) { + if (DBG) { + Log.d(TAG, "getIcuTimeZones(" + countryIso + + "): returned null, converting to empty list"); } + return Collections.emptyList(); } - - ArrayList tzs = new ArrayList(); - - if (country == null) { - if (DBG) Log.d(TAG, "getTimeZones(null): return empty list"); - return tzs; - } - - Resources r = Resources.getSystem(); - XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country); - - try { - XmlUtils.beginDocument(parser, "timezones"); - - while (true) { - XmlUtils.nextElement(parser); - - String element = parser.getName(); - if (element == null || !(element.equals("timezone"))) { - break; - } - - String code = parser.getAttributeValue(null, "code"); - - if (country.equals(code)) { - if (parser.next() == XmlPullParser.TEXT) { - String zoneIdString = parser.getText(); - TimeZone tz = TimeZone.getTimeZone(zoneIdString); - if (tz.getID().startsWith("GMT") == false) { - // tz.getID doesn't start not "GMT" so its valid - tzs.add(tz); - if (DBG) { - Log.d(TAG, "getTimeZone('" + country + "'): found tz.getID==" - + ((tz != null) ? tz.getID() : "")); - } - } - } - } - } - } catch (XmlPullParserException e) { - Log.e(TAG, "Got xml parser exception getTimeZone('" + country + "'): e=", e); - } catch (IOException e) { - Log.e(TAG, "Got IO exception getTimeZone('" + country + "'): e=", e); - } finally { - parser.close(); - } - - synchronized(sLastLockObj) { - // Cache the last result; - sLastZones = tzs; - sLastCountry = country; - return sLastZones; - } + return timeZones; } /** diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7f28c61757e64..7aad04383657b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1433,7 +1433,6 @@ - diff --git a/core/res/res/xml/time_zones_by_country.xml b/core/res/res/xml/time_zones_by_country.xml deleted file mode 100644 index 22bfea191d964..0000000000000 --- a/core/res/res/xml/time_zones_by_country.xml +++ /dev/null @@ -1,1372 +0,0 @@ - - - - - - Europe/Andorra - - - - Asia/Dubai - - - - Asia/Kabul - - - - America/Antigua - - - - America/Anguilla - - - - Europe/Tirane - - - - Asia/Yerevan - - - - Africa/Luanda - - - - Antarctica/McMurdo - - - - Antarctica/DumontDUrville - - - - Antarctica/Casey - - - - Antarctica/Davis - - - - Antarctica/Mawson - - - - Antarctica/Vostok - - - - Antarctica/Syowa - - - - Antarctica/Troll - - - - Antarctica/Rothera - - - - Antarctica/Palmer - - - - America/Argentina/Buenos_Aires - America/Argentina/Cordoba - America/Argentina/Salta - America/Argentina/Jujuy - America/Argentina/Tucuman - America/Argentina/Catamarca - America/Argentina/La_Rioja - America/Argentina/San_Juan - America/Argentina/Mendoza - America/Argentina/San_Luis - America/Argentina/Rio_Gallegos - America/Argentina/Ushuaia - - - - Pacific/Pago_Pago - - - - Europe/Vienna - - - - Australia/Sydney - Australia/Melbourne - Australia/Brisbane - Australia/Hobart - Australia/Currie - Australia/Lindeman - - - Antarctica/Macquarie - - - - Australia/Lord_Howe - - - - Australia/Adelaide - Australia/Broken_Hill - Australia/Darwin - - - - Australia/Perth - - - - Australia/Eucla - - - - America/Aruba - - - - Europe/Mariehamn - - - - Asia/Baku - - - - Europe/Sarajevo - - - - America/Barbados - - - - Asia/Dhaka - - - - Europe/Brussels - - - - Africa/Ouagadougou - - - - Europe/Sofia - - - - Asia/Bahrain - - - - Africa/Bujumbura - - - - Africa/Porto-Novo - - - - America/St_Barthelemy - - - - Atlantic/Bermuda - - - - Asia/Brunei - - - - America/La_Paz - - - - America/Kralendijk - - - - America/Noronha - - - - America/Sao_Paulo - America/Belem - America/Fortaleza - America/Recife - America/Araguaina - America/Maceio - America/Bahia - America/Santarem - - - - America/Manaus - America/Campo_Grande - America/Cuiaba - America/Porto_Velho - America/Boa_Vista - - - - America/Eirunepe - America/Rio_Branco - - - - America/Nassau - - - - Asia/Thimphu - - - - Africa/Gaborone - - - - Europe/Minsk - - - - America/Belize - - - - America/St_Johns - - - - America/Halifax - America/Glace_Bay - America/Moncton - America/Goose_Bay - America/Blanc-Sablon - - - - America/Toronto - America/Nipigon - America/Thunder_Bay - America/Iqaluit - America/Pangnirtung - America/Atikokan - - - - America/Winnipeg - America/Regina - America/Rankin_Inlet - America/Rainy_River - America/Swift_Current - America/Resolute - - - - America/Edmonton - America/Cambridge_Bay - America/Yellowknife - America/Inuvik - America/Dawson_Creek - America/Creston - America/Fort_Nelson - - - - America/Vancouver - America/Whitehorse - America/Dawson - - - - Indian/Cocos - - - - Africa/Lubumbashi - - - - Africa/Kinshasa - - - - Africa/Bangui - - - - Africa/Brazzaville - - - - Europe/Zurich - - - - Africa/Abidjan - - - - Pacific/Rarotonga - - - - America/Punta_Arenas - - - - America/Santiago - - - - Pacific/Easter - - - - Africa/Douala - - - - Asia/Shanghai - - - - Asia/Urumqi - - - - America/Bogota - - - - America/Costa_Rica - - - - America/Havana - - - - Atlantic/Cape_Verde - - - - America/Curacao - - - - Indian/Christmas - - - - Asia/Nicosia - - - - Asia/Famagusta - - - - Europe/Prague - - - - Europe/Berlin - Europe/Busingen - - - - Africa/Djibouti - - - - Europe/Copenhagen - - - - America/Dominica - - - - America/Santo_Domingo - - - - Africa/Algiers - - - - America/Guayaquil - - - - Pacific/Galapagos - - - - Europe/Tallinn - - - - Africa/Cairo - - - - Africa/El_Aaiun - - - - Africa/Asmara - - - - Europe/Madrid - Africa/Ceuta - - - - Atlantic/Canary - - - - Africa/Addis_Ababa - - - - Europe/Helsinki - - - - Pacific/Fiji - - - - Atlantic/Stanley - - - - Pacific/Pohnpei - Pacific/Kosrae - - - - Pacific/Chuuk - - - - Atlantic/Faroe - - - - Europe/Paris - - - - Africa/Libreville - - - - Europe/London - - - - America/Grenada - - - - Asia/Tbilisi - - - - America/Cayenne - - - - Europe/Guernsey - - - - Africa/Accra - - - - Europe/Gibraltar - - - - America/Danmarkshavn - - - - America/Scoresbysund - - - - America/Godthab - - - - America/Thule - - - - Africa/Banjul - - - - Africa/Conakry - - - - America/Guadeloupe - - - - Africa/Malabo - - - - Europe/Athens - - - - Atlantic/South_Georgia - - - - America/Guatemala - - - - Pacific/Guam - - - - Africa/Bissau - - - - America/Guyana - - - - Asia/Hong_Kong - - - - America/Tegucigalpa - - - - Europe/Zagreb - - - - America/Port-au-Prince - - - - Europe/Budapest - - - - Asia/Jayapura - - - - Asia/Makassar - - - - Asia/Jakarta - Asia/Pontianak - - - - Europe/Dublin - - - - Asia/Jerusalem - - - - Europe/Isle_of_Man - - - - Asia/Kolkata - - - - Indian/Chagos - - - - Asia/Baghdad - - - - Asia/Tehran - - - - Atlantic/Reykjavik - - - - Europe/Rome - - - - Europe/Jersey - - - - America/Jamaica - - - - Asia/Amman - - - - Asia/Tokyo - - - - Africa/Nairobi - - - - Asia/Bishkek - - - - Asia/Phnom_Penh - - - - Pacific/Kiritimati - - - - Pacific/Enderbury - - - - Pacific/Tarawa - - - - Indian/Comoro - - - - America/St_Kitts - - - - Asia/Pyongyang - - - - Asia/Seoul - - - - Asia/Kuwait - - - - America/Cayman - - - - Asia/Almaty - Asia/Qyzylorda - - - - Asia/Aqtau - Asia/Oral - Asia/Aqtobe - Asia/Atyrau - - - - Asia/Vientiane - - - - Asia/Beirut - - - - America/St_Lucia - - - - Europe/Vaduz - - - - Asia/Colombo - - - - Africa/Monrovia - - - - Africa/Maseru - - - - Europe/Vilnius - - - - Europe/Luxembourg - - - - Europe/Riga - - - - Africa/Tripoli - - - - Africa/Casablanca - - - - Europe/Monaco - - - - Europe/Chisinau - - - - Europe/Podgorica - - - - America/Marigot - - - - Indian/Antananarivo - - - - Pacific/Majuro - Pacific/Kwajalein - - - - Europe/Skopje - - - - Africa/Bamako - - - - Asia/Yangon - - - - Asia/Choibalsan - Asia/Ulaanbaatar - - - - Asia/Hovd - - - - Asia/Macau - - - - Pacific/Saipan - - - - America/Martinique - - - - Africa/Nouakchott - - - - America/Montserrat - - - - Europe/Malta - - - - Indian/Mauritius - - - - Indian/Maldives - - - - Africa/Blantyre - - - - America/Mexico_City - America/Merida - America/Monterrey - America/Matamoros - America/Bahia_Banderas - - - - America/Cancun - - - - America/Chihuahua - America/Hermosillo - America/Mazatlan - America/Ojinaga - - - - America/Tijuana - - - - Asia/Kuala_Lumpur - Asia/Kuching - - - - Africa/Maputo - - - - Africa/Windhoek - - - - Pacific/Noumea - - - - Africa/Niamey - - - - Pacific/Norfolk - - - - Africa/Lagos - - - - America/Managua - - - - Europe/Amsterdam - - - - Europe/Oslo - - - - Asia/Kathmandu - - - - Pacific/Nauru - - - - Pacific/Niue - - - - Pacific/Auckland - - - - Pacific/Chatham - - - - Asia/Muscat - - - - America/Panama - - - - America/Lima - - - - Pacific/Gambier - - - - Pacific/Marquesas - - - - Pacific/Tahiti - - - - Pacific/Port_Moresby - - - - Pacific/Bougainville - - - - Asia/Manila - - - - Asia/Karachi - - - - Europe/Warsaw - - - - America/Miquelon - - - - Pacific/Pitcairn - - - - America/Puerto_Rico - - - - Asia/Gaza - Asia/Hebron - - - - Europe/Lisbon - Atlantic/Madeira - - - - Atlantic/Azores - - - - Pacific/Palau - - - - America/Asuncion - - - - Asia/Qatar - - - - Indian/Reunion - - - - Europe/Bucharest - - - - Europe/Belgrade - - - - Asia/Kamchatka - Asia/Anadyr - - - - Asia/Magadan - Asia/Sakhalin - Asia/Srednekolymsk - - - - Asia/Vladivostok - Asia/Ust-Nera - - - - Asia/Yakutsk - Asia/Chita - Asia/Khandyga - - - - Asia/Irkutsk - - - - Asia/Krasnoyarsk - Asia/Novosibirsk - Asia/Barnaul - Asia/Novokuznetsk - Asia/Tomsk - - - - Asia/Omsk - - - - Asia/Yekaterinburg - - - - Europe/Samara - Europe/Astrakhan - Europe/Ulyanovsk - Europe/Saratov - - - - Europe/Moscow - Europe/Volgograd - Europe/Kirov - Europe/Simferopol - - - - Europe/Kaliningrad - - - - Africa/Kigali - - - - Asia/Riyadh - - - - Pacific/Guadalcanal - - - - Indian/Mahe - - - - Africa/Khartoum - - - - Europe/Stockholm - - - - Asia/Singapore - - - - Atlantic/St_Helena - - - - Europe/Ljubljana - - - - Arctic/Longyearbyen - - - - Europe/Bratislava - - - - Africa/Freetown - - - - Europe/San_Marino - - - - Africa/Dakar - - - - Africa/Mogadishu - - - - America/Paramaribo - - - - Africa/Juba - - - - Africa/Sao_Tome - - - - America/El_Salvador - - - - America/Lower_Princes - - - - Asia/Damascus - - - - Africa/Mbabane - - - - America/Grand_Turk - - - - Africa/Ndjamena - - - - Indian/Kerguelen - - - - Africa/Lome - - - - Asia/Bangkok - - - - Asia/Dushanbe - - - - Pacific/Fakaofo - - - - Asia/Dili - - - - Asia/Ashgabat - - - - Africa/Tunis - - - - Pacific/Tongatapu - - - - Europe/Istanbul - - - - America/Port_of_Spain - - - - Pacific/Funafuti - - - - Asia/Taipei - - - - Africa/Dar_es_Salaam - - - - Europe/Kiev - Europe/Uzhgorod - Europe/Zaporozhye - - - - Africa/Kampala - - - - Pacific/Wake - - - - Pacific/Midway - - - - America/New_York - America/Detroit - America/Kentucky/Louisville - America/Kentucky/Monticello - America/Indiana/Indianapolis - America/Indiana/Vincennes - America/Indiana/Winamac - America/Indiana/Marengo - America/Indiana/Petersburg - America/Indiana/Vevay - - - - America/Chicago - America/Indiana/Knox - America/Menominee - America/North_Dakota/Center - America/North_Dakota/New_Salem - America/Indiana/Tell_City - America/North_Dakota/Beulah - - - - America/Denver - America/Boise - America/Phoenix - - - - America/Los_Angeles - - - - America/Anchorage - America/Juneau - America/Yakutat - America/Nome - America/Metlakatla - America/Sitka - - - - Pacific/Honolulu - America/Adak - - - - America/Montevideo - - - - Asia/Tashkent - Asia/Samarkand - - - - Europe/Vatican - - - - America/St_Vincent - - - - America/Caracas - - - - America/Tortola - - - - America/St_Thomas - - - - Asia/Ho_Chi_Minh - - - - Pacific/Efate - - - - Pacific/Wallis - - - - Pacific/Apia - - - - Asia/Aden - - - - Indian/Mayotte - - - - Africa/Johannesburg - - - - Africa/Lusaka - - - - Africa/Harare -