11cb0ef41Sopenharmony_ci// © 2016 and later: Unicode, Inc. and others. 21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 31cb0ef41Sopenharmony_ci/* 41cb0ef41Sopenharmony_ci******************************************************************************* 51cb0ef41Sopenharmony_ci* Copyright (C) 2007-2014, International Business Machines Corporation and 61cb0ef41Sopenharmony_ci* others. All Rights Reserved. 71cb0ef41Sopenharmony_ci******************************************************************************* 81cb0ef41Sopenharmony_ci*/ 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#include "unicode/utypes.h" 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci#if !UCONFIG_NO_FORMATTING 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ci#include "zonemeta.h" 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ci#include "unicode/timezone.h" 171cb0ef41Sopenharmony_ci#include "unicode/ustring.h" 181cb0ef41Sopenharmony_ci#include "unicode/putil.h" 191cb0ef41Sopenharmony_ci#include "unicode/simpletz.h" 201cb0ef41Sopenharmony_ci#include "unicode/strenum.h" 211cb0ef41Sopenharmony_ci#include "umutex.h" 221cb0ef41Sopenharmony_ci#include "uvector.h" 231cb0ef41Sopenharmony_ci#include "cmemory.h" 241cb0ef41Sopenharmony_ci#include "gregoimp.h" 251cb0ef41Sopenharmony_ci#include "cstring.h" 261cb0ef41Sopenharmony_ci#include "ucln_in.h" 271cb0ef41Sopenharmony_ci#include "uassert.h" 281cb0ef41Sopenharmony_ci#include "uresimp.h" 291cb0ef41Sopenharmony_ci#include "uhash.h" 301cb0ef41Sopenharmony_ci#include "olsontz.h" 311cb0ef41Sopenharmony_ci#include "uinvchar.h" 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_cistatic icu::UMutex gZoneMetaLock; 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci// CLDR Canonical ID mapping table 361cb0ef41Sopenharmony_cistatic UHashtable *gCanonicalIDCache = nullptr; 371cb0ef41Sopenharmony_cistatic icu::UInitOnce gCanonicalIDCacheInitOnce {}; 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci// Metazone mapping table 401cb0ef41Sopenharmony_cistatic UHashtable *gOlsonToMeta = nullptr; 411cb0ef41Sopenharmony_cistatic icu::UInitOnce gOlsonToMetaInitOnce {}; 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci// Available metazone IDs vector and table 441cb0ef41Sopenharmony_cistatic icu::UVector *gMetaZoneIDs = nullptr; 451cb0ef41Sopenharmony_cistatic UHashtable *gMetaZoneIDTable = nullptr; 461cb0ef41Sopenharmony_cistatic icu::UInitOnce gMetaZoneIDsInitOnce {}; 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci// Country info vectors 491cb0ef41Sopenharmony_cistatic icu::UVector *gSingleZoneCountries = nullptr; 501cb0ef41Sopenharmony_cistatic icu::UVector *gMultiZonesCountries = nullptr; 511cb0ef41Sopenharmony_cistatic icu::UInitOnce gCountryInfoVectorsInitOnce {}; 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ciU_CDECL_BEGIN 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci/** 561cb0ef41Sopenharmony_ci * Cleanup callback func 571cb0ef41Sopenharmony_ci */ 581cb0ef41Sopenharmony_cistatic UBool U_CALLCONV zoneMeta_cleanup() 591cb0ef41Sopenharmony_ci{ 601cb0ef41Sopenharmony_ci if (gCanonicalIDCache != nullptr) { 611cb0ef41Sopenharmony_ci uhash_close(gCanonicalIDCache); 621cb0ef41Sopenharmony_ci gCanonicalIDCache = nullptr; 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci gCanonicalIDCacheInitOnce.reset(); 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci if (gOlsonToMeta != nullptr) { 671cb0ef41Sopenharmony_ci uhash_close(gOlsonToMeta); 681cb0ef41Sopenharmony_ci gOlsonToMeta = nullptr; 691cb0ef41Sopenharmony_ci } 701cb0ef41Sopenharmony_ci gOlsonToMetaInitOnce.reset(); 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci if (gMetaZoneIDTable != nullptr) { 731cb0ef41Sopenharmony_ci uhash_close(gMetaZoneIDTable); 741cb0ef41Sopenharmony_ci gMetaZoneIDTable = nullptr; 751cb0ef41Sopenharmony_ci } 761cb0ef41Sopenharmony_ci // delete after closing gMetaZoneIDTable, because it holds 771cb0ef41Sopenharmony_ci // value objects held by the hashtable 781cb0ef41Sopenharmony_ci delete gMetaZoneIDs; 791cb0ef41Sopenharmony_ci gMetaZoneIDs = nullptr; 801cb0ef41Sopenharmony_ci gMetaZoneIDsInitOnce.reset(); 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci delete gSingleZoneCountries; 831cb0ef41Sopenharmony_ci gSingleZoneCountries = nullptr; 841cb0ef41Sopenharmony_ci delete gMultiZonesCountries; 851cb0ef41Sopenharmony_ci gMultiZonesCountries = nullptr; 861cb0ef41Sopenharmony_ci gCountryInfoVectorsInitOnce.reset(); 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci return true; 891cb0ef41Sopenharmony_ci} 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci/** 921cb0ef41Sopenharmony_ci * Deleter for char16_t* string 931cb0ef41Sopenharmony_ci */ 941cb0ef41Sopenharmony_cistatic void U_CALLCONV 951cb0ef41Sopenharmony_cideleteUCharString(void *obj) { 961cb0ef41Sopenharmony_ci char16_t *entry = (char16_t*)obj; 971cb0ef41Sopenharmony_ci uprv_free(entry); 981cb0ef41Sopenharmony_ci} 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci/** 1011cb0ef41Sopenharmony_ci * Deleter for OlsonToMetaMappingEntry 1021cb0ef41Sopenharmony_ci */ 1031cb0ef41Sopenharmony_cistatic void U_CALLCONV 1041cb0ef41Sopenharmony_cideleteOlsonToMetaMappingEntry(void *obj) { 1051cb0ef41Sopenharmony_ci icu::OlsonToMetaMappingEntry *entry = (icu::OlsonToMetaMappingEntry*)obj; 1061cb0ef41Sopenharmony_ci delete entry; 1071cb0ef41Sopenharmony_ci} 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ciU_CDECL_END 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ciU_NAMESPACE_BEGIN 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci#define ZID_KEY_MAX 128 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_cistatic const char gMetaZones[] = "metaZones"; 1161cb0ef41Sopenharmony_cistatic const char gMetazoneInfo[] = "metazoneInfo"; 1171cb0ef41Sopenharmony_cistatic const char gMapTimezonesTag[] = "mapTimezones"; 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_cistatic const char gKeyTypeData[] = "keyTypeData"; 1201cb0ef41Sopenharmony_cistatic const char gTypeAliasTag[] = "typeAlias"; 1211cb0ef41Sopenharmony_cistatic const char gTypeMapTag[] = "typeMap"; 1221cb0ef41Sopenharmony_cistatic const char gTimezoneTag[] = "timezone"; 1231cb0ef41Sopenharmony_cistatic const char gIanaMapTag[] = "ianaMap"; 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_cistatic const char gPrimaryZonesTag[] = "primaryZones"; 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_cistatic const char gWorldTag[] = "001"; 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_cistatic const char16_t gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001" 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_cistatic const char16_t gDefaultFrom[] = {0x31, 0x39, 0x37, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31, 1321cb0ef41Sopenharmony_ci 0x20, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x00}; // "1970-01-01 00:00" 1331cb0ef41Sopenharmony_cistatic const char16_t gDefaultTo[] = {0x39, 0x39, 0x39, 0x39, 0x2D, 0x31, 0x32, 0x2D, 0x33, 0x31, 1341cb0ef41Sopenharmony_ci 0x20, 0x32, 0x33, 0x3A, 0x35, 0x39, 0x00}; // "9999-12-31 23:59" 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_cistatic const char16_t gCustomTzPrefix[] = {0x47, 0x4D, 0x54, 0}; // "GMT" 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci#define ASCII_DIGIT(c) (((c)>=0x30 && (c)<=0x39) ? (c)-0x30 : -1) 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci/* 1411cb0ef41Sopenharmony_ci * Convert a date string used by metazone mappings to UDate. 1421cb0ef41Sopenharmony_ci * The format used by CLDR metazone mapping is "yyyy-MM-dd HH:mm". 1431cb0ef41Sopenharmony_ci */ 1441cb0ef41Sopenharmony_cistatic UDate 1451cb0ef41Sopenharmony_ciparseDate (const char16_t *text, UErrorCode &status) { 1461cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 1471cb0ef41Sopenharmony_ci return 0; 1481cb0ef41Sopenharmony_ci } 1491cb0ef41Sopenharmony_ci int32_t len = u_strlen(text); 1501cb0ef41Sopenharmony_ci if (len != 16 && len != 10) { 1511cb0ef41Sopenharmony_ci // It must be yyyy-MM-dd HH:mm (length 16) or yyyy-MM-dd (length 10) 1521cb0ef41Sopenharmony_ci status = U_INVALID_FORMAT_ERROR; 1531cb0ef41Sopenharmony_ci return 0; 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci int32_t year = 0, month = 0, day = 0, hour = 0, min = 0, n; 1571cb0ef41Sopenharmony_ci int32_t idx; 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci // "yyyy" (0 - 3) 1601cb0ef41Sopenharmony_ci for (idx = 0; idx <= 3 && U_SUCCESS(status); idx++) { 1611cb0ef41Sopenharmony_ci n = ASCII_DIGIT((int32_t)text[idx]); 1621cb0ef41Sopenharmony_ci if (n >= 0) { 1631cb0ef41Sopenharmony_ci year = 10*year + n; 1641cb0ef41Sopenharmony_ci } else { 1651cb0ef41Sopenharmony_ci status = U_INVALID_FORMAT_ERROR; 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci // "MM" (5 - 6) 1691cb0ef41Sopenharmony_ci for (idx = 5; idx <= 6 && U_SUCCESS(status); idx++) { 1701cb0ef41Sopenharmony_ci n = ASCII_DIGIT((int32_t)text[idx]); 1711cb0ef41Sopenharmony_ci if (n >= 0) { 1721cb0ef41Sopenharmony_ci month = 10*month + n; 1731cb0ef41Sopenharmony_ci } else { 1741cb0ef41Sopenharmony_ci status = U_INVALID_FORMAT_ERROR; 1751cb0ef41Sopenharmony_ci } 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci // "dd" (8 - 9) 1781cb0ef41Sopenharmony_ci for (idx = 8; idx <= 9 && U_SUCCESS(status); idx++) { 1791cb0ef41Sopenharmony_ci n = ASCII_DIGIT((int32_t)text[idx]); 1801cb0ef41Sopenharmony_ci if (n >= 0) { 1811cb0ef41Sopenharmony_ci day = 10*day + n; 1821cb0ef41Sopenharmony_ci } else { 1831cb0ef41Sopenharmony_ci status = U_INVALID_FORMAT_ERROR; 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci } 1861cb0ef41Sopenharmony_ci if (len == 16) { 1871cb0ef41Sopenharmony_ci // "HH" (11 - 12) 1881cb0ef41Sopenharmony_ci for (idx = 11; idx <= 12 && U_SUCCESS(status); idx++) { 1891cb0ef41Sopenharmony_ci n = ASCII_DIGIT((int32_t)text[idx]); 1901cb0ef41Sopenharmony_ci if (n >= 0) { 1911cb0ef41Sopenharmony_ci hour = 10*hour + n; 1921cb0ef41Sopenharmony_ci } else { 1931cb0ef41Sopenharmony_ci status = U_INVALID_FORMAT_ERROR; 1941cb0ef41Sopenharmony_ci } 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci // "mm" (14 - 15) 1971cb0ef41Sopenharmony_ci for (idx = 14; idx <= 15 && U_SUCCESS(status); idx++) { 1981cb0ef41Sopenharmony_ci n = ASCII_DIGIT((int32_t)text[idx]); 1991cb0ef41Sopenharmony_ci if (n >= 0) { 2001cb0ef41Sopenharmony_ci min = 10*min + n; 2011cb0ef41Sopenharmony_ci } else { 2021cb0ef41Sopenharmony_ci status = U_INVALID_FORMAT_ERROR; 2031cb0ef41Sopenharmony_ci } 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 2081cb0ef41Sopenharmony_ci UDate date = Grego::fieldsToDay(year, month - 1, day) * U_MILLIS_PER_DAY 2091cb0ef41Sopenharmony_ci + hour * U_MILLIS_PER_HOUR + min * U_MILLIS_PER_MINUTE; 2101cb0ef41Sopenharmony_ci return date; 2111cb0ef41Sopenharmony_ci } 2121cb0ef41Sopenharmony_ci return 0; 2131cb0ef41Sopenharmony_ci} 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_cistatic void U_CALLCONV initCanonicalIDCache(UErrorCode &status) { 2161cb0ef41Sopenharmony_ci gCanonicalIDCache = uhash_open(uhash_hashUChars, uhash_compareUChars, nullptr, &status); 2171cb0ef41Sopenharmony_ci if (gCanonicalIDCache == nullptr) { 2181cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 2211cb0ef41Sopenharmony_ci gCanonicalIDCache = nullptr; 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci // No key/value deleters - keys/values are from a resource bundle 2241cb0ef41Sopenharmony_ci ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); 2251cb0ef41Sopenharmony_ci} 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ciconst char16_t* U_EXPORT2 2291cb0ef41Sopenharmony_ciZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) { 2301cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 2311cb0ef41Sopenharmony_ci return nullptr; 2321cb0ef41Sopenharmony_ci } 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci if (tzid.isBogus() || tzid.length() > ZID_KEY_MAX) { 2351cb0ef41Sopenharmony_ci status = U_ILLEGAL_ARGUMENT_ERROR; 2361cb0ef41Sopenharmony_ci return nullptr; 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci // Checking the cached results 2401cb0ef41Sopenharmony_ci umtx_initOnce(gCanonicalIDCacheInitOnce, &initCanonicalIDCache, status); 2411cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 2421cb0ef41Sopenharmony_ci return nullptr; 2431cb0ef41Sopenharmony_ci } 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci const char16_t *canonicalID = nullptr; 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ci UErrorCode tmpStatus = U_ZERO_ERROR; 2481cb0ef41Sopenharmony_ci char16_t utzid[ZID_KEY_MAX + 1]; 2491cb0ef41Sopenharmony_ci tzid.extract(utzid, ZID_KEY_MAX + 1, tmpStatus); 2501cb0ef41Sopenharmony_ci U_ASSERT(tmpStatus == U_ZERO_ERROR); // we checked the length of tzid already 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci if (!uprv_isInvariantUString(utzid, -1)) { 2531cb0ef41Sopenharmony_ci // All of known tz IDs are only containing ASCII invariant characters. 2541cb0ef41Sopenharmony_ci status = U_ILLEGAL_ARGUMENT_ERROR; 2551cb0ef41Sopenharmony_ci return nullptr; 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci // Check if it was already cached 2591cb0ef41Sopenharmony_ci umtx_lock(&gZoneMetaLock); 2601cb0ef41Sopenharmony_ci { 2611cb0ef41Sopenharmony_ci canonicalID = (const char16_t *)uhash_get(gCanonicalIDCache, utzid); 2621cb0ef41Sopenharmony_ci } 2631cb0ef41Sopenharmony_ci umtx_unlock(&gZoneMetaLock); 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci if (canonicalID != nullptr) { 2661cb0ef41Sopenharmony_ci return canonicalID; 2671cb0ef41Sopenharmony_ci } 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci // If not, resolve CLDR canonical ID with resource data 2701cb0ef41Sopenharmony_ci UBool isInputCanonical = false; 2711cb0ef41Sopenharmony_ci char id[ZID_KEY_MAX + 1]; 2721cb0ef41Sopenharmony_ci tzid.extract(0, 0x7fffffff, id, UPRV_LENGTHOF(id), US_INV); 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci // replace '/' with ':' 2751cb0ef41Sopenharmony_ci char *p = id; 2761cb0ef41Sopenharmony_ci while (*p++) { 2771cb0ef41Sopenharmony_ci if (*p == '/') { 2781cb0ef41Sopenharmony_ci *p = ':'; 2791cb0ef41Sopenharmony_ci } 2801cb0ef41Sopenharmony_ci } 2811cb0ef41Sopenharmony_ci 2821cb0ef41Sopenharmony_ci UResourceBundle *top = ures_openDirect(nullptr, gKeyTypeData, &tmpStatus); 2831cb0ef41Sopenharmony_ci UResourceBundle *rb = ures_getByKey(top, gTypeMapTag, nullptr, &tmpStatus); 2841cb0ef41Sopenharmony_ci ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus); 2851cb0ef41Sopenharmony_ci ures_getByKey(rb, id, rb, &tmpStatus); 2861cb0ef41Sopenharmony_ci if (U_SUCCESS(tmpStatus)) { 2871cb0ef41Sopenharmony_ci // type entry (canonical) found 2881cb0ef41Sopenharmony_ci // the input is the canonical ID. resolve to const char16_t* 2891cb0ef41Sopenharmony_ci canonicalID = TimeZone::findID(tzid); 2901cb0ef41Sopenharmony_ci isInputCanonical = true; 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci if (canonicalID == nullptr) { 2941cb0ef41Sopenharmony_ci // If a map element not found, then look for an alias 2951cb0ef41Sopenharmony_ci tmpStatus = U_ZERO_ERROR; 2961cb0ef41Sopenharmony_ci ures_getByKey(top, gTypeAliasTag, rb, &tmpStatus); 2971cb0ef41Sopenharmony_ci ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus); 2981cb0ef41Sopenharmony_ci const char16_t *canonical = ures_getStringByKey(rb,id,nullptr,&tmpStatus); 2991cb0ef41Sopenharmony_ci if (U_SUCCESS(tmpStatus)) { 3001cb0ef41Sopenharmony_ci // canonical map found 3011cb0ef41Sopenharmony_ci canonicalID = canonical; 3021cb0ef41Sopenharmony_ci } 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci if (canonicalID == nullptr) { 3051cb0ef41Sopenharmony_ci // Dereference the input ID using the tz data 3061cb0ef41Sopenharmony_ci const char16_t *derefer = TimeZone::dereferOlsonLink(tzid); 3071cb0ef41Sopenharmony_ci if (derefer == nullptr) { 3081cb0ef41Sopenharmony_ci status = U_ILLEGAL_ARGUMENT_ERROR; 3091cb0ef41Sopenharmony_ci } else { 3101cb0ef41Sopenharmony_ci int32_t len = u_strlen(derefer); 3111cb0ef41Sopenharmony_ci u_UCharsToChars(derefer,id,len); 3121cb0ef41Sopenharmony_ci id[len] = (char) 0; // Make sure it is null terminated. 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci // replace '/' with ':' 3151cb0ef41Sopenharmony_ci char *q = id; 3161cb0ef41Sopenharmony_ci while (*q++) { 3171cb0ef41Sopenharmony_ci if (*q == '/') { 3181cb0ef41Sopenharmony_ci *q = ':'; 3191cb0ef41Sopenharmony_ci } 3201cb0ef41Sopenharmony_ci } 3211cb0ef41Sopenharmony_ci 3221cb0ef41Sopenharmony_ci // If a dereference turned something up then look for an alias. 3231cb0ef41Sopenharmony_ci // rb still points to the alias table, so we don't have to go looking 3241cb0ef41Sopenharmony_ci // for it. 3251cb0ef41Sopenharmony_ci tmpStatus = U_ZERO_ERROR; 3261cb0ef41Sopenharmony_ci canonical = ures_getStringByKey(rb,id,nullptr,&tmpStatus); 3271cb0ef41Sopenharmony_ci if (U_SUCCESS(tmpStatus)) { 3281cb0ef41Sopenharmony_ci // canonical map for the dereferenced ID found 3291cb0ef41Sopenharmony_ci canonicalID = canonical; 3301cb0ef41Sopenharmony_ci } else { 3311cb0ef41Sopenharmony_ci canonicalID = derefer; 3321cb0ef41Sopenharmony_ci isInputCanonical = true; 3331cb0ef41Sopenharmony_ci } 3341cb0ef41Sopenharmony_ci } 3351cb0ef41Sopenharmony_ci } 3361cb0ef41Sopenharmony_ci } 3371cb0ef41Sopenharmony_ci ures_close(rb); 3381cb0ef41Sopenharmony_ci ures_close(top); 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 3411cb0ef41Sopenharmony_ci U_ASSERT(canonicalID != nullptr); // canocanilD must be non-nullptr here 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci // Put the resolved canonical ID to the cache 3441cb0ef41Sopenharmony_ci umtx_lock(&gZoneMetaLock); 3451cb0ef41Sopenharmony_ci { 3461cb0ef41Sopenharmony_ci const char16_t* idInCache = (const char16_t *)uhash_get(gCanonicalIDCache, utzid); 3471cb0ef41Sopenharmony_ci if (idInCache == nullptr) { 3481cb0ef41Sopenharmony_ci const char16_t* key = ZoneMeta::findTimeZoneID(tzid); 3491cb0ef41Sopenharmony_ci U_ASSERT(key != nullptr); 3501cb0ef41Sopenharmony_ci if (key != nullptr) { 3511cb0ef41Sopenharmony_ci idInCache = (const char16_t *)uhash_put(gCanonicalIDCache, (void *)key, (void *)canonicalID, &status); 3521cb0ef41Sopenharmony_ci U_ASSERT(idInCache == nullptr); 3531cb0ef41Sopenharmony_ci } 3541cb0ef41Sopenharmony_ci } 3551cb0ef41Sopenharmony_ci if (U_SUCCESS(status) && isInputCanonical) { 3561cb0ef41Sopenharmony_ci // Also put canonical ID itself into the cache if not exist 3571cb0ef41Sopenharmony_ci const char16_t *canonicalInCache = (const char16_t*)uhash_get(gCanonicalIDCache, canonicalID); 3581cb0ef41Sopenharmony_ci if (canonicalInCache == nullptr) { 3591cb0ef41Sopenharmony_ci canonicalInCache = (const char16_t *)uhash_put(gCanonicalIDCache, (void *)canonicalID, (void *)canonicalID, &status); 3601cb0ef41Sopenharmony_ci U_ASSERT(canonicalInCache == nullptr); 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci } 3631cb0ef41Sopenharmony_ci } 3641cb0ef41Sopenharmony_ci umtx_unlock(&gZoneMetaLock); 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci 3671cb0ef41Sopenharmony_ci return canonicalID; 3681cb0ef41Sopenharmony_ci} 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ciUnicodeString& U_EXPORT2 3711cb0ef41Sopenharmony_ciZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status) { 3721cb0ef41Sopenharmony_ci const char16_t *canonicalID = getCanonicalCLDRID(tzid, status); 3731cb0ef41Sopenharmony_ci if (U_FAILURE(status) || canonicalID == nullptr) { 3741cb0ef41Sopenharmony_ci systemID.setToBogus(); 3751cb0ef41Sopenharmony_ci return systemID; 3761cb0ef41Sopenharmony_ci } 3771cb0ef41Sopenharmony_ci systemID.setTo(true, canonicalID, -1); 3781cb0ef41Sopenharmony_ci return systemID; 3791cb0ef41Sopenharmony_ci} 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ciconst char16_t* U_EXPORT2 3821cb0ef41Sopenharmony_ciZoneMeta::getCanonicalCLDRID(const TimeZone& tz) { 3831cb0ef41Sopenharmony_ci if (dynamic_cast<const OlsonTimeZone *>(&tz) != nullptr) { 3841cb0ef41Sopenharmony_ci // short cut for OlsonTimeZone 3851cb0ef41Sopenharmony_ci const OlsonTimeZone *otz = (const OlsonTimeZone*)&tz; 3861cb0ef41Sopenharmony_ci return otz->getCanonicalID(); 3871cb0ef41Sopenharmony_ci } 3881cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 3891cb0ef41Sopenharmony_ci UnicodeString tzID; 3901cb0ef41Sopenharmony_ci return getCanonicalCLDRID(tz.getID(tzID), status); 3911cb0ef41Sopenharmony_ci} 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ciUnicodeString& U_EXPORT2 3941cb0ef41Sopenharmony_ciZoneMeta::getIanaID(const UnicodeString& tzid, UnicodeString& ianaID, UErrorCode& status) { 3951cb0ef41Sopenharmony_ci // First, get CLDR canonical ID 3961cb0ef41Sopenharmony_ci const char16_t *canonicalID = getCanonicalCLDRID(tzid, status); 3971cb0ef41Sopenharmony_ci if (U_FAILURE(status) || canonicalID == nullptr) { 3981cb0ef41Sopenharmony_ci ianaID.setToBogus(); 3991cb0ef41Sopenharmony_ci return ianaID; 4001cb0ef41Sopenharmony_ci } 4011cb0ef41Sopenharmony_ci // Find IANA mapping if any. 4021cb0ef41Sopenharmony_ci UErrorCode tmpStatus = U_ZERO_ERROR; 4031cb0ef41Sopenharmony_ci UnicodeString tmpKey(canonicalID); 4041cb0ef41Sopenharmony_ci tmpKey.findAndReplace(UnicodeString("/"), UnicodeString(":")); 4051cb0ef41Sopenharmony_ci char keyBuf[ZID_KEY_MAX + 1]; 4061cb0ef41Sopenharmony_ci /* int32_t keyLen = */ tmpKey.extract(0, tmpKey.length(), keyBuf, sizeof(keyBuf), US_INV); 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci StackUResourceBundle r; 4091cb0ef41Sopenharmony_ci ures_openDirectFillIn(r.getAlias(), nullptr, gKeyTypeData, &tmpStatus); 4101cb0ef41Sopenharmony_ci ures_getByKey(r.getAlias(), gIanaMapTag, r.getAlias(), &tmpStatus); 4111cb0ef41Sopenharmony_ci ures_getByKey(r.getAlias(), gTimezoneTag, r.getAlias(), &tmpStatus); 4121cb0ef41Sopenharmony_ci int32_t tmpLen = 0; 4131cb0ef41Sopenharmony_ci const char16_t* tmpIana = ures_getStringByKey(r.getAlias(), keyBuf, &tmpLen, &tmpStatus); 4141cb0ef41Sopenharmony_ci if (U_SUCCESS(tmpStatus)) { 4151cb0ef41Sopenharmony_ci ianaID.setTo(true, tmpIana, -1); 4161cb0ef41Sopenharmony_ci } else { 4171cb0ef41Sopenharmony_ci ianaID.setTo(true, canonicalID, -1); 4181cb0ef41Sopenharmony_ci } 4191cb0ef41Sopenharmony_ci return ianaID; 4201cb0ef41Sopenharmony_ci} 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_cistatic void U_CALLCONV countryInfoVectorsInit(UErrorCode &status) { 4231cb0ef41Sopenharmony_ci // Create empty vectors 4241cb0ef41Sopenharmony_ci // No deleters for these UVectors, it's a reference to a resource bundle string. 4251cb0ef41Sopenharmony_ci gSingleZoneCountries = new UVector(nullptr, uhash_compareUChars, status); 4261cb0ef41Sopenharmony_ci if (gSingleZoneCountries == nullptr) { 4271cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 4281cb0ef41Sopenharmony_ci } 4291cb0ef41Sopenharmony_ci gMultiZonesCountries = new UVector(nullptr, uhash_compareUChars, status); 4301cb0ef41Sopenharmony_ci if (gMultiZonesCountries == nullptr) { 4311cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 4321cb0ef41Sopenharmony_ci } 4331cb0ef41Sopenharmony_ci 4341cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 4351cb0ef41Sopenharmony_ci delete gSingleZoneCountries; 4361cb0ef41Sopenharmony_ci delete gMultiZonesCountries; 4371cb0ef41Sopenharmony_ci gSingleZoneCountries = nullptr; 4381cb0ef41Sopenharmony_ci gMultiZonesCountries = nullptr; 4391cb0ef41Sopenharmony_ci } 4401cb0ef41Sopenharmony_ci ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); 4411cb0ef41Sopenharmony_ci} 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ciUnicodeString& U_EXPORT2 4451cb0ef41Sopenharmony_ciZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &country, UBool *isPrimary /* = nullptr */) { 4461cb0ef41Sopenharmony_ci if (isPrimary != nullptr) { 4471cb0ef41Sopenharmony_ci *isPrimary = false; 4481cb0ef41Sopenharmony_ci } 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_ci const char16_t *region = TimeZone::getRegion(tzid); 4511cb0ef41Sopenharmony_ci if (region != nullptr && u_strcmp(gWorld, region) != 0) { 4521cb0ef41Sopenharmony_ci country.setTo(region, -1); 4531cb0ef41Sopenharmony_ci } else { 4541cb0ef41Sopenharmony_ci country.setToBogus(); 4551cb0ef41Sopenharmony_ci return country; 4561cb0ef41Sopenharmony_ci } 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_ci if (isPrimary != nullptr) { 4591cb0ef41Sopenharmony_ci char regionBuf[] = {0, 0, 0}; 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_ci // Checking the cached results 4621cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 4631cb0ef41Sopenharmony_ci umtx_initOnce(gCountryInfoVectorsInitOnce, &countryInfoVectorsInit, status); 4641cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 4651cb0ef41Sopenharmony_ci return country; 4661cb0ef41Sopenharmony_ci } 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci // Check if it was already cached 4691cb0ef41Sopenharmony_ci UBool cached = false; 4701cb0ef41Sopenharmony_ci UBool singleZone = false; 4711cb0ef41Sopenharmony_ci umtx_lock(&gZoneMetaLock); 4721cb0ef41Sopenharmony_ci { 4731cb0ef41Sopenharmony_ci singleZone = cached = gSingleZoneCountries->contains((void*)region); 4741cb0ef41Sopenharmony_ci if (!cached) { 4751cb0ef41Sopenharmony_ci cached = gMultiZonesCountries->contains((void*)region); 4761cb0ef41Sopenharmony_ci } 4771cb0ef41Sopenharmony_ci } 4781cb0ef41Sopenharmony_ci umtx_unlock(&gZoneMetaLock); 4791cb0ef41Sopenharmony_ci 4801cb0ef41Sopenharmony_ci if (!cached) { 4811cb0ef41Sopenharmony_ci // We need to go through all zones associated with the region. 4821cb0ef41Sopenharmony_ci // This is relatively heavy operation. 4831cb0ef41Sopenharmony_ci 4841cb0ef41Sopenharmony_ci U_ASSERT(u_strlen(region) == 2); 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci u_UCharsToChars(region, regionBuf, 2); 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci StringEnumeration *ids = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL_LOCATION, regionBuf, nullptr, status); 4891cb0ef41Sopenharmony_ci int32_t idsLen = ids->count(status); 4901cb0ef41Sopenharmony_ci if (U_SUCCESS(status) && idsLen == 1) { 4911cb0ef41Sopenharmony_ci // only the single zone is available for the region 4921cb0ef41Sopenharmony_ci singleZone = true; 4931cb0ef41Sopenharmony_ci } 4941cb0ef41Sopenharmony_ci delete ids; 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ci // Cache the result 4971cb0ef41Sopenharmony_ci umtx_lock(&gZoneMetaLock); 4981cb0ef41Sopenharmony_ci { 4991cb0ef41Sopenharmony_ci UErrorCode ec = U_ZERO_ERROR; 5001cb0ef41Sopenharmony_ci if (singleZone) { 5011cb0ef41Sopenharmony_ci if (!gSingleZoneCountries->contains((void*)region)) { 5021cb0ef41Sopenharmony_ci gSingleZoneCountries->addElement((void*)region, ec); 5031cb0ef41Sopenharmony_ci } 5041cb0ef41Sopenharmony_ci } else { 5051cb0ef41Sopenharmony_ci if (!gMultiZonesCountries->contains((void*)region)) { 5061cb0ef41Sopenharmony_ci gMultiZonesCountries->addElement((void*)region, ec); 5071cb0ef41Sopenharmony_ci } 5081cb0ef41Sopenharmony_ci } 5091cb0ef41Sopenharmony_ci } 5101cb0ef41Sopenharmony_ci umtx_unlock(&gZoneMetaLock); 5111cb0ef41Sopenharmony_ci } 5121cb0ef41Sopenharmony_ci 5131cb0ef41Sopenharmony_ci if (singleZone) { 5141cb0ef41Sopenharmony_ci *isPrimary = true; 5151cb0ef41Sopenharmony_ci } else { 5161cb0ef41Sopenharmony_ci // Note: We may cache the primary zone map in future. 5171cb0ef41Sopenharmony_ci 5181cb0ef41Sopenharmony_ci // Even a country has multiple zones, one of them might be 5191cb0ef41Sopenharmony_ci // dominant and treated as a primary zone 5201cb0ef41Sopenharmony_ci int32_t idLen = 0; 5211cb0ef41Sopenharmony_ci if (regionBuf[0] == 0) { 5221cb0ef41Sopenharmony_ci u_UCharsToChars(region, regionBuf, 2); 5231cb0ef41Sopenharmony_ci } 5241cb0ef41Sopenharmony_ci 5251cb0ef41Sopenharmony_ci UResourceBundle *rb = ures_openDirect(nullptr, gMetaZones, &status); 5261cb0ef41Sopenharmony_ci ures_getByKey(rb, gPrimaryZonesTag, rb, &status); 5271cb0ef41Sopenharmony_ci const char16_t *primaryZone = ures_getStringByKey(rb, regionBuf, &idLen, &status); 5281cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 5291cb0ef41Sopenharmony_ci if (tzid.compare(primaryZone, idLen) == 0) { 5301cb0ef41Sopenharmony_ci *isPrimary = true; 5311cb0ef41Sopenharmony_ci } else { 5321cb0ef41Sopenharmony_ci // The given ID might not be a canonical ID 5331cb0ef41Sopenharmony_ci UnicodeString canonicalID; 5341cb0ef41Sopenharmony_ci TimeZone::getCanonicalID(tzid, canonicalID, status); 5351cb0ef41Sopenharmony_ci if (U_SUCCESS(status) && canonicalID.compare(primaryZone, idLen) == 0) { 5361cb0ef41Sopenharmony_ci *isPrimary = true; 5371cb0ef41Sopenharmony_ci } 5381cb0ef41Sopenharmony_ci } 5391cb0ef41Sopenharmony_ci } 5401cb0ef41Sopenharmony_ci ures_close(rb); 5411cb0ef41Sopenharmony_ci } 5421cb0ef41Sopenharmony_ci } 5431cb0ef41Sopenharmony_ci 5441cb0ef41Sopenharmony_ci return country; 5451cb0ef41Sopenharmony_ci} 5461cb0ef41Sopenharmony_ci 5471cb0ef41Sopenharmony_ciUnicodeString& U_EXPORT2 5481cb0ef41Sopenharmony_ciZoneMeta::getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &result) { 5491cb0ef41Sopenharmony_ci UBool isSet = false; 5501cb0ef41Sopenharmony_ci const UVector *mappings = getMetazoneMappings(tzid); 5511cb0ef41Sopenharmony_ci if (mappings != nullptr) { 5521cb0ef41Sopenharmony_ci for (int32_t i = 0; i < mappings->size(); i++) { 5531cb0ef41Sopenharmony_ci OlsonToMetaMappingEntry *mzm = (OlsonToMetaMappingEntry*)mappings->elementAt(i); 5541cb0ef41Sopenharmony_ci if (mzm->from <= date && mzm->to > date) { 5551cb0ef41Sopenharmony_ci result.setTo(mzm->mzid, -1); 5561cb0ef41Sopenharmony_ci isSet = true; 5571cb0ef41Sopenharmony_ci break; 5581cb0ef41Sopenharmony_ci } 5591cb0ef41Sopenharmony_ci } 5601cb0ef41Sopenharmony_ci } 5611cb0ef41Sopenharmony_ci if (!isSet) { 5621cb0ef41Sopenharmony_ci result.setToBogus(); 5631cb0ef41Sopenharmony_ci } 5641cb0ef41Sopenharmony_ci return result; 5651cb0ef41Sopenharmony_ci} 5661cb0ef41Sopenharmony_ci 5671cb0ef41Sopenharmony_cistatic void U_CALLCONV olsonToMetaInit(UErrorCode &status) { 5681cb0ef41Sopenharmony_ci U_ASSERT(gOlsonToMeta == nullptr); 5691cb0ef41Sopenharmony_ci ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); 5701cb0ef41Sopenharmony_ci gOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, nullptr, &status); 5711cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 5721cb0ef41Sopenharmony_ci gOlsonToMeta = nullptr; 5731cb0ef41Sopenharmony_ci } else { 5741cb0ef41Sopenharmony_ci uhash_setKeyDeleter(gOlsonToMeta, deleteUCharString); 5751cb0ef41Sopenharmony_ci uhash_setValueDeleter(gOlsonToMeta, uprv_deleteUObject); 5761cb0ef41Sopenharmony_ci } 5771cb0ef41Sopenharmony_ci} 5781cb0ef41Sopenharmony_ci 5791cb0ef41Sopenharmony_ci 5801cb0ef41Sopenharmony_ciconst UVector* U_EXPORT2 5811cb0ef41Sopenharmony_ciZoneMeta::getMetazoneMappings(const UnicodeString &tzid) { 5821cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 5831cb0ef41Sopenharmony_ci char16_t tzidUChars[ZID_KEY_MAX + 1]; 5841cb0ef41Sopenharmony_ci tzid.extract(tzidUChars, ZID_KEY_MAX + 1, status); 5851cb0ef41Sopenharmony_ci if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) { 5861cb0ef41Sopenharmony_ci return nullptr; 5871cb0ef41Sopenharmony_ci } 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_ci umtx_initOnce(gOlsonToMetaInitOnce, &olsonToMetaInit, status); 5901cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 5911cb0ef41Sopenharmony_ci return nullptr; 5921cb0ef41Sopenharmony_ci } 5931cb0ef41Sopenharmony_ci 5941cb0ef41Sopenharmony_ci // get the mapping from cache 5951cb0ef41Sopenharmony_ci const UVector *result = nullptr; 5961cb0ef41Sopenharmony_ci 5971cb0ef41Sopenharmony_ci umtx_lock(&gZoneMetaLock); 5981cb0ef41Sopenharmony_ci { 5991cb0ef41Sopenharmony_ci result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars); 6001cb0ef41Sopenharmony_ci } 6011cb0ef41Sopenharmony_ci umtx_unlock(&gZoneMetaLock); 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_ci if (result != nullptr) { 6041cb0ef41Sopenharmony_ci return result; 6051cb0ef41Sopenharmony_ci } 6061cb0ef41Sopenharmony_ci 6071cb0ef41Sopenharmony_ci // miss the cache - create new one 6081cb0ef41Sopenharmony_ci UVector *tmpResult = createMetazoneMappings(tzid); 6091cb0ef41Sopenharmony_ci if (tmpResult == nullptr) { 6101cb0ef41Sopenharmony_ci // not available 6111cb0ef41Sopenharmony_ci return nullptr; 6121cb0ef41Sopenharmony_ci } 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci // put the new one into the cache 6151cb0ef41Sopenharmony_ci umtx_lock(&gZoneMetaLock); 6161cb0ef41Sopenharmony_ci { 6171cb0ef41Sopenharmony_ci // make sure it's already created 6181cb0ef41Sopenharmony_ci result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars); 6191cb0ef41Sopenharmony_ci if (result == nullptr) { 6201cb0ef41Sopenharmony_ci // add the one just created 6211cb0ef41Sopenharmony_ci int32_t tzidLen = tzid.length() + 1; 6221cb0ef41Sopenharmony_ci char16_t *key = (char16_t*)uprv_malloc(tzidLen * sizeof(char16_t)); 6231cb0ef41Sopenharmony_ci if (key == nullptr) { 6241cb0ef41Sopenharmony_ci // memory allocation error.. just return nullptr 6251cb0ef41Sopenharmony_ci result = nullptr; 6261cb0ef41Sopenharmony_ci delete tmpResult; 6271cb0ef41Sopenharmony_ci } else { 6281cb0ef41Sopenharmony_ci tzid.extract(key, tzidLen, status); 6291cb0ef41Sopenharmony_ci uhash_put(gOlsonToMeta, key, tmpResult, &status); 6301cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 6311cb0ef41Sopenharmony_ci // delete the mapping 6321cb0ef41Sopenharmony_ci result = nullptr; 6331cb0ef41Sopenharmony_ci delete tmpResult; 6341cb0ef41Sopenharmony_ci } else { 6351cb0ef41Sopenharmony_ci result = tmpResult; 6361cb0ef41Sopenharmony_ci } 6371cb0ef41Sopenharmony_ci } 6381cb0ef41Sopenharmony_ci } else { 6391cb0ef41Sopenharmony_ci // another thread already put the one 6401cb0ef41Sopenharmony_ci delete tmpResult; 6411cb0ef41Sopenharmony_ci } 6421cb0ef41Sopenharmony_ci } 6431cb0ef41Sopenharmony_ci umtx_unlock(&gZoneMetaLock); 6441cb0ef41Sopenharmony_ci 6451cb0ef41Sopenharmony_ci return result; 6461cb0ef41Sopenharmony_ci} 6471cb0ef41Sopenharmony_ci 6481cb0ef41Sopenharmony_ciUVector* 6491cb0ef41Sopenharmony_ciZoneMeta::createMetazoneMappings(const UnicodeString &tzid) { 6501cb0ef41Sopenharmony_ci LocalPointer <UVector> mzMappings; 6511cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 6521cb0ef41Sopenharmony_ci 6531cb0ef41Sopenharmony_ci UnicodeString canonicalID; 6541cb0ef41Sopenharmony_ci UResourceBundle *rb = ures_openDirect(nullptr, gMetaZones, &status); 6551cb0ef41Sopenharmony_ci ures_getByKey(rb, gMetazoneInfo, rb, &status); 6561cb0ef41Sopenharmony_ci getCanonicalCLDRID(tzid, canonicalID, status); 6571cb0ef41Sopenharmony_ci 6581cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 6591cb0ef41Sopenharmony_ci char tzKey[ZID_KEY_MAX + 1]; 6601cb0ef41Sopenharmony_ci int32_t tzKeyLen = canonicalID.extract(0, canonicalID.length(), tzKey, sizeof(tzKey), US_INV); 6611cb0ef41Sopenharmony_ci tzKey[tzKeyLen] = 0; 6621cb0ef41Sopenharmony_ci 6631cb0ef41Sopenharmony_ci // tzid keys are using ':' as separators 6641cb0ef41Sopenharmony_ci char *p = tzKey; 6651cb0ef41Sopenharmony_ci while (*p) { 6661cb0ef41Sopenharmony_ci if (*p == '/') { 6671cb0ef41Sopenharmony_ci *p = ':'; 6681cb0ef41Sopenharmony_ci } 6691cb0ef41Sopenharmony_ci p++; 6701cb0ef41Sopenharmony_ci } 6711cb0ef41Sopenharmony_ci 6721cb0ef41Sopenharmony_ci ures_getByKey(rb, tzKey, rb, &status); 6731cb0ef41Sopenharmony_ci 6741cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 6751cb0ef41Sopenharmony_ci UResourceBundle *mz = nullptr; 6761cb0ef41Sopenharmony_ci while (ures_hasNext(rb)) { 6771cb0ef41Sopenharmony_ci mz = ures_getNextResource(rb, mz, &status); 6781cb0ef41Sopenharmony_ci 6791cb0ef41Sopenharmony_ci const char16_t *mz_name = ures_getStringByIndex(mz, 0, nullptr, &status); 6801cb0ef41Sopenharmony_ci const char16_t *mz_from = gDefaultFrom; 6811cb0ef41Sopenharmony_ci const char16_t *mz_to = gDefaultTo; 6821cb0ef41Sopenharmony_ci 6831cb0ef41Sopenharmony_ci if (ures_getSize(mz) == 3) { 6841cb0ef41Sopenharmony_ci mz_from = ures_getStringByIndex(mz, 1, nullptr, &status); 6851cb0ef41Sopenharmony_ci mz_to = ures_getStringByIndex(mz, 2, nullptr, &status); 6861cb0ef41Sopenharmony_ci } 6871cb0ef41Sopenharmony_ci 6881cb0ef41Sopenharmony_ci if(U_FAILURE(status)){ 6891cb0ef41Sopenharmony_ci status = U_ZERO_ERROR; 6901cb0ef41Sopenharmony_ci continue; 6911cb0ef41Sopenharmony_ci } 6921cb0ef41Sopenharmony_ci // We do not want to use SimpleDateformat to parse boundary dates, 6931cb0ef41Sopenharmony_ci // because this code could be triggered by the initialization code 6941cb0ef41Sopenharmony_ci // used by SimpleDateFormat. 6951cb0ef41Sopenharmony_ci UDate from = parseDate(mz_from, status); 6961cb0ef41Sopenharmony_ci UDate to = parseDate(mz_to, status); 6971cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 6981cb0ef41Sopenharmony_ci status = U_ZERO_ERROR; 6991cb0ef41Sopenharmony_ci continue; 7001cb0ef41Sopenharmony_ci } 7011cb0ef41Sopenharmony_ci 7021cb0ef41Sopenharmony_ci LocalPointer<OlsonToMetaMappingEntry> entry(new OlsonToMetaMappingEntry, status); 7031cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 7041cb0ef41Sopenharmony_ci break; 7051cb0ef41Sopenharmony_ci } 7061cb0ef41Sopenharmony_ci entry->mzid = mz_name; 7071cb0ef41Sopenharmony_ci entry->from = from; 7081cb0ef41Sopenharmony_ci entry->to = to; 7091cb0ef41Sopenharmony_ci 7101cb0ef41Sopenharmony_ci if (mzMappings.isNull()) { 7111cb0ef41Sopenharmony_ci mzMappings.adoptInsteadAndCheckErrorCode( 7121cb0ef41Sopenharmony_ci new UVector(deleteOlsonToMetaMappingEntry, nullptr, status), status); 7131cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 7141cb0ef41Sopenharmony_ci break; 7151cb0ef41Sopenharmony_ci } 7161cb0ef41Sopenharmony_ci } 7171cb0ef41Sopenharmony_ci 7181cb0ef41Sopenharmony_ci mzMappings->adoptElement(entry.orphan(), status); 7191cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 7201cb0ef41Sopenharmony_ci break; 7211cb0ef41Sopenharmony_ci } 7221cb0ef41Sopenharmony_ci } 7231cb0ef41Sopenharmony_ci ures_close(mz); 7241cb0ef41Sopenharmony_ci } 7251cb0ef41Sopenharmony_ci } 7261cb0ef41Sopenharmony_ci ures_close(rb); 7271cb0ef41Sopenharmony_ci return U_SUCCESS(status) ? mzMappings.orphan() : nullptr; 7281cb0ef41Sopenharmony_ci} 7291cb0ef41Sopenharmony_ci 7301cb0ef41Sopenharmony_ciUnicodeString& U_EXPORT2 7311cb0ef41Sopenharmony_ciZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString ®ion, UnicodeString &result) { 7321cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 7331cb0ef41Sopenharmony_ci const char16_t *tzid = nullptr; 7341cb0ef41Sopenharmony_ci int32_t tzidLen = 0; 7351cb0ef41Sopenharmony_ci char keyBuf[ZID_KEY_MAX + 1]; 7361cb0ef41Sopenharmony_ci int32_t keyLen = 0; 7371cb0ef41Sopenharmony_ci 7381cb0ef41Sopenharmony_ci if (mzid.isBogus() || mzid.length() > ZID_KEY_MAX) { 7391cb0ef41Sopenharmony_ci result.setToBogus(); 7401cb0ef41Sopenharmony_ci return result; 7411cb0ef41Sopenharmony_ci } 7421cb0ef41Sopenharmony_ci 7431cb0ef41Sopenharmony_ci keyLen = mzid.extract(0, mzid.length(), keyBuf, ZID_KEY_MAX + 1, US_INV); 7441cb0ef41Sopenharmony_ci keyBuf[keyLen] = 0; 7451cb0ef41Sopenharmony_ci 7461cb0ef41Sopenharmony_ci UResourceBundle *rb = ures_openDirect(nullptr, gMetaZones, &status); 7471cb0ef41Sopenharmony_ci ures_getByKey(rb, gMapTimezonesTag, rb, &status); 7481cb0ef41Sopenharmony_ci ures_getByKey(rb, keyBuf, rb, &status); 7491cb0ef41Sopenharmony_ci 7501cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 7511cb0ef41Sopenharmony_ci // check region mapping 7521cb0ef41Sopenharmony_ci if (region.length() == 2 || region.length() == 3) { 7531cb0ef41Sopenharmony_ci keyLen = region.extract(0, region.length(), keyBuf, ZID_KEY_MAX + 1, US_INV); 7541cb0ef41Sopenharmony_ci keyBuf[keyLen] = 0; 7551cb0ef41Sopenharmony_ci tzid = ures_getStringByKey(rb, keyBuf, &tzidLen, &status); 7561cb0ef41Sopenharmony_ci if (status == U_MISSING_RESOURCE_ERROR) { 7571cb0ef41Sopenharmony_ci status = U_ZERO_ERROR; 7581cb0ef41Sopenharmony_ci } 7591cb0ef41Sopenharmony_ci } 7601cb0ef41Sopenharmony_ci if (U_SUCCESS(status) && tzid == nullptr) { 7611cb0ef41Sopenharmony_ci // try "001" 7621cb0ef41Sopenharmony_ci tzid = ures_getStringByKey(rb, gWorldTag, &tzidLen, &status); 7631cb0ef41Sopenharmony_ci } 7641cb0ef41Sopenharmony_ci } 7651cb0ef41Sopenharmony_ci ures_close(rb); 7661cb0ef41Sopenharmony_ci 7671cb0ef41Sopenharmony_ci if (tzid == nullptr) { 7681cb0ef41Sopenharmony_ci result.setToBogus(); 7691cb0ef41Sopenharmony_ci } else { 7701cb0ef41Sopenharmony_ci result.setTo(tzid, tzidLen); 7711cb0ef41Sopenharmony_ci } 7721cb0ef41Sopenharmony_ci 7731cb0ef41Sopenharmony_ci return result; 7741cb0ef41Sopenharmony_ci} 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_cistatic void U_CALLCONV initAvailableMetaZoneIDs () { 7771cb0ef41Sopenharmony_ci U_ASSERT(gMetaZoneIDs == nullptr); 7781cb0ef41Sopenharmony_ci U_ASSERT(gMetaZoneIDTable == nullptr); 7791cb0ef41Sopenharmony_ci ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); 7801cb0ef41Sopenharmony_ci 7811cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 7821cb0ef41Sopenharmony_ci gMetaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, nullptr, &status); 7831cb0ef41Sopenharmony_ci if (U_FAILURE(status) || gMetaZoneIDTable == nullptr) { 7841cb0ef41Sopenharmony_ci gMetaZoneIDTable = nullptr; 7851cb0ef41Sopenharmony_ci return; 7861cb0ef41Sopenharmony_ci } 7871cb0ef41Sopenharmony_ci uhash_setKeyDeleter(gMetaZoneIDTable, uprv_deleteUObject); 7881cb0ef41Sopenharmony_ci // No valueDeleter, because the vector maintain the value objects 7891cb0ef41Sopenharmony_ci gMetaZoneIDs = new UVector(nullptr, uhash_compareUChars, status); 7901cb0ef41Sopenharmony_ci if (U_FAILURE(status) || gMetaZoneIDs == nullptr) { 7911cb0ef41Sopenharmony_ci delete gMetaZoneIDs; 7921cb0ef41Sopenharmony_ci gMetaZoneIDs = nullptr; 7931cb0ef41Sopenharmony_ci uhash_close(gMetaZoneIDTable); 7941cb0ef41Sopenharmony_ci gMetaZoneIDTable = nullptr; 7951cb0ef41Sopenharmony_ci return; 7961cb0ef41Sopenharmony_ci } 7971cb0ef41Sopenharmony_ci gMetaZoneIDs->setDeleter(uprv_free); 7981cb0ef41Sopenharmony_ci 7991cb0ef41Sopenharmony_ci UResourceBundle *rb = ures_openDirect(nullptr, gMetaZones, &status); 8001cb0ef41Sopenharmony_ci UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, nullptr, &status); 8011cb0ef41Sopenharmony_ci StackUResourceBundle res; 8021cb0ef41Sopenharmony_ci while (U_SUCCESS(status) && ures_hasNext(bundle)) { 8031cb0ef41Sopenharmony_ci ures_getNextResource(bundle, res.getAlias(), &status); 8041cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 8051cb0ef41Sopenharmony_ci break; 8061cb0ef41Sopenharmony_ci } 8071cb0ef41Sopenharmony_ci const char *mzID = ures_getKey(res.getAlias()); 8081cb0ef41Sopenharmony_ci int32_t len = static_cast<int32_t>(uprv_strlen(mzID)); 8091cb0ef41Sopenharmony_ci LocalMemory<char16_t> uMzID((char16_t*)uprv_malloc(sizeof(char16_t) * (len + 1))); 8101cb0ef41Sopenharmony_ci if (uMzID.isNull()) { 8111cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 8121cb0ef41Sopenharmony_ci break; 8131cb0ef41Sopenharmony_ci } 8141cb0ef41Sopenharmony_ci u_charsToUChars(mzID, uMzID.getAlias(), len); 8151cb0ef41Sopenharmony_ci uMzID[len] = 0; 8161cb0ef41Sopenharmony_ci LocalPointer<UnicodeString> usMzID(new UnicodeString(uMzID.getAlias()), status); 8171cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 8181cb0ef41Sopenharmony_ci break; 8191cb0ef41Sopenharmony_ci } 8201cb0ef41Sopenharmony_ci if (uhash_get(gMetaZoneIDTable, usMzID.getAlias()) == nullptr) { 8211cb0ef41Sopenharmony_ci // Note: gMetaZoneIDTable adopts its keys, but not its values. 8221cb0ef41Sopenharmony_ci // gMetaZoneIDs adopts its values. 8231cb0ef41Sopenharmony_ci uhash_put(gMetaZoneIDTable, usMzID.orphan(), uMzID.getAlias(), &status); 8241cb0ef41Sopenharmony_ci gMetaZoneIDs->adoptElement(uMzID.orphan(), status); 8251cb0ef41Sopenharmony_ci } 8261cb0ef41Sopenharmony_ci } 8271cb0ef41Sopenharmony_ci ures_close(bundle); 8281cb0ef41Sopenharmony_ci ures_close(rb); 8291cb0ef41Sopenharmony_ci 8301cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 8311cb0ef41Sopenharmony_ci uhash_close(gMetaZoneIDTable); 8321cb0ef41Sopenharmony_ci delete gMetaZoneIDs; 8331cb0ef41Sopenharmony_ci gMetaZoneIDTable = nullptr; 8341cb0ef41Sopenharmony_ci gMetaZoneIDs = nullptr; 8351cb0ef41Sopenharmony_ci } 8361cb0ef41Sopenharmony_ci} 8371cb0ef41Sopenharmony_ci 8381cb0ef41Sopenharmony_ciconst UVector* 8391cb0ef41Sopenharmony_ciZoneMeta::getAvailableMetazoneIDs() { 8401cb0ef41Sopenharmony_ci umtx_initOnce(gMetaZoneIDsInitOnce, &initAvailableMetaZoneIDs); 8411cb0ef41Sopenharmony_ci return gMetaZoneIDs; 8421cb0ef41Sopenharmony_ci} 8431cb0ef41Sopenharmony_ci 8441cb0ef41Sopenharmony_ciconst char16_t* 8451cb0ef41Sopenharmony_ciZoneMeta::findMetaZoneID(const UnicodeString& mzid) { 8461cb0ef41Sopenharmony_ci umtx_initOnce(gMetaZoneIDsInitOnce, &initAvailableMetaZoneIDs); 8471cb0ef41Sopenharmony_ci if (gMetaZoneIDTable == nullptr) { 8481cb0ef41Sopenharmony_ci return nullptr; 8491cb0ef41Sopenharmony_ci } 8501cb0ef41Sopenharmony_ci return (const char16_t*)uhash_get(gMetaZoneIDTable, &mzid); 8511cb0ef41Sopenharmony_ci} 8521cb0ef41Sopenharmony_ci 8531cb0ef41Sopenharmony_ciconst char16_t* 8541cb0ef41Sopenharmony_ciZoneMeta::findTimeZoneID(const UnicodeString& tzid) { 8551cb0ef41Sopenharmony_ci return TimeZone::findID(tzid); 8561cb0ef41Sopenharmony_ci} 8571cb0ef41Sopenharmony_ci 8581cb0ef41Sopenharmony_ci 8591cb0ef41Sopenharmony_ciTimeZone* 8601cb0ef41Sopenharmony_ciZoneMeta::createCustomTimeZone(int32_t offset) { 8611cb0ef41Sopenharmony_ci UBool negative = false; 8621cb0ef41Sopenharmony_ci int32_t tmp = offset; 8631cb0ef41Sopenharmony_ci if (offset < 0) { 8641cb0ef41Sopenharmony_ci negative = true; 8651cb0ef41Sopenharmony_ci tmp = -offset; 8661cb0ef41Sopenharmony_ci } 8671cb0ef41Sopenharmony_ci uint8_t hour, min, sec; 8681cb0ef41Sopenharmony_ci 8691cb0ef41Sopenharmony_ci tmp /= 1000; 8701cb0ef41Sopenharmony_ci sec = static_cast<uint8_t>(tmp % 60); 8711cb0ef41Sopenharmony_ci tmp /= 60; 8721cb0ef41Sopenharmony_ci min = static_cast<uint8_t>(tmp % 60); 8731cb0ef41Sopenharmony_ci hour = static_cast<uint8_t>(tmp / 60); 8741cb0ef41Sopenharmony_ci 8751cb0ef41Sopenharmony_ci UnicodeString zid; 8761cb0ef41Sopenharmony_ci formatCustomID(hour, min, sec, negative, zid); 8771cb0ef41Sopenharmony_ci return new SimpleTimeZone(offset, zid); 8781cb0ef41Sopenharmony_ci} 8791cb0ef41Sopenharmony_ci 8801cb0ef41Sopenharmony_ciUnicodeString& 8811cb0ef41Sopenharmony_ciZoneMeta::formatCustomID(uint8_t hour, uint8_t min, uint8_t sec, UBool negative, UnicodeString& id) { 8821cb0ef41Sopenharmony_ci // Create normalized time zone ID - GMT[+|-]HH:mm[:ss] 8831cb0ef41Sopenharmony_ci id.setTo(gCustomTzPrefix, -1); 8841cb0ef41Sopenharmony_ci if (hour != 0 || min != 0) { 8851cb0ef41Sopenharmony_ci if (negative) { 8861cb0ef41Sopenharmony_ci id.append((char16_t)0x2D); // '-' 8871cb0ef41Sopenharmony_ci } else { 8881cb0ef41Sopenharmony_ci id.append((char16_t)0x2B); // '+' 8891cb0ef41Sopenharmony_ci } 8901cb0ef41Sopenharmony_ci // Always use US-ASCII digits 8911cb0ef41Sopenharmony_ci id.append((char16_t)(0x30 + (hour%100)/10)); 8921cb0ef41Sopenharmony_ci id.append((char16_t)(0x30 + (hour%10))); 8931cb0ef41Sopenharmony_ci id.append((char16_t)0x3A); // ':' 8941cb0ef41Sopenharmony_ci id.append((char16_t)(0x30 + (min%100)/10)); 8951cb0ef41Sopenharmony_ci id.append((char16_t)(0x30 + (min%10))); 8961cb0ef41Sopenharmony_ci if (sec != 0) { 8971cb0ef41Sopenharmony_ci id.append((char16_t)0x3A); // ':' 8981cb0ef41Sopenharmony_ci id.append((char16_t)(0x30 + (sec%100)/10)); 8991cb0ef41Sopenharmony_ci id.append((char16_t)(0x30 + (sec%10))); 9001cb0ef41Sopenharmony_ci } 9011cb0ef41Sopenharmony_ci } 9021cb0ef41Sopenharmony_ci return id; 9031cb0ef41Sopenharmony_ci} 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_ciconst char16_t* 9061cb0ef41Sopenharmony_ciZoneMeta::getShortID(const TimeZone& tz) { 9071cb0ef41Sopenharmony_ci const char16_t* canonicalID = nullptr; 9081cb0ef41Sopenharmony_ci if (dynamic_cast<const OlsonTimeZone *>(&tz) != nullptr) { 9091cb0ef41Sopenharmony_ci // short cut for OlsonTimeZone 9101cb0ef41Sopenharmony_ci const OlsonTimeZone *otz = (const OlsonTimeZone*)&tz; 9111cb0ef41Sopenharmony_ci canonicalID = otz->getCanonicalID(); 9121cb0ef41Sopenharmony_ci } 9131cb0ef41Sopenharmony_ci if (canonicalID == nullptr) { 9141cb0ef41Sopenharmony_ci return nullptr; 9151cb0ef41Sopenharmony_ci } 9161cb0ef41Sopenharmony_ci return getShortIDFromCanonical(canonicalID); 9171cb0ef41Sopenharmony_ci} 9181cb0ef41Sopenharmony_ci 9191cb0ef41Sopenharmony_ciconst char16_t* 9201cb0ef41Sopenharmony_ciZoneMeta::getShortID(const UnicodeString& id) { 9211cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 9221cb0ef41Sopenharmony_ci const char16_t* canonicalID = ZoneMeta::getCanonicalCLDRID(id, status); 9231cb0ef41Sopenharmony_ci if (U_FAILURE(status) || canonicalID == nullptr) { 9241cb0ef41Sopenharmony_ci return nullptr; 9251cb0ef41Sopenharmony_ci } 9261cb0ef41Sopenharmony_ci return ZoneMeta::getShortIDFromCanonical(canonicalID); 9271cb0ef41Sopenharmony_ci} 9281cb0ef41Sopenharmony_ci 9291cb0ef41Sopenharmony_ciconst char16_t* 9301cb0ef41Sopenharmony_ciZoneMeta::getShortIDFromCanonical(const char16_t* canonicalID) { 9311cb0ef41Sopenharmony_ci const char16_t* shortID = nullptr; 9321cb0ef41Sopenharmony_ci int32_t len = u_strlen(canonicalID); 9331cb0ef41Sopenharmony_ci char tzidKey[ZID_KEY_MAX + 1]; 9341cb0ef41Sopenharmony_ci 9351cb0ef41Sopenharmony_ci u_UCharsToChars(canonicalID, tzidKey, len); 9361cb0ef41Sopenharmony_ci tzidKey[len] = (char) 0; // Make sure it is null terminated. 9371cb0ef41Sopenharmony_ci 9381cb0ef41Sopenharmony_ci // replace '/' with ':' 9391cb0ef41Sopenharmony_ci char *p = tzidKey; 9401cb0ef41Sopenharmony_ci while (*p++) { 9411cb0ef41Sopenharmony_ci if (*p == '/') { 9421cb0ef41Sopenharmony_ci *p = ':'; 9431cb0ef41Sopenharmony_ci } 9441cb0ef41Sopenharmony_ci } 9451cb0ef41Sopenharmony_ci 9461cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 9471cb0ef41Sopenharmony_ci UResourceBundle *rb = ures_openDirect(nullptr, gKeyTypeData, &status); 9481cb0ef41Sopenharmony_ci ures_getByKey(rb, gTypeMapTag, rb, &status); 9491cb0ef41Sopenharmony_ci ures_getByKey(rb, gTimezoneTag, rb, &status); 9501cb0ef41Sopenharmony_ci shortID = ures_getStringByKey(rb, tzidKey, nullptr, &status); 9511cb0ef41Sopenharmony_ci ures_close(rb); 9521cb0ef41Sopenharmony_ci 9531cb0ef41Sopenharmony_ci return shortID; 9541cb0ef41Sopenharmony_ci} 9551cb0ef41Sopenharmony_ci 9561cb0ef41Sopenharmony_ciU_NAMESPACE_END 9571cb0ef41Sopenharmony_ci 9581cb0ef41Sopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */ 959