ZoneInfoDB.java revision 6cbefca623f55004ba65f11577fc25f92f6297dc
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;
24e810d3b49631329b11440aa5b7a54db181d42ed1Elliott Hughesimport java.nio.charset.Charsets;
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
346d82ce5d35a5e84aedf08528fd98b849f3f565a6Elliott Hughes// TODO: repackage this class, used by frameworks/base.
356d82ce5d35a5e84aedf08528fd98b849f3f565a6Elliott Hughesimport org.apache.harmony.luni.internal.util.TimezoneGetter;
366d82ce5d35a5e84aedf08528fd98b849f3f565a6Elliott Hughes
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
386cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes * A class used to initialize the time zone database. This implementation uses the
396cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes * Olson tzdata as the source of time zone information. However, to conserve
406cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes * disk space (inodes) and reduce I/O, all the data is concatenated into a single file,
416cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes * with an index to indicate the starting position of each time zone record.
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
436d82ce5d35a5e84aedf08528fd98b849f3f565a6Elliott Hughes * @hide - used to implement TimeZone
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic final class ZoneInfoDB {
46f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes    private static final Object LOCK = new Object();
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
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
539b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes     * enough that we'll just keep the byte[] in memory.
549b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes     */
556cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes    private static final MemoryMappedFile TZDATA = mapData();
566cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes
576cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes    private static String version;
589b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes
599b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    /**
603ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes     * The 'ids' array contains time zone ids sorted alphabetically, for binary searching.
613ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes     * The other two arrays are in the same order. 'byteOffsets' gives the byte offset
626cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes     * of each time zone, and 'rawUtcOffsets' gives the time zone's raw UTC offset.
633ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes     */
643ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes    private static String[] ids;
653ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes    private static int[] byteOffsets;
663ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes    private static int[] rawUtcOffsets;
676cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes
68f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes    static {
696cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        readHeader();
70f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes    }
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
729b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    private ZoneInfoDB() {
739b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    }
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
756cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes    private static void readHeader() {
766cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        // byte[12] tzdata_version  -- "tzdata2012f\0"
776cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        // int file_format_version  -- 1
786cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        // int index_offset
796cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        // int data_offset
806cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        // int zonetab_offset
816cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        BufferIterator it = TZDATA.bigEndianIterator();
826cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes
836cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        byte[] tzdata_version = new byte[12];
846cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        it.readByteArray(tzdata_version, 0, tzdata_version.length);
856cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        String magic = new String(tzdata_version, 0, 6, Charsets.US_ASCII);
866cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        if (!magic.equals("tzdata") || tzdata_version[11] != 0) {
876cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes            throw new RuntimeException("bad tzdata magic: " + Arrays.toString(tzdata_version));
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
896cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        version = new String(tzdata_version, 6, 5, Charsets.US_ASCII);
906cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes
916cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        int file_format_version = it.readInt();
926cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        if (file_format_version != 1) {
936cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes            throw new RuntimeException("unknown tzdata file format version: " + file_format_version);
946cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        }
956cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes
966cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        int index_offset = it.readInt();
976cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        int data_offset = it.readInt();
986cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        int zonetab_offset = it.readInt();
996cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        if (zonetab_offset != 0) {
1006cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes            throw new RuntimeException("non-zero zonetab offset: " + zonetab_offset);
1016cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        }
1026cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes
1036cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        readIndex(it, index_offset, data_offset);
104f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes    }
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1069b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    private static MemoryMappedFile mapData() {
1079b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        try {
1086cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes            String path = System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo/tzdata";
1096cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes            return MemoryMappedFile.mmapRO(path);
1109b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        } catch (ErrnoException errnoException) {
1119b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            throw new AssertionError(errnoException);
1129b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        }
1139b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    }
1149b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes
1156cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes    private static void readIndex(BufferIterator it, int indexOffset, int dataOffset) {
1166cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        it.seek(indexOffset);
117f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes
118bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        // The database reserves 40 bytes for each id.
119bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        final int SIZEOF_TZNAME = 40;
120bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        // The database uses 32-bit (4 byte) integers.
121bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        final int SIZEOF_TZINT = 4;
122f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes
123bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        byte[] idBytes = new byte[SIZEOF_TZNAME];
1246cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        int indexSize = (dataOffset - indexOffset);
1256cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        int entryCount = indexSize / (SIZEOF_TZNAME + 3*SIZEOF_TZINT);
126f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes
1276cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        char[] idChars = new char[entryCount * SIZEOF_TZNAME];
1286cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        int[] idEnd = new int[entryCount];
129bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        int idOffset = 0;
130f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes
1316cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        byteOffsets = new int[entryCount];
1326cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        rawUtcOffsets = new int[entryCount];
133f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes
1346cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        for (int i = 0; i < entryCount; i++) {
135bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            it.readByteArray(idBytes, 0, idBytes.length);
1366cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes
137bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            byteOffsets[i] = it.readInt();
1386cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes            byteOffsets[i] += dataOffset; // TODO: change the file format so this is included.
1396cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes
140bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            int length = it.readInt();
141bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            if (length < 44) {
142bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes                throw new AssertionError("length in index file < sizeof(tzhead)");
143f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes            }
144bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            rawUtcOffsets[i] = it.readInt();
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
146bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            // Don't include null chars in the String
147bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            int len = idBytes.length;
148bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            for (int j = 0; j < len; j++) {
149bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes                if (idBytes[j] == 0) {
150bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes                    break;
151bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes                }
152bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes                idChars[idOffset++] = (char) (idBytes[j] & 0xFF);
153f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes            }
154bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes
155bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            idEnd[i] = idOffset;
156bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        }
157bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes
158bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        // We create one string containing all the ids, and then break that into substrings.
159bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        // This way, all ids share a single char[] on the heap.
160bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes        String allIds = new String(idChars, 0, idOffset);
1616cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        ids = new String[entryCount];
1626cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        for (int i = 0; i < entryCount; i++) {
163bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes            ids[i] = allIds.substring(i == 0 ? 0 : idEnd[i - 1], idEnd[i]);
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
16778c3de051d68b703af480778c100ca335690b250Elliott Hughes    public static TimeZone makeTimeZone(String id) throws IOException {
1683ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        // Work out where in the big data file this time zone is.
1693ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        int index = Arrays.binarySearch(ids, id);
1703ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        if (index < 0) {
1713ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            return null;
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1746cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        BufferIterator data = TZDATA.bigEndianIterator();
175d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes        data.skip(byteOffsets[index]);
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1773ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        // Variable names beginning tzh_ correspond to those in "tzfile.h".
1783ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        // Check tzh_magic.
179d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes        if (data.readInt() != 0x545a6966) { // "TZif"
1803ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            return null;
1813ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        }
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1833ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        // Skip the uninteresting part of the header.
184d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes        data.skip(28);
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1863ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        // Read the sizes of the arrays we're about to read.
187d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes        int tzh_timecnt = data.readInt();
188d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes        int tzh_typecnt = data.readInt();
189d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes
190d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes        data.skip(4); // Skip tzh_charcnt.
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1923ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        int[] transitions = new int[tzh_timecnt];
193d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes        data.readIntArray(transitions, 0, transitions.length);
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1953ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        byte[] type = new byte[tzh_timecnt];
196d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes        data.readByteArray(type, 0, type.length);
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1983ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        int[] gmtOffsets = new int[tzh_typecnt];
1993ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        byte[] isDsts = new byte[tzh_typecnt];
2003ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        for (int i = 0; i < tzh_typecnt; ++i) {
201d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes            gmtOffsets[i] = data.readInt();
202d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes            isDsts[i] = data.readByte();
203102b3a86bde04a4cffcbecd5b6d175d7790b132aElliott Hughes            // We skip the abbreviation index. This would let us provide historically-accurate
204102b3a86bde04a4cffcbecd5b6d175d7790b132aElliott Hughes            // time zone abbreviations (such as "AHST", "YST", and "AKST" for standard time in
205102b3a86bde04a4cffcbecd5b6d175d7790b132aElliott Hughes            // America/Anchorage in 1982, 1983, and 1984 respectively). ICU only knows the current
206102b3a86bde04a4cffcbecd5b6d175d7790b132aElliott Hughes            // names, though, so even if we did use this data to provide the correct abbreviations
207102b3a86bde04a4cffcbecd5b6d175d7790b132aElliott Hughes            // for en_US, we wouldn't be able to provide correct abbreviations for other locales,
208102b3a86bde04a4cffcbecd5b6d175d7790b132aElliott Hughes            // nor would we be able to provide correct long forms (such as "Yukon Standard Time")
209102b3a86bde04a4cffcbecd5b6d175d7790b132aElliott Hughes            // for any locale. (The RI doesn't do any better than us here either.)
210102b3a86bde04a4cffcbecd5b6d175d7790b132aElliott Hughes            data.skip(1);
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
213d6b9f2e0e9640ff9c896b394716cf5e7eee6e257Elliott Hughes        return new ZoneInfo(id, transitions, type, gmtOffsets, isDsts);
2143ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes    }
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2163ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes    public static String[] getAvailableIDs() {
217866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes        return ids.clone();
2183ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes    }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2203ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes    public static String[] getAvailableIDs(int rawOffset) {
2213ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        List<String> matches = new ArrayList<String>();
2226cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        for (int i = 0, end = rawUtcOffsets.length; i < end; ++i) {
2233ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            if (rawUtcOffsets[i] == rawOffset) {
2243ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes                matches.add(ids[i]);
2253ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            }
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
2273ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        return matches.toArray(new String[matches.size()]);
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2303ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes    public static TimeZone getSystemDefault() {
2313ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        synchronized (LOCK) {
2323ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            TimezoneGetter tzGetter = TimezoneGetter.getInstance();
2333ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            String zoneName = tzGetter != null ? tzGetter.getId() : null;
2343ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            if (zoneName != null) {
2353ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes                zoneName = zoneName.trim();
2363ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            }
2373ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            if (zoneName == null || zoneName.isEmpty()) {
2383ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes                // use localtime for the simulator
2393ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes                // TODO: what does that correspond to?
2403ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes                zoneName = "localtime";
2413ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            }
2423ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes            return TimeZone.getTimeZone(zoneName);
2433ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes        }
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2463ab13ebe9d67b0b210865853902b854711ef45b0Elliott Hughes    public static String getVersion() {
2476cbefca623f55004ba65f11577fc25f92f6297dcElliott Hughes        return version;
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
250