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 "i18n_calendar.h"
16
17 #include "buddhcal.h"
18 #include "chnsecal.h"
19 #include "coptccal.h"
20 #include "ethpccal.h"
21 #include "hebrwcal.h"
22 #include "indiancal.h"
23 #include "islamcal.h"
24 #include "japancal.h"
25 #include "locale_config.h"
26 #include "unicode/locdspnm.h"
27 #include "persncal.h"
28 #include "string"
29 #include "ureslocs.h"
30 #include "ulocimp.h"
31 #include "unicode/umachine.h"
32 #include "unicode/gregocal.h"
33 #include "unicode/timezone.h"
34 #include "unicode/unistr.h"
35 #include "unicode/urename.h"
36 #include "ustr_imp.h"
37 #include "unicode/ustring.h"
38 #include "utils.h"
39
40 namespace OHOS {
41 namespace Global {
42 namespace I18n {
43 static std::unordered_map<WeekDay, UCalendarDaysOfWeek> WEEK_DAY_TO_ICU {
44 { WeekDay::MON, UCalendarDaysOfWeek::UCAL_MONDAY },
45 { WeekDay::TUE, UCalendarDaysOfWeek::UCAL_TUESDAY },
46 { WeekDay::WED, UCalendarDaysOfWeek::UCAL_WEDNESDAY },
47 { WeekDay::THU, UCalendarDaysOfWeek::UCAL_THURSDAY },
48 { WeekDay::FRI, UCalendarDaysOfWeek::UCAL_FRIDAY },
49 { WeekDay::SAT, UCalendarDaysOfWeek::UCAL_SATURDAY },
50 { WeekDay::SUN, UCalendarDaysOfWeek::UCAL_SUNDAY }
51 };
52
53 static std::unordered_map<std::string, UCalendarDaysOfWeek> WEEK_DAY_STR_TO_ICU {
54 { "mon", UCalendarDaysOfWeek::UCAL_MONDAY },
55 { "tue", UCalendarDaysOfWeek::UCAL_TUESDAY },
56 { "wed", UCalendarDaysOfWeek::UCAL_WEDNESDAY },
57 { "thu", UCalendarDaysOfWeek::UCAL_THURSDAY },
58 { "fri", UCalendarDaysOfWeek::UCAL_FRIDAY },
59 { "sat", UCalendarDaysOfWeek::UCAL_SATURDAY },
60 { "sun", UCalendarDaysOfWeek::UCAL_SUNDAY }
61 };
62
I18nCalendar(std::string localeTag)63 I18nCalendar::I18nCalendar(std::string localeTag)
64 {
65 UErrorCode status = U_ZERO_ERROR;
66 icu::Locale tempLocale = icu::Locale::forLanguageTag(localeTag, status);
67 if (U_FAILURE(status)) {
68 calendar_ = new icu::GregorianCalendar(status);
69 if (!U_SUCCESS(status)) {
70 if (calendar_ != nullptr) {
71 delete calendar_;
72 }
73 calendar_ = nullptr;
74 }
75 return;
76 }
77 calendar_ = icu::Calendar::createInstance(tempLocale, status);
78 if (U_FAILURE(status)) {
79 if (calendar_ != nullptr) {
80 delete calendar_;
81 }
82 calendar_ = nullptr;
83 }
84 InitFirstDayOfWeek(localeTag);
85 }
86
I18nCalendar(std::string localeTag,CalendarType type)87 I18nCalendar::I18nCalendar(std::string localeTag, CalendarType type)
88 {
89 UErrorCode status = U_ZERO_ERROR;
90 icu::Locale tempLocale = icu::Locale::forLanguageTag(localeTag, status);
91 if (U_FAILURE(status)) {
92 calendar_ = new icu::GregorianCalendar(status);
93 if (!U_SUCCESS(status)) {
94 if (calendar_ != nullptr) {
95 delete calendar_;
96 }
97 calendar_ = nullptr;
98 }
99 return;
100 }
101 InitCalendar(tempLocale, type);
102 InitFirstDayOfWeek(localeTag);
103 }
104
InitCalendar(const icu::Locale & locale,CalendarType type)105 void I18nCalendar::InitCalendar(const icu::Locale &locale, CalendarType type)
106 {
107 UErrorCode status = U_ZERO_ERROR;
108 switch (type) {
109 case BUDDHIST: {
110 calendar_ = new icu::BuddhistCalendar(locale, status);
111 break;
112 }
113 case CHINESE: {
114 calendar_ = new icu::ChineseCalendar(locale, status);
115 break;
116 }
117 case COPTIC: {
118 calendar_ = new icu::CopticCalendar(locale, status);
119 break;
120 }
121 case ETHIOPIC: {
122 calendar_ = new icu::EthiopicCalendar(locale, status);
123 break;
124 }
125 case HEBREW: {
126 calendar_ = new icu::HebrewCalendar(locale, status);
127 break;
128 }
129 case INDIAN: {
130 calendar_ = new icu::IndianCalendar(locale, status);
131 break;
132 }
133 case ISLAMIC_CIVIL: {
134 calendar_ = new icu::IslamicCalendar(locale, status, icu::IslamicCalendar::ECalculationType::CIVIL);
135 break;
136 }
137 default: {
138 InitCalendar2(locale, type, status);
139 }
140 }
141 if (!U_SUCCESS(status)) {
142 if (calendar_ != nullptr) {
143 delete calendar_;
144 }
145 calendar_ = nullptr;
146 }
147 }
148
InitCalendar2(const icu::Locale & locale,CalendarType type,UErrorCode & status)149 void I18nCalendar::InitCalendar2(const icu::Locale &locale, CalendarType type, UErrorCode &status)
150 {
151 switch (type) {
152 case ISLAMIC_TBLA: {
153 calendar_ = new icu::IslamicCalendar(locale, status, icu::IslamicCalendar::ECalculationType::TBLA);
154 break;
155 }
156 case ISLAMIC_UMALQURA: {
157 calendar_ = new icu::IslamicCalendar(locale, status, icu::IslamicCalendar::ECalculationType::UMALQURA);
158 break;
159 }
160 case JAPANESE: {
161 calendar_ = new icu::JapaneseCalendar(locale, status);
162 break;
163 }
164 case PERSIAN: {
165 calendar_ = new icu::PersianCalendar(locale, status);
166 break;
167 }
168 case GREGORY: {
169 calendar_ = new icu::GregorianCalendar(locale, status);
170 break;
171 }
172 default: {
173 calendar_ = icu::Calendar::createInstance(locale, status);
174 }
175 }
176 }
177
~I18nCalendar()178 I18nCalendar::~I18nCalendar()
179 {
180 if (calendar_ != nullptr) {
181 delete calendar_;
182 }
183 }
184
SetTime(double value)185 void I18nCalendar::SetTime(double value)
186 {
187 icu::Calendar* icuCalendar = GetIcuCalendar();
188 if (icuCalendar != nullptr) {
189 UErrorCode status = U_ZERO_ERROR;
190 icuCalendar->setTime(value, status);
191 return;
192 }
193 }
194
SetTimeZone(std::string id)195 void I18nCalendar::SetTimeZone(std::string id)
196 {
197 icu::UnicodeString zone = icu::UnicodeString::fromUTF8(id);
198 icu::TimeZone *timezone = icu::TimeZone::createTimeZone(zone);
199 if (timezone != nullptr) {
200 icu::Calendar* icuCalendar = GetIcuCalendar();
201 if (icuCalendar != nullptr) {
202 icuCalendar->setTimeZone(*timezone);
203 }
204 delete(timezone);
205 }
206 }
207
GetTimeZone(void)208 std::string I18nCalendar::GetTimeZone(void)
209 {
210 std::string ret;
211 icu::Calendar* icuCalendar = GetIcuCalendar();
212 if (icuCalendar) {
213 icu::UnicodeString unistr;
214 icuCalendar->getTimeZone().getID(unistr);
215 unistr.toUTF8String<std::string>(ret);
216 }
217 return ret;
218 }
219
Set(int32_t year,int32_t month,int32_t date)220 void I18nCalendar::Set(int32_t year, int32_t month, int32_t date)
221 {
222 icu::Calendar* icuCalendar = GetIcuCalendar();
223 if (icuCalendar != nullptr) {
224 icuCalendar->set(year, month, date);
225 return;
226 }
227 }
228
Set(UCalendarDateFields field,int32_t value)229 void I18nCalendar::Set(UCalendarDateFields field, int32_t value)
230 {
231 icu::Calendar* icuCalendar = GetIcuCalendar();
232 if (icuCalendar != nullptr) {
233 icuCalendar->set(field, value);
234 return;
235 }
236 }
237
Get(UCalendarDateFields field) const238 int32_t I18nCalendar::Get(UCalendarDateFields field) const
239 {
240 icu::Calendar* icuCalendar = GetIcuCalendar();
241 if (icuCalendar != nullptr) {
242 UErrorCode status = U_ZERO_ERROR;
243 return icuCalendar->get(field, status);
244 }
245 return 0;
246 }
247
Add(UCalendarDateFields field,int32_t amount)248 void I18nCalendar::Add(UCalendarDateFields field, int32_t amount)
249 {
250 icu::Calendar* icuCalendar = GetIcuCalendar();
251 if (icuCalendar != nullptr) {
252 UErrorCode status = U_ZERO_ERROR;
253 icuCalendar->add(field, amount, status);
254 }
255 }
256
SetMinimalDaysInFirstWeek(int32_t value)257 void I18nCalendar::SetMinimalDaysInFirstWeek(int32_t value)
258 {
259 icu::Calendar* icuCalendar = GetIcuCalendar();
260 if (icuCalendar != nullptr) {
261 icuCalendar->setMinimalDaysInFirstWeek((uint8_t)value);
262 return;
263 }
264 }
265
SetFirstDayOfWeek(int32_t value)266 void I18nCalendar::SetFirstDayOfWeek(int32_t value)
267 {
268 if (value < UCalendarDaysOfWeek::UCAL_SUNDAY || value > UCAL_SATURDAY) {
269 return;
270 }
271 icu::Calendar* icuCalendar = GetIcuCalendar();
272 if (icuCalendar != nullptr) {
273 icuCalendar->setFirstDayOfWeek(UCalendarDaysOfWeek(value));
274 return;
275 }
276 }
277
GetTimeInMillis(void)278 UDate I18nCalendar::GetTimeInMillis(void)
279 {
280 icu::Calendar* icuCalendar = GetIcuCalendar();
281 if (icuCalendar != nullptr) {
282 UErrorCode status = U_ZERO_ERROR;
283 return icuCalendar->getTime(status);
284 }
285 return 0;
286 }
287
GetMinimalDaysInFirstWeek(void)288 int32_t I18nCalendar::GetMinimalDaysInFirstWeek(void)
289 {
290 icu::Calendar* icuCalendar = GetIcuCalendar();
291 if (icuCalendar != nullptr) {
292 return icuCalendar->getMinimalDaysInFirstWeek();
293 }
294 return 1;
295 }
296
GetFirstDayOfWeek(void)297 int32_t I18nCalendar::GetFirstDayOfWeek(void)
298 {
299 icu::Calendar* icuCalendar = GetIcuCalendar();
300 if (icuCalendar != nullptr) {
301 return static_cast<int>(icuCalendar->getFirstDayOfWeek());
302 }
303 return UCAL_SUNDAY;
304 }
305
IsWeekend(int64_t date,UErrorCode & status)306 bool I18nCalendar::IsWeekend(int64_t date, UErrorCode &status)
307 {
308 icu::Calendar* icuCalendar = GetIcuCalendar();
309 if (icuCalendar != nullptr) {
310 return icuCalendar->isWeekend(date, status);
311 }
312 return false;
313 }
314
IsWeekend(void)315 bool I18nCalendar::IsWeekend(void)
316 {
317 icu::Calendar* icuCalendar = GetIcuCalendar();
318 if (icuCalendar != nullptr) {
319 return icuCalendar->isWeekend();
320 }
321 return false;
322 }
323
GetDisplayName(std::string & displayLocaleTag)324 std::string I18nCalendar::GetDisplayName(std::string &displayLocaleTag)
325 {
326 icu::Calendar* icuCalendar = GetIcuCalendar();
327 if (icuCalendar == nullptr) {
328 return PseudoLocalizationProcessor("");
329 }
330 const char *type = icuCalendar->getType();
331 if (type == nullptr) {
332 return PseudoLocalizationProcessor("");
333 }
334 UErrorCode status = U_ZERO_ERROR;
335 icu::Locale displayLocale = icu::Locale::forLanguageTag(displayLocaleTag, status);
336 if (U_FAILURE(status)) {
337 return PseudoLocalizationProcessor("");
338 }
339 icu::LocaleDisplayNames *dspName = icu::LocaleDisplayNames::createInstance(displayLocale);
340 icu::UnicodeString unistr;
341 if (dspName != nullptr) {
342 dspName->keyValueDisplayName("calendar", type, unistr);
343 delete dspName;
344 }
345 std::string ret;
346 unistr.toUTF8String<std::string>(ret);
347 return PseudoLocalizationProcessor(ret);
348 }
349
CompareDays(UDate date)350 int32_t I18nCalendar::CompareDays(UDate date)
351 {
352 icu::Calendar* icuCalendar = GetIcuCalendar();
353 if (icuCalendar != nullptr) {
354 UErrorCode status = U_ZERO_ERROR;
355 UDate nowMs = icuCalendar->getTime(status);
356 double ret = (date - nowMs) / (24 * 60 * 60 * 1000); // Convert 24 hours into milliseconds
357 return ret > 0 ? std::ceil(ret) : std::floor(ret);
358 }
359 return 0;
360 }
361
GetIcuCalendar() const362 icu::Calendar* I18nCalendar::GetIcuCalendar() const
363 {
364 return this->calendar_;
365 }
366
InitFirstDayOfWeek(const std::string & localeTag)367 void I18nCalendar::InitFirstDayOfWeek(const std::string& localeTag)
368 {
369 icu::Calendar* icuCalendar = GetIcuCalendar();
370 if (icuCalendar == nullptr) {
371 return;
372 }
373 std::string param = LocaleConfig::QueryExtParam(localeTag, "fw", "-u-");
374 if (param.empty()) {
375 return;
376 }
377 if (WEEK_DAY_STR_TO_ICU.find(param) != WEEK_DAY_STR_TO_ICU.end()) {
378 icuCalendar->setFirstDayOfWeek(WEEK_DAY_STR_TO_ICU[param]);
379 }
380 }
381 } // namespace I18n
382 } // namespace Global
383 } // namespace OHOS