19596a2c1Sopenharmony_ci/* 29596a2c1Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 39596a2c1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 49596a2c1Sopenharmony_ci * you may not use this file except in compliance with the License. 59596a2c1Sopenharmony_ci * You may obtain a copy of the License at 69596a2c1Sopenharmony_ci * 79596a2c1Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 89596a2c1Sopenharmony_ci * 99596a2c1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 109596a2c1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 119596a2c1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 129596a2c1Sopenharmony_ci * See the License for the specific language governing permissions and 139596a2c1Sopenharmony_ci * limitations under the License. 149596a2c1Sopenharmony_ci */ 159596a2c1Sopenharmony_ci 169596a2c1Sopenharmony_ci#include <filesystem> 179596a2c1Sopenharmony_ci#include <sys/stat.h> 189596a2c1Sopenharmony_ci#include "i18n_hilog.h" 199596a2c1Sopenharmony_ci#include "i18n_timezone.h" 209596a2c1Sopenharmony_ci#include "ohos/init_data.h" 219596a2c1Sopenharmony_ci#include "unicode/strenum.h" 229596a2c1Sopenharmony_ci#include "unicode/timezone.h" 239596a2c1Sopenharmony_ci#include "utils.h" 249596a2c1Sopenharmony_ci#include "zone_util.h" 259596a2c1Sopenharmony_ci 269596a2c1Sopenharmony_ciusing namespace OHOS::Global::I18n; 279596a2c1Sopenharmony_ciusing namespace icu; 289596a2c1Sopenharmony_ciusing namespace std; 299596a2c1Sopenharmony_ci 309596a2c1Sopenharmony_ciconst char *ZoneUtil::COUNTRY_ZONE_DATA_PATH = "/system/usr/ohos_timezone/tzlookup.xml"; 319596a2c1Sopenharmony_ciconst char *ZoneUtil::DISTRO_COUNTRY_ZONE_DATA_PATH = "/system/etc/tzdata_distro/hos/tzlookup.xml"; 329596a2c1Sopenharmony_ciconst char *ZoneUtil::DEFAULT_TIMEZONE = "GMT"; 339596a2c1Sopenharmony_ciconst char *ZoneUtil::TIMEZONES_TAG = "timezones"; 349596a2c1Sopenharmony_ciconst char *ZoneUtil::ID_TAG = "id"; 359596a2c1Sopenharmony_ciconst char *ZoneUtil::DEFAULT_TAG = "default"; 369596a2c1Sopenharmony_ciconst char *ZoneUtil::BOOSTED_TAG = "defaultBoost"; 379596a2c1Sopenharmony_ciconst char *ZoneUtil::ROOT_TAG = "countryzones"; 389596a2c1Sopenharmony_ciconst char *ZoneUtil::SECOND_TAG = "country"; 399596a2c1Sopenharmony_ciconst char *ZoneUtil::CODE_TAG = "code"; 409596a2c1Sopenharmony_ciconst char *ZoneUtil::TIMEZONE_KEY = "persist.time.timezone"; 419596a2c1Sopenharmony_ciconst char *ZoneUtil::TZLOOKUP_FILE_PATH = ZoneUtil::GetTZLookupDataPath(); 429596a2c1Sopenharmony_ci 439596a2c1Sopenharmony_ciunordered_map<string, string> ZoneUtil::defaultMap = { 449596a2c1Sopenharmony_ci {"AQ", "Antarctica/McMurdo"}, 459596a2c1Sopenharmony_ci {"AR", "America/Argentina/Buenos_Aires"}, 469596a2c1Sopenharmony_ci {"AU", "Australia/Sydney"}, 479596a2c1Sopenharmony_ci {"BR", "America/Noronha"}, 489596a2c1Sopenharmony_ci {"CA", "America/St_Johns"}, 499596a2c1Sopenharmony_ci {"CD", "Africa/Kinshasa"}, 509596a2c1Sopenharmony_ci {"CL", "America/Santiago"}, 519596a2c1Sopenharmony_ci {"CN", "Asia/Shanghai"}, 529596a2c1Sopenharmony_ci {"CY", "Asia/Nicosia"}, 539596a2c1Sopenharmony_ci {"DE", "Europe/Berlin"}, 549596a2c1Sopenharmony_ci {"EC", "America/Guayaquil"}, 559596a2c1Sopenharmony_ci {"ES", "Europe/Madrid"}, 569596a2c1Sopenharmony_ci {"FM", "Pacific/Pohnpei"}, 579596a2c1Sopenharmony_ci {"GL", "America/Godthab"}, 589596a2c1Sopenharmony_ci {"ID", "Asia/Jakarta"}, 599596a2c1Sopenharmony_ci {"KI", "Pacific/Tarawa"}, 609596a2c1Sopenharmony_ci {"KZ", "Asia/Almaty"}, 619596a2c1Sopenharmony_ci {"MH", "Pacific/Majuro"}, 629596a2c1Sopenharmony_ci {"MN", "Asia/Ulaanbaatar"}, 639596a2c1Sopenharmony_ci {"MX", "America/Mexico_City"}, 649596a2c1Sopenharmony_ci {"MY", "Asia/Kuala_Lumpur"}, 659596a2c1Sopenharmony_ci {"NZ", "Pacific/Auckland"}, 669596a2c1Sopenharmony_ci {"PF", "Pacific/Tahiti"}, 679596a2c1Sopenharmony_ci {"PG", "Pacific/Port_Moresby"}, 689596a2c1Sopenharmony_ci {"PS", "Asia/Gaza"}, 699596a2c1Sopenharmony_ci {"PT", "Europe/Lisbon"}, 709596a2c1Sopenharmony_ci {"RU", "Europe/Moscow"}, 719596a2c1Sopenharmony_ci {"UA", "Europe/Kiev"}, 729596a2c1Sopenharmony_ci {"UM", "Pacific/Wake"}, 739596a2c1Sopenharmony_ci {"US", "America/New_York"}, 749596a2c1Sopenharmony_ci {"UZ", "Asia/Tashkent"}, 759596a2c1Sopenharmony_ci}; 769596a2c1Sopenharmony_ci 779596a2c1Sopenharmony_cibool ZoneUtil::icuInitialized = ZoneUtil::Init(); 789596a2c1Sopenharmony_ci 799596a2c1Sopenharmony_cistring ZoneUtil::GetDefaultZone(const string &country) 809596a2c1Sopenharmony_ci{ 819596a2c1Sopenharmony_ci string temp(country); 829596a2c1Sopenharmony_ci for (size_t i = 0; i < temp.size(); i++) { 839596a2c1Sopenharmony_ci temp[i] = (char)toupper(temp[i]); 849596a2c1Sopenharmony_ci } 859596a2c1Sopenharmony_ci if (defaultMap.find(temp) != defaultMap.end()) { 869596a2c1Sopenharmony_ci return defaultMap[temp]; 879596a2c1Sopenharmony_ci } 889596a2c1Sopenharmony_ci string ret; 899596a2c1Sopenharmony_ci StringEnumeration *strEnum = TimeZone::createEnumeration(temp.c_str()); 909596a2c1Sopenharmony_ci GetString(strEnum, ret); 919596a2c1Sopenharmony_ci if (strEnum != nullptr) { 929596a2c1Sopenharmony_ci delete strEnum; 939596a2c1Sopenharmony_ci } 949596a2c1Sopenharmony_ci return ret; 959596a2c1Sopenharmony_ci} 969596a2c1Sopenharmony_ci 979596a2c1Sopenharmony_cistring ZoneUtil::GetDefaultZone(const int32_t number) 989596a2c1Sopenharmony_ci{ 999596a2c1Sopenharmony_ci using i18n::phonenumbers::PhoneNumberUtil; 1009596a2c1Sopenharmony_ci string *region_code = new(nothrow) string(); 1019596a2c1Sopenharmony_ci if (!region_code) { 1029596a2c1Sopenharmony_ci return ""; 1039596a2c1Sopenharmony_ci } 1049596a2c1Sopenharmony_ci PhoneNumberUtil* phoneUtil = PhoneNumberUtil::GetInstance(); 1059596a2c1Sopenharmony_ci phoneUtil->GetRegionCodeForCountryCode(number, region_code); 1069596a2c1Sopenharmony_ci if (!region_code) { 1079596a2c1Sopenharmony_ci return ""; 1089596a2c1Sopenharmony_ci } 1099596a2c1Sopenharmony_ci string ret = GetDefaultZone(*region_code); 1109596a2c1Sopenharmony_ci delete region_code; 1119596a2c1Sopenharmony_ci return ret; 1129596a2c1Sopenharmony_ci} 1139596a2c1Sopenharmony_ci 1149596a2c1Sopenharmony_cistring ZoneUtil::GetDefaultZone(const string country, const int32_t offset) 1159596a2c1Sopenharmony_ci{ 1169596a2c1Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 1179596a2c1Sopenharmony_ci StringEnumeration *strEnum = 1189596a2c1Sopenharmony_ci TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, country.c_str(), &offset, status); 1199596a2c1Sopenharmony_ci if (U_FAILURE(status)) { 1209596a2c1Sopenharmony_ci return ""; 1219596a2c1Sopenharmony_ci } 1229596a2c1Sopenharmony_ci string ret; 1239596a2c1Sopenharmony_ci GetString(strEnum, ret); 1249596a2c1Sopenharmony_ci if (strEnum != nullptr) { 1259596a2c1Sopenharmony_ci delete strEnum; 1269596a2c1Sopenharmony_ci strEnum = nullptr; 1279596a2c1Sopenharmony_ci } 1289596a2c1Sopenharmony_ci return ret; 1299596a2c1Sopenharmony_ci} 1309596a2c1Sopenharmony_ci 1319596a2c1Sopenharmony_cistring ZoneUtil::GetDefaultZone(const int32_t number, const int32_t offset) 1329596a2c1Sopenharmony_ci{ 1339596a2c1Sopenharmony_ci using i18n::phonenumbers::PhoneNumberUtil; 1349596a2c1Sopenharmony_ci string *region_code = new(nothrow) string(); 1359596a2c1Sopenharmony_ci if (!region_code) { 1369596a2c1Sopenharmony_ci return ""; 1379596a2c1Sopenharmony_ci } 1389596a2c1Sopenharmony_ci PhoneNumberUtil* phoneUtil = PhoneNumberUtil::GetInstance(); 1399596a2c1Sopenharmony_ci phoneUtil->GetRegionCodeForCountryCode(number, region_code); 1409596a2c1Sopenharmony_ci if (!region_code) { 1419596a2c1Sopenharmony_ci return ""; 1429596a2c1Sopenharmony_ci } 1439596a2c1Sopenharmony_ci string ret = GetDefaultZone(*region_code, offset); 1449596a2c1Sopenharmony_ci delete region_code; 1459596a2c1Sopenharmony_ci return ret; 1469596a2c1Sopenharmony_ci} 1479596a2c1Sopenharmony_ci 1489596a2c1Sopenharmony_civoid ZoneUtil::GetZoneList(const string country, vector<string> &retVec) 1499596a2c1Sopenharmony_ci{ 1509596a2c1Sopenharmony_ci StringEnumeration *strEnum = TimeZone::createEnumeration(country.c_str()); 1519596a2c1Sopenharmony_ci GetList(strEnum, retVec); 1529596a2c1Sopenharmony_ci if (strEnum != nullptr) { 1539596a2c1Sopenharmony_ci delete strEnum; 1549596a2c1Sopenharmony_ci strEnum = nullptr; 1559596a2c1Sopenharmony_ci } 1569596a2c1Sopenharmony_ci} 1579596a2c1Sopenharmony_ci 1589596a2c1Sopenharmony_civoid ZoneUtil::GetZoneList(const string country, const int32_t offset, vector<string> &retVec) 1599596a2c1Sopenharmony_ci{ 1609596a2c1Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 1619596a2c1Sopenharmony_ci StringEnumeration *strEnum = 1629596a2c1Sopenharmony_ci TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, country.c_str(), &offset, status); 1639596a2c1Sopenharmony_ci if (U_FAILURE(status)) { 1649596a2c1Sopenharmony_ci delete strEnum; 1659596a2c1Sopenharmony_ci strEnum = nullptr; 1669596a2c1Sopenharmony_ci return; 1679596a2c1Sopenharmony_ci } 1689596a2c1Sopenharmony_ci GetList(strEnum, retVec); 1699596a2c1Sopenharmony_ci if (strEnum != nullptr) { 1709596a2c1Sopenharmony_ci delete strEnum; 1719596a2c1Sopenharmony_ci strEnum = nullptr; 1729596a2c1Sopenharmony_ci } 1739596a2c1Sopenharmony_ci} 1749596a2c1Sopenharmony_ci 1759596a2c1Sopenharmony_civoid ZoneUtil::GetString(StringEnumeration *strEnum, string& ret) 1769596a2c1Sopenharmony_ci{ 1779596a2c1Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 1789596a2c1Sopenharmony_ci UnicodeString uniString; 1799596a2c1Sopenharmony_ci if (!strEnum) { 1809596a2c1Sopenharmony_ci return; 1819596a2c1Sopenharmony_ci } 1829596a2c1Sopenharmony_ci int32_t count = strEnum->count(status); 1839596a2c1Sopenharmony_ci if (U_FAILURE(status) || count <= 0) { 1849596a2c1Sopenharmony_ci return; 1859596a2c1Sopenharmony_ci } 1869596a2c1Sopenharmony_ci const UnicodeString *uniStr = strEnum->snext(status); 1879596a2c1Sopenharmony_ci if (U_FAILURE(status) || (!uniStr)) { 1889596a2c1Sopenharmony_ci return; 1899596a2c1Sopenharmony_ci } 1909596a2c1Sopenharmony_ci UnicodeString canonicalUnistring; 1919596a2c1Sopenharmony_ci TimeZone::getCanonicalID(*uniStr, canonicalUnistring, status); 1929596a2c1Sopenharmony_ci if (U_FAILURE(status)) { 1939596a2c1Sopenharmony_ci return; 1949596a2c1Sopenharmony_ci } 1959596a2c1Sopenharmony_ci canonicalUnistring.toUTF8String(ret); 1969596a2c1Sopenharmony_ci return; 1979596a2c1Sopenharmony_ci} 1989596a2c1Sopenharmony_ci 1999596a2c1Sopenharmony_civoid ZoneUtil::GetList(StringEnumeration *strEnum, vector<string> &retVec) 2009596a2c1Sopenharmony_ci{ 2019596a2c1Sopenharmony_ci if (!strEnum) { 2029596a2c1Sopenharmony_ci return; 2039596a2c1Sopenharmony_ci } 2049596a2c1Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 2059596a2c1Sopenharmony_ci int32_t count = strEnum->count(status); 2069596a2c1Sopenharmony_ci if (count <= 0 || U_FAILURE(status)) { 2079596a2c1Sopenharmony_ci return; 2089596a2c1Sopenharmony_ci } 2099596a2c1Sopenharmony_ci while (count > 0) { 2109596a2c1Sopenharmony_ci const UnicodeString *uniStr = strEnum->snext(status); 2119596a2c1Sopenharmony_ci if ((!uniStr) || U_FAILURE(status)) { 2129596a2c1Sopenharmony_ci retVec.clear(); 2139596a2c1Sopenharmony_ci break; 2149596a2c1Sopenharmony_ci } 2159596a2c1Sopenharmony_ci UnicodeString canonicalUnistring; 2169596a2c1Sopenharmony_ci TimeZone::getCanonicalID(*uniStr, canonicalUnistring, status); 2179596a2c1Sopenharmony_ci if (U_FAILURE(status)) { 2189596a2c1Sopenharmony_ci retVec.clear(); 2199596a2c1Sopenharmony_ci break; 2209596a2c1Sopenharmony_ci } 2219596a2c1Sopenharmony_ci string canonicalString = ""; 2229596a2c1Sopenharmony_ci canonicalUnistring.toUTF8String(canonicalString); 2239596a2c1Sopenharmony_ci if ((canonicalString != "") && (find(retVec.begin(), retVec.end(), canonicalString) == retVec.end())) { 2249596a2c1Sopenharmony_ci retVec.push_back(canonicalString); 2259596a2c1Sopenharmony_ci } 2269596a2c1Sopenharmony_ci --count; 2279596a2c1Sopenharmony_ci } 2289596a2c1Sopenharmony_ci return; 2299596a2c1Sopenharmony_ci} 2309596a2c1Sopenharmony_ci 2319596a2c1Sopenharmony_cibool ZoneUtil::Init() 2329596a2c1Sopenharmony_ci{ 2339596a2c1Sopenharmony_ci SetHwIcuDirectory(); 2349596a2c1Sopenharmony_ci return true; 2359596a2c1Sopenharmony_ci} 2369596a2c1Sopenharmony_ci 2379596a2c1Sopenharmony_ciCountryResult ZoneUtil::LookupTimezoneByCountryAndNITZ(std::string ®ion, NITZData &nitzData) 2389596a2c1Sopenharmony_ci{ 2399596a2c1Sopenharmony_ci std::vector<std::string> zones; 2409596a2c1Sopenharmony_ci std::string defaultTimezone; 2419596a2c1Sopenharmony_ci std::string systemTimezone = ReadSystemParameter(TIMEZONE_KEY, SYS_PARAM_LEN); 2429596a2c1Sopenharmony_ci if (systemTimezone.length() == 0) { 2439596a2c1Sopenharmony_ci systemTimezone = DEFAULT_TIMEZONE; 2449596a2c1Sopenharmony_ci } 2459596a2c1Sopenharmony_ci if (TZLOOKUP_FILE_PATH != nullptr) { 2469596a2c1Sopenharmony_ci bool isBoosted = false; 2479596a2c1Sopenharmony_ci HILOG_INFO_I18N("ZoneUtil::LookupTimezoneByCountryAndNITZ use tzlookup.xml"); 2489596a2c1Sopenharmony_ci GetCountryZones(region, defaultTimezone, isBoosted, zones); 2499596a2c1Sopenharmony_ci } else { 2509596a2c1Sopenharmony_ci HILOG_INFO_I18N("ZoneUtil::LookupTimezoneByCountryAndNITZ use icu data"); 2519596a2c1Sopenharmony_ci GetICUCountryZones(region, zones, defaultTimezone); 2529596a2c1Sopenharmony_ci } 2539596a2c1Sopenharmony_ci return Match(zones, nitzData, systemTimezone); 2549596a2c1Sopenharmony_ci} 2559596a2c1Sopenharmony_ci 2569596a2c1Sopenharmony_ciCountryResult ZoneUtil::LookupTimezoneByNITZ(NITZData &nitzData) 2579596a2c1Sopenharmony_ci{ 2589596a2c1Sopenharmony_ci std::string systemTimezone = ReadSystemParameter(TIMEZONE_KEY, SYS_PARAM_LEN); 2599596a2c1Sopenharmony_ci if (systemTimezone.length() == 0) { 2609596a2c1Sopenharmony_ci systemTimezone = DEFAULT_TIMEZONE; 2619596a2c1Sopenharmony_ci } 2629596a2c1Sopenharmony_ci I18nErrorCode status = I18nErrorCode::SUCCESS; 2639596a2c1Sopenharmony_ci std::set<std::string> icuTimezones = I18nTimeZone::GetAvailableIDs(status); 2649596a2c1Sopenharmony_ci if (status != I18nErrorCode::SUCCESS) { 2659596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::LookupTimezoneByNITZ can not get icu data"); 2669596a2c1Sopenharmony_ci } 2679596a2c1Sopenharmony_ci std::vector<std::string> validZones; 2689596a2c1Sopenharmony_ci for (auto it = icuTimezones.begin(); it != icuTimezones.end(); ++it) { 2699596a2c1Sopenharmony_ci validZones.push_back(*it); 2709596a2c1Sopenharmony_ci } 2719596a2c1Sopenharmony_ci 2729596a2c1Sopenharmony_ci CountryResult result = Match(validZones, nitzData, systemTimezone); 2739596a2c1Sopenharmony_ci if (result.timezoneId.length() == 0 && nitzData.isDST >= 0) { 2749596a2c1Sopenharmony_ci NITZData newNITZData = { -1, nitzData.totalOffset, nitzData.currentMillis }; // -1 means not consider DST 2759596a2c1Sopenharmony_ci result = Match(validZones, newNITZData, systemTimezone); 2769596a2c1Sopenharmony_ci } 2779596a2c1Sopenharmony_ci return result; 2789596a2c1Sopenharmony_ci} 2799596a2c1Sopenharmony_ci 2809596a2c1Sopenharmony_ciCountryResult ZoneUtil::LookupTimezoneByCountry(std::string ®ion, int64_t currentMillis) 2819596a2c1Sopenharmony_ci{ 2829596a2c1Sopenharmony_ci std::vector<std::string> zones; 2839596a2c1Sopenharmony_ci bool isBoosted = false; 2849596a2c1Sopenharmony_ci std::string defaultTimezone; 2859596a2c1Sopenharmony_ci CountryResult result = { true, MatchQuality::DEFAULT_BOOSTED, defaultTimezone }; 2869596a2c1Sopenharmony_ci if (TZLOOKUP_FILE_PATH != nullptr) { 2879596a2c1Sopenharmony_ci HILOG_INFO_I18N("ZoneUtil::LookupTimezoneByCountry use tzlookup.xml"); 2889596a2c1Sopenharmony_ci GetCountryZones(region, defaultTimezone, isBoosted, zones); 2899596a2c1Sopenharmony_ci if (defaultTimezone.length() == 0) { 2909596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::LookupTimezoneByCountry can't find default timezone for region %{public}s", 2919596a2c1Sopenharmony_ci region.c_str()); 2929596a2c1Sopenharmony_ci } 2939596a2c1Sopenharmony_ci } else { 2949596a2c1Sopenharmony_ci HILOG_INFO_I18N("ZoneUtil::LookupTimezoneByCountry use icu data"); 2959596a2c1Sopenharmony_ci GetICUCountryZones(region, zones, defaultTimezone); 2969596a2c1Sopenharmony_ci } 2979596a2c1Sopenharmony_ci result.timezoneId = defaultTimezone; 2989596a2c1Sopenharmony_ci if (isBoosted) { 2999596a2c1Sopenharmony_ci return result; 3009596a2c1Sopenharmony_ci } 3019596a2c1Sopenharmony_ci if (zones.size() == 0) { 3029596a2c1Sopenharmony_ci result.quality = MatchQuality::MULTIPLE_ZONES_DIFFERENT_OFFSET; 3039596a2c1Sopenharmony_ci } else if (zones.size() == 1) { 3049596a2c1Sopenharmony_ci result.quality = MatchQuality::SINGLE_ZONE; 3059596a2c1Sopenharmony_ci } else if (CheckSameDstOffset(zones, defaultTimezone, currentMillis)) { 3069596a2c1Sopenharmony_ci result.quality = MatchQuality::MULTIPLE_ZONES_SAME_OFFSET; 3079596a2c1Sopenharmony_ci } else { 3089596a2c1Sopenharmony_ci result.quality = MatchQuality::MULTIPLE_ZONES_DIFFERENT_OFFSET; 3099596a2c1Sopenharmony_ci } 3109596a2c1Sopenharmony_ci return result; 3119596a2c1Sopenharmony_ci} 3129596a2c1Sopenharmony_ci 3139596a2c1Sopenharmony_ciconst char *ZoneUtil::GetTZLookupDataPath() 3149596a2c1Sopenharmony_ci{ 3159596a2c1Sopenharmony_ci using std::filesystem::directory_iterator; 3169596a2c1Sopenharmony_ci struct stat s; 3179596a2c1Sopenharmony_ci if (stat(DISTRO_COUNTRY_ZONE_DATA_PATH, &s) == 0) { 3189596a2c1Sopenharmony_ci return DISTRO_COUNTRY_ZONE_DATA_PATH; 3199596a2c1Sopenharmony_ci } 3209596a2c1Sopenharmony_ci if (stat(COUNTRY_ZONE_DATA_PATH, &s) == 0) { 3219596a2c1Sopenharmony_ci return COUNTRY_ZONE_DATA_PATH; 3229596a2c1Sopenharmony_ci } else { 3239596a2c1Sopenharmony_ci return nullptr; 3249596a2c1Sopenharmony_ci } 3259596a2c1Sopenharmony_ci} 3269596a2c1Sopenharmony_ci 3279596a2c1Sopenharmony_civoid ZoneUtil::GetCountryZones(std::string ®ion, std::string &defaultTimzone, bool &isBoosted, 3289596a2c1Sopenharmony_ci std::vector<std::string> &zones) 3299596a2c1Sopenharmony_ci{ 3309596a2c1Sopenharmony_ci xmlKeepBlanksDefault(0); 3319596a2c1Sopenharmony_ci xmlDocPtr doc = xmlParseFile(TZLOOKUP_FILE_PATH); 3329596a2c1Sopenharmony_ci if (!doc) { 3339596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::GetCountryZones can not open tzlookup.xml"); 3349596a2c1Sopenharmony_ci return; 3359596a2c1Sopenharmony_ci } 3369596a2c1Sopenharmony_ci xmlNodePtr cur = xmlDocGetRootElement(doc); 3379596a2c1Sopenharmony_ci if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(ROOT_TAG)) != 0) { 3389596a2c1Sopenharmony_ci xmlFreeDoc(doc); 3399596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::GetCountryZones invalid Root_tag"); 3409596a2c1Sopenharmony_ci return; 3419596a2c1Sopenharmony_ci } 3429596a2c1Sopenharmony_ci cur = cur->xmlChildrenNode; 3439596a2c1Sopenharmony_ci xmlNodePtr value; 3449596a2c1Sopenharmony_ci bool findCountry = false; 3459596a2c1Sopenharmony_ci while (cur != nullptr && xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(SECOND_TAG)) == 0) { 3469596a2c1Sopenharmony_ci value = cur->xmlChildrenNode; 3479596a2c1Sopenharmony_ci if (xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>(CODE_TAG)) != 0) { 3489596a2c1Sopenharmony_ci xmlFreeDoc(doc); 3499596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::GetCountryZones invalid code_tag"); 3509596a2c1Sopenharmony_ci return; 3519596a2c1Sopenharmony_ci } 3529596a2c1Sopenharmony_ci xmlChar *codePtr = xmlNodeGetContent(value); 3539596a2c1Sopenharmony_ci if (codePtr == nullptr) { 3549596a2c1Sopenharmony_ci cur = cur->next; 3559596a2c1Sopenharmony_ci continue; 3569596a2c1Sopenharmony_ci } 3579596a2c1Sopenharmony_ci if (strcmp(region.c_str(), reinterpret_cast<const char*>(codePtr)) == 0) { 3589596a2c1Sopenharmony_ci findCountry = true; 3599596a2c1Sopenharmony_ci xmlFree(codePtr); 3609596a2c1Sopenharmony_ci break; 3619596a2c1Sopenharmony_ci } else { 3629596a2c1Sopenharmony_ci xmlFree(codePtr); 3639596a2c1Sopenharmony_ci cur = cur->next; 3649596a2c1Sopenharmony_ci continue; 3659596a2c1Sopenharmony_ci } 3669596a2c1Sopenharmony_ci } 3679596a2c1Sopenharmony_ci if (findCountry) { 3689596a2c1Sopenharmony_ci value = value->next; 3699596a2c1Sopenharmony_ci GetDefaultAndBoost(value, defaultTimzone, isBoosted, zones); 3709596a2c1Sopenharmony_ci } 3719596a2c1Sopenharmony_ci xmlFreeDoc(doc); 3729596a2c1Sopenharmony_ci return; 3739596a2c1Sopenharmony_ci} 3749596a2c1Sopenharmony_ci 3759596a2c1Sopenharmony_civoid ZoneUtil::GetDefaultAndBoost(xmlNodePtr &value, std::string &defaultTimezone, bool &isBoosted, 3769596a2c1Sopenharmony_ci std::vector<std::string> &zones) 3779596a2c1Sopenharmony_ci{ 3789596a2c1Sopenharmony_ci if (value == nullptr || xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>(DEFAULT_TAG)) != 0) { 3799596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::GetDefaultAndBoost invalid default_tag"); 3809596a2c1Sopenharmony_ci return; 3819596a2c1Sopenharmony_ci } 3829596a2c1Sopenharmony_ci xmlChar *defaultPtr = xmlNodeGetContent(value); 3839596a2c1Sopenharmony_ci if (defaultPtr != nullptr) { 3849596a2c1Sopenharmony_ci defaultTimezone = reinterpret_cast<const char*>(defaultPtr); 3859596a2c1Sopenharmony_ci xmlFree(defaultPtr); 3869596a2c1Sopenharmony_ci } 3879596a2c1Sopenharmony_ci value = value->next; 3889596a2c1Sopenharmony_ci if (value == nullptr) { 3899596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::GetDefaultAndBoost doesn't contains id"); 3909596a2c1Sopenharmony_ci return; 3919596a2c1Sopenharmony_ci } 3929596a2c1Sopenharmony_ci if (xmlStrcmp(value->name, reinterpret_cast<const xmlChar *>(BOOSTED_TAG)) == 0) { 3939596a2c1Sopenharmony_ci isBoosted = true; 3949596a2c1Sopenharmony_ci value = value->next; 3959596a2c1Sopenharmony_ci } else { 3969596a2c1Sopenharmony_ci isBoosted = false; 3979596a2c1Sopenharmony_ci } 3989596a2c1Sopenharmony_ci GetTimezones(value, zones); 3999596a2c1Sopenharmony_ci} 4009596a2c1Sopenharmony_ci 4019596a2c1Sopenharmony_civoid ZoneUtil::GetTimezones(xmlNodePtr &value, std::vector<std::string> &zones) 4029596a2c1Sopenharmony_ci{ 4039596a2c1Sopenharmony_ci if (xmlStrcmp(value->name, reinterpret_cast<const xmlChar *>(TIMEZONES_TAG)) != 0) { 4049596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::GetTimezones invalid timezones_tag"); 4059596a2c1Sopenharmony_ci return; 4069596a2c1Sopenharmony_ci } 4079596a2c1Sopenharmony_ci value = value->xmlChildrenNode; 4089596a2c1Sopenharmony_ci while (value != nullptr) { 4099596a2c1Sopenharmony_ci if (xmlStrcmp(value->name, reinterpret_cast<const xmlChar *>(ID_TAG)) != 0) { 4109596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::GetTimezones invalid id_tag"); 4119596a2c1Sopenharmony_ci return; 4129596a2c1Sopenharmony_ci } 4139596a2c1Sopenharmony_ci xmlChar *idPtr = xmlNodeGetContent(value); 4149596a2c1Sopenharmony_ci if (idPtr != nullptr) { 4159596a2c1Sopenharmony_ci zones.push_back(reinterpret_cast<const char*>(idPtr)); 4169596a2c1Sopenharmony_ci xmlFree(idPtr); 4179596a2c1Sopenharmony_ci } 4189596a2c1Sopenharmony_ci value = value->next; 4199596a2c1Sopenharmony_ci } 4209596a2c1Sopenharmony_ci} 4219596a2c1Sopenharmony_ci 4229596a2c1Sopenharmony_civoid ZoneUtil::GetICUCountryZones(std::string ®ion, std::vector<std::string> &zones, std::string &defaultTimezone) 4239596a2c1Sopenharmony_ci{ 4249596a2c1Sopenharmony_ci I18nErrorCode errorCode = I18nErrorCode::SUCCESS; 4259596a2c1Sopenharmony_ci std::set<std::string> validZoneIds = I18nTimeZone::GetAvailableIDs(errorCode); 4269596a2c1Sopenharmony_ci if (errorCode != I18nErrorCode::SUCCESS) { 4279596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::GetICUCountryZones can not get icu data"); 4289596a2c1Sopenharmony_ci } 4299596a2c1Sopenharmony_ci std::set<std::string> countryZoneIds; 4309596a2c1Sopenharmony_ci StringEnumeration *strEnum = TimeZone::createEnumeration(region.c_str()); 4319596a2c1Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 4329596a2c1Sopenharmony_ci const UnicodeString *timezoneIdUStr = strEnum->snext(status); 4339596a2c1Sopenharmony_ci while (timezoneIdUStr != nullptr && U_SUCCESS(status)) { 4349596a2c1Sopenharmony_ci UnicodeString canonicalUnistring; 4359596a2c1Sopenharmony_ci TimeZone::getCanonicalID(*timezoneIdUStr, canonicalUnistring, status); 4369596a2c1Sopenharmony_ci std::string timezoneId; 4379596a2c1Sopenharmony_ci canonicalUnistring.toUTF8String(timezoneId); 4389596a2c1Sopenharmony_ci if (validZoneIds.find(timezoneId) != validZoneIds.end()) { 4399596a2c1Sopenharmony_ci countryZoneIds.insert(timezoneId); 4409596a2c1Sopenharmony_ci } 4419596a2c1Sopenharmony_ci timezoneIdUStr = strEnum->snext(status); 4429596a2c1Sopenharmony_ci } 4439596a2c1Sopenharmony_ci for (auto it = countryZoneIds.begin(); it != countryZoneIds.end(); ++it) { 4449596a2c1Sopenharmony_ci zones.push_back(*it); 4459596a2c1Sopenharmony_ci } 4469596a2c1Sopenharmony_ci if (defaultMap.find(region) != defaultMap.end()) { 4479596a2c1Sopenharmony_ci defaultTimezone = defaultMap[region]; 4489596a2c1Sopenharmony_ci } else { 4499596a2c1Sopenharmony_ci if (zones.size() > 0) { 4509596a2c1Sopenharmony_ci defaultTimezone = zones[0]; 4519596a2c1Sopenharmony_ci } 4529596a2c1Sopenharmony_ci } 4539596a2c1Sopenharmony_ci} 4549596a2c1Sopenharmony_ci 4559596a2c1Sopenharmony_ciCountryResult ZoneUtil::Match(std::vector<std::string> &zones, NITZData &nitzData, std::string &systemTimezone) 4569596a2c1Sopenharmony_ci{ 4579596a2c1Sopenharmony_ci bool isOnlyMatch = true; 4589596a2c1Sopenharmony_ci std::string matchedZoneId; 4599596a2c1Sopenharmony_ci bool local = false; 4609596a2c1Sopenharmony_ci bool useSystemTimezone = false; 4619596a2c1Sopenharmony_ci for (size_t i = 0; i < zones.size(); i++) { 4629596a2c1Sopenharmony_ci std::string zoneId = zones[i]; 4639596a2c1Sopenharmony_ci UnicodeString unicodeZoneID(zoneId.data(), zoneId.length()); 4649596a2c1Sopenharmony_ci TimeZone *timezone = TimeZone::createTimeZone(unicodeZoneID); 4659596a2c1Sopenharmony_ci int32_t rawOffset; 4669596a2c1Sopenharmony_ci int32_t dstOffset; 4679596a2c1Sopenharmony_ci UErrorCode status = UErrorCode::U_ZERO_ERROR; 4689596a2c1Sopenharmony_ci timezone->getOffset(nitzData.currentMillis, static_cast<UBool>(local), rawOffset, dstOffset, status); 4699596a2c1Sopenharmony_ci if ((nitzData.totalOffset - rawOffset == dstOffset) && 4709596a2c1Sopenharmony_ci (nitzData.isDST < 0 || nitzData.isDST == (dstOffset != 0))) { 4719596a2c1Sopenharmony_ci if (matchedZoneId.length() == 0) { 4729596a2c1Sopenharmony_ci matchedZoneId = zoneId; 4739596a2c1Sopenharmony_ci } else { 4749596a2c1Sopenharmony_ci isOnlyMatch = false; 4759596a2c1Sopenharmony_ci } 4769596a2c1Sopenharmony_ci if (strcmp(zoneId.c_str(), systemTimezone.c_str()) == 0) { 4779596a2c1Sopenharmony_ci matchedZoneId = systemTimezone; 4789596a2c1Sopenharmony_ci useSystemTimezone = true; 4799596a2c1Sopenharmony_ci } 4809596a2c1Sopenharmony_ci if (!isOnlyMatch && useSystemTimezone) { 4819596a2c1Sopenharmony_ci break; 4829596a2c1Sopenharmony_ci } 4839596a2c1Sopenharmony_ci } 4849596a2c1Sopenharmony_ci } 4859596a2c1Sopenharmony_ci CountryResult result = {isOnlyMatch, MatchQuality::DEFAULT_BOOSTED, matchedZoneId}; 4869596a2c1Sopenharmony_ci return result; 4879596a2c1Sopenharmony_ci} 4889596a2c1Sopenharmony_ci 4899596a2c1Sopenharmony_cibool ZoneUtil::CheckSameDstOffset(std::vector<std::string> &zones, std::string &defaultTimezoneId, 4909596a2c1Sopenharmony_ci int64_t currentMillis) 4919596a2c1Sopenharmony_ci{ 4929596a2c1Sopenharmony_ci UnicodeString defaultID(defaultTimezoneId.data(), defaultTimezoneId.length()); 4939596a2c1Sopenharmony_ci TimeZone *defaultTimezone = TimeZone::createTimeZone(defaultID); 4949596a2c1Sopenharmony_ci int32_t rawOffset = 0; 4959596a2c1Sopenharmony_ci int32_t dstOffset = 0; 4969596a2c1Sopenharmony_ci bool local = false; 4979596a2c1Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 4989596a2c1Sopenharmony_ci defaultTimezone->getOffset(currentMillis, (UBool)local, rawOffset, dstOffset, status); 4999596a2c1Sopenharmony_ci if (U_FAILURE(status)) { 5009596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::CheckSameDstOffset can not get timezone defaultID offset"); 5019596a2c1Sopenharmony_ci return false; 5029596a2c1Sopenharmony_ci } 5039596a2c1Sopenharmony_ci int32_t totalOffset = rawOffset + dstOffset; 5049596a2c1Sopenharmony_ci for (size_t i = 0; i < zones.size(); i++) { 5059596a2c1Sopenharmony_ci UnicodeString unicodeZoneID(zones[i].data(), zones[i].length()); 5069596a2c1Sopenharmony_ci TimeZone *timezone = TimeZone::createTimeZone(unicodeZoneID); 5079596a2c1Sopenharmony_ci timezone->getOffset(currentMillis, (UBool)local, rawOffset, dstOffset, status); 5089596a2c1Sopenharmony_ci if (U_FAILURE(status)) { 5099596a2c1Sopenharmony_ci HILOG_ERROR_I18N("ZoneUtil::CheckSameDstOffset can not get timezone unicodeZoneID offset"); 5109596a2c1Sopenharmony_ci return false; 5119596a2c1Sopenharmony_ci } 5129596a2c1Sopenharmony_ci if (totalOffset - rawOffset != dstOffset) { 5139596a2c1Sopenharmony_ci return false; 5149596a2c1Sopenharmony_ci } 5159596a2c1Sopenharmony_ci } 5169596a2c1Sopenharmony_ci return true; 5179596a2c1Sopenharmony_ci} 518