1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License. 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 176d82ce5d35a5e84aedf08528fd98b849f3f565a6Elliott Hughespackage libcore.util; 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.RandomAccessFile; 213ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughesimport java.nio.ByteBuffer; 223ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughesimport java.nio.ByteOrder; 23d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughesimport java.nio.channels.FileChannel.MapMode; 242a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughesimport java.nio.charset.StandardCharsets; 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList; 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Arrays; 27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.List; 28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.TimeZone; 29d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughesimport libcore.io.BufferIterator; 309b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughesimport libcore.io.ErrnoException; 31f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughesimport libcore.io.IoUtils; 32d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughesimport libcore.io.MemoryMappedFile; 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 356cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes * A class used to initialize the time zone database. This implementation uses the 366cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes * Olson tzdata as the source of time zone information. However, to conserve 376cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes * disk space (inodes) and reduce I/O, all the data is concatenated into a single file, 386cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes * with an index to indicate the starting position of each time zone record. 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 406d82ce5d35a5e84aedf08528fd98b849f3f565a6Elliott Hughes * @hide - used to implement TimeZone 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic final class ZoneInfoDB { 43995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private static final TzData DATA = 44995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes new TzData(System.getenv("ANDROID_DATA") + "/misc/zoneinfo/tzdata", 45995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo/tzdata"); 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 47995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes public static class TzData { 483ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes /** 499b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes * Rather than open, read, and close the big data file each time we look up a time zone, 509b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes * we map the big data file during startup, and then just use the MemoryMappedFile. 519b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes * 529b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes * At the moment, this "big" data file is about 500 KiB. At some point, that will be small 53995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes * enough that we could just keep the byte[] in memory, but using mmap(2) like this has the 54995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes * nice property that even if someone replaces the file under us (because multiple gservices 55995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes * updates have gone out, say), we still get a consistent (if outdated) view of the world. 569b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes */ 57995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private MemoryMappedFile mappedFile; 586cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes 59995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private String version; 60995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private String zoneTab; 619b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes 629b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes /** 633ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes * The 'ids' array contains time zone ids sorted alphabetically, for binary searching. 643ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes * The other two arrays are in the same order. 'byteOffsets' gives the byte offset 656cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes * of each time zone, and 'rawUtcOffsets' gives the time zone's raw UTC offset. 663ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes */ 67995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private String[] ids; 68995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private int[] byteOffsets; 69995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private int[] rawUtcOffsets; 70995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 71995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes public TzData(String... paths) { 72995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes for (String path : paths) { 73995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes if (loadData(path)) { 74995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return; 75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 76995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 77995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 78995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // We didn't find any usable tzdata on disk, so let's just hard-code knowledge of "GMT". 79995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // This is actually implemented in TimeZone itself, so if this is the only time zone 80995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // we report, we won't be asked any more questions. 81995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes System.logE("Couldn't find any tzdata!"); 82995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes version = "missing"; 83995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes zoneTab = "# Emergency fallback data.\n"; 84995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes ids = new String[] { "GMT" }; 85995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes byteOffsets = rawUtcOffsets = new int[1]; 86f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes } 87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 88995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private boolean loadData(String path) { 89995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes try { 90995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes mappedFile = MemoryMappedFile.mmapRO(path); 91995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } catch (ErrnoException errnoException) { 92995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return false; 93995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 94995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes try { 95995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes readHeader(); 96995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return true; 97995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } catch (Exception ex) { 98995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // Something's wrong with the file. 99995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // Log the problem and return false so we try the next choice. 100995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes System.logE("tzdata file \"" + path + "\" was present but invalid!", ex); 101995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return false; 102995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 1034c0cbc2cf60df843387233801784ae43c2cd747cElliott Hughes } 1044c0cbc2cf60df843387233801784ae43c2cd747cElliott Hughes 105995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private void readHeader() { 106995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // byte[12] tzdata_version -- "tzdata2012f\0" 107995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // int index_offset 108995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // int data_offset 109995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // int zonetab_offset 110995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes BufferIterator it = mappedFile.bigEndianIterator(); 111995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 112995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes byte[] tzdata_version = new byte[12]; 113995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes it.readByteArray(tzdata_version, 0, tzdata_version.length); 1142a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughes String magic = new String(tzdata_version, 0, 6, StandardCharsets.US_ASCII); 115995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes if (!magic.equals("tzdata") || tzdata_version[11] != 0) { 116995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes throw new RuntimeException("bad tzdata magic: " + Arrays.toString(tzdata_version)); 117995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 1182a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughes version = new String(tzdata_version, 6, 5, StandardCharsets.US_ASCII); 119995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 120995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int index_offset = it.readInt(); 121995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int data_offset = it.readInt(); 122995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int zonetab_offset = it.readInt(); 123995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 124995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes readIndex(it, index_offset, data_offset); 125995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes readZoneTab(it, zonetab_offset, (int) mappedFile.size() - zonetab_offset); 1269b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes } 1279b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes 128995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private void readZoneTab(BufferIterator it, int zoneTabOffset, int zoneTabSize) { 129995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes byte[] bytes = new byte[zoneTabSize]; 130995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes it.seek(zoneTabOffset); 131995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes it.readByteArray(bytes, 0, bytes.length); 1322a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughes zoneTab = new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII); 133dad6760aedf4c6b29b47dea6352d88fc3df9b2e5Elliott Hughes } 134dad6760aedf4c6b29b47dea6352d88fc3df9b2e5Elliott Hughes 135995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private void readIndex(BufferIterator it, int indexOffset, int dataOffset) { 136995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes it.seek(indexOffset); 137f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes 138995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // The database reserves 40 bytes for each id. 139995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes final int SIZEOF_TZNAME = 40; 140995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // The database uses 32-bit (4 byte) integers. 141995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes final int SIZEOF_TZINT = 4; 142f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes 143995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes byte[] idBytes = new byte[SIZEOF_TZNAME]; 144995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int indexSize = (dataOffset - indexOffset); 145995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int entryCount = indexSize / (SIZEOF_TZNAME + 3*SIZEOF_TZINT); 146f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes 147995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes char[] idChars = new char[entryCount * SIZEOF_TZNAME]; 148995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int[] idEnd = new int[entryCount]; 149995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int idOffset = 0; 150f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes 151995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes byteOffsets = new int[entryCount]; 152995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes rawUtcOffsets = new int[entryCount]; 153f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes 154995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes for (int i = 0; i < entryCount; i++) { 155995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes it.readByteArray(idBytes, 0, idBytes.length); 1566cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes 157995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes byteOffsets[i] = it.readInt(); 158995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes byteOffsets[i] += dataOffset; // TODO: change the file format so this is included. 1596cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes 160995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int length = it.readInt(); 161995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes if (length < 44) { 162995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes throw new AssertionError("length in index file < sizeof(tzhead)"); 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 164995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes rawUtcOffsets[i] = it.readInt(); 165995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 166995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // Don't include null chars in the String 167995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int len = idBytes.length; 168995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes for (int j = 0; j < len; j++) { 169995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes if (idBytes[j] == 0) { 170995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes break; 171995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 172995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes idChars[idOffset++] = (char) (idBytes[j] & 0xFF); 173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 175995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes idEnd[i] = idOffset; 176995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 178995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // We create one string containing all the ids, and then break that into substrings. 179995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // This way, all ids share a single char[] on the heap. 180995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes String allIds = new String(idChars, 0, idOffset); 181995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes ids = new String[entryCount]; 182995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes for (int i = 0; i < entryCount; i++) { 183995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes ids[i] = allIds.substring(i == 0 ? 0 : idEnd[i - 1], idEnd[i]); 184995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 1853ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes } 186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 187995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes public String[] getAvailableIDs() { 188995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return ids.clone(); 1893ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes } 190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 191995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes public String[] getAvailableIDs(int rawOffset) { 192995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes List<String> matches = new ArrayList<String>(); 193995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes for (int i = 0, end = rawUtcOffsets.length; i < end; ++i) { 194995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes if (rawUtcOffsets[i] == rawOffset) { 195995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes matches.add(ids[i]); 196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 197995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 198995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return matches.toArray(new String[matches.size()]); 199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 201995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes public String getVersion() { 202995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return version; 203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 205995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes public String getZoneTab() { 206995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return zoneTab; 207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 208dad6760aedf4c6b29b47dea6352d88fc3df9b2e5Elliott Hughes 209995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes public TimeZone makeTimeZone(String id) throws IOException { 210995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes // Work out where in the big data file this time zone is. 211995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes int index = Arrays.binarySearch(ids, id); 212995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes if (index < 0) { 213995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return null; 214995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 215995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 216995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes BufferIterator it = mappedFile.bigEndianIterator(); 217995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes it.skip(byteOffsets[index]); 218995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 219995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return ZoneInfo.makeTimeZone(id, it); 220dad6760aedf4c6b29b47dea6352d88fc3df9b2e5Elliott Hughes } 221995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 222995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 223995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes private ZoneInfoDB() { 224995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 225995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes 226995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes public static TzData getInstance() { 227995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes return DATA; 228995caee51334a4f1a1429e29680ea079c900c37aElliott Hughes } 229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 230