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 &region, 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 &region, 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 &region, 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 &region, 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