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 #include "date_time_format.h"
16 #include "locale_config.h"
17 #include "ohos/init_data.h"
18 #include "parameter.h"
19 #include "utils.h"
20 
21 namespace OHOS {
22 namespace Global {
23 namespace I18n {
24 const char* DateTimeFormat::DEVICE_TYPE_NAME = "const.product.devicetype";
25 const char *DateTimeFormat::TIMEZONE_KEY = "persist.time.timezone";
26 const char *DateTimeFormat::DEFAULT_TIMEZONE = "GMT";
27 
28 using namespace icu;
29 bool DateTimeFormat::icuInitialized = DateTimeFormat::Init();
30 
31 std::map<std::string, DateFormat::EStyle> DateTimeFormat::dateTimeStyle = {
32     { "full", DateFormat::EStyle::kFull },
33     { "long", DateFormat::EStyle::kLong },
34     { "medium", DateFormat::EStyle::kMedium },
35     { "short", DateFormat::EStyle::kShort }
36 };
37 
38 std::unordered_map<std::string, DateTimeFormat::DefaultStyle> DateTimeFormat::DeviceToStyle = {
39     { "tablet", DefaultStyle::LONG },
40     { "2in1", DefaultStyle::LONG },
41     { "tv", DefaultStyle::LONG },
42     { "pc", DefaultStyle::LONG },
43     { "liteWearable", DefaultStyle::SHORT },
44     { "wearable", DefaultStyle::SHORT },
45     { "watch", DefaultStyle::SHORT }
46 };
47 
48 std::unordered_map<DateTimeFormat::DefaultStyle, DateFormat::EStyle> DateTimeFormat::DefaultDTStyle = {
49     { DefaultStyle::LONG, DateFormat::EStyle::kMedium },
50     { DefaultStyle::DEFAULT, DateFormat::EStyle::kShort },
51     { DefaultStyle::SHORT, DateFormat::EStyle::kShort },
52 };
53 
DateTimeFormat(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)54 DateTimeFormat::DateTimeFormat(const std::vector<std::string> &localeTags, std::map<std::string, std::string> &configs)
55 {
56     defaultStyle = GetDefaultStyle();
57     UErrorCode status = U_ZERO_ERROR;
58     ParseConfigsPartOne(configs);
59     ParseConfigsPartTwo(configs);
60     for (size_t i = 0; i < localeTags.size(); i++) {
61         std::string curLocale = localeTags[i];
62         locale = Locale::forLanguageTag(StringPiece(curLocale), status);
63         if (U_FAILURE(status)) {
64             status = U_ZERO_ERROR;
65             continue;
66         }
67         if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) {
68             createSuccess = InitWithLocale(curLocale, configs);
69             if (!createSuccess || !dateFormat) {
70                 FreeDateTimeFormat();
71                 continue;
72             }
73             break;
74         }
75     }
76     if (!localeInfo || !dateFormat) {
77         createSuccess = InitWithDefaultLocale(configs);
78     }
79 }
80 
FreeDateTimeFormat()81 void DateTimeFormat::FreeDateTimeFormat()
82 {
83     if (calendar != nullptr) {
84         delete calendar;
85         calendar = nullptr;
86     }
87     if (dateFormat != nullptr) {
88         delete dateFormat;
89         dateFormat = nullptr;
90     }
91     if (localeInfo != nullptr) {
92         delete localeInfo;
93         localeInfo = nullptr;
94     }
95 }
96 
~DateTimeFormat()97 DateTimeFormat::~DateTimeFormat()
98 {
99     FreeDateTimeFormat();
100 }
101 
CheckInitSuccess()102 bool DateTimeFormat::CheckInitSuccess()
103 {
104     if (dateIntvFormat == nullptr || calendar == nullptr || dateFormat == nullptr || localeInfo == nullptr) {
105         return false;
106     }
107     return true;
108 }
109 
CreateInstance(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)110 std::unique_ptr<DateTimeFormat> DateTimeFormat::CreateInstance(const std::vector<std::string> &localeTags,
111                                                                std::map<std::string, std::string> &configs)
112 {
113     std::unique_ptr<DateTimeFormat> dateTimeFormat = std::make_unique<DateTimeFormat>(localeTags, configs);
114     if (!dateTimeFormat->CheckInitSuccess()) {
115         return nullptr;
116     }
117     return dateTimeFormat;
118 }
119 
InitWithLocale(const std::string & curLocale,std::map<std::string,std::string> & configs)120 bool DateTimeFormat::InitWithLocale(const std::string &curLocale, std::map<std::string, std::string> &configs)
121 {
122     localeInfo = new LocaleInfo(curLocale, configs);
123     if (localeInfo == nullptr || !localeInfo->InitSuccess()) {
124         return false;
125     }
126     locale = localeInfo->GetLocale();
127     localeTag = localeInfo->GetBaseName();
128     if (hourCycle.empty()) {
129         hourCycle = localeInfo->GetHourCycle();
130     }
131     if (hour12.empty() && hourCycle.empty() && !LocaleConfig::IsEmpty24HourClock()) {
132         bool is24HourClock = LocaleConfig::Is24HourClock();
133         if (is24HourClock) {
134             hour12 = "false";
135         } else {
136             hour12 = "true";
137         }
138     }
139     ComputeHourCycleChars();
140     ComputeSkeleton();
141     UErrorCode status = U_ZERO_ERROR;
142     if (!configs.size()) {
143         InitDateFormatWithoutConfigs(status);
144     } else {
145         InitDateFormat(status);
146     }
147     if (!U_SUCCESS(status)) {
148         return false;
149     }
150     status = U_ZERO_ERROR;
151     calendar = Calendar::createInstance(locale, status);
152     if (!U_SUCCESS(status)) {
153         return false;
154     }
155     return true;
156 }
157 
InitWithDefaultLocale(std::map<std::string,std::string> & configs)158 bool DateTimeFormat::InitWithDefaultLocale(std::map<std::string, std::string> &configs)
159 {
160     if (localeInfo != nullptr) {
161         delete localeInfo;
162         localeInfo = nullptr;
163     }
164     if (dateFormat != nullptr) {
165         delete dateFormat;
166         dateFormat = nullptr;
167     }
168     return InitWithLocale(LocaleConfig::GetSystemLocale(), configs);
169 }
170 
InitDateFormatWithoutConfigs(UErrorCode & status)171 void DateTimeFormat::InitDateFormatWithoutConfigs(UErrorCode &status)
172 {
173     dateFormat = DateFormat::createDateInstance(DefaultDTStyle[defaultStyle], locale);
174     SimpleDateFormat *simDateFormat = static_cast<SimpleDateFormat*>(dateFormat);
175     if (simDateFormat != nullptr) {
176         simDateFormat->toPattern(pattern);
177     }
178     dateIntvFormat =
179         std::unique_ptr<DateIntervalFormat>(DateIntervalFormat::createInstance(pattern, locale, status));
180 }
181 
FixPatternPartOne()182 void DateTimeFormat::FixPatternPartOne()
183 {
184     if (hour12 == "true") {
185         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("H")),
186             icu::UnicodeString::fromUTF8(StringPiece("h")));
187         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),
188             icu::UnicodeString::fromUTF8(StringPiece("h")));
189         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),
190             icu::UnicodeString::fromUTF8(StringPiece("h")));
191     } else if (hour12 == "false") {
192         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("h")),
193             icu::UnicodeString::fromUTF8(StringPiece("H")));
194         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),
195             icu::UnicodeString::fromUTF8(StringPiece("H")));
196         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),
197             icu::UnicodeString::fromUTF8(StringPiece("H")));
198         RemoveAmPmChar();
199     } else if (hourCycle != "") {
200         FixPatternPartTwo();
201     }
202 }
203 
FixPatternPartTwo()204 void DateTimeFormat::FixPatternPartTwo()
205 {
206     if (hourCycle == "h11") {
207         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("h")),
208             icu::UnicodeString::fromUTF8(StringPiece("k")));
209         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("H")),
210             icu::UnicodeString::fromUTF8(StringPiece("k")));
211         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),
212             icu::UnicodeString::fromUTF8(StringPiece("k")));
213     } else if (hourCycle == "h12") {
214         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("H")),
215             icu::UnicodeString::fromUTF8(StringPiece("h")));
216         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),
217             icu::UnicodeString::fromUTF8(StringPiece("h")));
218         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),
219             icu::UnicodeString::fromUTF8(StringPiece("h")));
220     } else if (hourCycle == "h23") {
221         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("h")),
222             icu::UnicodeString::fromUTF8(StringPiece("K")));
223         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("H")),
224             icu::UnicodeString::fromUTF8(StringPiece("K")));
225         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),
226             icu::UnicodeString::fromUTF8(StringPiece("K")));
227         RemoveAmPmChar();
228     } else if (hourCycle == "h24") {
229         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("h")),
230             icu::UnicodeString::fromUTF8(StringPiece("H")));
231         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),
232             icu::UnicodeString::fromUTF8(StringPiece("H")));
233         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),
234             icu::UnicodeString::fromUTF8(StringPiece("H")));
235         RemoveAmPmChar();
236     }
237 }
238 
RemoveAmPmChar()239 void DateTimeFormat::RemoveAmPmChar()
240 {
241     std::string patternString = "";
242     pattern.toUTF8String(patternString);
243     size_t amPmCharStartIdx = 0;
244     size_t amPmCharEndIdx = 0;
245     for (size_t i = 0; i < patternString.length(); i++) {
246         if (patternString[i] != 'a') {
247             continue;
248         }
249         if ((i + 1) < patternString.length() && patternString[i + 1] == 't') {
250             continue;
251         }
252         if (!i) {
253             amPmCharStartIdx = i;
254         } else {
255             amPmCharStartIdx = i - 1;
256             while (amPmCharStartIdx > 0 && patternString[amPmCharStartIdx] == ' ') {
257                 amPmCharStartIdx -= 1;
258             }
259             if (amPmCharStartIdx || patternString[amPmCharStartIdx] != ' ') {
260                 amPmCharStartIdx += 1;
261             }
262         }
263         amPmCharEndIdx = i + 1;
264         while (amPmCharEndIdx < patternString.length() && patternString[amPmCharEndIdx] == ' ') {
265             amPmCharEndIdx += 1;
266         }
267         break;
268     }
269     size_t length = amPmCharEndIdx - amPmCharStartIdx;
270     if (length) {
271         if (!amPmCharStartIdx || amPmCharEndIdx == patternString.length()) {
272             patternString = patternString.replace(amPmCharStartIdx, length, "");
273         } else {
274             patternString = patternString.replace(amPmCharStartIdx, length, " ");
275         }
276         pattern = icu::UnicodeString(patternString.data(), patternString.length());
277     }
278 }
279 
InitDateFormat(UErrorCode & status)280 void DateTimeFormat::InitDateFormat(UErrorCode &status)
281 {
282     if (!dateStyle.empty() || !timeStyle.empty()) {
283         DateFormat::EStyle dateStyleValue = DateFormat::EStyle::kNone;
284         DateFormat::EStyle timeStyleValue = DateFormat::EStyle::kNone;
285         if (!dateStyle.empty()) {
286             if (dateTimeStyle.count(dateStyle) > 0) {
287                 dateStyleValue = dateTimeStyle[dateStyle];
288             } else if (dateStyle == "auto") {
289                 dateStyleValue = DefaultDTStyle[defaultStyle];
290             }
291         }
292         if (!timeStyle.empty()) {
293             if (dateTimeStyle.count(timeStyle) > 0) {
294                 timeStyleValue = dateTimeStyle[timeStyle];
295             } else if (timeStyle == "auto") {
296                 timeStyleValue = DefaultDTStyle[defaultStyle];
297             }
298         }
299         dateFormat = DateFormat::createDateTimeInstance(dateStyleValue, timeStyleValue, locale);
300         SimpleDateFormat *simDateFormat = static_cast<SimpleDateFormat*>(dateFormat);
301         if (simDateFormat != nullptr) {
302             simDateFormat->toPattern(pattern);
303         }
304         FixPatternPartOne();
305         delete dateFormat;
306         dateFormat = new SimpleDateFormat(pattern, locale, status);
307         if (!U_SUCCESS(status)) {
308             return;
309         }
310     } else {
311         auto patternGenerator =
312             std::unique_ptr<DateTimePatternGenerator>(DateTimePatternGenerator::createInstance(locale, status));
313         if (!U_SUCCESS(status)) {
314             return;
315         }
316         ComputePattern();
317         pattern =
318             patternGenerator->replaceFieldTypes(patternGenerator->getBestPattern(pattern, status), pattern, status);
319         pattern = patternGenerator->getBestPattern(pattern, status);
320         SetDayPeriod();
321         status = U_ZERO_ERROR;
322         dateFormat = new SimpleDateFormat(pattern, locale, status);
323         if (!U_SUCCESS(status)) {
324             return;
325         }
326     }
327     status = U_ZERO_ERROR;
328     dateIntvFormat =
329         std::unique_ptr<DateIntervalFormat>(DateIntervalFormat::createInstance(pattern, locale, status));
330 }
331 
SetDayPeriod()332 void DateTimeFormat::SetDayPeriod()
333 {
334     if (dayPeriod == "short" || (dayPeriod == "auto" && defaultStyle ==  DefaultStyle::DEFAULT)) {
335         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("a")),
336             icu::UnicodeString::fromUTF8(StringPiece("B")));
337     } else if (dayPeriod == "long" || (dayPeriod == "auto" && defaultStyle ==  DefaultStyle::LONG)) {
338         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("a")),
339             icu::UnicodeString::fromUTF8(StringPiece("BBBB")));
340     } else if (dayPeriod == "narrow" || (dayPeriod == "auto" && defaultStyle ==  DefaultStyle::SHORT)) {
341         pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("a")),
342             icu::UnicodeString::fromUTF8(StringPiece("BBBBB")));
343     }
344 }
345 
ParseConfigsPartOne(std::map<std::string,std::string> & configs)346 void DateTimeFormat::ParseConfigsPartOne(std::map<std::string, std::string> &configs)
347 {
348     if (configs.count("dateStyle") > 0) {
349         dateStyle = configs["dateStyle"];
350     }
351     if (configs.count("timeStyle") > 0) {
352         timeStyle = configs["timeStyle"];
353     }
354     if (configs.count("year") > 0) {
355         year = configs["year"];
356     }
357     if (configs.count("month") > 0) {
358         month = configs["month"];
359     }
360     if (configs.count("day") > 0) {
361         day = configs["day"];
362     }
363     if (configs.count("hour") > 0) {
364         hour = configs["hour"];
365     }
366     if (configs.count("minute") > 0) {
367         minute = configs["minute"];
368     }
369     if (configs.count("second") > 0) {
370         second = configs["second"];
371     }
372 }
373 
ParseConfigsPartTwo(std::map<std::string,std::string> & configs)374 void DateTimeFormat::ParseConfigsPartTwo(std::map<std::string, std::string> &configs)
375 {
376     if (configs.count("hourCycle") > 0) {
377         hourCycle = configs["hourCycle"];
378     }
379     if (configs.count("timeZone") > 0) {
380         timeZone = configs["timeZone"];
381     }
382     if (configs.count("numberingSystem") > 0) {
383         numberingSystem = configs["numberingSystem"];
384     }
385     if (configs.count("hour12") > 0) {
386         hour12 = configs["hour12"];
387     }
388     if (configs.count("weekday") > 0) {
389         weekday = configs["weekday"];
390     }
391     if (configs.count("era") > 0) {
392         era = configs["era"];
393     }
394     if (configs.count("timeZoneName") > 0) {
395         timeZoneName = configs["timeZoneName"];
396     }
397     if (configs.count("dayPeriod") > 0) {
398         dayPeriod = configs["dayPeriod"];
399     }
400     if (configs.count("localeMatcher") > 0) {
401         localeMatcher = configs["localeMatcher"];
402     }
403     if (configs.count("formatMatcher") > 0) {
404         formatMatcher = configs["formatMatcher"];
405     }
406 }
407 
ComputeSkeleton()408 void DateTimeFormat::ComputeSkeleton()
409 {
410     if (year.empty() && month.empty() && day.empty() && hour.empty() && minute.empty() && second.empty() &&
411         weekday.empty()) {
412         pattern.append("yMd");
413     }
414     AddOptions(year, yearChar);
415     AddOptions(month, monthChar);
416     AddOptions(day, dayChar);
417     AddOptions(hour, hourChar);
418     AddOptions(minute, minuteChar);
419     AddOptions(second, secondChar);
420     if ((hourCycle == "h12" || hourCycle == "h11" || hour12 == "true") && !hour.empty()) {
421         pattern.append(amPmChar);
422     }
423     AddOptions(timeZoneName, timeZoneChar);
424     AddOptions(weekday, weekdayChar);
425     AddOptions(era, eraChar);
426 }
427 
AddOptions(std::string option,char16_t optionChar)428 void DateTimeFormat::AddOptions(std::string option, char16_t optionChar)
429 {
430     if (!option.empty()) {
431         pattern.append(optionChar);
432     }
433 }
434 
ComputeHourCycleChars()435 void DateTimeFormat::ComputeHourCycleChars()
436 {
437     if (!hour12.empty()) {
438         if (hour12 == "true") {
439             hourNumericString = "h";
440             hourTwoDigitString = "hh";
441         } else {
442             hourNumericString = "H";
443             hourTwoDigitString = "HH";
444         }
445     } else {
446         if (hourCycle == "h11") {
447             hourNumericString = "K";
448             hourTwoDigitString = "KK";
449         } else if (hourCycle == "h12") {
450             hourNumericString = "h";
451             hourTwoDigitString = "hh";
452         } else if (hourCycle == "h23") {
453             hourNumericString = "H";
454             hourTwoDigitString = "HH";
455         } else if (hourCycle == "h24") {
456             hourNumericString = "k";
457             hourTwoDigitString = "kk";
458         }
459     }
460 }
461 
ComputePattern()462 void DateTimeFormat::ComputePattern()
463 {
464     ComputePartOfPattern(year, yearChar, "yy", "yyyy");
465     ComputePartOfPattern(day, dayChar, "dd", "d");
466     ComputePartOfPattern(hour, hourChar, hourTwoDigitString, hourNumericString);
467     ComputePartOfPattern(minute, minuteChar, "mm", "mm");
468     ComputePartOfPattern(second, secondChar, "ss", "ss");
469     if (!month.empty()) {
470         UnicodeString monthOfPattern = UnicodeString(monthChar);
471         int32_t length = monthOfPattern.length();
472         if (month == "numeric" && length != NUMERIC_LENGTH) {
473             pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("M")));
474         } else if (month == "2-digit" && length != TWO_DIGIT_LENGTH) {
475             pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("MM")));
476         } else if ((month == "long" && length != LONG_LENGTH) || (month == "auto" &&
477             defaultStyle ==  DefaultStyle::LONG)) {
478             pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("MMMM")));
479         } else if ((month == "short" && length != SHORT_LENGTH) || (month == "auto" &&
480             (defaultStyle ==  DefaultStyle::DEFAULT || defaultStyle ==  DefaultStyle::SHORT))) {
481             pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("MMM")));
482         } else if (month == "narrow" && length != NARROW_LENGTH) {
483             pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("MMMMM")));
484         }
485     }
486 
487     ComputeTimeZoneOfPattern(timeZoneName, timeZoneChar, "zzzz", "O");
488     ComputeWeekdayOfPattern(weekday, weekdayChar, "EEEE", "E", "EEEEE");
489     ComputeEraOfPattern(era, eraChar, "GGGG", "G", "GGGGG");
490 }
491 
ComputePartOfPattern(std::string option,char16_t character,std::string twoDigitChar,std::string numericChar)492 void DateTimeFormat::ComputePartOfPattern(std::string option, char16_t character, std::string twoDigitChar,
493     std::string numericChar)
494 {
495     if (!option.empty()) {
496         UnicodeString curPartOfPattern = UnicodeString(character);
497         if (option == "2-digit") {
498             pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(twoDigitChar)));
499         } else if (option == "numeric") {
500             pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(numericChar)));
501         }
502     }
503 }
504 
ComputeTimeZoneOfPattern(std::string option,char16_t character,std::string longChar,std::string shortChar)505 void DateTimeFormat::ComputeTimeZoneOfPattern(std::string option, char16_t character, std::string longChar,
506     std::string shortChar)
507 {
508     if (!option.empty()) {
509         UnicodeString timeZoneOfPattern = UnicodeString(character);
510         if (option == "long" || (option == "auto" && defaultStyle ==  DefaultStyle::LONG)) {
511             pattern.findAndReplace(timeZoneOfPattern, UnicodeString::fromUTF8(StringPiece(longChar)));
512         } else if (option == "short" || (option == "auto" && (defaultStyle ==  DefaultStyle::DEFAULT ||
513             defaultStyle ==  DefaultStyle::SHORT))) {
514             pattern.findAndReplace(timeZoneOfPattern, UnicodeString::fromUTF8(StringPiece(shortChar)));
515         }
516     }
517 }
518 
ComputeWeekdayOfPattern(std::string option,char16_t character,std::string longChar,std::string shortChar,std::string narrowChar)519 void DateTimeFormat::ComputeWeekdayOfPattern(std::string option, char16_t character, std::string longChar,
520     std::string shortChar, std::string narrowChar)
521 {
522     if (!option.empty()) {
523         UnicodeString curPartOfPattern = UnicodeString(character);
524         int32_t length = curPartOfPattern.length();
525         if ((option == "long" && length != LONG_ERA_LENGTH) || (option == "auto" &&
526             defaultStyle ==  DefaultStyle::LONG)) {
527             pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(longChar)));
528         } else if ((option == "short" && length != SHORT_ERA_LENGTH) || (option == "auto" &&
529             (defaultStyle ==  DefaultStyle::DEFAULT || defaultStyle ==  DefaultStyle::SHORT))) {
530             pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(shortChar)));
531         } else if (option == "narrow" && length != NARROW_LENGTH) {
532             pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(narrowChar)));
533         }
534     }
535 }
536 
ComputeEraOfPattern(std::string option,char16_t character,std::string longChar,std::string shortChar,std::string narrowChar)537 void DateTimeFormat::ComputeEraOfPattern(std::string option, char16_t character, std::string longChar,
538     std::string shortChar, std::string narrowChar)
539 {
540     if (!option.empty()) {
541         UnicodeString curPartOfPattern = UnicodeString(character);
542         int32_t length = curPartOfPattern.length();
543         if ((option == "long" && length != LONG_ERA_LENGTH) || (option == "auto" &&
544             defaultStyle ==  DefaultStyle::LONG)) {
545             pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(longChar)));
546         } else if ((option == "short" && length != SHORT_ERA_LENGTH) || (option == "auto" &&
547             defaultStyle ==  DefaultStyle::DEFAULT)) {
548             pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(shortChar)));
549         } else if ((option == "narrow" && length != NARROW_LENGTH) || (option == "auto" &&
550             defaultStyle ==  DefaultStyle::SHORT)) {
551             pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(narrowChar)));
552         }
553     }
554 }
555 
GetSystemTimezone()556 std::string DateTimeFormat::GetSystemTimezone()
557 {
558     std::string systemTimezone = ReadSystemParameter(TIMEZONE_KEY, SYS_PARAM_LEN);
559     if (systemTimezone.length() == 0) {
560         systemTimezone = DEFAULT_TIMEZONE;
561     }
562     return systemTimezone;
563 }
564 
Format(int64_t milliseconds)565 std::string DateTimeFormat::Format(int64_t milliseconds)
566 {
567     if (!createSuccess) {
568         return PseudoLocalizationProcessor("");
569     }
570     UErrorCode status = U_ZERO_ERROR;
571     std::string result;
572     UnicodeString dateString;
573     calendar->clear();
574     std::string timezoneStr = timeZone.empty() ? GetSystemTimezone() : timeZone;
575     auto zone = std::unique_ptr<TimeZone>(TimeZone::createTimeZone(timezoneStr.c_str()));
576     if (zone != nullptr) {
577         calendar->setTimeZone(*zone);
578         dateFormat->setTimeZone(*zone);
579     }
580     calendar->setTime((UDate)milliseconds, status);
581     dateFormat->format(calendar->getTime(status), dateString, status);
582     dateString.toUTF8String(result);
583     return PseudoLocalizationProcessor(result);
584 }
585 
FormatRange(int64_t fromMilliseconds,int64_t toMilliseconds)586 std::string DateTimeFormat::FormatRange(int64_t fromMilliseconds, int64_t toMilliseconds)
587 {
588     if (!createSuccess || calendar == nullptr) {
589         return PseudoLocalizationProcessor("");
590     }
591     UErrorCode status = U_ZERO_ERROR;
592     std::string result;
593     UnicodeString dateString;
594     calendar->clear();
595     std::string timezoneStr = timeZone.empty() ? GetSystemTimezone() : timeZone;
596     auto zone = std::unique_ptr<TimeZone>(TimeZone::createTimeZone(timezoneStr.c_str()));
597     if (zone != nullptr) {
598         calendar->setTimeZone(*zone);
599         dateIntvFormat->setTimeZone(*zone);
600     }
601     calendar->setTime((UDate)fromMilliseconds, status);
602 
603     auto toCalendar = std::unique_ptr<Calendar>(Calendar::createInstance(locale, status));
604     if (U_FAILURE(status) || toCalendar == nullptr) {
605         return PseudoLocalizationProcessor("");
606     }
607     toCalendar->clear();
608     if (zone != nullptr) {
609         toCalendar->setTimeZone(*zone);
610     }
611     toCalendar->setTime((UDate)toMilliseconds, status);
612     FieldPosition pos = 0;
613     dateIntvFormat->format(*calendar, *toCalendar, dateString, pos, status);
614     dateString.toUTF8String(result);
615     return PseudoLocalizationProcessor(result);
616 }
617 
GetResolvedOptions(std::map<std::string,std::string> & map)618 void DateTimeFormat::GetResolvedOptions(std::map<std::string, std::string> &map)
619 {
620     map.insert(std::make_pair("locale", localeTag));
621     if (!(localeInfo->GetCalendar()).empty()) {
622         map.insert(std::make_pair("calendar", localeInfo->GetCalendar()));
623     } else {
624         map.insert(std::make_pair("calendar", calendar->getType()));
625     }
626     if (!dateStyle.empty()) {
627         map.insert(std::make_pair("dateStyle", dateStyle));
628     }
629     if (!timeStyle.empty()) {
630         map.insert(std::make_pair("timeStyle", timeStyle));
631     }
632     if (!hourCycle.empty()) {
633         map.insert(std::make_pair("hourCycle", hourCycle));
634     } else if (!(localeInfo->GetHourCycle()).empty()) {
635         map.insert(std::make_pair("hourCycle", localeInfo->GetHourCycle()));
636     }
637     if (!timeZone.empty()) {
638         map.insert(std::make_pair("timeZone", timeZone));
639     } else {
640         UnicodeString timeZoneID("");
641         std::string timeZoneString;
642         dateFormat->getTimeZone().getID(timeZoneID).toUTF8String(timeZoneString);
643         map.insert(std::make_pair("timeZone", timeZoneString));
644     }
645     if (!timeZoneName.empty()) {
646         map.insert(std::make_pair("timeZoneName", timeZoneName));
647     }
648     if (!numberingSystem.empty()) {
649         map.insert(std::make_pair("numberingSystem", numberingSystem));
650     } else if (!(localeInfo->GetNumberingSystem()).empty()) {
651         map.insert(std::make_pair("numberingSystem", localeInfo->GetNumberingSystem()));
652     } else {
653         UErrorCode status = U_ZERO_ERROR;
654         auto numSys = std::unique_ptr<NumberingSystem>(NumberingSystem::createInstance(locale, status));
655         if (U_SUCCESS(status)) {
656             map.insert(std::make_pair("numberingSystem", numSys->getName()));
657         }
658     }
659     GetAdditionalResolvedOptions(map);
660 }
661 
GetAdditionalResolvedOptions(std::map<std::string,std::string> & map)662 void DateTimeFormat::GetAdditionalResolvedOptions(std::map<std::string, std::string> &map)
663 {
664     if (!hour12.empty()) {
665         map.insert(std::make_pair("hour12", hour12));
666     }
667     if (!weekday.empty()) {
668         map.insert(std::make_pair("weekday", weekday));
669     }
670     if (!era.empty()) {
671         map.insert(std::make_pair("era", era));
672     }
673     if (!year.empty()) {
674         map.insert(std::make_pair("year", year));
675     }
676     if (!month.empty()) {
677         map.insert(std::make_pair("month", month));
678     }
679     if (!day.empty()) {
680         map.insert(std::make_pair("day", day));
681     }
682     if (!hour.empty()) {
683         map.insert(std::make_pair("hour", hour));
684     }
685     if (!minute.empty()) {
686         map.insert(std::make_pair("minute", minute));
687     }
688     if (!second.empty()) {
689         map.insert(std::make_pair("second", second));
690     }
691     if (!dayPeriod.empty()) {
692         map.insert(std::make_pair("dayPeriod", dayPeriod));
693     }
694     if (!localeMatcher.empty()) {
695         map.insert(std::make_pair("localeMatcher", localeMatcher));
696     }
697     if (!formatMatcher.empty()) {
698         map.insert(std::make_pair("formatMatcher", formatMatcher));
699     }
700 }
701 
GetDateStyle() const702 std::string DateTimeFormat::GetDateStyle() const
703 {
704     return dateStyle;
705 }
706 
GetTimeStyle() const707 std::string DateTimeFormat::GetTimeStyle() const
708 {
709     return timeStyle;
710 }
711 
GetHourCycle() const712 std::string DateTimeFormat::GetHourCycle() const
713 {
714     return hourCycle;
715 }
716 
GetTimeZone() const717 std::string DateTimeFormat::GetTimeZone() const
718 {
719     return timeZone;
720 }
721 
GetTimeZoneName() const722 std::string DateTimeFormat::GetTimeZoneName() const
723 {
724     return timeZoneName;
725 }
726 
GetNumberingSystem() const727 std::string DateTimeFormat::GetNumberingSystem() const
728 {
729     return numberingSystem;
730 }
731 
GetHour12() const732 std::string DateTimeFormat::GetHour12() const
733 {
734     return hour12;
735 }
736 
GetWeekday() const737 std::string DateTimeFormat::GetWeekday() const
738 {
739     return weekday;
740 }
741 
GetEra() const742 std::string DateTimeFormat::GetEra() const
743 {
744     return era;
745 }
746 
GetYear() const747 std::string DateTimeFormat::GetYear() const
748 {
749     return year;
750 }
751 
GetMonth() const752 std::string DateTimeFormat::GetMonth() const
753 {
754     return month;
755 }
756 
GetDay() const757 std::string DateTimeFormat::GetDay() const
758 {
759     return day;
760 }
761 
GetHour() const762 std::string DateTimeFormat::GetHour() const
763 {
764     return hour;
765 }
766 
GetMinute() const767 std::string DateTimeFormat::GetMinute() const
768 {
769     return minute;
770 }
771 
GetSecond() const772 std::string DateTimeFormat::GetSecond() const
773 {
774     return second;
775 }
776 
Init()777 bool DateTimeFormat::Init()
778 {
779     SetHwIcuDirectory();
780     return true;
781 }
782 
GetDefaultStyle()783 DateTimeFormat::DefaultStyle DateTimeFormat::GetDefaultStyle()
784 {
785     char value[BUFFER_LEN];
786     int code = GetParameter(DEVICE_TYPE_NAME, "", value, BUFFER_LEN);
787     if (code > 0) {
788         std::string deviceType = value;
789         if (DeviceToStyle.find(deviceType) != DeviceToStyle.end()) {
790             return DeviceToStyle[deviceType];
791         }
792     }
793     return DefaultStyle::DEFAULT;
794 }
795 } // namespace I18n
796 } // namespace Global
797 } // namespace OHOS
798