• 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 #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