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