1 /*
2 * Copyright (c) 2021 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_module.h"
16 #if (FEATURE_DATE_FORMAT == 1)
17 #include <cstring>
18 #include "ace_log.h"
19 #include "locale_util.h"
20 #include "keys.h"
21 #include "key_parser.h"
22 #include "string_util.h"
23
24 namespace OHOS {
25 namespace ACELite {
26 using namespace I18N;
27 jerry_object_native_info_t DateTimeFormatModule::GC_CALLBACK = {.free_cb = DateTimeFormatModule::DeleteDateFormat};
28
DateTimeFormatModule()29 DateTimeFormatModule::DateTimeFormatModule()
30 : dateFormat_(nullptr),
31 info_(nullptr),
32 timePattern_(I18N::AvailableDateTimeFormatPattern::SHORT),
33 datePattern_(I18N::AvailableDateTimeFormatPattern::SHORT),
34 weekStyle_(StyleState::UNKNOWN),
35 monthStyle_(StyleState::UNKNOWN),
36 numArray_(nullptr),
37 isSetTime_(false),
38 isSetDate_(false)
39 {
40 if (memset_s(digitArray_, TIME_NUMBER_LEN, 0, TIME_NUMBER_LEN) != EOK) {
41 HILOG_ERROR(HILOG_MODULE_ACE, "init digit array failed");
42 }
43 }
44
Init(jerry_value_t intlHandle)45 void DateTimeFormatModule::Init(jerry_value_t intlHandle)
46 {
47 jerry_value_t constructor = jerry_create_external_function(CreateDateTimeFormat);
48 jerry_value_t format = jerry_create_external_function(Format);
49 jerry_value_t baseObj = jerry_create_object();
50 JerrySetNamedProperty(baseObj, "format", format);
51 JerrySetNamedProperty(constructor, "prototype", baseObj);
52 JerrySetNamedProperty(intlHandle, "DateTimeFormat", constructor);
53 ReleaseJerryValue(constructor, format, baseObj, VA_ARG_END_FLAG);
54 }
55
~DateTimeFormatModule()56 DateTimeFormatModule::~DateTimeFormatModule()
57 {
58 ACE_DELETE(dateFormat_);
59 ACE_DELETE(info_);
60 ReleaseNumArray();
61 }
62
ReleaseNumArray()63 void DateTimeFormatModule::ReleaseNumArray()
64 {
65 if (numArray_ != nullptr) {
66 for (int i = 0; i < MAX_NUM_LEN; i++) {
67 ACE_FREE(numArray_[i]);
68 }
69 ace_free(numArray_);
70 numArray_ = nullptr;
71 }
72 }
73
InitNumArray(LocaleInfo info)74 bool DateTimeFormatModule::InitNumArray(LocaleInfo info)
75 {
76 ReleaseNumArray();
77 int status = 0;
78 NumberFormat numFormat(info, status);
79 if (status == I18nStatus::IERROR) {
80 HILOG_ERROR(HILOG_MODULE_ACE, "init number format failed");
81 return false;
82 }
83 numArray_ = reinterpret_cast<char **>(ace_malloc(MAX_NUM_LEN * sizeof(char *)));
84 if (numArray_ == nullptr) {
85 HILOG_ERROR(HILOG_MODULE_ACE, "malloc number array failed");
86 return false;
87 }
88 // get the number value 0-9 in specified locale info
89 for (uint8_t i = 0; i < MAX_NUM_LEN; i++) {
90 int numStatus = 0;
91 std::string result = numFormat.Format(i, numStatus);
92 if ((numStatus == I18nStatus::IERROR) || (result.empty())) {
93 HILOG_ERROR(HILOG_MODULE_ACE, "init array %{public}d failed", i);
94 ReleaseNumArray();
95 return false;
96 }
97 numArray_[i] = StringUtil::Copy(result.c_str());
98 }
99 return true;
100 }
101
CreateDateTimeFormat(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t argsNum)102 jerry_value_t DateTimeFormatModule::CreateDateTimeFormat(const jerry_value_t func,
103 const jerry_value_t context,
104 const jerry_value_t args[],
105 const jerry_length_t argsNum)
106 {
107 if (!jerry_value_is_constructor(func)) {
108 return jerry_create_error(JERRY_ERROR_EVAL,
109 reinterpret_cast<const jerry_char_t *>("use new to create number format"));
110 }
111 DateTimeFormatModule *dateModel = new DateTimeFormatModule();
112 if (dateModel == nullptr) {
113 return jerry_create_error(JERRY_ERROR_EVAL,
114 reinterpret_cast<const jerry_char_t *>("create date format model failed"));
115 }
116 char *value = nullptr;
117 if (argsNum >= 1) {
118 value = MallocStringOf(args[0]);
119 }
120 dateModel->info_ = LocaleUtil::GetLocaleInfo(value);
121 ACE_FREE(value);
122 if (dateModel->info_ == nullptr) {
123 HILOG_ERROR(HILOG_MODULE_ACE, "create LocaleInfo failed");
124 delete dateModel;
125 dateModel = nullptr;
126 return jerry_create_error(JERRY_ERROR_COMMON, reinterpret_cast<const jerry_char_t *>("lack of memory"));
127 }
128 // set the default format pattern year(numeric)-month(numeric)-day(numeric)
129 dateModel->dateFormat_ = new DateTimeFormat(AvailableDateTimeFormatPattern::SHORT, *dateModel->info_);
130 if ((dateModel->dateFormat_ == nullptr) || (!dateModel->InitNumArray(*dateModel->info_))) {
131 delete dateModel;
132 dateModel = nullptr;
133 return jerry_create_error(JERRY_ERROR_EVAL,
134 reinterpret_cast<const jerry_char_t *>("create dateTimeFormat failed"));
135 }
136 if (argsNum > 1) {
137 // deal the year month day style
138 const char *dateRes = dateModel->SetDateStyle(args[1]);
139 // deal the hour minute second style
140 const char *timeRes = dateModel->SetTimeStyle(args[1]);
141 // if dateRes or timeRes is not nullptr, the date style or time style is invalid
142 if ((dateRes != nullptr) || (timeRes != nullptr)) {
143 delete dateModel;
144 dateModel = nullptr;
145 const char *result = (dateRes != nullptr) ? dateRes : timeRes;
146 return (result == nullptr)
147 ? jerry_create_null()
148 : jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>(result));
149 }
150 }
151 jerry_set_object_native_pointer(context, dateModel, &GC_CALLBACK);
152 return UNDEFINED;
153 }
154
ConvertLocalToGMT(time_t & time) const155 void DateTimeFormatModule::ConvertLocalToGMT(time_t &time) const
156 {
157 struct tm gmTime = {0};
158 struct tm local = {0};
159 gmtime_r(&time, &gmTime);
160 localtime_r(&time, &local);
161 time += mktime(&local) - mktime(&gmTime);
162 }
163
Format(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t argsNum)164 jerry_value_t DateTimeFormatModule::Format(const jerry_value_t func,
165 const jerry_value_t context,
166 const jerry_value_t args[],
167 const jerry_length_t argsNum)
168 {
169 if (!jerry_is_feature_enabled(JERRY_FEATURE_DATE)) {
170 return jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>("the date is not enabled"));
171 }
172 if (argsNum < 1) {
173 return jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>("date is invalid"));
174 }
175 DateTimeFormatModule *formatter = nullptr;
176 if (!(jerry_get_object_native_pointer(context, reinterpret_cast<void **>(&formatter), &GC_CALLBACK)) ||
177 (formatter == nullptr) || (formatter->dateFormat_ == nullptr)) {
178 HILOG_ERROR(HILOG_MODULE_ACE, "get format object failed");
179 return UNDEFINED;
180 }
181 const uint16_t msToSec = 1000;
182 time_t dateTime = static_cast<time_t>(formatter->GetTimeVal(args[0], "getTime") / msToSec);
183 formatter->ConvertLocalToGMT(dateTime);
184 if (formatter->isSetDate_ || formatter->isSetTime_) {
185 uint8_t maxSize = 128;
186 char *res = reinterpret_cast<char *>(ace_malloc(maxSize));
187 if (res == nullptr) {
188 return UNDEFINED;
189 }
190 res[0] = '\0';
191 uint8_t start = 0;
192 if (formatter->isSetDate_) {
193 formatter->FormatDate(dateTime, res, maxSize, start);
194 }
195 if (formatter->isSetTime_) {
196 formatter->FormatTime(dateTime, res, maxSize, start);
197 }
198 jerry_value_t resultProp = jerry_create_string(reinterpret_cast<jerry_char_t *>(res));
199 ace_free(res);
200 res = nullptr;
201 return resultProp;
202 }
203 // the style group is not support, format the lonely support style week or month
204 if (formatter->weekStyle_ != StyleState::UNKNOWN) {
205 int8_t weekIndex = static_cast<int8_t>(formatter->GetTimeVal(args[0], "getDay"));
206 DateTimeDataType type = (formatter->weekStyle_ == StyleState::LONG) ? FORMAT_WIDE : FORMAT_ABBR;
207 std::string weekName = formatter->dateFormat_->GetWeekName(weekIndex, type);
208 return jerry_create_string(reinterpret_cast<const jerry_char_t *>(weekName.c_str()));
209 } else if (formatter->monthStyle_ != StyleState::UNKNOWN) {
210 return formatter->GetMonthVal(args[0]);
211 }
212 // if the style is valid, the style pattern is not support, format the date style as default style
213 std::string result, timeZone;
214 I18nStatus status = I18nStatus::ISUCCESS;
215 formatter->dateFormat_->Format(dateTime, timeZone, result, status);
216 if (status == I18nStatus::IERROR) {
217 return jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>("format date failed"));
218 }
219 return jerry_create_string(reinterpret_cast<const jerry_char_t *>(result.c_str()));
220 }
221
GetMonthVal(jerry_value_t time) const222 jerry_value_t DateTimeFormatModule::GetMonthVal(jerry_value_t time) const
223 {
224 int month = static_cast<int>(GetTimeVal(time, "getMonth"));
225 // format the long style ans short month style
226 if ((monthStyle_ == StyleState::LONG) || (monthStyle_ == StyleState::SHORT)) {
227 DateTimeDataType type = (monthStyle_ == StyleState::LONG) ? FORMAT_WIDE : FORMAT_ABBR;
228 std::string monthName = dateFormat_->GetMonthName(month, type);
229 return jerry_create_string(reinterpret_cast<const jerry_char_t *>(monthName.c_str()));
230 }
231 const uint8_t monthIndex = 1;
232 const uint8_t maxMonthLen = 20;
233 uint8_t start = 0;
234 char *result = reinterpret_cast<char *>(ace_malloc(maxMonthLen));
235 if (result == nullptr) {
236 HILOG_ERROR(HILOG_MODULE_ACE, "malloc month str failed");
237 return jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>("memory is not enough"));
238 }
239 std::string date = dateFormat_->GetMonthName(month, DateTimeDataType::STANDALONE_ABBR);
240 // format the number month to 2-digit or not through the month digit flag
241 jerry_value_t resultProp = UNDEFINED;
242 if (FormatDigit(date.c_str(), result, maxMonthLen, start, digitArray_[monthIndex]) > 0) {
243 resultProp = jerry_create_string(reinterpret_cast<jerry_char_t *>(result));
244 }
245 ace_free(result);
246 result = nullptr;
247 return resultProp;
248 }
249
GetNumInDate(const char * date) const250 uint8_t DateTimeFormatModule::GetNumInDate(const char *date) const
251 {
252 if (date == nullptr) {
253 return 0;
254 }
255 uint8_t len = 0;
256 int16_t dateLen = strlen(date);
257 bool check = true;
258 for (int16_t index = 0; index < dateLen; index++) {
259 int16_t numEnd = GetNumberEnd(date, index);
260 if (numEnd >= 0) {
261 if (check) {
262 len++;
263 check = false;
264 }
265 index = numEnd; // check the number from the next character
266 } else {
267 check = true;
268 }
269 }
270 return len;
271 }
272
FormatDate(time_t time,char * res,const uint8_t resSize,uint8_t & start)273 void DateTimeFormatModule::FormatDate(time_t time, char *res, const uint8_t resSize, uint8_t &start)
274 {
275 if (dateFormat_ == nullptr) {
276 HILOG_ERROR(HILOG_MODULE_ACE, "dateFormat is nullptr");
277 return;
278 }
279 std::string result, timeZone, check;
280 I18nStatus status = I18nStatus::ISUCCESS;
281 dateFormat_->ApplyPattern(datePattern_);
282 dateFormat_->Format(time, timeZone, result, status);
283 if (status == I18nStatus::IERROR) {
284 return;
285 }
286 bool isMonthFirst = false;
287 // if month is numeric, format the date to full year-month-day, if the first digit is number, the format string
288 // is day-month-year or year-month-day, else month-day-year
289 const char *dateStr = result.c_str();
290 const uint8_t numMaxInDate = 3;
291 uint8_t numInDate = GetNumInDate(dateStr);
292 if (numInDate == numMaxInDate) {
293 dateFormat_->ApplyPattern(AvailableDateTimeFormatPattern::YEAR_WIDE_MONTH_DAY);
294 dateFormat_->Format(time, timeZone, check, status);
295 if (status == I18nStatus::IERROR) {
296 return;
297 }
298 isMonthFirst = (GetNumberEnd(check.c_str(), 0) < 0);
299 }
300 const uint8_t dayStyleIndex = 2; // the day number style index
301 const uint8_t monthStyleIndex = 1; // the month style index
302 uint8_t firstFormatIndex = dayStyleIndex;
303 int16_t formatIndex = 0;
304 if (numInDate == numMaxInDate) {
305 uint8_t secondFormatIndex = monthStyleIndex;
306 if (isMonthFirst) {
307 // set the format order month-day-year
308 firstFormatIndex = monthStyleIndex;
309 secondFormatIndex = dayStyleIndex;
310 }
311 formatIndex = FormatDigit(dateStr, res, resSize, start, digitArray_[firstFormatIndex]);
312 if (formatIndex < 0) {
313 HILOG_ERROR(HILOG_MODULE_ACE, "format the first number in date str failed");
314 return;
315 }
316 formatIndex =
317 FormatDigit(dateStr + formatIndex, res, resSize, start, digitArray_[secondFormatIndex]) + formatIndex;
318 } else {
319 // format the day digit or year digit
320 formatIndex = FormatDigit(dateStr, res, resSize, start, digitArray_[dayStyleIndex]);
321 }
322 if (formatIndex < 0) {
323 HILOG_ERROR(HILOG_MODULE_ACE, "format date string failed");
324 return;
325 }
326 // format the year
327 if (FormatDigit(dateStr + formatIndex, res, resSize, start, digitArray_[firstFormatIndex]) < 0) {
328 res[0] = '\0';
329 }
330 }
331
FormatTime(time_t time,char * res,const uint8_t resSize,uint8_t & start)332 void DateTimeFormatModule::FormatTime(time_t time, char *res, const uint8_t resSize, uint8_t &start)
333 {
334 if (res == nullptr) {
335 return;
336 }
337 if (start != 0) {
338 res[start] = ' ';
339 start++;
340 }
341 std::string result, timeZone;
342 I18nStatus status = I18nStatus::ISUCCESS;
343 dateFormat_->ApplyPattern(timePattern_);
344 dateFormat_->Format(time, timeZone, result, status);
345 if (status == I18nStatus::IERROR) {
346 return;
347 }
348 const uint8_t hourIndex = 3;
349 const uint8_t minuteIndex = 4;
350 const uint8_t secondIndex = 5;
351 const char *timeStr = result.c_str();
352 int16_t curIndex = 0;
353 curIndex = FormatDigit(timeStr, res, resSize, start, digitArray_[hourIndex]);
354 if (curIndex < 0) {
355 HILOG_ERROR(HILOG_MODULE_ACE, "format hour style failed");
356 return;
357 }
358 curIndex = FormatDigit(timeStr + curIndex, res, resSize, start, digitArray_[minuteIndex]) + curIndex;
359 if (curIndex < 0) {
360 HILOG_ERROR(HILOG_MODULE_ACE, "format minute style failed");
361 return;
362 }
363 if (FormatDigit(timeStr + curIndex, res, resSize, start, digitArray_[secondIndex]) < 0) {
364 res[0] = '\0';
365 }
366 }
367
FormatDigit(const char * time,char * res,const uint8_t resSize,uint8_t & start,bool is2Digit) const368 int16_t DateTimeFormatModule::FormatDigit(const char *time,
369 char *res,
370 const uint8_t resSize,
371 uint8_t &start,
372 bool is2Digit) const
373 {
374 if ((time == nullptr) || (strlen(time) == 0)) {
375 return 0;
376 }
377 int16_t index = GetNum(time);
378 if (index >= 0) {
379 if (strncpy_s(res + start, resSize - start + 1, time, index + 1) != 0) {
380 HILOG_ERROR(HILOG_MODULE_ACE, "copy string before number failed");
381 return -1;
382 }
383 start = start + index + 1;
384 }
385 index = (index < 0) ? 0 : (index + 1);
386 int16_t num1 = GetNumberEnd(time, index);
387 if (num1 < 0) {
388 return -1;
389 }
390 int16_t num2 = GetNumberEnd(time, num1 + 1);
391 int16_t numEnd = num1;
392 if (num2 < 0) {
393 if (is2Digit && (numArray_[0] != nullptr)) {
394 uint8_t zeroLen = strlen(numArray_[0]);
395 if (strncpy_s(res + start, resSize - start + 1, numArray_[0], zeroLen)) {
396 HILOG_ERROR(HILOG_MODULE_ACE, "add zero failed");
397 return -1;
398 }
399 start = start + zeroLen;
400 }
401 } else {
402 int num3 = GetNumberEnd(time, num2 + 1);
403 // format the 4 digit year
404 if (num3 >= 0) {
405 // the year style is 2-digit
406 if (digitArray_[0]) {
407 index = num2 + 1;
408 }
409 numEnd = GetNumberEnd(time, num3 + 1);
410 } else {
411 numEnd = num2;
412 }
413 }
414 numEnd = GetNum(time + numEnd + 1) + numEnd + 1;
415 if (numEnd >= index) {
416 if (strncpy_s(res + start, resSize - start + 1, time + index, numEnd - index + 1) != 0) {
417 HILOG_ERROR(HILOG_MODULE_ACE, "copy string failed");
418 return -1;
419 }
420 start = start + numEnd - index + 1;
421 }
422 res[start] = '\0';
423 return numEnd + 1;
424 }
425
GetNum(const char * format) const426 int16_t DateTimeFormatModule::GetNum(const char *format) const
427 {
428 uint8_t len = strlen(format);
429 int16_t res = -1;
430 for (uint8_t index = 0; index < len; index++) {
431 int16_t numIndex = GetNumberEnd(format, index);
432 if (numIndex >= 0) {
433 break;
434 } else {
435 res = index;
436 }
437 }
438 return res;
439 }
440
GetNumberEnd(const char * compare,uint8_t start) const441 int16_t DateTimeFormatModule::GetNumberEnd(const char *compare, uint8_t start) const
442 {
443 for (uint8_t index = 0; index < MAX_NUM_LEN; index++) {
444 const char *str = compare + start;
445 if (StringUtil::StartsWith(str, numArray_[index])) {
446 return start + strlen(numArray_[index]) - 1;
447 }
448 }
449 return -1;
450 }
451
GetTimeVal(jerry_value_t time,const char * funcName) const452 double DateTimeFormatModule::GetTimeVal(jerry_value_t time, const char *funcName) const
453 {
454 jerry_value_t funcProp = jerryx_get_property_str(time, funcName);
455 if (IS_UNDEFINED(funcProp)) {
456 return 0;
457 }
458 jerry_value_t result = CallJSFunction(funcProp, time, nullptr, 0);
459 double timeVal = jerry_get_number_value(result);
460 ReleaseJerryValue(funcProp, result, VA_ARG_END_FLAG);
461 return timeVal;
462 }
463
DeleteDateFormat(void * pointer)464 void DateTimeFormatModule::DeleteDateFormat(void *pointer)
465 {
466 DateTimeFormatModule *formatter = reinterpret_cast<DateTimeFormatModule *>(pointer);
467 if (formatter != nullptr) {
468 delete formatter;
469 formatter = nullptr;
470 }
471 }
472
SetDateStyle(jerry_value_t style)473 const char *DateTimeFormatModule::SetDateStyle(jerry_value_t style)
474 {
475 weekStyle_ = GetWeekdayStyle(style);
476 if (weekStyle_ == StyleState::ERROR) {
477 return "the weekday style value is out of range";
478 }
479 const uint8_t yearIndex = 0;
480 StyleState yearStyle = GetStyle(style, "year", yearIndex);
481 if (yearStyle == StyleState::ERROR) {
482 return "the year style value is out of range";
483 }
484 monthStyle_ = GetMonthStyle(style);
485 if (monthStyle_ == StyleState::ERROR) {
486 return "the month style value is out of range";
487 }
488 const uint8_t dayIndex = 2;
489 StyleState dayStyle = GetStyle(style, "day", dayIndex);
490 if (dayStyle == StyleState::ERROR) {
491 return "the day style value is out of range";
492 }
493 isSetDate_ = SetDatePattern(weekStyle_, yearStyle, monthStyle_, dayStyle);
494 return nullptr;
495 }
496
GetWeekdayStyle(jerry_value_t style) const497 DateTimeFormatModule::StyleState DateTimeFormatModule::GetWeekdayStyle(jerry_value_t style) const
498 {
499 if (!jerryx_has_property_str(style, "weekday")) {
500 return StyleState::UNKNOWN;
501 }
502 StyleState weekdayStyle = StyleState::UNKNOWN;
503 jerry_value_t weekProp = jerryx_get_property_str(style, "weekday");
504 uint16_t len = 0;
505 char *weekStyle = MallocStringOf(weekProp, &len);
506 jerry_release_value(weekProp);
507 uint16_t weekId = KeyParser::ParseKeyId(weekStyle, len);
508 ACE_FREE(weekStyle);
509 if (!KeyParser::IsKeyValid(weekId)) {
510 return StyleState::ERROR;
511 }
512 switch (weekId) {
513 case K_SHORT: {
514 weekdayStyle = StyleState::SHORT;
515 break;
516 }
517 case K_LONG: {
518 weekdayStyle = StyleState::LONG;
519 break;
520 }
521 default: {
522 weekdayStyle = StyleState::ERROR;
523 break;
524 }
525 }
526 return weekdayStyle;
527 }
528
GetMonthStyle(jerry_value_t style)529 DateTimeFormatModule::StyleState DateTimeFormatModule::GetMonthStyle(jerry_value_t style)
530 {
531 if (!jerryx_has_property_str(style, "month")) {
532 return StyleState::UNKNOWN;
533 }
534 jerry_value_t monthProp = jerryx_get_property_str(style, "month");
535 uint16_t len = 0;
536 char *monthStyle = MallocStringOf(monthProp, &len);
537 jerry_release_value(monthProp);
538 uint16_t monthId = KeyParser::ParseKeyId(monthStyle, len);
539 ACE_FREE(monthStyle);
540 if (!KeyParser::IsKeyValid(monthId)) {
541 return StyleState::ERROR;
542 }
543 StyleState monthStyleState = StyleState::UNKNOWN;
544 switch (monthId) {
545 case K_LONG: {
546 monthStyleState = StyleState::LONG;
547 break;
548 }
549 case K_SHORT: {
550 monthStyleState = StyleState::SHORT;
551 break;
552 }
553 case K_NUMERIC: {
554 monthStyleState = StyleState::NUMERIC;
555 break;
556 }
557 case K_DIGIT2: {
558 const uint8_t monthIndex = 1;
559 digitArray_[monthIndex] = true;
560 monthStyleState = StyleState::NUMERIC;
561 break;
562 }
563 default: {
564 monthStyleState = StyleState::ERROR;
565 break;
566 }
567 }
568 return monthStyleState;
569 }
570
GetStyle(jerry_value_t style,const char * attrName,const uint8_t index)571 DateTimeFormatModule::StyleState DateTimeFormatModule::GetStyle(jerry_value_t style,
572 const char *attrName,
573 const uint8_t index)
574 {
575 if (!jerryx_has_property_str(style, attrName)) {
576 return StyleState::UNKNOWN;
577 }
578 jerry_value_t attrProp = jerryx_get_property_str(style, attrName);
579 uint16_t len = 0;
580 char *attrVal = MallocStringOf(attrProp, &len);
581 jerry_release_value(attrProp);
582 uint16_t attrId = KeyParser::ParseKeyId(attrVal, len);
583 ACE_FREE(attrVal);
584 if (!KeyParser::IsKeyValid(attrId)) {
585 return StyleState::ERROR;
586 }
587 StyleState styleState = StyleState::UNKNOWN;
588 switch (attrId) {
589 case K_NUMERIC: {
590 styleState = StyleState::NUMERIC;
591 break;
592 }
593 case K_DIGIT2: {
594 digitArray_[index] = true;
595 styleState = StyleState::NUMERIC;
596 break;
597 }
598 default: {
599 styleState = StyleState::ERROR;
600 break;
601 }
602 }
603 return styleState;
604 }
605
SetTimeStyle(jerry_value_t style)606 const char *DateTimeFormatModule::SetTimeStyle(jerry_value_t style)
607 {
608 const uint8_t hourIndex = 3;
609 StyleState hourStyle = GetStyle(style, "hour", hourIndex);
610 if (hourStyle == StyleState::ERROR) {
611 return "the hour style value is out of range";
612 }
613 const uint8_t minuteIndex = 4;
614 StyleState minuteStyle = GetStyle(style, "minute", minuteIndex);
615 if (minuteStyle == StyleState::ERROR) {
616 return "the minute style value is out of range";
617 }
618 const uint8_t secondIndex = 5;
619 StyleState secondStyle = GetStyle(style, "second", secondIndex);
620 if (secondStyle == StyleState::ERROR) {
621 return "the second style value is out of range";
622 }
623 // the hour12 style is invalid when hour style is not set
624 if (hourStyle != StyleState::UNKNOWN) {
625 if (jerryx_has_property_str(style, "hour12")) {
626 jerry_value_t hour12Style = jerryx_get_property_str(style, "hour12");
627 bool isHour12 = BoolOf(hour12Style);
628 jerry_release_value(hour12Style);
629 hourStyle = isHour12 ? StyleState::HOUR12 : StyleState::HOUR24;
630 } else {
631 hourStyle = StyleState::HOUR;
632 }
633 }
634 // find the most suitable mode for hour minute second style
635 isSetTime_ = GetTimePattern(hourStyle, minuteStyle, secondStyle);
636 if ((!isSetTime_) && (weekStyle_ == StyleState::UNKNOWN) && (monthStyle_ == StyleState::UNKNOWN)) {
637 isSetTime_ = true;
638 timePattern_ = AvailableDateTimeFormatPattern::SHORT;
639 }
640 return nullptr;
641 }
642
SetMonthPattern(StyleState monthStyle,AvailableDateTimeFormatPattern widePattern,AvailableDateTimeFormatPattern shortPattern,AvailableDateTimeFormatPattern numberPattern)643 bool DateTimeFormatModule::SetMonthPattern(StyleState monthStyle,
644 AvailableDateTimeFormatPattern widePattern,
645 AvailableDateTimeFormatPattern shortPattern,
646 AvailableDateTimeFormatPattern numberPattern)
647 {
648 bool result = true;
649 switch (monthStyle) {
650 case StyleState::LONG: {
651 datePattern_ = widePattern;
652 break;
653 }
654 case StyleState::SHORT: {
655 datePattern_ = shortPattern;
656 break;
657 }
658 case StyleState::NUMERIC: {
659 datePattern_ = numberPattern;
660 break;
661 }
662 default: {
663 result = false;
664 break;
665 }
666 }
667 return result;
668 }
669
SetDatePattern(StyleState weekdayStyle,StyleState yearStyle,StyleState monthStyle,StyleState dayStyle)670 bool DateTimeFormatModule::SetDatePattern(StyleState weekdayStyle,
671 StyleState yearStyle,
672 StyleState monthStyle,
673 StyleState dayStyle)
674 {
675 // the pattern support is (weekday)-year-month-day
676 if ((yearStyle == StyleState::UNKNOWN) || (dayStyle == StyleState::UNKNOWN) ||
677 (monthStyle == StyleState::UNKNOWN)) {
678 return false;
679 }
680 bool result = true;
681 switch (weekdayStyle) {
682 case StyleState::LONG: {
683 result = SetMonthPattern(monthStyle, AvailableDateTimeFormatPattern::FULL,
684 AvailableDateTimeFormatPattern::YEAR_ABBR_MONTH_WIDE_WEEKDAY_DAY,
685 AvailableDateTimeFormatPattern::YEAR_SHORT_MONTH_WIDE_WEEKDAY_DAY);
686 break;
687 }
688 case StyleState::SHORT: {
689 result = SetMonthPattern(monthStyle, AvailableDateTimeFormatPattern::YEAR_WIDE_MONTH_ABBR_WEEKDAY_DAY,
690 AvailableDateTimeFormatPattern::YEAR_ABBR_MONTH_ABBR_WEEKDAY_DAY,
691 AvailableDateTimeFormatPattern::YEAR_SHORT_MONTH_ABBR_WEEKDAY_DAY);
692 break;
693 }
694 default: {
695 result = SetMonthPattern(monthStyle, AvailableDateTimeFormatPattern::YEAR_WIDE_MONTH_DAY,
696 AvailableDateTimeFormatPattern::MEDIUM, AvailableDateTimeFormatPattern::SHORT);
697 break;
698 }
699 }
700 return result;
701 }
702
GetTimePattern(StyleState hourStyle,StyleState minuteStyle,StyleState secondStyle)703 bool DateTimeFormatModule::GetTimePattern(StyleState hourStyle, StyleState minuteStyle, StyleState secondStyle)
704 {
705 // the support pattern is hour-minute-(second)
706 if ((hourStyle == StyleState::UNKNOWN) || (minuteStyle == StyleState::UNKNOWN)) {
707 return false;
708 }
709 bool result = true;
710 switch (hourStyle) {
711 case StyleState::HOUR12: {
712 timePattern_ = (secondStyle == StyleState::UNKNOWN) ? AvailableDateTimeFormatPattern::HOUR12_MINUTE
713 : AvailableDateTimeFormatPattern::HOUR12_MINUTE_SECOND;
714 break;
715 }
716 case StyleState::HOUR24: {
717 timePattern_ = (secondStyle == StyleState::UNKNOWN) ? AvailableDateTimeFormatPattern::HOUR24_MINUTE
718 : AvailableDateTimeFormatPattern::HOUR24_MINUTE_SECOND;
719 break;
720 }
721 case StyleState::HOUR: {
722 timePattern_ =
723 (secondStyle == StyleState::UNKNOWN) ? AvailableDateTimeFormatPattern::HOUR_MINUTE : HOUR_MINUTE_SECOND;
724 break;
725 }
726 default: {
727 result = false;
728 break;
729 }
730 }
731 return result;
732 }
733 } // namespace ACELite
734 } // namespace OHOS
735 #endif
736