1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "TimeZoneNames" 18 19 #include "IcuUtilities.h" 20 #include "JNIHelp.h" 21 #include "JniConstants.h" 22 #include "JniException.h" 23 #include "ScopedJavaUnicodeString.h" 24 #include "ScopedLocalRef.h" 25 #include "ScopedUtfChars.h" 26 #include "UniquePtr.h" 27 #include "unicode/calendar.h" 28 #include "unicode/timezone.h" 29 #include "unicode/tznames.h" 30 31 static bool isUtc(const UnicodeString& id) { 32 static const UnicodeString kEtcUct("Etc/UCT", 7, US_INV); 33 static const UnicodeString kEtcUtc("Etc/UTC", 7, US_INV); 34 static const UnicodeString kEtcUniversal("Etc/Universal", 13, US_INV); 35 static const UnicodeString kEtcZulu("Etc/Zulu", 8, US_INV); 36 37 static const UnicodeString kUct("UCT", 3, US_INV); 38 static const UnicodeString kUtc("UTC", 3, US_INV); 39 static const UnicodeString kUniversal("Universal", 9, US_INV); 40 static const UnicodeString kZulu("Zulu", 4, US_INV); 41 42 return id == kEtcUct || id == kEtcUtc || id == kEtcUniversal || id == kEtcZulu || 43 id == kUct || id == kUtc || id == kUniversal || id == kZulu; 44 } 45 46 static void setStringArrayElement(JNIEnv* env, jobjectArray array, int i, const UnicodeString& s) { 47 // Fill in whatever we got. We don't use the display names if they're "GMT[+-]xx:xx" 48 // because icu4c doesn't use the up-to-date time zone transition data, so it gets these 49 // wrong. TimeZone.getDisplayName creates accurate names on demand. 50 // TODO: investigate whether it's worth doing that work once in the Java wrapper instead of on-demand. 51 static const UnicodeString kGmt("GMT", 3, US_INV); 52 if (!s.isBogus() && !s.startsWith(kGmt)) { 53 ScopedLocalRef<jstring> javaString(env, env->NewString(s.getBuffer(), s.length())); 54 env->SetObjectArrayElement(array, i, javaString.get()); 55 } 56 } 57 58 static void TimeZoneNames_fillZoneStrings(JNIEnv* env, jclass, jstring localeName, jobjectArray result) { 59 Locale locale = getLocale(env, localeName); 60 61 UErrorCode status = U_ZERO_ERROR; 62 UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(locale, status)); 63 if (maybeThrowIcuException(env, "TimeZoneNames::createInstance", status)) { 64 return; 65 } 66 67 const UDate now(Calendar::getNow()); 68 69 static const UnicodeString kUtc("UTC", 3, US_INV); 70 static const UnicodeString pacific_apia("Pacific/Apia", 12, US_INV); 71 72 size_t id_count = env->GetArrayLength(result); 73 for (size_t i = 0; i < id_count; ++i) { 74 ScopedLocalRef<jobjectArray> java_row(env, 75 reinterpret_cast<jobjectArray>(env->GetObjectArrayElement(result, i))); 76 ScopedLocalRef<jstring> java_zone_id(env, 77 reinterpret_cast<jstring>(env->GetObjectArrayElement(java_row.get(), 0))); 78 ScopedJavaUnicodeString zone_id(env, java_zone_id.get()); 79 if (!zone_id.valid()) { 80 return; 81 } 82 83 UnicodeString long_std; 84 names->getDisplayName(zone_id.unicodeString(), UTZNM_LONG_STANDARD, now, long_std); 85 UnicodeString short_std; 86 names->getDisplayName(zone_id.unicodeString(), UTZNM_SHORT_STANDARD, now, short_std); 87 UnicodeString long_dst; 88 names->getDisplayName(zone_id.unicodeString(), UTZNM_LONG_DAYLIGHT, now, long_dst); 89 UnicodeString short_dst; 90 names->getDisplayName(zone_id.unicodeString(), UTZNM_SHORT_DAYLIGHT, now, short_dst); 91 92 if (isUtc(zone_id.unicodeString())) { 93 // ICU doesn't have names for the UTC zones; it just says "GMT+00:00" for both 94 // long and short names. We don't want this. The best we can do is use "UTC" 95 // for everything (since we don't know how to say "Universal Coordinated Time" in 96 // every language). 97 // TODO: check CLDR doesn't actually have this somewhere. 98 long_std = short_std = long_dst = short_dst = kUtc; 99 } else if (zone_id.unicodeString() == pacific_apia) { 100 // icu4c 50 doesn't know Samoa has DST yet. http://b/7955614 101 if (long_dst.isBogus()) { 102 long_dst = "Samoa Daylight Time"; 103 } 104 } 105 106 setStringArrayElement(env, java_row.get(), 1, long_std); 107 setStringArrayElement(env, java_row.get(), 2, short_std); 108 setStringArrayElement(env, java_row.get(), 3, long_dst); 109 setStringArrayElement(env, java_row.get(), 4, short_dst); 110 } 111 } 112 113 static JNINativeMethod gMethods[] = { 114 NATIVE_METHOD(TimeZoneNames, fillZoneStrings, "(Ljava/lang/String;[[Ljava/lang/String;)V"), 115 }; 116 void register_libcore_icu_TimeZoneNames(JNIEnv* env) { 117 jniRegisterNativeMethods(env, "libcore/icu/TimeZoneNames", gMethods, NELEM(gMethods)); 118 } 119