• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "i18n_timezone.h"
16 
17 #include "libxml/globals.h"
18 #include "libxml/tree.h"
19 #include "libxml/xmlstring.h"
20 #include "locale_config.h"
21 #include "locale_info.h"
22 #include "map"
23 #include "set"
24 #include "string"
25 #include "type_traits"
26 #include "umachine.h"
27 #include "utility"
28 #include "utils.h"
29 #include "utypes.h"
30 #include "vector"
31 #include "unicode/locid.h"
32 #include "unicode/unistr.h"
33 
34 namespace OHOS {
35 namespace Global {
36 namespace I18n {
37 const char *I18nTimeZone::TIMEZONE_KEY = "persist.time.timezone";
38 const char *I18nTimeZone::DEFAULT_TIMEZONE = "GMT";
39 const char *I18nTimeZone::DEFAULT_LANGUAGE = "/system/usr/ohos_timezone/en-Latn.xml";
40 const char *I18nTimeZone::DEFAULT_LOCALE = "en-Latn";
41 const char *I18nTimeZone::TIMEZONES_PATH = "/system/usr/ohos_timezone/";
42 const char *I18nTimeZone::SUPPORT_LOCALES_PATH = "/system/usr/ohos_timezone/supported_locales.xml";
43 const char *I18nTimeZone::rootTag = "timezones";
44 const char *I18nTimeZone::secondRootTag = "timezone";
45 const char *I18nTimeZone::supportLocalesTag = "supported_locales";
46 std::string I18nTimeZone::displayLocale = "";
47 bool I18nTimeZone::isInitialized = false;
48 
49 std::map<std::string, std::string> I18nTimeZone::supportLocales {};
50 std::set<std::string> I18nTimeZone::availableIDs {};
51 std::vector<std::string> I18nTimeZone::availableZoneCityIDs {};
52 std::map<std::string, std::string> I18nTimeZone::city2DisplayName {};
53 std::map<std::string, std::string> I18nTimeZone::city2TimeZoneID {};
54 
I18nTimeZone(std::string & id,bool isZoneID)55 I18nTimeZone::I18nTimeZone(std::string &id, bool isZoneID)
56 {
57     if (isZoneID) {
58         if (id.empty()) {
59             std::string systemTimezone = ReadSystemParameter(TIMEZONE_KEY, SYS_PARAM_LEN);
60             if (systemTimezone.length() == 0) {
61                 systemTimezone = DEFAULT_TIMEZONE;
62             }
63             icu::UnicodeString unicodeZoneID(systemTimezone.data(), systemTimezone.length());
64             timezone = icu::TimeZone::createTimeZone(unicodeZoneID);
65         } else {
66             icu::UnicodeString unicodeZoneID(id.data(), id.length());
67             timezone = icu::TimeZone::createTimeZone(unicodeZoneID);
68         }
69     } else {
70         if (!isInitialized) {
71             ReadTimeZoneData(DEFAULT_LANGUAGE);
72             isInitialized = true;
73         }
74         if (city2TimeZoneID.find(id) == city2TimeZoneID.end()) {
75             timezone = icu::TimeZone::createDefault();
76         } else {
77             std::string timezoneID = city2TimeZoneID.at(id);
78             icu::UnicodeString unicodeZoneID(timezoneID.data(), timezoneID.length());
79             timezone = icu::TimeZone::createTimeZone(unicodeZoneID);
80         }
81     }
82 }
83 
~I18nTimeZone()84 I18nTimeZone::~I18nTimeZone()
85 {
86     if (timezone != nullptr) {
87         delete timezone;
88         timezone = nullptr;
89     }
90 }
91 
GetTimeZone()92 icu::TimeZone* I18nTimeZone::GetTimeZone()
93 {
94     return timezone;
95 }
96 
CreateInstance(std::string & id,bool isZoneID)97 std::unique_ptr<I18nTimeZone> I18nTimeZone::CreateInstance(std::string &id, bool isZoneID)
98 {
99     std::unique_ptr<I18nTimeZone> i18nTimeZone = std::make_unique<I18nTimeZone>(id, isZoneID);
100     if (i18nTimeZone->GetTimeZone() == nullptr) {
101         return nullptr;
102     }
103     return i18nTimeZone;
104 }
105 
GetOffset(double date)106 int32_t I18nTimeZone::GetOffset(double date)
107 {
108     int32_t rawOffset = 0;
109     int32_t dstOffset = 0;
110     bool local = false;
111     UErrorCode status = U_ZERO_ERROR;
112     if (timezone == nullptr) {
113         return 0;
114     }
115     timezone->getOffset(date, (UBool)local, rawOffset, dstOffset, status);
116     if (status != U_ZERO_ERROR) {
117         return 0;
118     }
119     return rawOffset + dstOffset;
120 }
121 
GetRawOffset()122 int32_t I18nTimeZone::GetRawOffset()
123 {
124     if (timezone == nullptr) {
125         return 0;
126     }
127     return timezone->getRawOffset();
128 }
129 
GetID()130 std::string I18nTimeZone::GetID()
131 {
132     if (timezone == nullptr) {
133         return "";
134     }
135     icu::UnicodeString zoneID;
136     timezone->getID(zoneID);
137     std::string result;
138     zoneID.toUTF8String(result);
139     return result;
140 }
141 
GetDisplayName()142 std::string I18nTimeZone::GetDisplayName()
143 {
144     if (timezone == nullptr) {
145         return "";
146     }
147     std::string localeStr = LocaleConfig::GetSystemLocale();
148     return GetDisplayName(localeStr, false);
149 }
150 
GetDisplayName(bool isDST)151 std::string I18nTimeZone::GetDisplayName(bool isDST)
152 {
153     std::string localeStr = LocaleConfig::GetSystemLocale();
154     return GetDisplayName(localeStr, isDST);
155 }
156 
GetDisplayName(std::string localeStr)157 std::string I18nTimeZone::GetDisplayName(std::string localeStr)
158 {
159     return GetDisplayName(localeStr, false);
160 }
161 
GetDisplayName(std::string localeStr,bool isDST)162 std::string I18nTimeZone::GetDisplayName(std::string localeStr, bool isDST)
163 {
164     icu::TimeZone::EDisplayType style = icu::TimeZone::EDisplayType::LONG_GENERIC;
165     icu::Locale locale(localeStr.data());
166     icu::UnicodeString name;
167     timezone->getDisplayName((UBool)isDST, style, locale, name);
168     std::string result;
169     name.toUTF8String(result);
170     return result;
171 }
172 
ReadTimeZoneData(const char * xmlPath)173 void I18nTimeZone::ReadTimeZoneData(const char *xmlPath)
174 {
175     xmlKeepBlanksDefault(0);
176     if (xmlPath == nullptr) {
177         return;
178     }
179     xmlDocPtr doc = xmlParseFile(xmlPath);
180     if (!doc) {
181         return;
182     }
183     xmlNodePtr cur = xmlDocGetRootElement(doc);
184     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(rootTag))) {
185         xmlFreeDoc(doc);
186         return;
187     }
188     cur = cur->xmlChildrenNode;
189     while (cur != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(secondRootTag))) {
190         xmlNodePtr value = cur->xmlChildrenNode;
191         xmlChar *contents[ELEMENT_NUM] = { 0 }; // 3 represent cityid, zoneid, displayname;
192         for (size_t i = 0; i < ELEMENT_NUM; i++) {
193             if (value != nullptr) {
194                 contents[i] = xmlNodeGetContent(value);
195                 value = value->next;
196             } else {
197                 break;
198             }
199         }
200         if (!isInitialized) {
201             // 0 represents cityid index, 1 represents zoneid index
202             availableZoneCityIDs.insert(availableZoneCityIDs.end(), reinterpret_cast<const char *>(contents[0]));
203             availableIDs.insert(reinterpret_cast<const char *>(contents[1]));
204             city2TimeZoneID.insert(
205                 std::make_pair<std::string, std::string>(reinterpret_cast<const char *>(contents[0]),
206                                                          reinterpret_cast<const char *>(contents[1])));
207         }
208         // 0 represents cityid index, 2 represents displayname index
209         city2DisplayName.insert(
210             std::make_pair<std::string, std::string>(reinterpret_cast<const char *>(contents[0]),
211                                                      reinterpret_cast<const char *>(contents[2])));
212         for (size_t i = 0; i < ELEMENT_NUM; i++) {
213             if (contents[i] != nullptr) {
214                 xmlFree(contents[i]);
215             }
216         }
217         cur = cur->next;
218     }
219     xmlFreeDoc(doc);
220 }
221 
GetAvailableIDs()222 std::set<std::string> I18nTimeZone::GetAvailableIDs()
223 {
224     if (!isInitialized) {
225         ReadTimeZoneData(DEFAULT_LANGUAGE);
226         isInitialized = true;
227     }
228     return availableIDs;
229 }
230 
GetAvailableZoneCityIDs()231 std::vector<std::string> I18nTimeZone::GetAvailableZoneCityIDs()
232 {
233     if (!isInitialized) {
234         ReadTimeZoneData(DEFAULT_LANGUAGE);
235         isInitialized = true;
236     }
237     return availableZoneCityIDs;
238 }
239 
ComputeLocale(std::string & locale)240 std::string I18nTimeZone::ComputeLocale(std::string &locale)
241 {
242     if (supportLocales.size() == 0) {
243         xmlKeepBlanksDefault(0);
244         xmlDocPtr doc = xmlParseFile(SUPPORT_LOCALES_PATH);
245         if (!doc) {
246             return DEFAULT_LOCALE;
247         }
248         xmlNodePtr cur = xmlDocGetRootElement(doc);
249         if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(supportLocalesTag))) {
250             xmlFreeDoc(doc);
251             return DEFAULT_LOCALE;
252         }
253         cur = cur->xmlChildrenNode;
254         while (cur != nullptr) {
255             xmlChar *content = xmlNodeGetContent(cur);
256             if (content == nullptr) {
257                 break;
258             }
259             std::map<std::string, std::string> configs = {};
260             LocaleInfo localeinfo(reinterpret_cast<const char*>(content), configs);
261             std::string language = localeinfo.GetLanguage();
262             std::string script = localeinfo.GetScript();
263             std::string languageAndScript = (script.length() == 0) ? language : language + "-" + script;
264             LocaleInfo newLocaleInfo(languageAndScript, configs);
265             std::string maximizeLocale = newLocaleInfo.Maximize();
266             supportLocales.insert(
267                 std::make_pair<std::string, std::string>(maximizeLocale.c_str(),
268                                                          reinterpret_cast<const char*>(content)));
269             xmlFree(content);
270             cur = cur->next;
271         }
272     }
273     std::map<std::string, std::string> configs = {};
274     LocaleInfo localeinfo(locale, configs);
275     std::string language = localeinfo.GetLanguage();
276     std::string script = localeinfo.GetScript();
277     std::string languageAndScript = (script.length() == 0) ? language : language + "-" + script;
278     LocaleInfo newLocaleInfo(languageAndScript, configs);
279     std::string maximizeLocale = newLocaleInfo.Maximize();
280     if (supportLocales.find(maximizeLocale) != supportLocales.end()) {
281         return supportLocales.at(maximizeLocale);
282     }
283     return DEFAULT_LOCALE;
284 }
285 
GetCityDisplayName(std::string & cityID,std::string & locale)286 std::string I18nTimeZone::GetCityDisplayName(std::string &cityID, std::string &locale)
287 {
288     std::string finalLocale = ComputeLocale(locale);
289     if (finalLocale.compare(displayLocale) != 0) {
290         std::string xmlPath = TIMEZONES_PATH + finalLocale + ".xml";
291         city2DisplayName.clear();
292         ReadTimeZoneData(xmlPath.c_str());
293         displayLocale = finalLocale;
294     }
295     if (city2DisplayName.find(cityID) == city2DisplayName.end()) {
296         return "";
297     }
298     return city2DisplayName.at(cityID);
299 }
300 }
301 }
302 }
303