static jobjectArray TimeZones_getZoneStringsImpl(JNIEnv* env, jclass, jstring localeName, jobjectArray timeZoneIds) {
    Locale locale = getLocale(env, localeName);

    // We could use TimeZone::getDisplayName, but that's even slower
    // because it creates a new SimpleDateFormat each time.
    // We're better off using SimpleDateFormat directly.

    // We can't use DateFormatSymbols::getZoneStrings because that
    // uses its own set of time zone ids and contains empty strings
    // instead of GMT offsets (a pity, because it's a bit faster than this code).

    UErrorCode status = U_ZERO_ERROR;
    UnicodeString longPattern("zzzz", 4, US_INV);
    SimpleDateFormat longFormat(longPattern, locale, status);
    // 'z' only uses "common" abbreviations. 'V' allows all known abbreviations.
    // For example, "PST" is in common use in en_US, but "CET" isn't.
    UnicodeString commonShortPattern("z", 1, US_INV);
    SimpleDateFormat shortFormat(commonShortPattern, locale, status);
    UnicodeString allShortPattern("V", 1, US_INV);
    SimpleDateFormat allShortFormat(allShortPattern, locale, status);

    UnicodeString utc("UTC", 3, US_INV);

    // TODO: use of fixed dates prevents us from using the correct historical name when formatting dates.
    // TODO: use of dates not in the current year could cause us to output obsoleted names.
    // 15th January 2008
    UDate date1 = 1203105600000.0;
    // 15th July 2008
    UDate date2 = 1218826800000.0;

    // In the first pass, we get the long names for the time zone.
    // We also get any commonly-used abbreviations.
    std::vector<TimeZoneNames> table;
    typedef std::map<UnicodeString, UnicodeString*> AbbreviationMap;
    AbbreviationMap usedAbbreviations;
    size_t idCount = env->GetArrayLength(timeZoneIds);
    for (size_t i = 0; i < idCount; ++i) {
        ScopedLocalRef<jstring> javaZoneId(env,
                reinterpret_cast<jstring>(env->GetObjectArrayElement(timeZoneIds, i)));
        ScopedJavaUnicodeString zoneId(env, javaZoneId.get());
        UnicodeString id(zoneId.unicodeString());

        TimeZoneNames row;
        if (isUtc(id)) {
            // ICU doesn't have names for the UTC zones; it just says "GMT+00:00" for both
            // long and short names. We don't want this. The best we can do is use "UTC"
            // for everything (since we don't know how to say "Universal Coordinated Time").
            row.tz = NULL;
            row.longStd = row.shortStd = row.longDst = row.shortDst = utc;
            table.push_back(row);
            usedAbbreviations[utc] = &utc;
            continue;
        }

        row.tz = TimeZone::createTimeZone(id);
        longFormat.setTimeZone(*row.tz);
        shortFormat.setTimeZone(*row.tz);

        int32_t daylightOffset;
        int32_t rawOffset;
        row.tz->getOffset(date1, false, rawOffset, daylightOffset, status);
        if (daylightOffset != 0) {
            // The TimeZone is reporting that we are in daylight time for the winter date.
            // The dates are for the wrong hemisphere, so swap them.
            row.standardDate = date2;
            row.daylightSavingDate = date1;
        } else {
            row.standardDate = date1;
            row.daylightSavingDate = date2;
        }

        longFormat.format(row.standardDate, row.longStd);
        shortFormat.format(row.standardDate, row.shortStd);
        if (row.tz->useDaylightTime()) {
            longFormat.format(row.daylightSavingDate, row.longDst);
            shortFormat.format(row.daylightSavingDate, row.shortDst);
        } else {
            row.longDst = row.longStd;
            row.shortDst = row.shortStd;
        }

        table.push_back(row);
        usedAbbreviations[row.shortStd] = &row.longStd;
        usedAbbreviations[row.shortDst] = &row.longDst;
    }

    // In the second pass, we create the Java String[][].
    // We also look for any uncommon abbreviations that don't conflict with ones we've already seen.
    jobjectArray result = env->NewObjectArray(idCount, JniConstants::stringArrayClass, NULL);
    UnicodeString gmt("GMT", 3, US_INV);
    for (size_t i = 0; i < table.size(); ++i) {
        TimeZoneNames& row(table[i]);
        // Did we get a GMT offset instead of an abbreviation?
        if (row.shortStd.length() > 3 && row.shortStd.startsWith(gmt)) {
            // See if we can do better...
            UnicodeString uncommonStd, uncommonDst;
            allShortFormat.setTimeZone(*row.tz);
            allShortFormat.format(row.standardDate, uncommonStd);
            if (row.tz->useDaylightTime()) {
                allShortFormat.format(row.daylightSavingDate, uncommonDst);
            } else {
                uncommonDst = uncommonStd;
            }

            // If this abbreviation isn't already in use, we can use it.
            AbbreviationMap::iterator it = usedAbbreviations.find(uncommonStd);
            if (it == usedAbbreviations.end() || *(it->second) == row.longStd) {
                row.shortStd = uncommonStd;
                usedAbbreviations[row.shortStd] = &row.longStd;
            }
            it = usedAbbreviations.find(uncommonDst);
            if (it == usedAbbreviations.end() || *(it->second) == row.longDst) {
                row.shortDst = uncommonDst;
                usedAbbreviations[row.shortDst] = &row.longDst;
            }
        }
        // Fill in whatever we got.
        ScopedLocalRef<jobjectArray> javaRow(env, env->NewObjectArray(5, JniConstants::stringClass, NULL));
        ScopedLocalRef<jstring> id(env, reinterpret_cast<jstring>(env->GetObjectArrayElement(timeZoneIds, i)));
        env->SetObjectArrayElement(javaRow.get(), 0, id.get());
        setStringArrayElement(env, javaRow.get(), 1, row.longStd);
        setStringArrayElement(env, javaRow.get(), 2, row.shortStd);
        setStringArrayElement(env, javaRow.get(), 3, row.longDst);
        setStringArrayElement(env, javaRow.get(), 4, row.shortDst);
        env->SetObjectArrayElement(result, i, javaRow.get());
        delete row.tz;
    }

    return result;
}
Esempio n. 2
0
static void getTimeZonesNative(JNIEnv* env, jclass clazz,
        jobjectArray outerArray, jstring locale) {

    // get all timezone objects
    jobjectArray zoneIdArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 0);
    int count = env->GetArrayLength(zoneIdArray);
    TimeZone* zones[count];
    for(int i = 0; i < count; i++) {
        jstring id = (jstring) env->GetObjectArrayElement(zoneIdArray, i);
        zones[i] = timeZoneFromId(env, id);
        env->DeleteLocalRef(id);
    }

    Locale loc = getLocale(env, locale);

    UErrorCode status = U_ZERO_ERROR;
    UnicodeString longPattern("zzzz","");
    SimpleDateFormat longFormat(longPattern, loc, status);
    UnicodeString shortPattern("z","");
    SimpleDateFormat shortFormat(shortPattern, loc, status);

    jobjectArray longStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 1);
    jobjectArray shortStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 2);
    jobjectArray longDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 3);
    jobjectArray shortDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 4);

    // 15th January 2008
    UDate date1 = 1203105600000.0;
    // 15th July 2008
    UDate date2 = 1218826800000.0;

    for (int i = 0; i < count; ++i) {
        TimeZone* tz = zones[i];
        longFormat.setTimeZone(*tz);
        shortFormat.setTimeZone(*tz);

        int32_t daylightOffset;
        int32_t rawOffset;
        tz->getOffset(date1, false, rawOffset, daylightOffset, status);
        UDate standardDate;
        UDate daylightSavingDate;
        if (daylightOffset != 0) {
            // The Timezone is reporting that we are in daylight time
            // for the winter date.  The dates are for the wrong hemisphere,
            // swap them.
            standardDate = date2;
            daylightSavingDate = date1;
        } else {
            standardDate = date1;
            daylightSavingDate = date2;
        }

        jstring content = formatDate(env, shortFormat, daylightSavingDate);
        env->SetObjectArrayElement(shortDlTimeArray, i, content);
        env->DeleteLocalRef(content);

        content = formatDate(env, shortFormat, standardDate);
        env->SetObjectArrayElement(shortStdTimeArray, i, content);
        env->DeleteLocalRef(content);

        content = formatDate(env, longFormat, daylightSavingDate);
        env->SetObjectArrayElement(longDlTimeArray, i, content);
        env->DeleteLocalRef(content);

        content = formatDate(env, longFormat, standardDate);
        env->SetObjectArrayElement(longStdTimeArray, i, content);
        env->DeleteLocalRef(content);

        delete tz;
    }
}
static void getTimeZonesNative(JNIEnv* env, jclass clazz,
        jobjectArray outerArray, jstring locale) {
    // LOGI("ENTER getTimeZonesNative");
    
    UErrorCode status = U_ZERO_ERROR;

    jobjectArray zoneIdArray;
    jobjectArray longStdTimeArray;
    jobjectArray shortStdTimeArray;
    jobjectArray longDlTimeArray;
    jobjectArray shortDlTimeArray;

    jstring content;
    jstring strObj;
    const jchar *res;
    UnicodeString resU;
    jint length;
    const UnicodeString *zoneID;
    DateFormat *df;

    UnicodeString longPattern("zzzz","");
    UnicodeString shortPattern("z","");
      
    Locale loc = getLocale(env, locale);

    SimpleDateFormat longFormat(longPattern, loc, status);
    SimpleDateFormat shortFormat(shortPattern, loc, status);


    zoneIdArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 0);
    longStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 1);
    shortStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 2);
    longDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 3);
    shortDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 4);

    int count = env->GetArrayLength(zoneIdArray);

    TimeZone* zones[count];
    
    // get all timezone objects
    for(int i = 0; i < count; i++) {
        strObj = (jstring) env->GetObjectArrayElement(zoneIdArray, i);
        length = env->GetStringLength(strObj);
        res = env->GetStringChars(strObj, NULL);
        const UnicodeString zoneID((UChar *)res, length);
        env->ReleaseStringChars(strObj, res);
        zones[i] = TimeZone::createTimeZone(zoneID);
    }

    // 15th January 2008
    UDate date1 = 1203105600000.0;
    // 15th July 2008
    UDate date2 = 1218826800000.0;

    for (int i = 0; i < count; i++) {
           TimeZone *tz = zones[i];
           longFormat.setTimeZone(*tz);
           shortFormat.setTimeZone(*tz);
           
           int32_t daylightOffset;
           int32_t rawOffset;
           UDate standardDate;
           UDate daylightSavingDate;
           tz->getOffset(date1, false, rawOffset, daylightOffset, status);
           if (daylightOffset != 0) {
               // The Timezone is reporting that we are in daylight time
               // for the winter date.  The dates are for the wrong hemisphere,
               // swap them.
               standardDate = date2;
               daylightSavingDate = date1;
           } else {
               standardDate = date1;
               daylightSavingDate = date2;
           }
                     
           UnicodeString shortDayLight;
           UnicodeString longDayLight;
           UnicodeString shortStandard;
           UnicodeString longStandard;
           
           shortFormat.format(daylightSavingDate, shortDayLight);
           content = getJStringFromUnicodeString(env, shortDayLight);
           env->SetObjectArrayElement(shortDlTimeArray, i, content);
           env->DeleteLocalRef(content);

           shortFormat.format(standardDate, shortStandard);
           content = getJStringFromUnicodeString(env, shortStandard);
           env->SetObjectArrayElement(shortStdTimeArray, i, content);
           env->DeleteLocalRef(content);

           longFormat.format (daylightSavingDate, longDayLight);
           content = getJStringFromUnicodeString(env, longDayLight);
           env->SetObjectArrayElement(longDlTimeArray, i, content);
           env->DeleteLocalRef(content);

           longFormat.format (standardDate, longStandard);
           content = getJStringFromUnicodeString(env, longStandard);
           env->SetObjectArrayElement(longStdTimeArray, i, content);
           env->DeleteLocalRef(content);
           delete(tz);
    }
}