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; }
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); } }