• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "base/i18n/date_time_sequence.h"
16 #include "unicode/dtptngen.h"
17 #include "unicode/smpdtfmt.h"
18 #include <regex>
19 
20 namespace OHOS::Ace {
21 
22 using namespace icu;
23 
GetDateOrder(const std::string & locale)24 OrderResult DateTimeSequence::GetDateOrder(const std::string& locale)
25 {
26     UErrorCode icuStatus = U_ZERO_ERROR;
27     OrderResult orderResult;
28     icu::Locale localeObj = icu::Locale::forLanguageTag(locale.data(), icuStatus);
29     if (U_FAILURE(icuStatus)) {
30         return orderResult;
31     }
32     const char* language = localeObj.getBaseName();
33     if (language == nullptr) {
34         return orderResult;
35     }
36     const std::unordered_map<std::string, std::string> DATE_ORDER_MAP = {
37         { "ug", "M-d-y" },
38         { "ar", "y-M-d" },
39         { "fa", "y-M-d" },
40         { "ur", "y-M-d" },
41         { "iw", "y-M-d" },
42         { "he", "y-M-d" },
43     };
44     std::string languageTag = language;
45     if (DATE_ORDER_MAP.find(languageTag) != DATE_ORDER_MAP.end()) {
46         orderResult.dateOrder = DATE_ORDER_MAP.find(languageTag)->second;
47         return orderResult;
48     }
49     icu::SimpleDateFormat* formatter = static_cast<icu::SimpleDateFormat*>
50         (icu::DateFormat::createDateInstance(icu::DateFormat::EStyle::kDefault, localeObj));
51     if (U_FAILURE(icuStatus) || formatter == nullptr) {
52         return orderResult;
53     }
54     std::string tempValue;
55     icu::UnicodeString unistr;
56     formatter->toPattern(unistr);
57     unistr.toUTF8String<std::string>(tempValue);
58     std::string value = ModifyOrder(tempValue);
59     std::regex pattern("d+");
60     std::regex reg("M+");
61     value = regex_replace(value, pattern, "d");
62     value = regex_replace(value, reg, "M");
63     orderResult = {value};
64     delete formatter;
65     return orderResult;
66 }
67 
GetDateTimeOrder(const std::string & locale)68 OrderResult DateTimeSequence::GetDateTimeOrder(const std::string& locale)
69 {
70     UErrorCode status = U_ZERO_ERROR;
71     OrderResult orderResult;
72     icu::Locale localeObj = icu::Locale::forLanguageTag(locale.data(), status);
73     if (U_FAILURE(status)) {
74         orderResult.dateTimeOrder = "-1";
75         return orderResult;
76     }
77     const std::unordered_map<std::string, std::string> DATETIME_ORDER_MAP = {
78         { "ug", "01" },
79         { "ar", "10" },
80         { "fa", "01" },
81         { "ur", "10" },
82         { "iw", "10" },
83         { "he", "10" },
84     };
85     const char* language = localeObj.getBaseName();
86     std::string languageTag = language == nullptr ? "" : language;
87     if (DATETIME_ORDER_MAP.find(languageTag) != DATETIME_ORDER_MAP.end()) {
88         orderResult.dateTimeOrder = DATETIME_ORDER_MAP.find(languageTag)->second;
89         return orderResult;
90     }
91     icu::SimpleDateFormat* formatter = static_cast<icu::SimpleDateFormat*>
92         (icu::DateFormat::createDateInstance(icu::DateFormat::EStyle::kDateTime, localeObj));
93     if (status != U_ZERO_ERROR || formatter == nullptr) {
94         orderResult.dateTimeOrder = "-1";
95         return orderResult;
96     }
97     icu::UnicodeString pattern;
98     formatter->toPattern(pattern);
99     std::string result;
100     pattern.toUTF8String<std::string>(result);
101 
102     std::regex pattrn("0([^01]+)1");
103     std::smatch match;
104     bool found = std::regex_search(result, match, pattrn);
105     // 1 represent date position, 0 represent time position
106     std::string dateTimeOrder = found ? "01" : "10";
107     orderResult = {result, dateTimeOrder};
108     delete formatter;
109     return orderResult;
110 }
111 
GetAmPmTimeOrder(const std::string & locale)112 OrderResult DateTimeSequence::GetAmPmTimeOrder(const std::string& locale)
113 {
114     UErrorCode status = U_ZERO_ERROR;
115     OrderResult orderResult;
116     icu::Locale localeObj = icu::Locale::forLanguageTag(locale.data(), status);
117     if (status != U_ZERO_ERROR) {
118         orderResult.amPmTimeOrder = "-1";
119         return orderResult;
120     }
121     const char* language = localeObj.getBaseName();
122     // 0 represents am/pm position, 1 represents time position
123     const std::string amPmFirst = "10";
124     const std::string amPmLast = "01";
125     const std::unordered_map<std::string, std::string> AM_PM_TIME_ORDER_MAP = {
126         { "ug", amPmFirst },
127         { "ar", amPmFirst },
128         { "fa", amPmLast },
129         { "ur", amPmFirst },
130         { "iw", amPmLast },
131         { "he", amPmLast },
132         { "bo", amPmFirst },
133     };
134     std::string languageTag = language == nullptr ? "" : language;
135     if (AM_PM_TIME_ORDER_MAP.find(languageTag) != AM_PM_TIME_ORDER_MAP.end()) {
136         orderResult.amPmTimeOrder = AM_PM_TIME_ORDER_MAP.find(languageTag)->second;
137         return orderResult;
138     }
139     icu::DateTimePatternGenerator* gen = icu::DateTimePatternGenerator::createInstance(localeObj, status);
140     icu::UnicodeString skeleton("h");
141     if (gen == nullptr) {
142         orderResult.amPmTimeOrder = "-1";
143         return orderResult;
144     }
145     icu::UnicodeString resultStr = gen->getBestPattern(skeleton, status);
146     if (U_FAILURE(status)) {
147         orderResult.amPmTimeOrder = "-1";
148         return orderResult;
149     }
150     std::string result;
151     resultStr.toUTF8String<std::string>(result);
152     std::regex pattrn("a[^ah]*h");
153     std::smatch match;
154     bool found = std::regex_search(result, match, pattrn);
155     std::string amPmTimeOrder = found ? amPmFirst : amPmLast;
156     orderResult = {result, "", amPmTimeOrder};
157     delete gen;
158     return orderResult;
159 }
160 
ModifyOrder(std::string & pattern)161 std::string DateTimeSequence::ModifyOrder(std::string& pattern)
162 {
163     int order[3] = { 0 }; // total 3 elements 'y', 'M'/'L', 'd'
164     int lengths[4] = { 0 }; // first elements is the currently found elememnts, thus 4 elements totally.
165     bool flag = true;
166     for (size_t i = 0; i < pattern.length(); ++i) {
167         char ch = pattern[i];
168         if (flag && std::isalpha(ch)) {
169             ProcessNormal(ch, order, 3, lengths, 4); // 3, 4 are lengths of these arrays
170         } else if (ch == '\'') {
171             flag = !flag;
172         }
173     }
174     std::unordered_map<char, int> pattern2index = {
175         { 'y', 1 },
176         { 'M', 2 },
177         { 'd', 3 },
178     };
179     std::string ret;
180     for (int i = 0; i < 3; ++i) { // 3 is the size of orders
181         auto it = pattern2index.find(order[i]);
182         if (it == pattern2index.end()) {
183             continue;
184         }
185         int index = it->second;
186         if ((lengths[index] > 0) && (lengths[index] <= 6)) { // 6 is the max length of a filed
187             ret.append(lengths[index], order[i]);
188         }
189         if (i < 2) { // 2 is the size of the order minus one
190             ret.append(1, '-');
191         }
192     }
193     return ret;
194 }
195 
ProcessNormal(char ch,int * order,size_t orderSize,int * lengths,size_t lengsSize)196 void DateTimeSequence::ProcessNormal(char ch, int* order, size_t orderSize, int* lengths, size_t lengsSize)
197 {
198     char adjust;
199     int index = -1;
200     if (ch == 'd') {
201         adjust = 'd';
202         index = 3; // 3 is the index of 'd'
203     } else if ((ch == 'L') || (ch == 'M')) {
204         adjust = 'M';
205         index = 2; // 2 is the index of 'M'
206     } else if (ch == 'y') {
207         adjust = 'y';
208         index = 1;
209     } else {
210         return;
211     }
212     if ((index < 0) || (index >= static_cast<int>(lengsSize))) {
213         return;
214     }
215     if (lengths[index] == 0) {
216         if (lengths[0] >= 3) { // 3 is the index of order
217             return;
218         }
219         order[lengths[0]] = static_cast<int>(adjust);
220         ++lengths[0];
221         lengths[index] = 1;
222     } else {
223         ++lengths[index];
224     }
225 }
226 
227 } // namespace OHOS::Ace