• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <filesystem>
17 #include <sys/stat.h>
18 #include "i18n_hilog.h"
19 #include "i18n_timezone.h"
20 #include "ohos/init_data.h"
21 #include "phonenumbers/phonenumberutil.h"
22 #include "unicode/strenum.h"
23 #include "unicode/timezone.h"
24 #include "utils.h"
25 #include "zone_util.h"
26 
27 using namespace OHOS::Global::I18n;
28 using namespace icu;
29 using namespace std;
30 
31 const char *ZoneUtil::COUNTRY_ZONE_DATA_PATH = "/system/usr/ohos_timezone/tzlookup.xml";
32 const char *ZoneUtil::DISTRO_COUNTRY_ZONE_DATA_PATH = "/system/etc/tzdata_distro/hos/tzlookup.xml";
33 const char *ZoneUtil::DEFAULT_TIMEZONE = "GMT";
34 const char *ZoneUtil::TIMEZONES_TAG = "timezones";
35 const char *ZoneUtil::ID_TAG = "id";
36 const char *ZoneUtil::DEFAULT_TAG = "default";
37 const char *ZoneUtil::BOOSTED_TAG = "defaultBoost";
38 const char *ZoneUtil::ROOT_TAG = "countryzones";
39 const char *ZoneUtil::SECOND_TAG = "country";
40 const char *ZoneUtil::CODE_TAG = "code";
41 const char *ZoneUtil::TIMEZONE_KEY = "persist.time.timezone";
42 const char *ZoneUtil::TZLOOKUP_FILE_PATH = ZoneUtil::GetTZLookupDataPath();
43 
44 unordered_map<string, string> ZoneUtil::defaultMap = {
45     {"AQ", "Antarctica/McMurdo"},
46     {"AR", "America/Argentina/Buenos_Aires"},
47     {"AU", "Australia/Sydney"},
48     {"BR", "America/Noronha"},
49     {"BT", "Asia/Thimbu"}, // alias Asia/Thimphu
50     {"CA", "America/St_Johns"},
51     {"CD", "Africa/Kinshasa"},
52     {"CL", "America/Santiago"},
53     {"CN", "Asia/Shanghai"},
54     {"CY", "Asia/Nicosia"},
55     {"DE", "Europe/Berlin"},
56     {"DG", "Indian/Chagos"},
57     {"EA", "Africa/Ceuta"},
58     {"EC", "America/Guayaquil"},
59     {"ER", "Africa/Asmara"}, // alias Africa/Asmera
60     {"ES", "Europe/Madrid"},
61     {"FM", "Pacific/Pohnpei"},
62     {"FO", "Atlantic/Faroe"}, // alias Atlantic/Faeroe
63     {"GL", "America/Godthab"},
64     {"IC", "Atlantic/Canary"},
65     {"ID", "Asia/Jakarta"},
66     {"IN", "Asia/Kolkata"}, // alias Asia/Calcutta
67     {"KI", "Pacific/Tarawa"},
68     {"KZ", "Asia/Almaty"},
69     {"MH", "Pacific/Majuro"},
70     {"MN", "Asia/Ulaanbaatar"},
71     {"MX", "America/Mexico_City"},
72     {"MY", "Asia/Kuala_Lumpur"},
73     {"NP", "Asia/Kathmandu"}, // alias Asia/Katmandu
74     {"NZ", "Pacific/Auckland"},
75     {"PF", "Pacific/Tahiti"},
76     {"PG", "Pacific/Port_Moresby"},
77     {"PS", "Asia/Gaza"},
78     {"PT", "Europe/Lisbon"},
79     {"RU", "Europe/Moscow"},
80     {"UA", "Europe/Kiev"},
81     {"UM", "Pacific/Wake"},
82     {"US", "America/New_York"},
83     {"UZ", "Asia/Tashkent"},
84     {"VN", "Asia/Ho_Chi_Minh"}, // alias Asia/Saigon
85 };
86 
87 bool ZoneUtil::icuInitialized = ZoneUtil::Init();
88 
GetDefaultZone(const std::string & country)89 std::string ZoneUtil::GetDefaultZone(const std::string& country)
90 {
91     string temp(country);
92     for (size_t i = 0; i < temp.size(); i++) {
93         temp[i] = (char)toupper(temp[i]);
94     }
95     if (defaultMap.find(temp) != defaultMap.end()) {
96         return defaultMap[temp];
97     }
98     string ret;
99     StringEnumeration *strEnum = TimeZone::createEnumeration(temp.c_str());
100     GetString(strEnum, ret);
101     if (strEnum != nullptr) {
102         delete strEnum;
103     }
104     return ret;
105 }
106 
GetDefaultZone(int32_t number)107 std::string ZoneUtil::GetDefaultZone(int32_t number)
108 {
109     using i18n::phonenumbers::PhoneNumberUtil;
110     PhoneNumberUtil* phoneUtil = PhoneNumberUtil::GetInstance();
111     if (phoneUtil == nullptr) {
112         HILOG_ERROR_I18N("ZoneUtil::GetDefaultZone: Get phone number util failed.");
113         return "";
114     }
115     std::string regionCode;
116     phoneUtil->GetRegionCodeForCountryCode(number, &regionCode);
117     return GetDefaultZone(regionCode);
118 }
119 
GetDefaultZone(const std::string & country,int32_t offset)120 std::string ZoneUtil::GetDefaultZone(const std::string& country, int32_t offset)
121 {
122     UErrorCode status = U_ZERO_ERROR;
123     StringEnumeration *strEnum =
124         TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, country.c_str(), &offset, status);
125     if (U_FAILURE(status)) {
126         return "";
127     }
128     string ret;
129     GetString(strEnum, ret);
130     if (strEnum != nullptr) {
131         delete strEnum;
132         strEnum = nullptr;
133     }
134     return ret;
135 }
136 
GetDefaultZone(int32_t number,int32_t offset)137 std::string ZoneUtil::GetDefaultZone(int32_t number, int32_t offset)
138 {
139     using i18n::phonenumbers::PhoneNumberUtil;
140     PhoneNumberUtil* phoneUtil = PhoneNumberUtil::GetInstance();
141     if (phoneUtil == nullptr) {
142         HILOG_ERROR_I18N("ZoneUtil::GetDefaultZone: Get phone number util failed.");
143         return "";
144     }
145     std::string regionCode;
146     phoneUtil->GetRegionCodeForCountryCode(number, &regionCode);
147     return GetDefaultZone(regionCode, offset);
148 }
149 
GetZoneList(const std::string & country,std::vector<std::string> & retVec)150 void ZoneUtil::GetZoneList(const std::string& country, std::vector<std::string>& retVec)
151 {
152     StringEnumeration *strEnum = TimeZone::createEnumeration(country.c_str());
153     GetList(strEnum, retVec);
154     if (strEnum != nullptr) {
155         delete strEnum;
156         strEnum = nullptr;
157     }
158 }
159 
GetZoneList(const std::string & country,int32_t offset,std::vector<std::string> & retVec)160 void ZoneUtil::GetZoneList(const std::string& country, int32_t offset, std::vector<std::string>& retVec)
161 {
162     UErrorCode status = U_ZERO_ERROR;
163     StringEnumeration *strEnum =
164         TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, country.c_str(), &offset, status);
165     if (U_FAILURE(status)) {
166         delete strEnum;
167         strEnum = nullptr;
168         return;
169     }
170     GetList(strEnum, retVec);
171     if (strEnum != nullptr) {
172         delete strEnum;
173         strEnum = nullptr;
174     }
175 }
176 
GetString(StringEnumeration * strEnum,string & ret)177 void ZoneUtil::GetString(StringEnumeration *strEnum, string& ret)
178 {
179     UErrorCode status = U_ZERO_ERROR;
180     if (!strEnum) {
181         return;
182     }
183     int32_t count = strEnum->count(status);
184     if (U_FAILURE(status) || count <= 0) {
185         return;
186     }
187     const UnicodeString *uniStr = strEnum->snext(status);
188     if (U_FAILURE(status) || (!uniStr)) {
189         return;
190     }
191     UnicodeString canonicalUnistring;
192     TimeZone::getCanonicalID(*uniStr, canonicalUnistring, status);
193     if (U_FAILURE(status)) {
194         return;
195     }
196     canonicalUnistring.toUTF8String(ret);
197     return;
198 }
199 
GetList(StringEnumeration * strEnum,vector<string> & retVec)200 void ZoneUtil::GetList(StringEnumeration *strEnum, vector<string> &retVec)
201 {
202     if (!strEnum) {
203         return;
204     }
205     UErrorCode status = U_ZERO_ERROR;
206     int32_t count = strEnum->count(status);
207     if (count <= 0 || U_FAILURE(status)) {
208         return;
209     }
210     while (count > 0) {
211         const UnicodeString *uniStr = strEnum->snext(status);
212         if ((!uniStr) || U_FAILURE(status)) {
213             retVec.clear();
214             break;
215         }
216         UnicodeString canonicalUnistring;
217         TimeZone::getCanonicalID(*uniStr, canonicalUnistring, status);
218         if (U_FAILURE(status)) {
219             retVec.clear();
220             break;
221         }
222         string canonicalString = "";
223         canonicalUnistring.toUTF8String(canonicalString);
224         if ((canonicalString != "") && (find(retVec.begin(), retVec.end(), canonicalString) == retVec.end())) {
225             retVec.push_back(canonicalString);
226         }
227         --count;
228     }
229     return;
230 }
231 
Init()232 bool ZoneUtil::Init()
233 {
234     SetHwIcuDirectory();
235     return true;
236 }
237 
LookupTimezoneByCountryAndNITZ(std::string & region,NITZData & nitzData)238 CountryResult ZoneUtil::LookupTimezoneByCountryAndNITZ(std::string &region, NITZData &nitzData)
239 {
240     std::vector<std::string> zones;
241     std::string defaultTimezone;
242     std::string systemTimezone = ReadSystemParameter(TIMEZONE_KEY, SYS_PARAM_LEN);
243     if (systemTimezone.length() == 0) {
244         systemTimezone = DEFAULT_TIMEZONE;
245     }
246     if (TZLOOKUP_FILE_PATH != nullptr) {
247         bool isBoosted = false;
248         HILOG_INFO_I18N("ZoneUtil::LookupTimezoneByCountryAndNITZ use tzlookup.xml");
249         GetCountryZones(region, defaultTimezone, isBoosted, zones);
250     } else {
251         HILOG_INFO_I18N("ZoneUtil::LookupTimezoneByCountryAndNITZ use icu data");
252         GetICUCountryZones(region, zones, defaultTimezone);
253     }
254     return Match(zones, nitzData, systemTimezone);
255 }
256 
LookupTimezoneByNITZ(NITZData & nitzData)257 CountryResult ZoneUtil::LookupTimezoneByNITZ(NITZData &nitzData)
258 {
259     std::string systemTimezone = ReadSystemParameter(TIMEZONE_KEY, SYS_PARAM_LEN);
260     if (systemTimezone.length() == 0) {
261         systemTimezone = DEFAULT_TIMEZONE;
262     }
263     I18nErrorCode status = I18nErrorCode::SUCCESS;
264     std::set<std::string> icuTimezones = I18nTimeZone::GetAvailableIDs(status);
265     if (status != I18nErrorCode::SUCCESS) {
266         HILOG_ERROR_I18N("ZoneUtil::LookupTimezoneByNITZ can not get icu data");
267     }
268     std::vector<std::string> validZones;
269     for (auto it = icuTimezones.begin(); it != icuTimezones.end(); ++it) {
270         validZones.push_back(*it);
271     }
272 
273     CountryResult result = Match(validZones, nitzData, systemTimezone);
274     if (result.timezoneId.empty() && nitzData.isDST >= 0) {
275         NITZData newNITZData = { -1, nitzData.totalOffset, nitzData.currentMillis };  // -1 means not consider DST
276         result = Match(validZones, newNITZData, systemTimezone);
277     }
278     return result;
279 }
280 
LookupTimezoneByCountry(std::string & region,int64_t currentMillis)281 CountryResult ZoneUtil::LookupTimezoneByCountry(std::string &region, int64_t currentMillis)
282 {
283     std::vector<std::string> zones;
284     bool isBoosted = false;
285     std::string defaultTimezone;
286     CountryResult result = { true, MatchQuality::DEFAULT_BOOSTED, defaultTimezone };
287     if (TZLOOKUP_FILE_PATH != nullptr) {
288         HILOG_INFO_I18N("ZoneUtil::LookupTimezoneByCountry use tzlookup.xml");
289         GetCountryZones(region, defaultTimezone, isBoosted, zones);
290         if (defaultTimezone.empty()) {
291             HILOG_ERROR_I18N("ZoneUtil::LookupTimezoneByCountry can't find default timezone for region %{public}s",
292                 region.c_str());
293         }
294     } else {
295         HILOG_INFO_I18N("ZoneUtil::LookupTimezoneByCountry use icu data");
296         GetICUCountryZones(region, zones, defaultTimezone);
297     }
298     result.timezoneId = defaultTimezone;
299     if (isBoosted) {
300         return result;
301     }
302     if (zones.size() == 0) {
303         result.quality = MatchQuality::MULTIPLE_ZONES_DIFFERENT_OFFSET;
304     } else if (zones.size() == 1) {
305         result.quality = MatchQuality::SINGLE_ZONE;
306     } else if (CheckSameDstOffset(zones, defaultTimezone, currentMillis)) {
307         result.quality = MatchQuality::MULTIPLE_ZONES_SAME_OFFSET;
308     } else {
309         result.quality = MatchQuality::MULTIPLE_ZONES_DIFFERENT_OFFSET;
310     }
311     return result;
312 }
313 
GetTZLookupDataPath()314 const char *ZoneUtil::GetTZLookupDataPath()
315 {
316     using std::filesystem::directory_iterator;
317     struct stat s;
318     if (stat(DISTRO_COUNTRY_ZONE_DATA_PATH, &s) == 0) {
319         return DISTRO_COUNTRY_ZONE_DATA_PATH;
320     }
321     if (stat(COUNTRY_ZONE_DATA_PATH, &s) == 0) {
322         return COUNTRY_ZONE_DATA_PATH;
323     } else {
324         return nullptr;
325     }
326 }
327 
IsFindCountry(xmlDocPtr & doc,xmlNodePtr & cur,xmlNodePtr & value,std::string & region)328 bool ZoneUtil::IsFindCountry(xmlDocPtr &doc, xmlNodePtr &cur, xmlNodePtr &value,
329     std::string &region)
330 {
331     while (cur != nullptr && xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(SECOND_TAG)) == 0) {
332         value = cur->xmlChildrenNode;
333         if (value == nullptr) {
334             cur = cur->next;
335             continue;
336         }
337         if (xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>(CODE_TAG)) != 0) {
338             xmlFreeDoc(doc);
339             HILOG_ERROR_I18N("ZoneUtil::GetCountryZones invalid code_tag");
340             return false;
341         }
342         xmlChar *codePtr = xmlNodeGetContent(value);
343         if (codePtr == nullptr) {
344             cur = cur->next;
345             continue;
346         }
347         const char* xmlRegion = reinterpret_cast<const char*>(codePtr);
348         if (region.compare(xmlRegion) == 0) {
349             xmlFree(codePtr);
350             return true;
351         } else {
352             xmlFree(codePtr);
353             cur = cur->next;
354             continue;
355         }
356     }
357     return false;
358 }
359 
GetCountryZones(std::string & region,std::string & defaultTimzone,bool & isBoosted,std::vector<std::string> & zones)360 void ZoneUtil::GetCountryZones(std::string &region, std::string &defaultTimzone, bool &isBoosted,
361     std::vector<std::string> &zones)
362 {
363     xmlKeepBlanksDefault(0);
364     xmlDocPtr doc = xmlParseFile(TZLOOKUP_FILE_PATH);
365     if (!doc) {
366         HILOG_ERROR_I18N("ZoneUtil::GetCountryZones can not open tzlookup.xml");
367         return;
368     }
369     xmlNodePtr cur = xmlDocGetRootElement(doc);
370     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(ROOT_TAG)) != 0) {
371         xmlFreeDoc(doc);
372         HILOG_ERROR_I18N("ZoneUtil::GetCountryZones invalid Root_tag");
373         return;
374     }
375     cur = cur->xmlChildrenNode;
376     xmlNodePtr value;
377     bool findCountry = IsFindCountry(doc, cur, value, region);
378     if (findCountry) {
379         value = value->next;
380         GetDefaultAndBoost(value, defaultTimzone, isBoosted, zones);
381     }
382     xmlUnlinkNode(cur);
383     xmlFreeNode(cur);
384     xmlFreeDoc(doc);
385     return;
386 }
387 
GetDefaultAndBoost(xmlNodePtr & value,std::string & defaultTimezone,bool & isBoosted,std::vector<std::string> & zones)388 void ZoneUtil::GetDefaultAndBoost(xmlNodePtr &value, std::string &defaultTimezone, bool &isBoosted,
389     std::vector<std::string> &zones)
390 {
391     if (value == nullptr || xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>(DEFAULT_TAG)) != 0) {
392         HILOG_ERROR_I18N("ZoneUtil::GetDefaultAndBoost invalid default_tag");
393         return;
394     }
395     xmlChar *defaultPtr = xmlNodeGetContent(value);
396     if (defaultPtr != nullptr) {
397         defaultTimezone = reinterpret_cast<const char*>(defaultPtr);
398         xmlFree(defaultPtr);
399     }
400     value = value->next;
401     if (value == nullptr) {
402         HILOG_ERROR_I18N("ZoneUtil::GetDefaultAndBoost doesn't contains id");
403         return;
404     }
405     if (xmlStrcmp(value->name, reinterpret_cast<const xmlChar *>(BOOSTED_TAG)) == 0) {
406         isBoosted = true;
407         value = value->next;
408     } else {
409         isBoosted = false;
410     }
411     GetTimezones(value, zones);
412 }
413 
GetTimezones(xmlNodePtr & value,std::vector<std::string> & zones)414 void ZoneUtil::GetTimezones(xmlNodePtr &value, std::vector<std::string> &zones)
415 {
416     if (xmlStrcmp(value->name, reinterpret_cast<const xmlChar *>(TIMEZONES_TAG)) != 0) {
417         HILOG_ERROR_I18N("ZoneUtil::GetTimezones invalid timezones_tag");
418         return;
419     }
420     value = value->xmlChildrenNode;
421     while (value != nullptr) {
422         if (xmlStrcmp(value->name, reinterpret_cast<const xmlChar *>(ID_TAG)) != 0) {
423             HILOG_ERROR_I18N("ZoneUtil::GetTimezones invalid id_tag");
424             return;
425         }
426         xmlChar *idPtr = xmlNodeGetContent(value);
427         if (idPtr != nullptr) {
428             zones.push_back(reinterpret_cast<const char*>(idPtr));
429             xmlFree(idPtr);
430         }
431         value = value->next;
432     }
433 }
434 
GetICUCountryZones(std::string & region,std::vector<std::string> & zones,std::string & defaultTimezone)435 void ZoneUtil::GetICUCountryZones(std::string &region, std::vector<std::string> &zones, std::string &defaultTimezone)
436 {
437     I18nErrorCode errorCode = I18nErrorCode::SUCCESS;
438     std::set<std::string> validZoneIds = I18nTimeZone::GetAvailableIDs(errorCode);
439     if (errorCode != I18nErrorCode::SUCCESS) {
440         HILOG_ERROR_I18N("ZoneUtil::GetICUCountryZones can not get icu data");
441     }
442     std::set<std::string> countryZoneIds;
443     StringEnumeration *strEnum = TimeZone::createEnumeration(region.c_str());
444     UErrorCode status = U_ZERO_ERROR;
445     const UnicodeString *timezoneIdUStr = strEnum == nullptr ? nullptr : strEnum->snext(status);
446     while (timezoneIdUStr != nullptr && U_SUCCESS(status)) {
447         UnicodeString canonicalUnistring;
448         TimeZone::getCanonicalID(*timezoneIdUStr, canonicalUnistring, status);
449         std::string timezoneId;
450         canonicalUnistring.toUTF8String(timezoneId);
451         if (validZoneIds.find(timezoneId) != validZoneIds.end()) {
452             countryZoneIds.insert(timezoneId);
453         }
454         timezoneIdUStr = strEnum->snext(status);
455     }
456     for (auto it = countryZoneIds.begin(); it != countryZoneIds.end(); ++it) {
457         zones.push_back(*it);
458     }
459     if (defaultMap.find(region) != defaultMap.end()) {
460         defaultTimezone = defaultMap[region];
461     } else {
462         if (zones.size() > 0) {
463             defaultTimezone = zones[0];
464         }
465     }
466     delete strEnum;
467 }
468 
Match(std::vector<std::string> & zones,NITZData & nitzData,std::string & systemTimezone)469 CountryResult ZoneUtil::Match(std::vector<std::string> &zones, NITZData &nitzData, std::string &systemTimezone)
470 {
471     bool isOnlyMatch = true;
472     std::string matchedZoneId;
473     bool local = false;
474     bool useSystemTimezone = false;
475     for (size_t i = 0; i < zones.size(); i++) {
476         std::string zoneId = zones[i];
477         UnicodeString unicodeZoneID(zoneId.data(), zoneId.length());
478         TimeZone *timezone = TimeZone::createTimeZone(unicodeZoneID);
479         if (timezone == nullptr) {
480             HILOG_ERROR_I18N("ZoneUtil::Match: Create time zone failed.");
481             continue;
482         }
483         int32_t rawOffset;
484         int32_t dstOffset;
485         UErrorCode status = UErrorCode::U_ZERO_ERROR;
486         timezone->getOffset(nitzData.currentMillis, static_cast<UBool>(local), rawOffset, dstOffset, status);
487         if (U_FAILURE(status)) {
488             HILOG_ERROR_I18N("ZoneUtil::Match: Time zone get offset failed.");
489             delete timezone;
490             continue;
491         }
492         if ((nitzData.totalOffset - rawOffset == dstOffset) &&
493             (nitzData.isDST < 0 || nitzData.isDST == (dstOffset != 0))) {
494             if (matchedZoneId.empty()) {
495                 matchedZoneId = zoneId;
496             } else {
497                 isOnlyMatch = false;
498             }
499             if (strcmp(zoneId.c_str(), systemTimezone.c_str()) == 0) {
500                 matchedZoneId = systemTimezone;
501                 useSystemTimezone = true;
502             }
503             if (!isOnlyMatch && useSystemTimezone) {
504                 delete timezone;
505                 break;
506             }
507         }
508         delete timezone;
509     }
510     CountryResult result = {isOnlyMatch, MatchQuality::DEFAULT_BOOSTED, matchedZoneId};
511     return result;
512 }
513 
CheckSameDstOffset(std::vector<std::string> & zones,std::string & defaultTimezoneId,int64_t currentMillis)514 bool ZoneUtil::CheckSameDstOffset(std::vector<std::string> &zones, std::string &defaultTimezoneId,
515     int64_t currentMillis)
516 {
517     UnicodeString defaultID(defaultTimezoneId.data(), defaultTimezoneId.length());
518     TimeZone *defaultTimezone = TimeZone::createTimeZone(defaultID);
519     if (defaultTimezone == nullptr) {
520         HILOG_ERROR_I18N("ZoneUtil::CheckSameDstOffset: Create default time zone failed.");
521         return false;
522     }
523     int32_t rawOffset = 0;
524     int32_t dstOffset = 0;
525     bool local = false;
526     UErrorCode status = U_ZERO_ERROR;
527     defaultTimezone->getOffset(currentMillis, (UBool)local, rawOffset, dstOffset, status);
528     if (U_FAILURE(status)) {
529         delete defaultTimezone;
530         HILOG_ERROR_I18N("ZoneUtil::CheckSameDstOffset can not get timezone defaultID offset");
531         return false;
532     }
533     delete defaultTimezone;
534     int32_t totalOffset = rawOffset + dstOffset;
535     for (size_t i = 0; i < zones.size(); i++) {
536         UnicodeString unicodeZoneID(zones[i].data(), zones[i].length());
537         TimeZone *timezone = TimeZone::createTimeZone(unicodeZoneID);
538         if (timezone == nullptr) {
539             HILOG_ERROR_I18N("ZoneUtil::CheckSameDstOffset: Create time zone failed.");
540             return false;
541         }
542         timezone->getOffset(currentMillis, (UBool)local, rawOffset, dstOffset, status);
543         if (U_FAILURE(status)) {
544             delete timezone;
545             HILOG_ERROR_I18N("ZoneUtil::CheckSameDstOffset can not get timezone unicodeZoneID offset");
546             return false;
547         }
548         if (totalOffset - rawOffset != dstOffset) {
549             delete timezone;
550             return false;
551         }
552         delete timezone;
553     }
554     return true;
555 }
556