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