FileDocCategorySizeDatePackage
TimeZoneData.javaAPI DocAndroid 5.1 API19864Thu Mar 12 22:22:54 GMT 2015com.android.timezonepicker

TimeZoneData

public class TimeZoneData extends Object

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
private static final int
OFFSET_ARRAY_OFFSET
private static final String
PALESTINE_COUNTRY_CODE
ArrayList
mTimeZones
LinkedHashMap
mTimeZonesByCountry
HashSet
mTimeZoneNames
private long
mTimeMillis
private HashMap
mCountryCodeToNameMap
public String
mDefaultTimeZoneId
public static boolean
is24HourFormat
private TimeZoneInfo
mDefaultTimeZoneInfo
private String
mAlternateDefaultTimeZoneId
private String
mDefaultTimeZoneCountry
private HashMap
mTimeZonesById
private boolean[]
mHasTimeZonesInHrOffset
android.util.SparseArray
mTimeZonesByOffsets
private android.content.Context
mContext
private String
mPalestineDisplayName
private static Locale
mBackupCountryLocale
private static String[]
mBackupCountryCodes
private static String[]
mBackupCountryNames
Constructors Summary
public TimeZoneData(android.content.Context context, String defaultTimeZoneId, long timeMillis)


           
        mContext = context;
        is24HourFormat = TimeZoneInfo.is24HourFormat = DateFormat.is24HourFormat(context);
        mDefaultTimeZoneId = mAlternateDefaultTimeZoneId = defaultTimeZoneId;
        long now = System.currentTimeMillis();

        if (timeMillis == 0) {
            mTimeMillis = now;
        } else {
            mTimeMillis = timeMillis;
        }

        mPalestineDisplayName = context.getResources().getString(R.string.palestine_display_name);

        loadTzs(context);

        Log.i(TAG, "Time to load time zones (ms): " + (System.currentTimeMillis() - now));

        // now = System.currentTimeMillis();
        // printTz();
        // Log.i(TAG, "Time to print time zones (ms): " +
        // (System.currentTimeMillis() - now));
    
Methods Summary
public intfindIndexByTimeZoneIdSlow(java.lang.String timeZoneId)

        int idx = 0;
        for (TimeZoneInfo tzi : mTimeZones) {
            if (timeZoneId.equals(tzi.mTzId)) {
                return idx;
            }
            idx++;
        }
        return -1;
    
public TimeZoneInfoget(int position)

        return mTimeZones.get(position);
    
private java.lang.StringgetCountryNames(java.lang.String lang, java.lang.String countryCode)

        final Locale defaultLocale = Locale.getDefault();
        String countryDisplayName;
        if (PALESTINE_COUNTRY_CODE.equalsIgnoreCase(countryCode)) {
            countryDisplayName = mPalestineDisplayName;
        } else {
            countryDisplayName = new Locale(lang, countryCode).getDisplayCountry(defaultLocale);
        }

        if (!countryCode.equals(countryDisplayName)) {
            return countryDisplayName;
        }

        if (mBackupCountryCodes == null || !defaultLocale.equals(mBackupCountryLocale)) {
            mBackupCountryLocale = defaultLocale;
            mBackupCountryCodes = mContext.getResources().getStringArray(
                    R.array.backup_country_codes);
            mBackupCountryNames = mContext.getResources().getStringArray(
                    R.array.backup_country_names);
        }

        int length = Math.min(mBackupCountryCodes.length, mBackupCountryNames.length);

        for (int i = 0; i < length; i++) {
            if (mBackupCountryCodes[i].equals(countryCode)) {
                return mBackupCountryNames[i];
            }
        }

        return countryCode;
    
public intgetDefaultTimeZoneIndex()

        return mTimeZones.indexOf(mDefaultTimeZoneInfo);
    
private intgetIdenticalTimeZoneInTheCountry(TimeZoneInfo timeZoneInfo)

        int idx = 0;
        for (TimeZoneInfo tzi : mTimeZones) {
            if (tzi.hasSameRules(timeZoneInfo)) {
                if (tzi.mCountry == null) {
                    if (timeZoneInfo.mCountry == null) {
                        return idx;
                    }
                } else if (tzi.mCountry.equals(timeZoneInfo.mCountry)) {
                    return idx;
                }
            }
            ++idx;
        }
        return -1;
    
public java.util.ArrayListgetTimeZonesByOffset(int offsetHr)

        int index = OFFSET_ARRAY_OFFSET + offsetHr;
        if (index >= mHasTimeZonesInHrOffset.length || index < 0) {
            return null;
        }
        return mTimeZonesByOffsets.get(index);
    
public booleanhasTimeZonesInHrOffset(int offsetHr)

        int index = OFFSET_ARRAY_OFFSET + offsetHr;
        if (index >= mHasTimeZonesInHrOffset.length || index < 0) {
            return false;
        }
        return mHasTimeZonesInHrOffset[index];
    
private voidindexByOffsets(int idx, TimeZoneInfo tzi)

        int offsetMillis = tzi.getNowOffsetMillis();
        int index = OFFSET_ARRAY_OFFSET + (int) (offsetMillis / DateUtils.HOUR_IN_MILLIS);
        mHasTimeZonesInHrOffset[index] = true;

        ArrayList<Integer> group = mTimeZonesByOffsets.get(index);
        if (group == null) {
            group = new ArrayList<Integer>();
            mTimeZonesByOffsets.put(index, group);
        }
        group.add(idx);
    
voidloadTzs(android.content.Context context)

        mTimeZones = new ArrayList<TimeZoneInfo>();
        HashSet<String> processedTimeZones = loadTzsInZoneTab(context);
        String[] tzIds = TimeZone.getAvailableIDs();

        if (DEBUG) {
            Log.e(TAG, "Available time zones: " + tzIds.length);
        }

        for (String tzId : tzIds) {
            if (processedTimeZones.contains(tzId)) {
                continue;
            }

            /*
             * Dropping non-GMT tzs without a country code. They are not really
             * needed and they are dups but missing proper country codes. e.g.
             * WET CET MST7MDT PST8PDT Asia/Khandyga Asia/Ust-Nera EST
             */
            if (!tzId.startsWith("Etc/GMT")) {
                continue;
            }

            final TimeZone tz = TimeZone.getTimeZone(tzId);
            if (tz == null) {
                Log.e(TAG, "Timezone not found: " + tzId);
                continue;
            }

            TimeZoneInfo tzInfo = new TimeZoneInfo(tz, null);

            if (getIdenticalTimeZoneInTheCountry(tzInfo) == -1) {
                if (DEBUG) {
                    Log.e(TAG, "# Adding time zone from getAvailId: " + tzInfo.toString());
                }
                mTimeZones.add(tzInfo);
            } else {
                if (DEBUG) {
                    Log.e(TAG,
                            "# Dropping identical time zone from getAvailId: " + tzInfo.toString());
                }
                continue;
            }
            //
            // TODO check for dups
            // checkForNameDups(tz, tzInfo.mCountry, false /* dls */,
            // TimeZone.SHORT, groupIdx, !found);
            // checkForNameDups(tz, tzInfo.mCountry, false /* dls */,
            // TimeZone.LONG, groupIdx, !found);
            // if (tz.useDaylightTime()) {
            // checkForNameDups(tz, tzInfo.mCountry, true /* dls */,
            // TimeZone.SHORT, groupIdx,
            // !found);
            // checkForNameDups(tz, tzInfo.mCountry, true /* dls */,
            // TimeZone.LONG, groupIdx,
            // !found);
            // }
        }

        // Don't change the order of mTimeZones after this sort
        Collections.sort(mTimeZones);

        mTimeZonesByCountry = new LinkedHashMap<String, ArrayList<Integer>>();
        mTimeZonesByOffsets = new SparseArray<ArrayList<Integer>>(mHasTimeZonesInHrOffset.length);
        mTimeZonesById = new HashMap<String, TimeZoneInfo>(mTimeZones.size());
        for (TimeZoneInfo tz : mTimeZones) {
            // /////////////////////
            // Lookup map for id -> tz
            mTimeZonesById.put(tz.mTzId, tz);
        }
        populateDisplayNameOverrides(mContext.getResources());

        Date date = new Date(mTimeMillis);
        Locale defaultLocal = Locale.getDefault();

        int idx = 0;
        for (TimeZoneInfo tz : mTimeZones) {
            // /////////////////////
            // Populate display name
            if (tz.mDisplayName == null) {
                tz.mDisplayName = tz.mTz.getDisplayName(tz.mTz.inDaylightTime(date),
                        TimeZone.LONG, defaultLocal);
            }

            // /////////////////////
            // Grouping tz's by country for search by country
            ArrayList<Integer> group = mTimeZonesByCountry.get(tz.mCountry);
            if (group == null) {
                group = new ArrayList<Integer>();
                mTimeZonesByCountry.put(tz.mCountry, group);
            }

            group.add(idx);

            // /////////////////////
            // Grouping tz's by GMT offsets
            indexByOffsets(idx, tz);

            // Skip all the GMT+xx:xx style display names from search
            if (!tz.mDisplayName.endsWith(":00")) {
                mTimeZoneNames.add(tz.mDisplayName);
            } else if (DEBUG) {
                Log.e(TAG, "# Hiding from pretty name search: " +
                        tz.mDisplayName);
            }

            idx++;
        }

        // printTimeZones();
    
private java.util.HashSetloadTzsInZoneTab(android.content.Context context)

        HashSet<String> processedTimeZones = new HashSet<String>();
        AssetManager am = context.getAssets();
        InputStream is = null;

        /*
         * The 'backward' file contain mappings between new and old time zone
         * ids. We will explicitly ignore the old ones.
         */
        try {
            is = am.open("backward");
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            String line;

            while ((line = reader.readLine()) != null) {
                // Skip comment lines
                if (!line.startsWith("#") && line.length() > 0) {
                    // 0: "Link"
                    // 1: New tz id
                    // Last: Old tz id
                    String[] fields = line.split("\t+");
                    String newTzId = fields[1];
                    String oldTzId = fields[fields.length - 1];

                    final TimeZone tz = TimeZone.getTimeZone(newTzId);
                    if (tz == null) {
                        Log.e(TAG, "Timezone not found: " + newTzId);
                        continue;
                    }

                    processedTimeZones.add(oldTzId);

                    if (DEBUG) {
                        Log.e(TAG, "# Dropping identical time zone from backward: " + oldTzId);
                    }

                    // Remember the cooler/newer time zone id
                    if (mDefaultTimeZoneId != null && mDefaultTimeZoneId.equals(oldTzId)) {
                        mAlternateDefaultTimeZoneId = newTzId;
                    }
                }
            }
        } catch (IOException ex) {
            Log.e(TAG, "Failed to read 'backward' file.");
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException ignored) {
            }
        }

        /*
         * zone.tab contains a list of time zones and country code. They are
         * "sorted first by country, then an order within the country that (1)
         * makes some geographical sense, and (2) puts the most populous zones
         * first, where that does not contradict (1)."
         */
        try {
            String lang = Locale.getDefault().getLanguage();
            is = am.open("zone.tab");
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = reader.readLine()) != null) {
                if (!line.startsWith("#")) { // Skip comment lines
                    // 0: country code
                    // 1: coordinates
                    // 2: time zone id
                    // 3: comments
                    final String[] fields = line.split("\t");
                    final String timeZoneId = fields[2];
                    final String countryCode = fields[0];
                    final TimeZone tz = TimeZone.getTimeZone(timeZoneId);
                    if (tz == null) {
                        Log.e(TAG, "Timezone not found: " + timeZoneId);
                        continue;
                    }

                    /*
                     * Dropping non-GMT tzs without a country code. They are not
                     * really needed and they are dups but missing proper
                     * country codes. e.g. WET CET MST7MDT PST8PDT Asia/Khandyga
                     * Asia/Ust-Nera EST
                     */
                    if (countryCode == null && !timeZoneId.startsWith("Etc/GMT")) {
                        processedTimeZones.add(timeZoneId);
                        continue;
                    }

                    // Remember the mapping between the country code and display
                    // name
                    String country = mCountryCodeToNameMap.get(countryCode);
                    if (country == null) {
                        country = getCountryNames(lang, countryCode);
                        mCountryCodeToNameMap.put(countryCode, country);
                    }

                    // TODO Don't like this here but need to get the country of
                    // the default tz.

                    // Find the country of the default tz
                    if (mDefaultTimeZoneId != null && mDefaultTimeZoneCountry == null
                            && timeZoneId.equals(mAlternateDefaultTimeZoneId)) {
                        mDefaultTimeZoneCountry = country;
                        TimeZone defaultTz = TimeZone.getTimeZone(mDefaultTimeZoneId);
                        if (defaultTz != null) {
                            mDefaultTimeZoneInfo = new TimeZoneInfo(defaultTz, country);

                            int tzToOverride = getIdenticalTimeZoneInTheCountry(mDefaultTimeZoneInfo);
                            if (tzToOverride == -1) {
                                if (DEBUG) {
                                    Log.e(TAG, "Adding default time zone: "
                                            + mDefaultTimeZoneInfo.toString());
                                }
                                mTimeZones.add(mDefaultTimeZoneInfo);
                            } else {
                                mTimeZones.add(tzToOverride, mDefaultTimeZoneInfo);
                                if (DEBUG) {
                                    TimeZoneInfo tzInfoToOverride = mTimeZones.get(tzToOverride);
                                    String tzIdToOverride = tzInfoToOverride.mTzId;
                                    Log.e(TAG, "Replaced by default tz: "
                                            + tzInfoToOverride.toString());
                                    Log.e(TAG, "Adding default time zone: "
                                            + mDefaultTimeZoneInfo.toString());
                                }
                            }
                        }
                    }

                    // Add to the list of time zones if the time zone is unique
                    // in the given country.
                    TimeZoneInfo timeZoneInfo = new TimeZoneInfo(tz, country);
                    int identicalTzIdx = getIdenticalTimeZoneInTheCountry(timeZoneInfo);
                    if (identicalTzIdx == -1) {
                        if (DEBUG) {
                            Log.e(TAG, "# Adding time zone: " + timeZoneId + " ## " +
                                    tz.getDisplayName());
                        }
                        mTimeZones.add(timeZoneInfo);
                    } else {
                        if (DEBUG) {
                            Log.e(TAG, "# Dropping identical time zone: " + timeZoneId + " ## " +
                                    tz.getDisplayName());
                        }
                    }
                    processedTimeZones.add(timeZoneId);
                }
            }

        } catch (IOException ex) {
            Log.e(TAG, "Failed to read 'zone.tab'.");
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException ignored) {
            }
        }

        return processedTimeZones;
    
private voidpopulateDisplayNameOverrides(android.content.res.Resources resources)

        String[] ids = resources.getStringArray(R.array.timezone_rename_ids);
        String[] labels = resources.getStringArray(R.array.timezone_rename_labels);

        int length = ids.length;
        if (ids.length != labels.length) {
            Log.e(TAG, "timezone_rename_ids len=" + ids.length + " timezone_rename_labels len="
                    + labels.length);
            length = Math.min(ids.length, labels.length);
        }

        for (int i = 0; i < length; i++) {
            TimeZoneInfo tzi = mTimeZonesById.get(ids[i]);
            if (tzi != null) {
                tzi.mDisplayName = labels[i];
            } else {
                Log.e(TAG, "Could not find timezone with label: "+labels[i]);
            }
        }
    
private voidprintTimeZones()

        TimeZoneInfo last = null;
        boolean first = true;
        for (TimeZoneInfo tz : mTimeZones) {
            // All
            if (false) {
                Log.e("ALL", tz.toString());
            }

            // GMT
            if (true) {
                String name = tz.mTz.getDisplayName();
                if (name.startsWith("GMT") && !tz.mTzId.startsWith("Etc/GMT")) {
                    Log.e("GMT", tz.toString());
                }
            }

            // Dups
            if (true && last != null) {
                if (last.compareTo(tz) == 0) {
                    if (first) {
                        Log.e("SAME", last.toString());
                        first = false;
                    }
                    Log.e("SAME", tz.toString());
                } else {
                    first = true;
                }
            }
            last = tz;
        }
        Log.e(TAG, "Total number of tz's = " + mTimeZones.size());
    
public voidsetTime(long timeMillis)

        mTimeMillis = timeMillis;
    
public intsize()

        return mTimeZones.size();