14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/js_date_time_format.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/checkpoint/thread_state_transition.h" 194514f5e3Sopenharmony_ci#include "ecmascript/intl/locale_helper.h" 204514f5e3Sopenharmony_ci#include "ecmascript/global_env.h" 214514f5e3Sopenharmony_ci#include "ecmascript/js_date.h" 224514f5e3Sopenharmony_ci#include "ecmascript/js_function.h" 234514f5e3Sopenharmony_ci#include "ecmascript/js_intl.h" 244514f5e3Sopenharmony_ci#include "ecmascript/object_factory-inl.h" 254514f5e3Sopenharmony_ci 264514f5e3Sopenharmony_cinamespace panda::ecmascript { 274514f5e3Sopenharmony_cistruct CommonDateFormatPart { 284514f5e3Sopenharmony_ci int32_t fField = 0; 294514f5e3Sopenharmony_ci int32_t fBeginIndex = 0; // NOLINT(misc-non-private-member-variables-in-classes) 304514f5e3Sopenharmony_ci int32_t fEndIndex = 0; // NOLINT(misc-non-private-member-variables-in-classes) 314514f5e3Sopenharmony_ci int32_t index = 0; // NOLINT(misc-non-private-member-variables-in-classes) 324514f5e3Sopenharmony_ci bool isPreExist = false; 334514f5e3Sopenharmony_ci 344514f5e3Sopenharmony_ci CommonDateFormatPart() = default; 354514f5e3Sopenharmony_ci CommonDateFormatPart(int32_t fField, int32_t fBeginIndex, int32_t fEndIndex, int32_t index, bool isPreExist) 364514f5e3Sopenharmony_ci : fField(fField), fBeginIndex(fBeginIndex), fEndIndex(fEndIndex), index(index), isPreExist(isPreExist) 374514f5e3Sopenharmony_ci { 384514f5e3Sopenharmony_ci } 394514f5e3Sopenharmony_ci 404514f5e3Sopenharmony_ci ~CommonDateFormatPart() = default; 414514f5e3Sopenharmony_ci 424514f5e3Sopenharmony_ci DEFAULT_COPY_SEMANTIC(CommonDateFormatPart); 434514f5e3Sopenharmony_ci DEFAULT_MOVE_SEMANTIC(CommonDateFormatPart); 444514f5e3Sopenharmony_ci}; 454514f5e3Sopenharmony_ci 464514f5e3Sopenharmony_cinamespace { 474514f5e3Sopenharmony_ciconst std::vector<std::string> ICU_LONG_SHORT = { 484514f5e3Sopenharmony_ci "long", "short", 494514f5e3Sopenharmony_ci "longOffset", "shortOffset", 504514f5e3Sopenharmony_ci "longGeneric", "shortGeneric" 514514f5e3Sopenharmony_ci}; 524514f5e3Sopenharmony_ciconst std::vector<std::string> ICU_NARROW_LONG_SHORT = {"narrow", "long", "short"}; 534514f5e3Sopenharmony_ciconst std::vector<std::string> ICU2_DIGIT_NUMERIC = {"2-digit", "numeric"}; 544514f5e3Sopenharmony_ciconst std::vector<std::string> ICU_NARROW_LONG_SHORT2_DIGIT_NUMERIC = {"narrow", "long", "short", "2-digit", "numeric"}; 554514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_WEEKDAY_PE = { 564514f5e3Sopenharmony_ci {"EEEEE", "narrow"}, {"EEEE", "long"}, {"EEE", "short"}, 574514f5e3Sopenharmony_ci {"ccccc", "narrow"}, {"cccc", "long"}, {"ccc", "short"} 584514f5e3Sopenharmony_ci}; 594514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_ERA_PE = {{"GGGGG", "narrow"}, {"GGGG", "long"}, {"GGG", "short"}}; 604514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_YEAR_PE = {{"yy", "2-digit"}, {"y", "numeric"}}; 614514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_MONTH_PE = { 624514f5e3Sopenharmony_ci {"MMMMM", "narrow"}, {"MMMM", "long"}, {"MMM", "short"}, {"MM", "2-digit"}, {"M", "numeric"}, 634514f5e3Sopenharmony_ci {"LLLLL", "narrow"}, {"LLLL", "long"}, {"LLL", "short"}, {"LL", "2-digit"}, {"L", "numeric"} 644514f5e3Sopenharmony_ci}; 654514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_DAY_PE = {{"dd", "2-digit"}, {"d", "numeric"}}; 664514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_DAY_PERIOD_PE = { 674514f5e3Sopenharmony_ci {"BBBBB", "narrow"}, {"bbbbb", "narrow"}, {"BBBB", "long"}, 684514f5e3Sopenharmony_ci {"bbbb", "long"}, {"B", "short"}, {"b", "short"} 694514f5e3Sopenharmony_ci}; 704514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_HOUR_PE = { 714514f5e3Sopenharmony_ci {"HH", "2-digit"}, {"H", "numeric"}, {"hh", "2-digit"}, {"h", "numeric"}, 724514f5e3Sopenharmony_ci {"kk", "2-digit"}, {"k", "numeric"}, {"KK", "2-digit"}, {"K", "numeric"} 734514f5e3Sopenharmony_ci}; 744514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_MINUTE_PE = {{"mm", "2-digit"}, {"m", "numeric"}}; 754514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_SECOND_PE = {{"ss", "2-digit"}, {"s", "numeric"}}; 764514f5e3Sopenharmony_ciconst std::vector<IcuPatternEntry> ICU_YIME_ZONE_NAME_PE = { 774514f5e3Sopenharmony_ci {"zzzz", "long"}, {"z", "short"}, 784514f5e3Sopenharmony_ci {"OOOO", "longOffset"}, {"O", "shortOffset"}, 794514f5e3Sopenharmony_ci {"vvvv", "longGeneric"}, {"v", "shortGeneric"} 804514f5e3Sopenharmony_ci}; 814514f5e3Sopenharmony_ci 824514f5e3Sopenharmony_ciconst std::map<char16_t, HourCycleOption> HOUR_CYCLE_MAP = { 834514f5e3Sopenharmony_ci {'K', HourCycleOption::H11}, 844514f5e3Sopenharmony_ci {'h', HourCycleOption::H12}, 854514f5e3Sopenharmony_ci {'H', HourCycleOption::H23}, 864514f5e3Sopenharmony_ci {'k', HourCycleOption::H24} 874514f5e3Sopenharmony_ci}; 884514f5e3Sopenharmony_ciconst std::map<std::string, HourCycleOption> TO_HOUR_CYCLE_MAP = { 894514f5e3Sopenharmony_ci {"h11", HourCycleOption::H11}, 904514f5e3Sopenharmony_ci {"h12", HourCycleOption::H12}, 914514f5e3Sopenharmony_ci {"h23", HourCycleOption::H23}, 924514f5e3Sopenharmony_ci {"h24", HourCycleOption::H24} 934514f5e3Sopenharmony_ci}; 944514f5e3Sopenharmony_ci 954514f5e3Sopenharmony_ci// The value of the [[RelevantExtensionKeys]] internal slot is « "ca", "nu", "hc" ». 964514f5e3Sopenharmony_ciconst std::set<std::string> RELEVANT_EXTENSION_KEYS = {"nu", "ca", "hc"}; 974514f5e3Sopenharmony_ci} 984514f5e3Sopenharmony_ci 994514f5e3Sopenharmony_ciicu::Locale *JSDateTimeFormat::GetIcuLocale() const 1004514f5e3Sopenharmony_ci{ 1014514f5e3Sopenharmony_ci ASSERT(GetLocaleIcu().IsJSNativePointer()); 1024514f5e3Sopenharmony_ci auto result = JSNativePointer::Cast(GetLocaleIcu().GetTaggedObject())->GetExternalPointer(); 1034514f5e3Sopenharmony_ci return reinterpret_cast<icu::Locale *>(result); 1044514f5e3Sopenharmony_ci} 1054514f5e3Sopenharmony_ci 1064514f5e3Sopenharmony_ci/* static */ 1074514f5e3Sopenharmony_civoid JSDateTimeFormat::SetIcuLocale(JSThread *thread, JSHandle<JSDateTimeFormat> obj, 1084514f5e3Sopenharmony_ci const icu::Locale &icuLocale, const NativePointerCallback &callback) 1094514f5e3Sopenharmony_ci{ 1104514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 1114514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 1124514f5e3Sopenharmony_ci icu::Locale *icuPointer = ecmaVm->GetNativeAreaAllocator()->New<icu::Locale>(icuLocale); 1134514f5e3Sopenharmony_ci ASSERT(icuPointer != nullptr); 1144514f5e3Sopenharmony_ci JSTaggedValue data = obj->GetLocaleIcu(); 1154514f5e3Sopenharmony_ci if (data.IsHeapObject() && data.IsJSNativePointer()) { 1164514f5e3Sopenharmony_ci JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject()); 1174514f5e3Sopenharmony_ci native->ResetExternalPointer(thread, icuPointer); 1184514f5e3Sopenharmony_ci return; 1194514f5e3Sopenharmony_ci } 1204514f5e3Sopenharmony_ci JSHandle<JSNativePointer> pointer = factory->NewJSNativePointer(icuPointer, callback, ecmaVm); 1214514f5e3Sopenharmony_ci obj->SetLocaleIcu(thread, pointer.GetTaggedValue()); 1224514f5e3Sopenharmony_ci} 1234514f5e3Sopenharmony_ci 1244514f5e3Sopenharmony_civoid JSDateTimeFormat::FreeIcuLocale([[maybe_unused]] void *env, void *pointer, void *data) 1254514f5e3Sopenharmony_ci{ 1264514f5e3Sopenharmony_ci if (pointer == nullptr) { 1274514f5e3Sopenharmony_ci return; 1284514f5e3Sopenharmony_ci } 1294514f5e3Sopenharmony_ci auto icuLocale = reinterpret_cast<icu::Locale *>(pointer); 1304514f5e3Sopenharmony_ci icuLocale->~Locale(); 1314514f5e3Sopenharmony_ci if (data != nullptr) { 1324514f5e3Sopenharmony_ci reinterpret_cast<EcmaVM *>(data)->GetNativeAreaAllocator()->FreeBuffer(pointer); 1334514f5e3Sopenharmony_ci } 1344514f5e3Sopenharmony_ci} 1354514f5e3Sopenharmony_ci 1364514f5e3Sopenharmony_ciicu::SimpleDateFormat *JSDateTimeFormat::GetIcuSimpleDateFormat() const 1374514f5e3Sopenharmony_ci{ 1384514f5e3Sopenharmony_ci ASSERT(GetSimpleDateTimeFormatIcu().IsJSNativePointer()); 1394514f5e3Sopenharmony_ci auto result = JSNativePointer::Cast(GetSimpleDateTimeFormatIcu().GetTaggedObject())->GetExternalPointer(); 1404514f5e3Sopenharmony_ci return reinterpret_cast<icu::SimpleDateFormat *>(result); 1414514f5e3Sopenharmony_ci} 1424514f5e3Sopenharmony_ci 1434514f5e3Sopenharmony_ci/* static */ 1444514f5e3Sopenharmony_civoid JSDateTimeFormat::SetIcuSimpleDateFormat(JSThread *thread, JSHandle<JSDateTimeFormat> obj, 1454514f5e3Sopenharmony_ci const icu::SimpleDateFormat &icuSimpleDateTimeFormat, const NativePointerCallback &callback) 1464514f5e3Sopenharmony_ci{ 1474514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 1484514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 1494514f5e3Sopenharmony_ci icu::SimpleDateFormat *icuPointer = 1504514f5e3Sopenharmony_ci ecmaVm->GetNativeAreaAllocator()->New<icu::SimpleDateFormat>(icuSimpleDateTimeFormat); 1514514f5e3Sopenharmony_ci ASSERT(icuPointer != nullptr); 1524514f5e3Sopenharmony_ci JSTaggedValue data = obj->GetSimpleDateTimeFormatIcu(); 1534514f5e3Sopenharmony_ci if (data.IsHeapObject() && data.IsJSNativePointer()) { 1544514f5e3Sopenharmony_ci JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject()); 1554514f5e3Sopenharmony_ci native->ResetExternalPointer(thread, icuPointer); 1564514f5e3Sopenharmony_ci return; 1574514f5e3Sopenharmony_ci } 1584514f5e3Sopenharmony_ci // According to the observed native memory, we give an approximate native binding value. 1594514f5e3Sopenharmony_ci constexpr static size_t icuBindingNativeSize = 64 * 1024; 1604514f5e3Sopenharmony_ci JSHandle<JSNativePointer> pointer = factory->NewJSNativePointer(icuPointer, callback, ecmaVm, 1614514f5e3Sopenharmony_ci false, icuBindingNativeSize); 1624514f5e3Sopenharmony_ci obj->SetSimpleDateTimeFormatIcu(thread, pointer.GetTaggedValue()); 1634514f5e3Sopenharmony_ci} 1644514f5e3Sopenharmony_ci 1654514f5e3Sopenharmony_civoid JSDateTimeFormat::FreeSimpleDateFormat([[maybe_unused]] void *env, void *pointer, void *data) 1664514f5e3Sopenharmony_ci{ 1674514f5e3Sopenharmony_ci if (pointer == nullptr) { 1684514f5e3Sopenharmony_ci return; 1694514f5e3Sopenharmony_ci } 1704514f5e3Sopenharmony_ci auto icuSimpleDateFormat = reinterpret_cast<icu::SimpleDateFormat *>(pointer); 1714514f5e3Sopenharmony_ci icuSimpleDateFormat->~SimpleDateFormat(); 1724514f5e3Sopenharmony_ci if (data != nullptr) { 1734514f5e3Sopenharmony_ci reinterpret_cast<EcmaVM *>(data)->GetNativeAreaAllocator()->FreeBuffer(pointer); 1744514f5e3Sopenharmony_ci } 1754514f5e3Sopenharmony_ci} 1764514f5e3Sopenharmony_ci 1774514f5e3Sopenharmony_ciJSHandle<EcmaString> JSDateTimeFormat::ToValueString(JSThread *thread, const Value value) 1784514f5e3Sopenharmony_ci{ 1794514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 1804514f5e3Sopenharmony_ci JSMutableHandle<EcmaString> result(thread, JSTaggedValue::Undefined()); 1814514f5e3Sopenharmony_ci switch (value) { 1824514f5e3Sopenharmony_ci case Value::SHARED: 1834514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledSharedString().GetTaggedValue()); 1844514f5e3Sopenharmony_ci break; 1854514f5e3Sopenharmony_ci case Value::START_RANGE: 1864514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledStartRangeString().GetTaggedValue()); 1874514f5e3Sopenharmony_ci break; 1884514f5e3Sopenharmony_ci case Value::END_RANGE: 1894514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledEndRangeString().GetTaggedValue()); 1904514f5e3Sopenharmony_ci break; 1914514f5e3Sopenharmony_ci default: 1924514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1934514f5e3Sopenharmony_ci UNREACHABLE(); 1944514f5e3Sopenharmony_ci } 1954514f5e3Sopenharmony_ci return result; 1964514f5e3Sopenharmony_ci} 1974514f5e3Sopenharmony_ci 1984514f5e3Sopenharmony_ciicu::DateFormat::EStyle DateTimeStyleToEStyle(DateTimeStyleOption style) 1994514f5e3Sopenharmony_ci{ 2004514f5e3Sopenharmony_ci switch (style) { 2014514f5e3Sopenharmony_ci case DateTimeStyleOption::FULL: { 2024514f5e3Sopenharmony_ci return icu::DateFormat::kFull; 2034514f5e3Sopenharmony_ci } 2044514f5e3Sopenharmony_ci case DateTimeStyleOption::LONG: { 2054514f5e3Sopenharmony_ci return icu::DateFormat::kLong; 2064514f5e3Sopenharmony_ci } 2074514f5e3Sopenharmony_ci case DateTimeStyleOption::MEDIUM: { 2084514f5e3Sopenharmony_ci return icu::DateFormat::kMedium; 2094514f5e3Sopenharmony_ci } 2104514f5e3Sopenharmony_ci case DateTimeStyleOption::SHORT: { 2114514f5e3Sopenharmony_ci return icu::DateFormat::kShort; 2124514f5e3Sopenharmony_ci } 2134514f5e3Sopenharmony_ci case DateTimeStyleOption::UNDEFINED: { 2144514f5e3Sopenharmony_ci return icu::DateFormat::kNone; 2154514f5e3Sopenharmony_ci } 2164514f5e3Sopenharmony_ci default: { 2174514f5e3Sopenharmony_ci return icu::DateFormat::kNone; 2184514f5e3Sopenharmony_ci } 2194514f5e3Sopenharmony_ci } 2204514f5e3Sopenharmony_ci} 2214514f5e3Sopenharmony_ci 2224514f5e3Sopenharmony_ciHourCycleOption HourCycleFromPattern(const icu::UnicodeString pattern) 2234514f5e3Sopenharmony_ci{ 2244514f5e3Sopenharmony_ci bool inQuote = false; 2254514f5e3Sopenharmony_ci for (int32_t i = 0; i < pattern.length(); i++) { 2264514f5e3Sopenharmony_ci char16_t ch = pattern[i]; 2274514f5e3Sopenharmony_ci switch (ch) { 2284514f5e3Sopenharmony_ci case '\'': 2294514f5e3Sopenharmony_ci inQuote = !inQuote; 2304514f5e3Sopenharmony_ci break; 2314514f5e3Sopenharmony_ci case 'K': 2324514f5e3Sopenharmony_ci if (!inQuote) { 2334514f5e3Sopenharmony_ci return HourCycleOption::H11; 2344514f5e3Sopenharmony_ci } 2354514f5e3Sopenharmony_ci break; 2364514f5e3Sopenharmony_ci case 'h': 2374514f5e3Sopenharmony_ci if (!inQuote) { 2384514f5e3Sopenharmony_ci return HourCycleOption::H12; 2394514f5e3Sopenharmony_ci } 2404514f5e3Sopenharmony_ci break; 2414514f5e3Sopenharmony_ci case 'H': 2424514f5e3Sopenharmony_ci if (!inQuote) { 2434514f5e3Sopenharmony_ci return HourCycleOption::H23; 2444514f5e3Sopenharmony_ci } 2454514f5e3Sopenharmony_ci break; 2464514f5e3Sopenharmony_ci case 'k': 2474514f5e3Sopenharmony_ci if (!inQuote) { 2484514f5e3Sopenharmony_ci return HourCycleOption::H24; 2494514f5e3Sopenharmony_ci } 2504514f5e3Sopenharmony_ci break; 2514514f5e3Sopenharmony_ci default : { 2524514f5e3Sopenharmony_ci break; 2534514f5e3Sopenharmony_ci } 2544514f5e3Sopenharmony_ci } 2554514f5e3Sopenharmony_ci } 2564514f5e3Sopenharmony_ci return HourCycleOption::UNDEFINED; 2574514f5e3Sopenharmony_ci} 2584514f5e3Sopenharmony_ci 2594514f5e3Sopenharmony_ciicu::UnicodeString ReplaceSkeleton(const icu::UnicodeString input, HourCycleOption hc) 2604514f5e3Sopenharmony_ci{ 2614514f5e3Sopenharmony_ci icu::UnicodeString result; 2624514f5e3Sopenharmony_ci char16_t to; 2634514f5e3Sopenharmony_ci switch (hc) { 2644514f5e3Sopenharmony_ci case HourCycleOption::H11: 2654514f5e3Sopenharmony_ci to = 'K'; 2664514f5e3Sopenharmony_ci break; 2674514f5e3Sopenharmony_ci case HourCycleOption::H12: 2684514f5e3Sopenharmony_ci to = 'h'; 2694514f5e3Sopenharmony_ci break; 2704514f5e3Sopenharmony_ci case HourCycleOption::H23: 2714514f5e3Sopenharmony_ci to = 'H'; 2724514f5e3Sopenharmony_ci break; 2734514f5e3Sopenharmony_ci case HourCycleOption::H24: 2744514f5e3Sopenharmony_ci to = 'k'; 2754514f5e3Sopenharmony_ci break; 2764514f5e3Sopenharmony_ci default: 2774514f5e3Sopenharmony_ci UNREACHABLE(); 2784514f5e3Sopenharmony_ci break; 2794514f5e3Sopenharmony_ci } 2804514f5e3Sopenharmony_ci int inputLength = input.length(); 2814514f5e3Sopenharmony_ci for (int32_t i = 0; i < inputLength; ++i) { 2824514f5e3Sopenharmony_ci switch (input[i]) { 2834514f5e3Sopenharmony_ci case 'a': 2844514f5e3Sopenharmony_ci case 'b': 2854514f5e3Sopenharmony_ci case 'B': 2864514f5e3Sopenharmony_ci break; 2874514f5e3Sopenharmony_ci case 'h': 2884514f5e3Sopenharmony_ci case 'H': 2894514f5e3Sopenharmony_ci case 'k': 2904514f5e3Sopenharmony_ci case 'K': 2914514f5e3Sopenharmony_ci result += to; 2924514f5e3Sopenharmony_ci break; 2934514f5e3Sopenharmony_ci default: 2944514f5e3Sopenharmony_ci result += input[i]; 2954514f5e3Sopenharmony_ci break; 2964514f5e3Sopenharmony_ci } 2974514f5e3Sopenharmony_ci } 2984514f5e3Sopenharmony_ci return result; 2994514f5e3Sopenharmony_ci} 3004514f5e3Sopenharmony_ci 3014514f5e3Sopenharmony_cistd::unique_ptr<icu::SimpleDateFormat> DateTimeStylePattern(DateTimeStyleOption dateStyle, 3024514f5e3Sopenharmony_ci DateTimeStyleOption timeStyle, 3034514f5e3Sopenharmony_ci icu::Locale &icuLocale, 3044514f5e3Sopenharmony_ci HourCycleOption hc, 3054514f5e3Sopenharmony_ci icu::DateTimePatternGenerator *generator) 3064514f5e3Sopenharmony_ci{ 3074514f5e3Sopenharmony_ci std::unique_ptr<icu::SimpleDateFormat> result; 3084514f5e3Sopenharmony_ci icu::DateFormat::EStyle icuDateStyle = DateTimeStyleToEStyle(dateStyle); 3094514f5e3Sopenharmony_ci icu::DateFormat::EStyle icuTimeStyle = DateTimeStyleToEStyle(timeStyle); 3104514f5e3Sopenharmony_ci result.reset(reinterpret_cast<icu::SimpleDateFormat *>( 3114514f5e3Sopenharmony_ci icu::DateFormat::createDateTimeInstance(icuDateStyle, icuTimeStyle, icuLocale))); 3124514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 3134514f5e3Sopenharmony_ci icu::UnicodeString pattern(""); 3144514f5e3Sopenharmony_ci pattern = result->toPattern(pattern); 3154514f5e3Sopenharmony_ci icu::UnicodeString skeleton = icu::DateTimePatternGenerator::staticGetSkeleton(pattern, status); 3164514f5e3Sopenharmony_ci ASSERT_PRINT(U_SUCCESS(status), "staticGetSkeleton failed"); 3174514f5e3Sopenharmony_ci if (hc == HourCycleFromPattern(pattern)) { 3184514f5e3Sopenharmony_ci return result; 3194514f5e3Sopenharmony_ci } 3204514f5e3Sopenharmony_ci skeleton = ReplaceSkeleton(skeleton, hc); 3214514f5e3Sopenharmony_ci pattern = generator->getBestPattern(skeleton, UDATPG_MATCH_HOUR_FIELD_LENGTH, status); 3224514f5e3Sopenharmony_ci result = std::make_unique<icu::SimpleDateFormat>(pattern, icuLocale, status); 3234514f5e3Sopenharmony_ci return result; 3244514f5e3Sopenharmony_ci} 3254514f5e3Sopenharmony_ci 3264514f5e3Sopenharmony_ci// 13.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options) 3274514f5e3Sopenharmony_ci// NOLINTNEXTLINE(readability-function-size) 3284514f5e3Sopenharmony_ciJSHandle<JSDateTimeFormat> JSDateTimeFormat::InitializeDateTimeFormat(JSThread *thread, 3294514f5e3Sopenharmony_ci const JSHandle<JSDateTimeFormat> &dateTimeFormat, 3304514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &locales, 3314514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &options, 3324514f5e3Sopenharmony_ci IcuCacheType type) 3334514f5e3Sopenharmony_ci{ 3344514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 3354514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 3364514f5e3Sopenharmony_ci const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 3374514f5e3Sopenharmony_ci 3384514f5e3Sopenharmony_ci // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). 3394514f5e3Sopenharmony_ci JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales); 3404514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 3414514f5e3Sopenharmony_ci 3424514f5e3Sopenharmony_ci // 2. Let options be ? ToDateTimeOptions(options, "any", "date"). 3434514f5e3Sopenharmony_ci JSHandle<JSObject> dateTimeOptions; 3444514f5e3Sopenharmony_ci if (options->IsUndefined()) { 3454514f5e3Sopenharmony_ci dateTimeOptions = factory->CreateNullJSObject(); 3464514f5e3Sopenharmony_ci } else { 3474514f5e3Sopenharmony_ci dateTimeOptions = JSTaggedValue::ToObject(thread, options); 3484514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 3494514f5e3Sopenharmony_ci } 3504514f5e3Sopenharmony_ci 3514514f5e3Sopenharmony_ci // 4. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit"). 3524514f5e3Sopenharmony_ci auto matcher = JSLocale::GetOptionOfString<LocaleMatcherOption>( 3534514f5e3Sopenharmony_ci thread, dateTimeOptions, globalConst->GetHandledLocaleMatcherString(), 3544514f5e3Sopenharmony_ci {LocaleMatcherOption::LOOKUP, LocaleMatcherOption::BEST_FIT}, {"lookup", "best fit"}, 3554514f5e3Sopenharmony_ci LocaleMatcherOption::BEST_FIT); 3564514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 3574514f5e3Sopenharmony_ci 3584514f5e3Sopenharmony_ci // 6. Let calendar be ? GetOption(options, "calendar", "string", undefined, undefined). 3594514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> calendar = 3604514f5e3Sopenharmony_ci JSLocale::GetOption(thread, dateTimeOptions, globalConst->GetHandledCalendarString(), OptionType::STRING, 3614514f5e3Sopenharmony_ci globalConst->GetHandledUndefined(), globalConst->GetHandledUndefined()); 3624514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 3634514f5e3Sopenharmony_ci dateTimeFormat->SetCalendar(thread, calendar); 3644514f5e3Sopenharmony_ci 3654514f5e3Sopenharmony_ci // 7. If calendar is not undefined, then 3664514f5e3Sopenharmony_ci // a. If calendar does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. 3674514f5e3Sopenharmony_ci std::string calendarStr; 3684514f5e3Sopenharmony_ci if (!calendar->IsUndefined()) { 3694514f5e3Sopenharmony_ci JSHandle<EcmaString> calendarEcmaStr = JSHandle<EcmaString>::Cast(calendar); 3704514f5e3Sopenharmony_ci calendarStr = intl::LocaleHelper::ConvertToStdString(calendarEcmaStr); 3714514f5e3Sopenharmony_ci if (!JSLocale::IsNormativeCalendar(calendarStr)) { 3724514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "invalid calendar", dateTimeFormat); 3734514f5e3Sopenharmony_ci } 3744514f5e3Sopenharmony_ci } 3754514f5e3Sopenharmony_ci 3764514f5e3Sopenharmony_ci // 9. Let numberingSystem be ? GetOption(options, "numberingSystem", "string", undefined, undefined). 3774514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> numberingSystem = 3784514f5e3Sopenharmony_ci JSLocale::GetOption(thread, dateTimeOptions, globalConst->GetHandledNumberingSystemString(), OptionType::STRING, 3794514f5e3Sopenharmony_ci globalConst->GetHandledUndefined(), globalConst->GetHandledUndefined()); 3804514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 3814514f5e3Sopenharmony_ci dateTimeFormat->SetNumberingSystem(thread, numberingSystem); 3824514f5e3Sopenharmony_ci 3834514f5e3Sopenharmony_ci // 10. If numberingSystem is not undefined, then 3844514f5e3Sopenharmony_ci // a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError 3854514f5e3Sopenharmony_ci // exception. 3864514f5e3Sopenharmony_ci std::string nsStr; 3874514f5e3Sopenharmony_ci if (!numberingSystem->IsUndefined()) { 3884514f5e3Sopenharmony_ci JSHandle<EcmaString> nsEcmaStr = JSHandle<EcmaString>::Cast(numberingSystem); 3894514f5e3Sopenharmony_ci nsStr = intl::LocaleHelper::ConvertToStdString(nsEcmaStr); 3904514f5e3Sopenharmony_ci if (!JSLocale::IsNormativeNumberingSystem(nsStr)) { 3914514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "invalid numberingSystem", dateTimeFormat); 3924514f5e3Sopenharmony_ci } 3934514f5e3Sopenharmony_ci } 3944514f5e3Sopenharmony_ci 3954514f5e3Sopenharmony_ci // 12. Let hour12 be ? GetOption(options, "hour12", "boolean", undefined, undefined). 3964514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> hour12 = 3974514f5e3Sopenharmony_ci JSLocale::GetOption(thread, dateTimeOptions, globalConst->GetHandledHour12String(), OptionType::BOOLEAN, 3984514f5e3Sopenharmony_ci globalConst->GetHandledUndefined(), globalConst->GetHandledUndefined()); 3994514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 4004514f5e3Sopenharmony_ci 4014514f5e3Sopenharmony_ci // 13. Let hourCycle be ? GetOption(options, "hourCycle", "string", « "h11", "h12", "h23", "h24" », undefined). 4024514f5e3Sopenharmony_ci auto hourCycle = JSLocale::GetOptionOfString<HourCycleOption>( 4034514f5e3Sopenharmony_ci thread, dateTimeOptions, globalConst->GetHandledHourCycleString(), 4044514f5e3Sopenharmony_ci {HourCycleOption::H11, HourCycleOption::H12, HourCycleOption::H23, HourCycleOption::H24}, 4054514f5e3Sopenharmony_ci {"h11", "h12", "h23", "h24"}, HourCycleOption::UNDEFINED); 4064514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 4074514f5e3Sopenharmony_ci 4084514f5e3Sopenharmony_ci // 14. If hour12 is not undefined, then 4094514f5e3Sopenharmony_ci // a. Let hourCycle be null. 4104514f5e3Sopenharmony_ci if (!hour12->IsUndefined()) { 4114514f5e3Sopenharmony_ci hourCycle = HourCycleOption::UNDEFINED; 4124514f5e3Sopenharmony_ci } 4134514f5e3Sopenharmony_ci 4144514f5e3Sopenharmony_ci // 16. Let localeData be %DateTimeFormat%.[[LocaleData]]. 4154514f5e3Sopenharmony_ci JSHandle<TaggedArray> availableLocales = (requestedLocales->GetLength() == 0) ? factory->EmptyArray() : 4164514f5e3Sopenharmony_ci GainAvailableLocales(thread); 4174514f5e3Sopenharmony_ci 4184514f5e3Sopenharmony_ci // 17. Let r be ResolveLocale(%DateTimeFormat%.[[AvailableLocales]], requestedLocales, opt, %DateTimeFormat% 4194514f5e3Sopenharmony_ci // .[[RelevantExtensionKeys]], localeData). 4204514f5e3Sopenharmony_ci ResolvedLocale resolvedLocale = 4214514f5e3Sopenharmony_ci JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, RELEVANT_EXTENSION_KEYS); 4224514f5e3Sopenharmony_ci 4234514f5e3Sopenharmony_ci // 18. Set icuLocale to r.[[locale]]. 4244514f5e3Sopenharmony_ci icu::Locale icuLocale = resolvedLocale.localeData; 4254514f5e3Sopenharmony_ci ASSERT_PRINT(!icuLocale.isBogus(), "icuLocale is bogus"); 4264514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 4274514f5e3Sopenharmony_ci 4284514f5e3Sopenharmony_ci if (numberingSystem->IsUndefined() || !JSLocale::IsWellNumberingSystem(nsStr)) { 4294514f5e3Sopenharmony_ci std::string numberingSystemStr = JSLocale::GetNumberingSystem(icuLocale); 4304514f5e3Sopenharmony_ci auto result = factory->NewFromStdString(numberingSystemStr); 4314514f5e3Sopenharmony_ci dateTimeFormat->SetNumberingSystem(thread, result); 4324514f5e3Sopenharmony_ci } 4334514f5e3Sopenharmony_ci 4344514f5e3Sopenharmony_ci // Set resolvedIcuLocaleCopy to a copy of icuLocale. 4354514f5e3Sopenharmony_ci // Set icuLocale.[[ca]] to calendar. 4364514f5e3Sopenharmony_ci // Set icuLocale.[[nu]] to numberingSystem. 4374514f5e3Sopenharmony_ci icu::Locale resolvedIcuLocaleCopy(icuLocale); 4384514f5e3Sopenharmony_ci if (!calendar->IsUndefined() && JSLocale::IsWellCalendar(icuLocale, calendarStr)) { 4394514f5e3Sopenharmony_ci icuLocale.setUnicodeKeywordValue("ca", calendarStr, status); 4404514f5e3Sopenharmony_ci } 4414514f5e3Sopenharmony_ci if (!numberingSystem->IsUndefined() && JSLocale::IsWellNumberingSystem(nsStr)) { 4424514f5e3Sopenharmony_ci icuLocale.setUnicodeKeywordValue("nu", nsStr, status); 4434514f5e3Sopenharmony_ci } 4444514f5e3Sopenharmony_ci 4454514f5e3Sopenharmony_ci // 24. Let timeZone be ? Get(options, "timeZone"). 4464514f5e3Sopenharmony_ci OperationResult operationResult = 4474514f5e3Sopenharmony_ci JSObject::GetProperty(thread, dateTimeOptions, globalConst->GetHandledTimeZoneString()); 4484514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 4494514f5e3Sopenharmony_ci dateTimeFormat->SetTimeZone(thread, operationResult.GetValue()); 4504514f5e3Sopenharmony_ci 4514514f5e3Sopenharmony_ci // 25. If timeZone is not undefined, then 4524514f5e3Sopenharmony_ci // a. Let timeZone be ? ToString(timeZone). 4534514f5e3Sopenharmony_ci // b. If the result of IsValidTimeZoneName(timeZone) is false, then 4544514f5e3Sopenharmony_ci // i. Throw a RangeError exception. 4554514f5e3Sopenharmony_ci std::unique_ptr<icu::TimeZone> icuTimeZone; 4564514f5e3Sopenharmony_ci if (!operationResult.GetValue()->IsUndefined()) { 4574514f5e3Sopenharmony_ci JSHandle<EcmaString> timezone = JSTaggedValue::ToString(thread, operationResult.GetValue()); 4584514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 4594514f5e3Sopenharmony_ci icuTimeZone = ConstructTimeZone(intl::LocaleHelper::ConvertToStdString(timezone)); 4604514f5e3Sopenharmony_ci if (icuTimeZone == nullptr) { 4614514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "invalid timeZone", dateTimeFormat); 4624514f5e3Sopenharmony_ci } 4634514f5e3Sopenharmony_ci } else { 4644514f5e3Sopenharmony_ci // 26. Else, 4654514f5e3Sopenharmony_ci // a. Let timeZone be DefaultTimeZone(). 4664514f5e3Sopenharmony_ci icuTimeZone = std::unique_ptr<icu::TimeZone>(icu::TimeZone::createDefault()); 4674514f5e3Sopenharmony_ci } 4684514f5e3Sopenharmony_ci 4694514f5e3Sopenharmony_ci // 36.a. Let hcDefault be dataLocaleData.[[hourCycle]]. 4704514f5e3Sopenharmony_ci std::unique_ptr<icu::DateTimePatternGenerator> generator; 4714514f5e3Sopenharmony_ci { 4724514f5e3Sopenharmony_ci ThreadNativeScope nativeScope(thread); 4734514f5e3Sopenharmony_ci generator.reset(icu::DateTimePatternGenerator::createInstance(icuLocale, status)); 4744514f5e3Sopenharmony_ci } 4754514f5e3Sopenharmony_ci if (U_FAILURE(status) || generator == nullptr) { 4764514f5e3Sopenharmony_ci if (status == UErrorCode::U_MISSING_RESOURCE_ERROR) { 4774514f5e3Sopenharmony_ci THROW_REFERENCE_ERROR_AND_RETURN(thread, "can not find icu data resources", dateTimeFormat); 4784514f5e3Sopenharmony_ci } 4794514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "create icu::DateTimePatternGenerator failed", dateTimeFormat); 4804514f5e3Sopenharmony_ci } 4814514f5e3Sopenharmony_ci HourCycleOption hcDefault = OptionToHourCycle(generator->getDefaultHourCycle(status)); 4824514f5e3Sopenharmony_ci // b. Let hc be dateTimeFormat.[[HourCycle]]. 4834514f5e3Sopenharmony_ci HourCycleOption hc = hourCycle; 4844514f5e3Sopenharmony_ci if (hourCycle == HourCycleOption::UNDEFINED 4854514f5e3Sopenharmony_ci && resolvedLocale.extensions.find("hc") != resolvedLocale.extensions.end()) { 4864514f5e3Sopenharmony_ci hc = OptionToHourCycle(resolvedLocale.extensions.find("hc")->second); 4874514f5e3Sopenharmony_ci } 4884514f5e3Sopenharmony_ci // c. If hc is null, then 4894514f5e3Sopenharmony_ci // i. Set hc to hcDefault. 4904514f5e3Sopenharmony_ci if (hc == HourCycleOption::UNDEFINED) { 4914514f5e3Sopenharmony_ci hc = hcDefault; 4924514f5e3Sopenharmony_ci } 4934514f5e3Sopenharmony_ci // d. If hour12 is not undefined, then 4944514f5e3Sopenharmony_ci if (!hour12->IsUndefined()) { 4954514f5e3Sopenharmony_ci // i. If hour12 is true, then 4964514f5e3Sopenharmony_ci if (JSTaggedValue::SameValue(hour12.GetTaggedValue(), JSTaggedValue::True())) { 4974514f5e3Sopenharmony_ci // 1. If hcDefault is "h11" or "h23", then 4984514f5e3Sopenharmony_ci if (hcDefault == HourCycleOption::H11 || hcDefault == HourCycleOption::H23) { 4994514f5e3Sopenharmony_ci // a. Set hc to "h11". 5004514f5e3Sopenharmony_ci hc = HourCycleOption::H11; 5014514f5e3Sopenharmony_ci } else { 5024514f5e3Sopenharmony_ci // 2. Else, 5034514f5e3Sopenharmony_ci // a. Set hc to "h12". 5044514f5e3Sopenharmony_ci hc = HourCycleOption::H12; 5054514f5e3Sopenharmony_ci } 5064514f5e3Sopenharmony_ci } else { 5074514f5e3Sopenharmony_ci // ii. Else, 5084514f5e3Sopenharmony_ci // 2. If hcDefault is "h11" or "h23", then 5094514f5e3Sopenharmony_ci if (hcDefault == HourCycleOption::H11 || hcDefault == HourCycleOption::H23) { 5104514f5e3Sopenharmony_ci // a. Set hc to "h23". 5114514f5e3Sopenharmony_ci hc = HourCycleOption::H23; 5124514f5e3Sopenharmony_ci } else { 5134514f5e3Sopenharmony_ci // 3. Else, 5144514f5e3Sopenharmony_ci // a. Set hc to "h24". 5154514f5e3Sopenharmony_ci hc = HourCycleOption::H24; 5164514f5e3Sopenharmony_ci } 5174514f5e3Sopenharmony_ci } 5184514f5e3Sopenharmony_ci } 5194514f5e3Sopenharmony_ci 5204514f5e3Sopenharmony_ci // Set isHourDefined be false when dateTimeFormat.[[Hour]] is not undefined. 5214514f5e3Sopenharmony_ci bool isHourDefined = false; 5224514f5e3Sopenharmony_ci 5234514f5e3Sopenharmony_ci // 29. For each row of Table 6, except the header row, in table order, do 5244514f5e3Sopenharmony_ci // a. Let prop be the name given in the Property column of the row. 5254514f5e3Sopenharmony_ci // b. Let value be ? GetOption(options, prop, "string", « the strings given in the Values column of the 5264514f5e3Sopenharmony_ci // row », undefined). 5274514f5e3Sopenharmony_ci // c. Set opt.[[<prop>]] to value. 5284514f5e3Sopenharmony_ci std::string skeleton; 5294514f5e3Sopenharmony_ci std::vector<IcuPatternDesc> data = GetIcuPatternDesc(hc); 5304514f5e3Sopenharmony_ci int32_t explicitFormatComponents = 0; 5314514f5e3Sopenharmony_ci std::vector<std::string> skeletonOpts; 5324514f5e3Sopenharmony_ci for (const IcuPatternDesc &item : data) { 5334514f5e3Sopenharmony_ci // prop be [[TimeZoneName]] 5344514f5e3Sopenharmony_ci if (item.property == "timeZoneName") { 5354514f5e3Sopenharmony_ci // b. If prop is "fractionalSecondDigits", then 5364514f5e3Sopenharmony_ci // i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined). 5374514f5e3Sopenharmony_ci int secondDigitsString = JSLocale::GetNumberOption(thread, dateTimeOptions, 5384514f5e3Sopenharmony_ci globalConst->GetHandledFractionalSecondDigitsString(), 5394514f5e3Sopenharmony_ci 1, 3, 0); 5404514f5e3Sopenharmony_ci skeleton.append(secondDigitsString, 'S'); 5414514f5e3Sopenharmony_ci // e. If value is not undefined, then 5424514f5e3Sopenharmony_ci // i. Set hasExplicitFormatComponents to true. 5434514f5e3Sopenharmony_ci if (secondDigitsString > 0) { 5444514f5e3Sopenharmony_ci explicitFormatComponents = 1; 5454514f5e3Sopenharmony_ci skeletonOpts.emplace_back(item.property); 5464514f5e3Sopenharmony_ci } 5474514f5e3Sopenharmony_ci } 5484514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> property(thread, factory->NewFromStdString(item.property).GetTaggedValue()); 5494514f5e3Sopenharmony_ci std::string value; 5504514f5e3Sopenharmony_ci bool isFind = JSLocale::GetOptionOfString(thread, dateTimeOptions, property, item.allowedValues, &value); 5514514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 5524514f5e3Sopenharmony_ci if (isFind) { 5534514f5e3Sopenharmony_ci skeletonOpts.emplace_back(item.property); 5544514f5e3Sopenharmony_ci explicitFormatComponents = 1; 5554514f5e3Sopenharmony_ci skeleton += item.map.find(value)->second; 5564514f5e3Sopenharmony_ci // [[Hour]] is defined. 5574514f5e3Sopenharmony_ci isHourDefined = (item.property == "hour") ? true : isHourDefined; 5584514f5e3Sopenharmony_ci } 5594514f5e3Sopenharmony_ci } 5604514f5e3Sopenharmony_ci 5614514f5e3Sopenharmony_ci // 13.1.3 BasicFormatMatcher (options, formats) 5624514f5e3Sopenharmony_ci [[maybe_unused]] auto formatMatcher = JSLocale::GetOptionOfString<FormatMatcherOption>( 5634514f5e3Sopenharmony_ci thread, dateTimeOptions, globalConst->GetHandledFormatMatcherString(), 5644514f5e3Sopenharmony_ci {FormatMatcherOption::BASIC, FormatMatcherOption::BEST_FIT}, {"basic", "best fit"}, 5654514f5e3Sopenharmony_ci FormatMatcherOption::BEST_FIT); 5664514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 5674514f5e3Sopenharmony_ci 5684514f5e3Sopenharmony_ci // Let dateStyle be ? GetOption(options, "string", «"full", "long", "medium", "short"», undefined). 5694514f5e3Sopenharmony_ci // Set dateTimeFormat.[[dateStyle]] 5704514f5e3Sopenharmony_ci auto dateStyle = JSLocale::GetOptionOfString<DateTimeStyleOption>( 5714514f5e3Sopenharmony_ci thread, dateTimeOptions, globalConst->GetHandledDateStyleString(), 5724514f5e3Sopenharmony_ci {DateTimeStyleOption::FULL, DateTimeStyleOption::LONG, DateTimeStyleOption::MEDIUM, DateTimeStyleOption::SHORT}, 5734514f5e3Sopenharmony_ci {"full", "long", "medium", "short"}, DateTimeStyleOption::UNDEFINED); 5744514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 5754514f5e3Sopenharmony_ci dateTimeFormat->SetDateStyle(dateStyle); 5764514f5e3Sopenharmony_ci 5774514f5e3Sopenharmony_ci // Let timeStyle be ? GetOption(options, "string", «"full", "long", "medium", "short"», undefined). 5784514f5e3Sopenharmony_ci // Set dateTimeFormat.[[timeStyle]] 5794514f5e3Sopenharmony_ci auto timeStyle = JSLocale::GetOptionOfString<DateTimeStyleOption>( 5804514f5e3Sopenharmony_ci thread, dateTimeOptions, globalConst->GetHandledTimeStyleString(), 5814514f5e3Sopenharmony_ci {DateTimeStyleOption::FULL, DateTimeStyleOption::LONG, DateTimeStyleOption::MEDIUM, DateTimeStyleOption::SHORT}, 5824514f5e3Sopenharmony_ci {"full", "long", "medium", "short"}, DateTimeStyleOption::UNDEFINED); 5834514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 5844514f5e3Sopenharmony_ci dateTimeFormat->SetTimeStyle(timeStyle); 5854514f5e3Sopenharmony_ci 5864514f5e3Sopenharmony_ci HourCycleOption dtfHourCycle = HourCycleOption::UNDEFINED; 5874514f5e3Sopenharmony_ci 5884514f5e3Sopenharmony_ci if (timeStyle != DateTimeStyleOption::UNDEFINED) { 5894514f5e3Sopenharmony_ci // Set dateTimeFormat.[[HourCycle]] to hc. 5904514f5e3Sopenharmony_ci dtfHourCycle = hc; 5914514f5e3Sopenharmony_ci } 5924514f5e3Sopenharmony_ci 5934514f5e3Sopenharmony_ci if (dateStyle == DateTimeStyleOption::UNDEFINED 5944514f5e3Sopenharmony_ci && timeStyle == DateTimeStyleOption::UNDEFINED) { 5954514f5e3Sopenharmony_ci ToDateTimeSkeleton(thread, skeletonOpts, skeleton, hc, RequiredOption::ANY, DefaultsOption::DATE); 5964514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 5974514f5e3Sopenharmony_ci // If dateTimeFormat.[[Hour]] is defined, then 5984514f5e3Sopenharmony_ci if (isHourDefined) { 5994514f5e3Sopenharmony_ci // e. Set dateTimeFormat.[[HourCycle]] to hc. 6004514f5e3Sopenharmony_ci dtfHourCycle = hc; 6014514f5e3Sopenharmony_ci } else { 6024514f5e3Sopenharmony_ci // 37. Else, 6034514f5e3Sopenharmony_ci // a. Set dateTimeFormat.[[HourCycle]] to undefined. 6044514f5e3Sopenharmony_ci dtfHourCycle = HourCycleOption::UNDEFINED; 6054514f5e3Sopenharmony_ci } 6064514f5e3Sopenharmony_ci } 6074514f5e3Sopenharmony_ci 6084514f5e3Sopenharmony_ci // Set dateTimeFormat.[[hourCycle]]. 6094514f5e3Sopenharmony_ci dateTimeFormat->SetHourCycle(dtfHourCycle); 6104514f5e3Sopenharmony_ci 6114514f5e3Sopenharmony_ci // Set dateTimeFormat.[[icuLocale]]. 6124514f5e3Sopenharmony_ci JSDateTimeFormat::SetIcuLocale(thread, dateTimeFormat, icuLocale, JSDateTimeFormat::FreeIcuLocale); 6134514f5e3Sopenharmony_ci 6144514f5e3Sopenharmony_ci // Creates a Calendar using the given timezone and given locale. 6154514f5e3Sopenharmony_ci // Set dateTimeFormat.[[icuSimpleDateFormat]]. 6164514f5e3Sopenharmony_ci icu::UnicodeString dtfSkeleton(skeleton.c_str()); 6174514f5e3Sopenharmony_ci status = U_ZERO_ERROR; 6184514f5e3Sopenharmony_ci icu::UnicodeString pattern = ChangeHourCyclePattern( 6194514f5e3Sopenharmony_ci generator.get()->getBestPattern(dtfSkeleton, UDATPG_MATCH_HOUR_FIELD_LENGTH, status), dtfHourCycle); 6204514f5e3Sopenharmony_ci ASSERT_PRINT((U_SUCCESS(status) != 0), "get best pattern failed"); 6214514f5e3Sopenharmony_ci auto simpleDateFormatIcu(std::make_unique<icu::SimpleDateFormat>(pattern, icuLocale, status)); 6224514f5e3Sopenharmony_ci if (dateStyle != DateTimeStyleOption::UNDEFINED || timeStyle != DateTimeStyleOption::UNDEFINED) { 6234514f5e3Sopenharmony_ci if (explicitFormatComponents != 0) { 6244514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "Invalid option : option", dateTimeFormat); 6254514f5e3Sopenharmony_ci } 6264514f5e3Sopenharmony_ci simpleDateFormatIcu = DateTimeStylePattern(dateStyle, timeStyle, icuLocale, 6274514f5e3Sopenharmony_ci hc, generator.get()); 6284514f5e3Sopenharmony_ci } 6294514f5e3Sopenharmony_ci if (U_FAILURE(status) != 0) { 6304514f5e3Sopenharmony_ci simpleDateFormatIcu = std::unique_ptr<icu::SimpleDateFormat>(); 6314514f5e3Sopenharmony_ci } 6324514f5e3Sopenharmony_ci ASSERT_PRINT(simpleDateFormatIcu != nullptr, "invalid icuSimpleDateFormat"); 6334514f5e3Sopenharmony_ci std::unique_ptr<icu::Calendar> calendarPtr = BuildCalendar(icuLocale, *icuTimeZone); 6344514f5e3Sopenharmony_ci ASSERT_PRINT(calendarPtr != nullptr, "invalid calendar"); 6354514f5e3Sopenharmony_ci simpleDateFormatIcu->adoptCalendar(calendarPtr.release()); 6364514f5e3Sopenharmony_ci if (type != IcuCacheType::NOT_CACHE) { 6374514f5e3Sopenharmony_ci std::string cacheEntry = 6384514f5e3Sopenharmony_ci locales->IsUndefined() ? "" : EcmaStringAccessor(locales.GetTaggedValue()).ToStdString(); 6394514f5e3Sopenharmony_ci switch (type) { 6404514f5e3Sopenharmony_ci case IcuCacheType::DEFAULT: 6414514f5e3Sopenharmony_ci thread->GetCurrentEcmaContext()->SetIcuFormatterToCache(IcuFormatterType::SIMPLE_DATE_FORMAT_DEFAULT, 6424514f5e3Sopenharmony_ci cacheEntry, simpleDateFormatIcu.release(), JSDateTimeFormat::FreeSimpleDateFormat); 6434514f5e3Sopenharmony_ci break; 6444514f5e3Sopenharmony_ci case IcuCacheType::DATE: 6454514f5e3Sopenharmony_ci thread->GetCurrentEcmaContext()->SetIcuFormatterToCache(IcuFormatterType::SIMPLE_DATE_FORMAT_DATE, 6464514f5e3Sopenharmony_ci cacheEntry, simpleDateFormatIcu.release(), JSDateTimeFormat::FreeSimpleDateFormat); 6474514f5e3Sopenharmony_ci break; 6484514f5e3Sopenharmony_ci case IcuCacheType::TIME: 6494514f5e3Sopenharmony_ci thread->GetCurrentEcmaContext()->SetIcuFormatterToCache(IcuFormatterType::SIMPLE_DATE_FORMAT_TIME, 6504514f5e3Sopenharmony_ci cacheEntry, simpleDateFormatIcu.release(), JSDateTimeFormat::FreeSimpleDateFormat); 6514514f5e3Sopenharmony_ci break; 6524514f5e3Sopenharmony_ci default: 6534514f5e3Sopenharmony_ci UNREACHABLE(); 6544514f5e3Sopenharmony_ci } 6554514f5e3Sopenharmony_ci } else { 6564514f5e3Sopenharmony_ci SetIcuSimpleDateFormat(thread, dateTimeFormat, *simpleDateFormatIcu, JSDateTimeFormat::FreeSimpleDateFormat); 6574514f5e3Sopenharmony_ci } 6584514f5e3Sopenharmony_ci 6594514f5e3Sopenharmony_ci // Set dateTimeFormat.[[iso8601]]. 6604514f5e3Sopenharmony_ci bool iso8601 = strstr(icuLocale.getName(), "calendar=iso8601") != nullptr; 6614514f5e3Sopenharmony_ci dateTimeFormat->SetIso8601(thread, JSTaggedValue(iso8601)); 6624514f5e3Sopenharmony_ci 6634514f5e3Sopenharmony_ci // Set dateTimeFormat.[[locale]]. 6644514f5e3Sopenharmony_ci if (!hour12->IsUndefined() || hourCycle != HourCycleOption::UNDEFINED) { 6654514f5e3Sopenharmony_ci if ((resolvedLocale.extensions.find("hc") != resolvedLocale.extensions.end()) && 6664514f5e3Sopenharmony_ci (dtfHourCycle != OptionToHourCycle((resolvedLocale.extensions.find("hc")->second)))) { 6674514f5e3Sopenharmony_ci resolvedIcuLocaleCopy.setUnicodeKeywordValue("hc", nullptr, status); 6684514f5e3Sopenharmony_ci ASSERT_PRINT(U_SUCCESS(status), "resolvedIcuLocaleCopy set hc failed"); 6694514f5e3Sopenharmony_ci } 6704514f5e3Sopenharmony_ci } 6714514f5e3Sopenharmony_ci JSHandle<EcmaString> localeStr = intl::LocaleHelper::ToLanguageTag(thread, resolvedIcuLocaleCopy); 6724514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); 6734514f5e3Sopenharmony_ci dateTimeFormat->SetLocale(thread, localeStr.GetTaggedValue()); 6744514f5e3Sopenharmony_ci 6754514f5e3Sopenharmony_ci // Set dateTimeFormat.[[boundFormat]]. 6764514f5e3Sopenharmony_ci dateTimeFormat->SetBoundFormat(thread, JSTaggedValue::Undefined()); 6774514f5e3Sopenharmony_ci 6784514f5e3Sopenharmony_ci // 39. Return dateTimeFormat. 6794514f5e3Sopenharmony_ci return dateTimeFormat; 6804514f5e3Sopenharmony_ci} 6814514f5e3Sopenharmony_ci 6824514f5e3Sopenharmony_ciicu::SimpleDateFormat *JSDateTimeFormat::GetCachedIcuSimpleDateFormat(JSThread *thread, 6834514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &locales, 6844514f5e3Sopenharmony_ci IcuFormatterType type) 6854514f5e3Sopenharmony_ci{ 6864514f5e3Sopenharmony_ci std::string cacheEntry = locales->IsUndefined() ? "" : EcmaStringAccessor(locales.GetTaggedValue()).ToStdString(); 6874514f5e3Sopenharmony_ci void *cachedSimpleDateFormat = thread->GetCurrentEcmaContext()->GetIcuFormatterFromCache(type, cacheEntry); 6884514f5e3Sopenharmony_ci if (cachedSimpleDateFormat != nullptr) { 6894514f5e3Sopenharmony_ci return reinterpret_cast<icu::SimpleDateFormat*>(cachedSimpleDateFormat); 6904514f5e3Sopenharmony_ci } 6914514f5e3Sopenharmony_ci return nullptr; 6924514f5e3Sopenharmony_ci} 6934514f5e3Sopenharmony_ci 6944514f5e3Sopenharmony_ci// 13.1.2 ToDateTimeOptions (options, required, defaults) 6954514f5e3Sopenharmony_ciJSHandle<JSObject> JSDateTimeFormat::ToDateTimeOptions(JSThread *thread, const JSHandle<JSTaggedValue> &options, 6964514f5e3Sopenharmony_ci const RequiredOption &required, const DefaultsOption &defaults) 6974514f5e3Sopenharmony_ci{ 6984514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 6994514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 7004514f5e3Sopenharmony_ci 7014514f5e3Sopenharmony_ci // 1. If options is undefined, let options be null; otherwise let options be ? ToObject(options). 7024514f5e3Sopenharmony_ci JSHandle<JSObject> optionsResult(thread, JSTaggedValue::Null()); 7034514f5e3Sopenharmony_ci if (!options->IsUndefined()) { 7044514f5e3Sopenharmony_ci optionsResult = JSTaggedValue::ToObject(thread, options); 7054514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 7064514f5e3Sopenharmony_ci } 7074514f5e3Sopenharmony_ci 7084514f5e3Sopenharmony_ci // 2. Let options be ObjectCreate(options). 7094514f5e3Sopenharmony_ci optionsResult = JSObject::ObjectCreate(thread, optionsResult); 7104514f5e3Sopenharmony_ci 7114514f5e3Sopenharmony_ci // 3. Let needDefaults be true. 7124514f5e3Sopenharmony_ci bool needDefaults = true; 7134514f5e3Sopenharmony_ci 7144514f5e3Sopenharmony_ci // 4. If required is "date" or "any", then 7154514f5e3Sopenharmony_ci // a. For each of the property names "weekday", "year", "month", "day", do 7164514f5e3Sopenharmony_ci // i. Let prop be the property name. 7174514f5e3Sopenharmony_ci // ii. Let value be ? Get(options, prop). 7184514f5e3Sopenharmony_ci // iii. If value is not undefined, let needDefaults be false. 7194514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 7204514f5e3Sopenharmony_ci if (required == RequiredOption::DATE || required == RequiredOption::ANY) { 7214514f5e3Sopenharmony_ci JSHandle<TaggedArray> array = factory->NewTaggedArray(CAPACITY_4); 7224514f5e3Sopenharmony_ci array->Set(thread, 0, globalConst->GetHandledWeekdayString()); 7234514f5e3Sopenharmony_ci array->Set(thread, 1, globalConst->GetHandledYearString()); 7244514f5e3Sopenharmony_ci array->Set(thread, 2, globalConst->GetHandledMonthString()); // 2 means the third slot 7254514f5e3Sopenharmony_ci array->Set(thread, 3, globalConst->GetHandledDayString()); // 3 means the fourth slot 7264514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 7274514f5e3Sopenharmony_ci uint32_t len = array->GetLength(); 7284514f5e3Sopenharmony_ci for (uint32_t i = 0; i < len; i++) { 7294514f5e3Sopenharmony_ci key.Update(array->Get(thread, i)); 7304514f5e3Sopenharmony_ci OperationResult operationResult = JSObject::GetProperty(thread, optionsResult, key); 7314514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 7324514f5e3Sopenharmony_ci if (!operationResult.GetValue()->IsUndefined()) { 7334514f5e3Sopenharmony_ci needDefaults = false; 7344514f5e3Sopenharmony_ci } 7354514f5e3Sopenharmony_ci } 7364514f5e3Sopenharmony_ci } 7374514f5e3Sopenharmony_ci 7384514f5e3Sopenharmony_ci // 5. If required is "time" or "any", then 7394514f5e3Sopenharmony_ci // a. For each of the property names "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits", do 7404514f5e3Sopenharmony_ci // i. Let prop be the property name. 7414514f5e3Sopenharmony_ci // ii. Let value be ? Get(options, prop). 7424514f5e3Sopenharmony_ci // iii. If value is not undefined, let needDefaults be false. 7434514f5e3Sopenharmony_ci if (required == RequiredOption::TIME || required == RequiredOption::ANY) { 7444514f5e3Sopenharmony_ci JSHandle<TaggedArray> array = factory->NewTaggedArray(CAPACITY_5); 7454514f5e3Sopenharmony_ci array->Set(thread, 0, globalConst->GetHandledDayPeriodString()); 7464514f5e3Sopenharmony_ci array->Set(thread, 1, globalConst->GetHandledHourString()); 7474514f5e3Sopenharmony_ci array->Set(thread, 2, globalConst->GetHandledMinuteString()); // 2 means the second slot 7484514f5e3Sopenharmony_ci array->Set(thread, 3, globalConst->GetHandledSecondString()); // 3 means the third slot 7494514f5e3Sopenharmony_ci array->Set(thread, 4, globalConst->GetHandledFractionalSecondDigitsString()); // 4 means the fourth slot 7504514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 7514514f5e3Sopenharmony_ci uint32_t len = array->GetLength(); 7524514f5e3Sopenharmony_ci for (uint32_t i = 0; i < len; i++) { 7534514f5e3Sopenharmony_ci key.Update(array->Get(thread, i)); 7544514f5e3Sopenharmony_ci OperationResult operationResult = JSObject::GetProperty(thread, optionsResult, key); 7554514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 7564514f5e3Sopenharmony_ci if (!operationResult.GetValue()->IsUndefined()) { 7574514f5e3Sopenharmony_ci needDefaults = false; 7584514f5e3Sopenharmony_ci } 7594514f5e3Sopenharmony_ci } 7604514f5e3Sopenharmony_ci } 7614514f5e3Sopenharmony_ci 7624514f5e3Sopenharmony_ci // Let dateStyle/timeStyle be ? Get(options, "dateStyle"/"timeStyle"). 7634514f5e3Sopenharmony_ci OperationResult dateStyleResult = 7644514f5e3Sopenharmony_ci JSObject::GetProperty(thread, optionsResult, globalConst->GetHandledDateStyleString()); 7654514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 7664514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> dateStyle = dateStyleResult.GetValue(); 7674514f5e3Sopenharmony_ci OperationResult timeStyleResult = 7684514f5e3Sopenharmony_ci JSObject::GetProperty(thread, optionsResult, globalConst->GetHandledTimeStyleString()); 7694514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 7704514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> timeStyle = timeStyleResult.GetValue(); 7714514f5e3Sopenharmony_ci 7724514f5e3Sopenharmony_ci // If dateStyle is not undefined or timeStyle is not undefined, let needDefaults be false. 7734514f5e3Sopenharmony_ci if (!dateStyle->IsUndefined() || !timeStyle->IsUndefined()) { 7744514f5e3Sopenharmony_ci needDefaults = false; 7754514f5e3Sopenharmony_ci } 7764514f5e3Sopenharmony_ci 7774514f5e3Sopenharmony_ci // If required is "date"/"time" and timeStyle is not undefined, throw a TypeError exception. 7784514f5e3Sopenharmony_ci if (required == RequiredOption::DATE && !timeStyle->IsUndefined()) { 7794514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "timeStyle is not undefined", optionsResult); 7804514f5e3Sopenharmony_ci } 7814514f5e3Sopenharmony_ci if (required == RequiredOption::TIME && !dateStyle->IsUndefined()) { 7824514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "dateStyle is not undefined", optionsResult); 7834514f5e3Sopenharmony_ci } 7844514f5e3Sopenharmony_ci 7854514f5e3Sopenharmony_ci // 6. If needDefaults is true and defaults is either "date" or "all", then 7864514f5e3Sopenharmony_ci // a. For each of the property names "year", "month", "day", do 7874514f5e3Sopenharmony_ci // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric"). 7884514f5e3Sopenharmony_ci if (needDefaults && (defaults == DefaultsOption::DATE || defaults == DefaultsOption::ALL)) { 7894514f5e3Sopenharmony_ci JSHandle<TaggedArray> array = factory->NewTaggedArray(CAPACITY_3); 7904514f5e3Sopenharmony_ci array->Set(thread, 0, globalConst->GetHandledYearString()); 7914514f5e3Sopenharmony_ci array->Set(thread, 1, globalConst->GetHandledMonthString()); 7924514f5e3Sopenharmony_ci array->Set(thread, 2, globalConst->GetHandledDayString()); // 2 means the third slot 7934514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 7944514f5e3Sopenharmony_ci uint32_t len = array->GetLength(); 7954514f5e3Sopenharmony_ci for (uint32_t i = 0; i < len; i++) { 7964514f5e3Sopenharmony_ci key.Update(array->Get(thread, i)); 7974514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, optionsResult, key, globalConst->GetHandledNumericString()); 7984514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 7994514f5e3Sopenharmony_ci } 8004514f5e3Sopenharmony_ci } 8014514f5e3Sopenharmony_ci 8024514f5e3Sopenharmony_ci // 7. If needDefaults is true and defaults is either "time" or "all", then 8034514f5e3Sopenharmony_ci // a. For each of the property names "hour", "minute", "second", do 8044514f5e3Sopenharmony_ci // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric"). 8054514f5e3Sopenharmony_ci if (needDefaults && (defaults == DefaultsOption::TIME || defaults == DefaultsOption::ALL)) { 8064514f5e3Sopenharmony_ci JSHandle<TaggedArray> array = factory->NewTaggedArray(CAPACITY_3); 8074514f5e3Sopenharmony_ci array->Set(thread, 0, globalConst->GetHandledHourString()); 8084514f5e3Sopenharmony_ci array->Set(thread, 1, globalConst->GetHandledMinuteString()); 8094514f5e3Sopenharmony_ci array->Set(thread, 2, globalConst->GetHandledSecondString()); // 2 means the third slot 8104514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 8114514f5e3Sopenharmony_ci uint32_t len = array->GetLength(); 8124514f5e3Sopenharmony_ci for (uint32_t i = 0; i < len; i++) { 8134514f5e3Sopenharmony_ci key.Update(array->Get(thread, i)); 8144514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, optionsResult, key, globalConst->GetHandledNumericString()); 8154514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 8164514f5e3Sopenharmony_ci } 8174514f5e3Sopenharmony_ci } 8184514f5e3Sopenharmony_ci 8194514f5e3Sopenharmony_ci // 8. Return options. 8204514f5e3Sopenharmony_ci return optionsResult; 8214514f5e3Sopenharmony_ci} 8224514f5e3Sopenharmony_ci 8234514f5e3Sopenharmony_civoid JSDateTimeFormat::ToDateTimeSkeleton(JSThread *thread, const std::vector<std::string> &options, 8244514f5e3Sopenharmony_ci std::string &skeleton, HourCycleOption hc, 8254514f5e3Sopenharmony_ci const RequiredOption &required, const DefaultsOption &defaults) 8264514f5e3Sopenharmony_ci{ 8274514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 8284514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 8294514f5e3Sopenharmony_ci 8304514f5e3Sopenharmony_ci // 1. Let needDefaults be true. 8314514f5e3Sopenharmony_ci bool needDefaults = true; 8324514f5e3Sopenharmony_ci 8334514f5e3Sopenharmony_ci // 2. If required is "date" or "any", then 8344514f5e3Sopenharmony_ci // a. For each of the property names "weekday", "year", "month", "day", do 8354514f5e3Sopenharmony_ci // i. Let prop be the property name. 8364514f5e3Sopenharmony_ci // ii. Let value be ? Get(options, prop). 8374514f5e3Sopenharmony_ci // iii. If value is not undefined, let needDefaults be false. 8384514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 8394514f5e3Sopenharmony_ci if (required == RequiredOption::DATE || required == RequiredOption::ANY) { 8404514f5e3Sopenharmony_ci JSHandle<TaggedArray> array = factory->NewTaggedArray(CAPACITY_4); 8414514f5e3Sopenharmony_ci array->Set(thread, 0, globalConst->GetHandledWeekdayString()); 8424514f5e3Sopenharmony_ci array->Set(thread, 1, globalConst->GetHandledYearString()); 8434514f5e3Sopenharmony_ci array->Set(thread, 2, globalConst->GetHandledMonthString()); // 2 means the third slot 8444514f5e3Sopenharmony_ci array->Set(thread, 3, globalConst->GetHandledDayString()); // 3 means the fourth slot 8454514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 8464514f5e3Sopenharmony_ci uint32_t len = array->GetLength(); 8474514f5e3Sopenharmony_ci for (uint32_t i = 0; i < len; i++) { 8484514f5e3Sopenharmony_ci key.Update(array->Get(thread, i)); 8494514f5e3Sopenharmony_ci std::string result = EcmaStringAccessor(key.GetTaggedValue()).ToStdString(); 8504514f5e3Sopenharmony_ci auto it = std::find(options.begin(), options.end(), result); 8514514f5e3Sopenharmony_ci if (it != options.end()) { 8524514f5e3Sopenharmony_ci needDefaults = false; 8534514f5e3Sopenharmony_ci break; 8544514f5e3Sopenharmony_ci } 8554514f5e3Sopenharmony_ci } 8564514f5e3Sopenharmony_ci } 8574514f5e3Sopenharmony_ci 8584514f5e3Sopenharmony_ci // 3. If required is "time" or "any", then 8594514f5e3Sopenharmony_ci // a. For each of the property names "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits", do 8604514f5e3Sopenharmony_ci // i. Let prop be the property name. 8614514f5e3Sopenharmony_ci // ii. Let value be ? Get(options, prop). 8624514f5e3Sopenharmony_ci // iii. If value is not undefined, let needDefaults be false. 8634514f5e3Sopenharmony_ci if (required == RequiredOption::TIME || required == RequiredOption::ANY) { 8644514f5e3Sopenharmony_ci JSHandle<TaggedArray> array = factory->NewTaggedArray(CAPACITY_5); 8654514f5e3Sopenharmony_ci array->Set(thread, 0, globalConst->GetHandledDayPeriodString()); 8664514f5e3Sopenharmony_ci array->Set(thread, 1, globalConst->GetHandledHourString()); 8674514f5e3Sopenharmony_ci array->Set(thread, 2, globalConst->GetHandledMinuteString()); // 2 means the second slot 8684514f5e3Sopenharmony_ci array->Set(thread, 3, globalConst->GetHandledSecondString()); // 3 means the third slot 8694514f5e3Sopenharmony_ci array->Set(thread, 4, globalConst->GetHandledFractionalSecondDigitsString()); // 4 means the fourth slot 8704514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 8714514f5e3Sopenharmony_ci uint32_t len = array->GetLength(); 8724514f5e3Sopenharmony_ci for (uint32_t i = 0; i < len; i++) { 8734514f5e3Sopenharmony_ci key.Update(array->Get(thread, i)); 8744514f5e3Sopenharmony_ci std::string result = EcmaStringAccessor(key.GetTaggedValue()).ToStdString(); 8754514f5e3Sopenharmony_ci auto it = std::find(options.begin(), options.end(), result); 8764514f5e3Sopenharmony_ci if (it != options.end()) { 8774514f5e3Sopenharmony_ci needDefaults = false; 8784514f5e3Sopenharmony_ci break; 8794514f5e3Sopenharmony_ci } 8804514f5e3Sopenharmony_ci } 8814514f5e3Sopenharmony_ci } 8824514f5e3Sopenharmony_ci 8834514f5e3Sopenharmony_ci // 4. If needDefaults is true and defaults is either "date" or "all", then 8844514f5e3Sopenharmony_ci // skeleton += "year", "month", "day" 8854514f5e3Sopenharmony_ci if (needDefaults && (defaults == DefaultsOption::DATE || defaults == DefaultsOption::ALL)) { 8864514f5e3Sopenharmony_ci skeleton += "yMd"; 8874514f5e3Sopenharmony_ci } 8884514f5e3Sopenharmony_ci 8894514f5e3Sopenharmony_ci // 5. If needDefaults is true and defaults is either "time" or "all", then 8904514f5e3Sopenharmony_ci // skeleton += "hour", "minute", "second" 8914514f5e3Sopenharmony_ci if (needDefaults && (defaults == DefaultsOption::TIME || defaults == DefaultsOption::ALL)) { 8924514f5e3Sopenharmony_ci switch (hc) { 8934514f5e3Sopenharmony_ci case HourCycleOption::H12: 8944514f5e3Sopenharmony_ci skeleton += "hms"; 8954514f5e3Sopenharmony_ci break; 8964514f5e3Sopenharmony_ci case HourCycleOption::H23: 8974514f5e3Sopenharmony_ci case HourCycleOption::UNDEFINED: 8984514f5e3Sopenharmony_ci skeleton += "Hms"; 8994514f5e3Sopenharmony_ci break; 9004514f5e3Sopenharmony_ci case HourCycleOption::H11: 9014514f5e3Sopenharmony_ci skeleton += "Kms"; 9024514f5e3Sopenharmony_ci break; 9034514f5e3Sopenharmony_ci case HourCycleOption::H24: 9044514f5e3Sopenharmony_ci skeleton += "kms"; 9054514f5e3Sopenharmony_ci break; 9064514f5e3Sopenharmony_ci default: 9074514f5e3Sopenharmony_ci break; 9084514f5e3Sopenharmony_ci } 9094514f5e3Sopenharmony_ci } 9104514f5e3Sopenharmony_ci} 9114514f5e3Sopenharmony_ci 9124514f5e3Sopenharmony_ci// 13.1.7 FormatDateTime(dateTimeFormat, x) 9134514f5e3Sopenharmony_ciJSHandle<EcmaString> JSDateTimeFormat::FormatDateTime(JSThread *thread, 9144514f5e3Sopenharmony_ci const JSHandle<JSDateTimeFormat> &dateTimeFormat, double x) 9154514f5e3Sopenharmony_ci{ 9164514f5e3Sopenharmony_ci icu::SimpleDateFormat *simpleDateFormat = dateTimeFormat->GetIcuSimpleDateFormat(); 9174514f5e3Sopenharmony_ci JSHandle<EcmaString> res = FormatDateTime(thread, simpleDateFormat, x); 9184514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread); 9194514f5e3Sopenharmony_ci return res; 9204514f5e3Sopenharmony_ci} 9214514f5e3Sopenharmony_ci 9224514f5e3Sopenharmony_ciJSHandle<EcmaString> JSDateTimeFormat::FormatDateTime(JSThread *thread, 9234514f5e3Sopenharmony_ci const icu::SimpleDateFormat *simpleDateFormat, double x) 9244514f5e3Sopenharmony_ci{ 9254514f5e3Sopenharmony_ci // 1. Let parts be ? PartitionDateTimePattern(dateTimeFormat, x). 9264514f5e3Sopenharmony_ci double xValue = JSDate::TimeClip(x); 9274514f5e3Sopenharmony_ci if (std::isnan(xValue)) { 9284514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid time value", thread->GetEcmaVM()->GetFactory()->GetEmptyString()); 9294514f5e3Sopenharmony_ci } 9304514f5e3Sopenharmony_ci 9314514f5e3Sopenharmony_ci // 2. Let result be the empty String. 9324514f5e3Sopenharmony_ci icu::UnicodeString result; 9334514f5e3Sopenharmony_ci 9344514f5e3Sopenharmony_ci // 3. Set result to the string-concatenation of result and part.[[Value]]. 9354514f5e3Sopenharmony_ci { 9364514f5e3Sopenharmony_ci ThreadNativeScope nativeScope(thread); 9374514f5e3Sopenharmony_ci simpleDateFormat->format(xValue, result); 9384514f5e3Sopenharmony_ci } 9394514f5e3Sopenharmony_ci 9404514f5e3Sopenharmony_ci // 4. Return result. 9414514f5e3Sopenharmony_ci return intl::LocaleHelper::UStringToString(thread, result); 9424514f5e3Sopenharmony_ci} 9434514f5e3Sopenharmony_ci 9444514f5e3Sopenharmony_ci// 13.1.8 FormatDateTimeToParts (dateTimeFormat, x) 9454514f5e3Sopenharmony_ciJSHandle<JSArray> JSDateTimeFormat::FormatDateTimeToParts(JSThread *thread, 9464514f5e3Sopenharmony_ci const JSHandle<JSDateTimeFormat> &dateTimeFormat, double x) 9474514f5e3Sopenharmony_ci{ 9484514f5e3Sopenharmony_ci icu::SimpleDateFormat *simpleDateFormat = dateTimeFormat->GetIcuSimpleDateFormat(); 9494514f5e3Sopenharmony_ci ASSERT(simpleDateFormat != nullptr); 9504514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 9514514f5e3Sopenharmony_ci icu::FieldPositionIterator fieldPositionIter; 9524514f5e3Sopenharmony_ci icu::UnicodeString formattedParts; 9534514f5e3Sopenharmony_ci { 9544514f5e3Sopenharmony_ci ThreadNativeScope nativeScope(thread); 9554514f5e3Sopenharmony_ci simpleDateFormat->format(x, formattedParts, &fieldPositionIter, status); 9564514f5e3Sopenharmony_ci } 9574514f5e3Sopenharmony_ci if (U_FAILURE(status) != 0) { 9584514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "format failed", thread->GetEcmaVM()->GetFactory()->NewJSArray()); 9594514f5e3Sopenharmony_ci } 9604514f5e3Sopenharmony_ci 9614514f5e3Sopenharmony_ci // 2. Let result be ArrayCreate(0). 9624514f5e3Sopenharmony_ci JSHandle<JSArray> result(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); 9634514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 9644514f5e3Sopenharmony_ci if (formattedParts.isBogus()) { 9654514f5e3Sopenharmony_ci return result; 9664514f5e3Sopenharmony_ci } 9674514f5e3Sopenharmony_ci 9684514f5e3Sopenharmony_ci // 3. Let n be 0. 9694514f5e3Sopenharmony_ci int32_t index = 0; 9704514f5e3Sopenharmony_ci int32_t preEdgePos = 0; 9714514f5e3Sopenharmony_ci std::vector<CommonDateFormatPart> parts; 9724514f5e3Sopenharmony_ci icu::FieldPosition fieldPosition; 9734514f5e3Sopenharmony_ci while (fieldPositionIter.next(fieldPosition)) { 9744514f5e3Sopenharmony_ci int32_t fField = fieldPosition.getField(); 9754514f5e3Sopenharmony_ci int32_t fBeginIndex = fieldPosition.getBeginIndex(); 9764514f5e3Sopenharmony_ci int32_t fEndIndex = fieldPosition.getEndIndex(); 9774514f5e3Sopenharmony_ci if (preEdgePos < fBeginIndex) { 9784514f5e3Sopenharmony_ci parts.emplace_back(CommonDateFormatPart(fField, preEdgePos, fBeginIndex, index, true)); 9794514f5e3Sopenharmony_ci ++index; 9804514f5e3Sopenharmony_ci } 9814514f5e3Sopenharmony_ci parts.emplace_back(CommonDateFormatPart(fField, fBeginIndex, fEndIndex, index, false)); 9824514f5e3Sopenharmony_ci preEdgePos = fEndIndex; 9834514f5e3Sopenharmony_ci ++index; 9844514f5e3Sopenharmony_ci } 9854514f5e3Sopenharmony_ci int32_t length = formattedParts.length(); 9864514f5e3Sopenharmony_ci if (preEdgePos < length) { 9874514f5e3Sopenharmony_ci parts.emplace_back(CommonDateFormatPart(-1, preEdgePos, length, index, true)); 9884514f5e3Sopenharmony_ci } 9894514f5e3Sopenharmony_ci JSMutableHandle<EcmaString> substring(thread, JSTaggedValue::Undefined()); 9904514f5e3Sopenharmony_ci 9914514f5e3Sopenharmony_ci // 4. For each part in parts, do 9924514f5e3Sopenharmony_ci for (auto part : parts) { 9934514f5e3Sopenharmony_ci substring.Update(intl::LocaleHelper::UStringToString(thread, formattedParts, part.fBeginIndex, 9944514f5e3Sopenharmony_ci part.fEndIndex).GetTaggedValue()); 9954514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 9964514f5e3Sopenharmony_ci // Let O be ObjectCreate(%ObjectPrototype%). 9974514f5e3Sopenharmony_ci // Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]). 9984514f5e3Sopenharmony_ci // Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]). 9994514f5e3Sopenharmony_ci // Perform ! CreateDataProperty(result, ! ToString(n), O). 10004514f5e3Sopenharmony_ci if (part.isPreExist) { 10014514f5e3Sopenharmony_ci JSLocale::PutElement(thread, part.index, result, ConvertFieldIdToDateType(thread, -1), 10024514f5e3Sopenharmony_ci JSHandle<JSTaggedValue>::Cast(substring)); 10034514f5e3Sopenharmony_ci } else { 10044514f5e3Sopenharmony_ci JSLocale::PutElement(thread, part.index, result, ConvertFieldIdToDateType(thread, part.fField), 10054514f5e3Sopenharmony_ci JSHandle<JSTaggedValue>::Cast(substring)); 10064514f5e3Sopenharmony_ci } 10074514f5e3Sopenharmony_ci } 10084514f5e3Sopenharmony_ci 10094514f5e3Sopenharmony_ci // 5. Return result. 10104514f5e3Sopenharmony_ci return result; 10114514f5e3Sopenharmony_ci} 10124514f5e3Sopenharmony_ci 10134514f5e3Sopenharmony_ci// 13.1.10 UnwrapDateTimeFormat(dtf) 10144514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSDateTimeFormat::UnwrapDateTimeFormat(JSThread *thread, 10154514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &dateTimeFormat) 10164514f5e3Sopenharmony_ci{ 10174514f5e3Sopenharmony_ci // 1. Assert: Type(dtf) is Object. 10184514f5e3Sopenharmony_ci ASSERT_PRINT(dateTimeFormat->IsJSObject(), "dateTimeFormat is not object"); 10194514f5e3Sopenharmony_ci 10204514f5e3Sopenharmony_ci // 2. If dateTimeFormat does not have an [[InitializedDateTimeFormat]] internal slot 10214514f5e3Sopenharmony_ci // and ? InstanceofOperator(dateTimeFormat, %DateTimeFormat%) is true, then 10224514f5e3Sopenharmony_ci // a. Let dateTimeFormat be ? Get(dateTimeFormat, %Intl%.[[FallbackSymbol]]). 10234514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 10244514f5e3Sopenharmony_ci bool isInstanceOf = JSFunction::OrdinaryHasInstance(thread, env->GetDateTimeFormatFunction(), dateTimeFormat); 10254514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, dateTimeFormat); 10264514f5e3Sopenharmony_ci if (!dateTimeFormat->IsJSDateTimeFormat() && isInstanceOf) { 10274514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key(thread, JSHandle<JSIntl>::Cast(env->GetIntlFunction())->GetFallbackSymbol()); 10284514f5e3Sopenharmony_ci OperationResult operationResult = JSTaggedValue::GetProperty(thread, dateTimeFormat, key); 10294514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, dateTimeFormat); 10304514f5e3Sopenharmony_ci return operationResult.GetValue(); 10314514f5e3Sopenharmony_ci } 10324514f5e3Sopenharmony_ci 10334514f5e3Sopenharmony_ci // 3. Perform ? RequireInternalSlot(dateTimeFormat, [[InitializedDateTimeFormat]]). 10344514f5e3Sopenharmony_ci if (!dateTimeFormat->IsJSDateTimeFormat()) { 10354514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "is not JSDateTimeFormat", 10364514f5e3Sopenharmony_ci JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception())); 10374514f5e3Sopenharmony_ci } 10384514f5e3Sopenharmony_ci 10394514f5e3Sopenharmony_ci // 4. Return dateTimeFormat. 10404514f5e3Sopenharmony_ci return dateTimeFormat; 10414514f5e3Sopenharmony_ci} 10424514f5e3Sopenharmony_ci 10434514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> ToHourCycleEcmaString(JSThread *thread, HourCycleOption hc) 10444514f5e3Sopenharmony_ci{ 10454514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 10464514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 10474514f5e3Sopenharmony_ci switch (hc) { 10484514f5e3Sopenharmony_ci case HourCycleOption::H11: 10494514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledH11String().GetTaggedValue()); 10504514f5e3Sopenharmony_ci break; 10514514f5e3Sopenharmony_ci case HourCycleOption::H12: 10524514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledH12String().GetTaggedValue()); 10534514f5e3Sopenharmony_ci break; 10544514f5e3Sopenharmony_ci case HourCycleOption::H23: 10554514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledH23String().GetTaggedValue()); 10564514f5e3Sopenharmony_ci break; 10574514f5e3Sopenharmony_ci case HourCycleOption::H24: 10584514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledH24String().GetTaggedValue()); 10594514f5e3Sopenharmony_ci break; 10604514f5e3Sopenharmony_ci default: 10614514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 10624514f5e3Sopenharmony_ci UNREACHABLE(); 10634514f5e3Sopenharmony_ci } 10644514f5e3Sopenharmony_ci return result; 10654514f5e3Sopenharmony_ci} 10664514f5e3Sopenharmony_ci 10674514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> ToDateTimeStyleEcmaString(JSThread *thread, DateTimeStyleOption style) 10684514f5e3Sopenharmony_ci{ 10694514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 10704514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 10714514f5e3Sopenharmony_ci switch (style) { 10724514f5e3Sopenharmony_ci case DateTimeStyleOption::FULL: 10734514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledFullString().GetTaggedValue()); 10744514f5e3Sopenharmony_ci break; 10754514f5e3Sopenharmony_ci case DateTimeStyleOption::LONG: 10764514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledLongString().GetTaggedValue()); 10774514f5e3Sopenharmony_ci break; 10784514f5e3Sopenharmony_ci case DateTimeStyleOption::MEDIUM: 10794514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledMediumString().GetTaggedValue()); 10804514f5e3Sopenharmony_ci break; 10814514f5e3Sopenharmony_ci case DateTimeStyleOption::SHORT: 10824514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledShortString().GetTaggedValue()); 10834514f5e3Sopenharmony_ci break; 10844514f5e3Sopenharmony_ci default: 10854514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 10864514f5e3Sopenharmony_ci UNREACHABLE(); 10874514f5e3Sopenharmony_ci } 10884514f5e3Sopenharmony_ci return result; 10894514f5e3Sopenharmony_ci} 10904514f5e3Sopenharmony_ci 10914514f5e3Sopenharmony_ci// 13.4.5 Intl.DateTimeFormat.prototype.resolvedOptions () 10924514f5e3Sopenharmony_civoid JSDateTimeFormat::ResolvedOptions(JSThread *thread, const JSHandle<JSDateTimeFormat> &dateTimeFormat, 10934514f5e3Sopenharmony_ci const JSHandle<JSObject> &options) 10944514f5e3Sopenharmony_ci{ // Table 8: Resolved Options of DateTimeFormat Instances 10954514f5e3Sopenharmony_ci // Internal Slot Property 10964514f5e3Sopenharmony_ci // [[Locale]] "locale" 10974514f5e3Sopenharmony_ci // [[Calendar]] "calendar" 10984514f5e3Sopenharmony_ci // [[NumberingSystem]] "numberingSystem" 10994514f5e3Sopenharmony_ci // [[TimeZone]] "timeZone" 11004514f5e3Sopenharmony_ci // [[HourCycle]] "hourCycle" 11014514f5e3Sopenharmony_ci // "hour12" 11024514f5e3Sopenharmony_ci // [[Weekday]] "weekday" 11034514f5e3Sopenharmony_ci // [[Era]] "era" 11044514f5e3Sopenharmony_ci // [[Year]] "year" 11054514f5e3Sopenharmony_ci // [[Month]] "month" 11064514f5e3Sopenharmony_ci // [[Day]] "day" 11074514f5e3Sopenharmony_ci // [[Hour]] "hour" 11084514f5e3Sopenharmony_ci // [[Minute]] "minute" 11094514f5e3Sopenharmony_ci // [[Second]] "second" 11104514f5e3Sopenharmony_ci // [[TimeZoneName]] "timeZoneName" 11114514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 11124514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 11134514f5e3Sopenharmony_ci 11144514f5e3Sopenharmony_ci // 5. For each row of Table 8, except the header row, in table order, do 11154514f5e3Sopenharmony_ci // Let p be the Property value of the current row. 11164514f5e3Sopenharmony_ci // [[Locale]] 11174514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> locale(thread, dateTimeFormat->GetLocale()); 11184514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> property = globalConst->GetHandledLocaleString(); 11194514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, locale); 11204514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11214514f5e3Sopenharmony_ci // [[Calendar]] 11224514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> calendarValue(thread, dateTimeFormat->GetCalendar()); 11234514f5e3Sopenharmony_ci icu::SimpleDateFormat *icuSimpleDateFormat = dateTimeFormat->GetIcuSimpleDateFormat(); 11244514f5e3Sopenharmony_ci const icu::Calendar *calendar = icuSimpleDateFormat->getCalendar(); 11254514f5e3Sopenharmony_ci std::string icuCalendar = calendar->getType(); 11264514f5e3Sopenharmony_ci if (icuCalendar == "gregorian") { 11274514f5e3Sopenharmony_ci if (dateTimeFormat->GetIso8601().IsTrue()) { 11284514f5e3Sopenharmony_ci calendarValue.Update(globalConst->GetHandledIso8601String().GetTaggedValue()); 11294514f5e3Sopenharmony_ci } else { 11304514f5e3Sopenharmony_ci calendarValue.Update(globalConst->GetHandledGregoryString().GetTaggedValue()); 11314514f5e3Sopenharmony_ci } 11324514f5e3Sopenharmony_ci } else if (icuCalendar == "ethiopic-amete-alem") { 11334514f5e3Sopenharmony_ci calendarValue.Update(globalConst->GetHandledEthioaaString().GetTaggedValue()); 11344514f5e3Sopenharmony_ci } else if (icuCalendar.length() != 0) { 11354514f5e3Sopenharmony_ci calendarValue.Update(factory->NewFromStdString(icuCalendar).GetTaggedValue()); 11364514f5e3Sopenharmony_ci } 11374514f5e3Sopenharmony_ci property = globalConst->GetHandledCalendarString(); 11384514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, calendarValue); 11394514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11404514f5e3Sopenharmony_ci // [[NumberingSystem]] 11414514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> numberingSystem(thread, dateTimeFormat->GetNumberingSystem()); 11424514f5e3Sopenharmony_ci if (numberingSystem->IsUndefined()) { 11434514f5e3Sopenharmony_ci numberingSystem = globalConst->GetHandledLatnString(); 11444514f5e3Sopenharmony_ci } 11454514f5e3Sopenharmony_ci property = globalConst->GetHandledNumberingSystemString(); 11464514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, numberingSystem); 11474514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11484514f5e3Sopenharmony_ci // [[TimeZone]] 11494514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> timezoneValue(thread, dateTimeFormat->GetTimeZone()); 11504514f5e3Sopenharmony_ci const icu::TimeZone &icuTZ = calendar->getTimeZone(); 11514514f5e3Sopenharmony_ci icu::UnicodeString timezone; 11524514f5e3Sopenharmony_ci icuTZ.getID(timezone); 11534514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 11544514f5e3Sopenharmony_ci icu::UnicodeString canonicalTimezone; 11554514f5e3Sopenharmony_ci icu::TimeZone::getCanonicalID(timezone, canonicalTimezone, status); 11564514f5e3Sopenharmony_ci if (U_SUCCESS(status) != 0) { 11574514f5e3Sopenharmony_ci if ((canonicalTimezone == UNICODE_STRING_SIMPLE("Etc/UTC")) != 0 || 11584514f5e3Sopenharmony_ci (canonicalTimezone == UNICODE_STRING_SIMPLE("Etc/GMT")) != 0) { 11594514f5e3Sopenharmony_ci timezoneValue.Update(globalConst->GetUTCString()); 11604514f5e3Sopenharmony_ci } else { 11614514f5e3Sopenharmony_ci timezoneValue.Update(intl::LocaleHelper::UStringToString(thread, canonicalTimezone).GetTaggedValue()); 11624514f5e3Sopenharmony_ci } 11634514f5e3Sopenharmony_ci } 11644514f5e3Sopenharmony_ci property = globalConst->GetHandledTimeZoneString(); 11654514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, timezoneValue); 11664514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11674514f5e3Sopenharmony_ci // [[HourCycle]] 11684514f5e3Sopenharmony_ci // For web compatibility reasons, if the property "hourCycle" is set, the "hour12" property should be set to true 11694514f5e3Sopenharmony_ci // when "hourCycle" is "h11" or "h12", or to false when "hourCycle" is "h23" or "h24". 11704514f5e3Sopenharmony_ci // i. Let hc be dtf.[[HourCycle]]. 11714514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> hcValue; 11724514f5e3Sopenharmony_ci HourCycleOption hc = dateTimeFormat->GetHourCycle(); 11734514f5e3Sopenharmony_ci if (hc != HourCycleOption::UNDEFINED) { 11744514f5e3Sopenharmony_ci property = globalConst->GetHandledHourCycleString(); 11754514f5e3Sopenharmony_ci hcValue = ToHourCycleEcmaString(thread, dateTimeFormat->GetHourCycle()); 11764514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, hcValue); 11774514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11784514f5e3Sopenharmony_ci if (hc == HourCycleOption::H11 || hc == HourCycleOption::H12) { 11794514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> trueValue(thread, JSTaggedValue::True()); 11804514f5e3Sopenharmony_ci hcValue = trueValue; 11814514f5e3Sopenharmony_ci } else if (hc == HourCycleOption::H23 || hc == HourCycleOption::H24) { 11824514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> falseValue(thread, JSTaggedValue::False()); 11834514f5e3Sopenharmony_ci hcValue = falseValue; 11844514f5e3Sopenharmony_ci } 11854514f5e3Sopenharmony_ci property = globalConst->GetHandledHour12String(); 11864514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, hcValue); 11874514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11884514f5e3Sopenharmony_ci } 11894514f5e3Sopenharmony_ci // [[DateStyle]], [[TimeStyle]]. 11904514f5e3Sopenharmony_ci if (dateTimeFormat->GetDateStyle() == DateTimeStyleOption::UNDEFINED && 11914514f5e3Sopenharmony_ci dateTimeFormat->GetTimeStyle() == DateTimeStyleOption::UNDEFINED) { 11924514f5e3Sopenharmony_ci icu::UnicodeString patternUnicode; 11934514f5e3Sopenharmony_ci icuSimpleDateFormat->toPattern(patternUnicode); 11944514f5e3Sopenharmony_ci std::string pattern; 11954514f5e3Sopenharmony_ci patternUnicode.toUTF8String(pattern); 11964514f5e3Sopenharmony_ci for (const auto &item : BuildIcuPatternDescs()) { 11974514f5e3Sopenharmony_ci // fractionalSecondsDigits need to be added before timeZoneName. 11984514f5e3Sopenharmony_ci if (item.property == "timeZoneName") { 11994514f5e3Sopenharmony_ci int tmpResult = count(pattern.begin(), pattern.end(), 'S'); 12004514f5e3Sopenharmony_ci int fsd = (tmpResult >= STRING_LENGTH_3) ? STRING_LENGTH_3 : tmpResult; 12014514f5e3Sopenharmony_ci if (fsd > 0) { 12024514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> fsdValue(thread, JSTaggedValue(fsd)); 12034514f5e3Sopenharmony_ci property = globalConst->GetHandledFractionalSecondDigitsString(); 12044514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, fsdValue); 12054514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 12064514f5e3Sopenharmony_ci } 12074514f5e3Sopenharmony_ci } 12084514f5e3Sopenharmony_ci for (const auto &pair : item.pairs) { 12094514f5e3Sopenharmony_ci if (pattern.find(pair.first) != std::string::npos) { 12104514f5e3Sopenharmony_ci hcValue = JSHandle<JSTaggedValue>::Cast(factory->NewFromStdString(pair.second)); 12114514f5e3Sopenharmony_ci property = JSHandle<JSTaggedValue>::Cast(factory->NewFromStdString(item.property)); 12124514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, hcValue); 12134514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 12144514f5e3Sopenharmony_ci break; 12154514f5e3Sopenharmony_ci } 12164514f5e3Sopenharmony_ci } 12174514f5e3Sopenharmony_ci } 12184514f5e3Sopenharmony_ci } 12194514f5e3Sopenharmony_ci if (dateTimeFormat->GetDateStyle() != DateTimeStyleOption::UNDEFINED) { 12204514f5e3Sopenharmony_ci property = globalConst->GetHandledDateStyleString(); 12214514f5e3Sopenharmony_ci hcValue = ToDateTimeStyleEcmaString(thread, dateTimeFormat->GetDateStyle()); 12224514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, hcValue); 12234514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 12244514f5e3Sopenharmony_ci } 12254514f5e3Sopenharmony_ci if (dateTimeFormat->GetTimeStyle() != DateTimeStyleOption::UNDEFINED) { 12264514f5e3Sopenharmony_ci property = globalConst->GetHandledTimeStyleString(); 12274514f5e3Sopenharmony_ci hcValue = ToDateTimeStyleEcmaString(thread, dateTimeFormat->GetTimeStyle()); 12284514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, hcValue); 12294514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 12304514f5e3Sopenharmony_ci } 12314514f5e3Sopenharmony_ci} 12324514f5e3Sopenharmony_ci 12334514f5e3Sopenharmony_ci// Use dateInterval(x, y) construct datetimeformatrange 12344514f5e3Sopenharmony_ciicu::FormattedDateInterval JSDateTimeFormat::ConstructDTFRange(JSThread *thread, const JSHandle<JSDateTimeFormat> &dtf, 12354514f5e3Sopenharmony_ci double x, double y) 12364514f5e3Sopenharmony_ci{ 12374514f5e3Sopenharmony_ci std::unique_ptr<icu::DateIntervalFormat> dateIntervalFormat(ConstructDateIntervalFormat(dtf)); 12384514f5e3Sopenharmony_ci if (dateIntervalFormat == nullptr) { 12394514f5e3Sopenharmony_ci icu::FormattedDateInterval emptyValue; 12404514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "create dateIntervalFormat failed", emptyValue); 12414514f5e3Sopenharmony_ci } 12424514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 12434514f5e3Sopenharmony_ci icu::DateInterval dateInterval(x, y); 12444514f5e3Sopenharmony_ci icu::FormattedDateInterval formatted = dateIntervalFormat->formatToValue(dateInterval, status); 12454514f5e3Sopenharmony_ci return formatted; 12464514f5e3Sopenharmony_ci} 12474514f5e3Sopenharmony_ci 12484514f5e3Sopenharmony_ciJSHandle<EcmaString> JSDateTimeFormat::NormDateTimeRange(JSThread *thread, const JSHandle<JSDateTimeFormat> &dtf, 12494514f5e3Sopenharmony_ci double x, double y) 12504514f5e3Sopenharmony_ci{ 12514514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 12524514f5e3Sopenharmony_ci JSHandle<EcmaString> result = factory->GetEmptyString(); 12534514f5e3Sopenharmony_ci // 1. Let x be TimeClip(x). 12544514f5e3Sopenharmony_ci x = JSDate::TimeClip(x); 12554514f5e3Sopenharmony_ci // 2. If x is NaN, throw a RangeError exception. 12564514f5e3Sopenharmony_ci if (std::isnan(x)) { 12574514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "x is NaN", result); 12584514f5e3Sopenharmony_ci } 12594514f5e3Sopenharmony_ci // 3. Let y be TimeClip(y). 12604514f5e3Sopenharmony_ci y = JSDate::TimeClip(y); 12614514f5e3Sopenharmony_ci // 4. If y is NaN, throw a RangeError exception. 12624514f5e3Sopenharmony_ci if (std::isnan(y)) { 12634514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "y is NaN", result); 12644514f5e3Sopenharmony_ci } 12654514f5e3Sopenharmony_ci 12664514f5e3Sopenharmony_ci icu::FormattedDateInterval formatted = ConstructDTFRange(thread, dtf, x, y); 12674514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread); 12684514f5e3Sopenharmony_ci 12694514f5e3Sopenharmony_ci // Formatted to string. 12704514f5e3Sopenharmony_ci bool outputRange = false; 12714514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 12724514f5e3Sopenharmony_ci icu::UnicodeString formatResult = formatted.toString(status); 12734514f5e3Sopenharmony_ci if (U_FAILURE(status) != 0) { 12744514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "format to string failed", 12754514f5e3Sopenharmony_ci thread->GetEcmaVM()->GetFactory()->GetEmptyString()); 12764514f5e3Sopenharmony_ci } 12774514f5e3Sopenharmony_ci icu::ConstrainedFieldPosition cfpos; 12784514f5e3Sopenharmony_ci while (formatted.nextPosition(cfpos, status) != 0) { 12794514f5e3Sopenharmony_ci if (cfpos.getCategory() == UFIELD_CATEGORY_DATE_INTERVAL_SPAN) { 12804514f5e3Sopenharmony_ci outputRange = true; 12814514f5e3Sopenharmony_ci break; 12824514f5e3Sopenharmony_ci } 12834514f5e3Sopenharmony_ci } 12844514f5e3Sopenharmony_ci result = intl::LocaleHelper::UStringToString(thread, formatResult); 12854514f5e3Sopenharmony_ci if (!outputRange) { 12864514f5e3Sopenharmony_ci return FormatDateTime(thread, dtf, x); 12874514f5e3Sopenharmony_ci } 12884514f5e3Sopenharmony_ci return result; 12894514f5e3Sopenharmony_ci} 12904514f5e3Sopenharmony_ci 12914514f5e3Sopenharmony_ciJSHandle<JSArray> JSDateTimeFormat::NormDateTimeRangeToParts(JSThread *thread, const JSHandle<JSDateTimeFormat> &dtf, 12924514f5e3Sopenharmony_ci double x, double y) 12934514f5e3Sopenharmony_ci{ 12944514f5e3Sopenharmony_ci JSHandle<JSArray> result(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); 12954514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 12964514f5e3Sopenharmony_ci // 1. Let x be TimeClip(x). 12974514f5e3Sopenharmony_ci x = JSDate::TimeClip(x); 12984514f5e3Sopenharmony_ci // 2. If x is NaN, throw a RangeError exception. 12994514f5e3Sopenharmony_ci if (std::isnan(x)) { 13004514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "x is invalid time value", result); 13014514f5e3Sopenharmony_ci } 13024514f5e3Sopenharmony_ci // 3. Let y be TimeClip(y). 13034514f5e3Sopenharmony_ci y = JSDate::TimeClip(y); 13044514f5e3Sopenharmony_ci // 4. If y is NaN, throw a RangeError exception. 13054514f5e3Sopenharmony_ci if (std::isnan(y)) { 13064514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "y is invalid time value", result); 13074514f5e3Sopenharmony_ci } 13084514f5e3Sopenharmony_ci 13094514f5e3Sopenharmony_ci icu::FormattedDateInterval formatted = ConstructDTFRange(thread, dtf, x, y); 13104514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 13114514f5e3Sopenharmony_ci return ConstructFDateIntervalToJSArray(thread, formatted); 13124514f5e3Sopenharmony_ci} 13134514f5e3Sopenharmony_ci 13144514f5e3Sopenharmony_ciJSHandle<TaggedArray> JSDateTimeFormat::GainAvailableLocales(JSThread *thread) 13154514f5e3Sopenharmony_ci{ 13164514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 13174514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> dateTimeFormatLocales = env->GetDateTimeFormatLocales(); 13184514f5e3Sopenharmony_ci const char *key = "calendar"; 13194514f5e3Sopenharmony_ci const char *path = nullptr; 13204514f5e3Sopenharmony_ci if (dateTimeFormatLocales->IsUndefined()) { 13214514f5e3Sopenharmony_ci std::vector<std::string> availableStringLocales = intl::LocaleHelper::GetAvailableLocales(thread, key, path); 13224514f5e3Sopenharmony_ci JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales); 13234514f5e3Sopenharmony_ci env->SetDateTimeFormatLocales(thread, availableLocales); 13244514f5e3Sopenharmony_ci return availableLocales; 13254514f5e3Sopenharmony_ci } 13264514f5e3Sopenharmony_ci return JSHandle<TaggedArray>::Cast(dateTimeFormatLocales); 13274514f5e3Sopenharmony_ci} 13284514f5e3Sopenharmony_ci 13294514f5e3Sopenharmony_ciJSHandle<JSArray> JSDateTimeFormat::ConstructFDateIntervalToJSArray(JSThread *thread, 13304514f5e3Sopenharmony_ci const icu::FormattedDateInterval &formatted) 13314514f5e3Sopenharmony_ci{ 13324514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 13334514f5e3Sopenharmony_ci icu::UnicodeString formattedValue = formatted.toTempString(status); 13344514f5e3Sopenharmony_ci // Let result be ArrayCreate(0). 13354514f5e3Sopenharmony_ci JSHandle<JSArray> array(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); 13364514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 13374514f5e3Sopenharmony_ci // Let index be 0. 13384514f5e3Sopenharmony_ci int index = 0; 13394514f5e3Sopenharmony_ci int32_t preEndPos = 0; 13404514f5e3Sopenharmony_ci // 2: number of elements 13414514f5e3Sopenharmony_ci std::array<int32_t, 2> begin {}; 13424514f5e3Sopenharmony_ci std::array<int32_t, 2> end {}; // 2: number of elements 13434514f5e3Sopenharmony_ci begin[0] = begin[1] = end[0] = end[1] = 0; 13444514f5e3Sopenharmony_ci std::vector<CommonDateFormatPart> parts; 13454514f5e3Sopenharmony_ci 13464514f5e3Sopenharmony_ci /** 13474514f5e3Sopenharmony_ci * From ICU header file document @unumberformatter.h 13484514f5e3Sopenharmony_ci * Sets a constraint on the field category. 13494514f5e3Sopenharmony_ci * 13504514f5e3Sopenharmony_ci * When this instance of ConstrainedFieldPosition is passed to FormattedValue#nextPosition, 13514514f5e3Sopenharmony_ci * positions are skipped unless they have the given category. 13524514f5e3Sopenharmony_ci * 13534514f5e3Sopenharmony_ci * Any previously set constraints are cleared. 13544514f5e3Sopenharmony_ci * 13554514f5e3Sopenharmony_ci * For example, to loop over only the number-related fields: 13564514f5e3Sopenharmony_ci * 13574514f5e3Sopenharmony_ci * ConstrainedFieldPosition cfpo; 13584514f5e3Sopenharmony_ci * cfpo.constrainCategory(UFIELDCATEGORY_NUMBER_FORMAT); 13594514f5e3Sopenharmony_ci * while (fmtval.nextPosition(cfpo, status)) { 13604514f5e3Sopenharmony_ci * // handle the number-related field position 13614514f5e3Sopenharmony_ci * } 13624514f5e3Sopenharmony_ci */ 13634514f5e3Sopenharmony_ci JSMutableHandle<EcmaString> substring(thread, JSTaggedValue::Undefined()); 13644514f5e3Sopenharmony_ci icu::ConstrainedFieldPosition cfpos; 13654514f5e3Sopenharmony_ci while (formatted.nextPosition(cfpos, status)) { 13664514f5e3Sopenharmony_ci int32_t fCategory = cfpos.getCategory(); 13674514f5e3Sopenharmony_ci int32_t fField = cfpos.getField(); 13684514f5e3Sopenharmony_ci int32_t fStart = cfpos.getStart(); 13694514f5e3Sopenharmony_ci int32_t fLimit = cfpos.getLimit(); 13704514f5e3Sopenharmony_ci 13714514f5e3Sopenharmony_ci // 2 means the number of elements in category 13724514f5e3Sopenharmony_ci if (fCategory == UFIELD_CATEGORY_DATE_INTERVAL_SPAN && (fField == 0 || fField == 1)) { 13734514f5e3Sopenharmony_ci begin[fField] = fStart; 13744514f5e3Sopenharmony_ci end[fField] = fLimit; 13754514f5e3Sopenharmony_ci } 13764514f5e3Sopenharmony_ci if (fCategory == UFIELD_CATEGORY_DATE) { 13774514f5e3Sopenharmony_ci if (preEndPos < fStart) { 13784514f5e3Sopenharmony_ci parts.emplace_back(CommonDateFormatPart(fField, preEndPos, fStart, index, true)); 13794514f5e3Sopenharmony_ci index++; 13804514f5e3Sopenharmony_ci } 13814514f5e3Sopenharmony_ci parts.emplace_back(CommonDateFormatPart(fField, fStart, fLimit, index, false)); 13824514f5e3Sopenharmony_ci preEndPos = fLimit; 13834514f5e3Sopenharmony_ci ++index; 13844514f5e3Sopenharmony_ci } 13854514f5e3Sopenharmony_ci } 13864514f5e3Sopenharmony_ci if (U_FAILURE(status) != 0) { 13874514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "format date interval error", array); 13884514f5e3Sopenharmony_ci } 13894514f5e3Sopenharmony_ci int32_t length = formattedValue.length(); 13904514f5e3Sopenharmony_ci if (length > preEndPos) { 13914514f5e3Sopenharmony_ci parts.emplace_back(CommonDateFormatPart(-1, preEndPos, length, index, true)); 13924514f5e3Sopenharmony_ci } 13934514f5e3Sopenharmony_ci for (auto part : parts) { 13944514f5e3Sopenharmony_ci substring.Update(intl::LocaleHelper::UStringToString(thread, formattedValue, part.fBeginIndex, 13954514f5e3Sopenharmony_ci part.fEndIndex).GetTaggedValue()); 13964514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 13974514f5e3Sopenharmony_ci JSHandle<JSObject> element; 13984514f5e3Sopenharmony_ci if (part.isPreExist) { 13994514f5e3Sopenharmony_ci element = JSLocale::PutElement(thread, part.index, array, ConvertFieldIdToDateType(thread, -1), 14004514f5e3Sopenharmony_ci JSHandle<JSTaggedValue>::Cast(substring)); 14014514f5e3Sopenharmony_ci } else { 14024514f5e3Sopenharmony_ci element = JSLocale::PutElement(thread, part.index, array, ConvertFieldIdToDateType(thread, part.fField), 14034514f5e3Sopenharmony_ci JSHandle<JSTaggedValue>::Cast(substring)); 14044514f5e3Sopenharmony_ci } 14054514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 14064514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> value = JSHandle<JSTaggedValue>::Cast( 14074514f5e3Sopenharmony_ci ToValueString(thread, TrackValue(part.fBeginIndex, part.fEndIndex, begin, end))); 14084514f5e3Sopenharmony_ci JSObject::SetProperty(thread, element, thread->GlobalConstants()->GetHandledSourceString(), value, true); 14094514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 14104514f5e3Sopenharmony_ci } 14114514f5e3Sopenharmony_ci return array; 14124514f5e3Sopenharmony_ci} 14134514f5e3Sopenharmony_ci 14144514f5e3Sopenharmony_ciValue JSDateTimeFormat::TrackValue(int32_t beginning, int32_t ending, 14154514f5e3Sopenharmony_ci std::array<int32_t, 2> begin, std::array<int32_t, 2> end) // 2: number of elements 14164514f5e3Sopenharmony_ci{ 14174514f5e3Sopenharmony_ci Value value = Value::SHARED; 14184514f5e3Sopenharmony_ci if ((begin[0] <= beginning) && (beginning <= end[0]) && (begin[0] <= ending) && (ending <= end[0])) { 14194514f5e3Sopenharmony_ci value = Value::START_RANGE; 14204514f5e3Sopenharmony_ci } else if ((begin[1] <= beginning) && (beginning <= end[1]) && (begin[1] <= ending) && (ending <= end[1])) { 14214514f5e3Sopenharmony_ci value = Value::END_RANGE; 14224514f5e3Sopenharmony_ci } 14234514f5e3Sopenharmony_ci return value; 14244514f5e3Sopenharmony_ci} 14254514f5e3Sopenharmony_ci 14264514f5e3Sopenharmony_cistd::vector<IcuPatternDesc> BuildIcuPatternDescs() 14274514f5e3Sopenharmony_ci{ 14284514f5e3Sopenharmony_ci static const std::vector<IcuPatternDesc> items = { 14294514f5e3Sopenharmony_ci IcuPatternDesc("weekday", ICU_WEEKDAY_PE, ICU_NARROW_LONG_SHORT), 14304514f5e3Sopenharmony_ci IcuPatternDesc("era", ICU_ERA_PE, ICU_NARROW_LONG_SHORT), 14314514f5e3Sopenharmony_ci IcuPatternDesc("year", ICU_YEAR_PE, ICU2_DIGIT_NUMERIC), 14324514f5e3Sopenharmony_ci IcuPatternDesc("month", ICU_MONTH_PE, ICU_NARROW_LONG_SHORT2_DIGIT_NUMERIC), 14334514f5e3Sopenharmony_ci IcuPatternDesc("day", ICU_DAY_PE, ICU2_DIGIT_NUMERIC), 14344514f5e3Sopenharmony_ci IcuPatternDesc("dayPeriod", ICU_DAY_PERIOD_PE, ICU_NARROW_LONG_SHORT), 14354514f5e3Sopenharmony_ci IcuPatternDesc("hour", ICU_HOUR_PE, ICU2_DIGIT_NUMERIC), 14364514f5e3Sopenharmony_ci IcuPatternDesc("minute", ICU_MINUTE_PE, ICU2_DIGIT_NUMERIC), 14374514f5e3Sopenharmony_ci IcuPatternDesc("second", ICU_SECOND_PE, ICU2_DIGIT_NUMERIC), 14384514f5e3Sopenharmony_ci IcuPatternDesc("timeZoneName", ICU_YIME_ZONE_NAME_PE, ICU_LONG_SHORT) 14394514f5e3Sopenharmony_ci }; 14404514f5e3Sopenharmony_ci return items; 14414514f5e3Sopenharmony_ci} 14424514f5e3Sopenharmony_ci 14434514f5e3Sopenharmony_cistd::vector<IcuPatternDesc> InitializePattern(const IcuPatternDesc &hourData) 14444514f5e3Sopenharmony_ci{ 14454514f5e3Sopenharmony_ci std::vector<IcuPatternDesc> result; 14464514f5e3Sopenharmony_ci std::vector<IcuPatternDesc> items = BuildIcuPatternDescs(); 14474514f5e3Sopenharmony_ci std::vector<IcuPatternDesc>::iterator item = items.begin(); 14484514f5e3Sopenharmony_ci while (item != items.end()) { 14494514f5e3Sopenharmony_ci if (item->property != "hour") { 14504514f5e3Sopenharmony_ci result.emplace_back(IcuPatternDesc(item->property, item->pairs, item->allowedValues)); 14514514f5e3Sopenharmony_ci } else { 14524514f5e3Sopenharmony_ci result.emplace_back(hourData); 14534514f5e3Sopenharmony_ci } 14544514f5e3Sopenharmony_ci ++item; 14554514f5e3Sopenharmony_ci } 14564514f5e3Sopenharmony_ci return result; 14574514f5e3Sopenharmony_ci} 14584514f5e3Sopenharmony_ci 14594514f5e3Sopenharmony_cistd::vector<IcuPatternDesc> JSDateTimeFormat::GetIcuPatternDesc(const HourCycleOption &hourCycle) 14604514f5e3Sopenharmony_ci{ 14614514f5e3Sopenharmony_ci if (hourCycle == HourCycleOption::H11) { 14624514f5e3Sopenharmony_ci Pattern h11("KK", "K"); 14634514f5e3Sopenharmony_ci return h11.Get(); 14644514f5e3Sopenharmony_ci } else if (hourCycle == HourCycleOption::H12) { 14654514f5e3Sopenharmony_ci Pattern h12("hh", "h"); 14664514f5e3Sopenharmony_ci return h12.Get(); 14674514f5e3Sopenharmony_ci } else if (hourCycle == HourCycleOption::H23) { 14684514f5e3Sopenharmony_ci Pattern h23("HH", "H"); 14694514f5e3Sopenharmony_ci return h23.Get(); 14704514f5e3Sopenharmony_ci } else if (hourCycle == HourCycleOption::H24) { 14714514f5e3Sopenharmony_ci Pattern h24("kk", "k"); 14724514f5e3Sopenharmony_ci return h24.Get(); 14734514f5e3Sopenharmony_ci } else if (hourCycle == HourCycleOption::UNDEFINED) { 14744514f5e3Sopenharmony_ci Pattern pattern("jj", "j"); 14754514f5e3Sopenharmony_ci return pattern.Get(); 14764514f5e3Sopenharmony_ci } 14774514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 14784514f5e3Sopenharmony_ci UNREACHABLE(); 14794514f5e3Sopenharmony_ci} 14804514f5e3Sopenharmony_ci 14814514f5e3Sopenharmony_ciicu::UnicodeString JSDateTimeFormat::ChangeHourCyclePattern(const icu::UnicodeString &pattern, HourCycleOption hc) 14824514f5e3Sopenharmony_ci{ 14834514f5e3Sopenharmony_ci if (hc == HourCycleOption::UNDEFINED || hc == HourCycleOption::EXCEPTION) { 14844514f5e3Sopenharmony_ci return pattern; 14854514f5e3Sopenharmony_ci } 14864514f5e3Sopenharmony_ci icu::UnicodeString result; 14874514f5e3Sopenharmony_ci char16_t key = u'\0'; 14884514f5e3Sopenharmony_ci auto mapIter = std::find_if(HOUR_CYCLE_MAP.begin(), HOUR_CYCLE_MAP.end(), 14894514f5e3Sopenharmony_ci [hc](const std::map<char16_t, HourCycleOption>::value_type item) { 14904514f5e3Sopenharmony_ci return item.second == hc; 14914514f5e3Sopenharmony_ci }); 14924514f5e3Sopenharmony_ci if (mapIter != HOUR_CYCLE_MAP.end()) { 14934514f5e3Sopenharmony_ci key = mapIter->first; 14944514f5e3Sopenharmony_ci } 14954514f5e3Sopenharmony_ci bool needChange = true; 14964514f5e3Sopenharmony_ci char16_t last = u'\0'; 14974514f5e3Sopenharmony_ci for (int32_t i = 0; i < pattern.length(); i++) { 14984514f5e3Sopenharmony_ci char16_t ch = pattern.charAt(i); 14994514f5e3Sopenharmony_ci if (ch == '\'') { 15004514f5e3Sopenharmony_ci needChange = !needChange; 15014514f5e3Sopenharmony_ci result.append(ch); 15024514f5e3Sopenharmony_ci } else if (HOUR_CYCLE_MAP.find(ch) != HOUR_CYCLE_MAP.end()) { 15034514f5e3Sopenharmony_ci result = (needChange && last == u'd') ? result.append(' ') : result; 15044514f5e3Sopenharmony_ci result.append(needChange ? key : ch); 15054514f5e3Sopenharmony_ci } else { 15064514f5e3Sopenharmony_ci result.append(ch); 15074514f5e3Sopenharmony_ci } 15084514f5e3Sopenharmony_ci last = ch; 15094514f5e3Sopenharmony_ci } 15104514f5e3Sopenharmony_ci return result; 15114514f5e3Sopenharmony_ci} 15124514f5e3Sopenharmony_ci 15134514f5e3Sopenharmony_cistd::unique_ptr<icu::SimpleDateFormat> JSDateTimeFormat::CreateICUSimpleDateFormat(const icu::Locale &icuLocale, 15144514f5e3Sopenharmony_ci const icu::UnicodeString &skeleton, 15154514f5e3Sopenharmony_ci icu::DateTimePatternGenerator *gn, 15164514f5e3Sopenharmony_ci HourCycleOption hc) 15174514f5e3Sopenharmony_ci{ 15184514f5e3Sopenharmony_ci // See https://github.com/tc39/ecma402/issues/225 15194514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 15204514f5e3Sopenharmony_ci icu::UnicodeString pattern = ChangeHourCyclePattern( 15214514f5e3Sopenharmony_ci gn->getBestPattern(skeleton, UDATPG_MATCH_HOUR_FIELD_LENGTH, status), hc); 15224514f5e3Sopenharmony_ci ASSERT_PRINT((U_SUCCESS(status) != 0), "get best pattern failed"); 15234514f5e3Sopenharmony_ci 15244514f5e3Sopenharmony_ci status = U_ZERO_ERROR; 15254514f5e3Sopenharmony_ci auto dateFormat(std::make_unique<icu::SimpleDateFormat>(pattern, icuLocale, status)); 15264514f5e3Sopenharmony_ci if (U_FAILURE(status) != 0) { 15274514f5e3Sopenharmony_ci return std::unique_ptr<icu::SimpleDateFormat>(); 15284514f5e3Sopenharmony_ci } 15294514f5e3Sopenharmony_ci ASSERT_PRINT(dateFormat != nullptr, "dateFormat failed"); 15304514f5e3Sopenharmony_ci return dateFormat; 15314514f5e3Sopenharmony_ci} 15324514f5e3Sopenharmony_ci 15334514f5e3Sopenharmony_cistd::unique_ptr<icu::Calendar> JSDateTimeFormat::BuildCalendar(const icu::Locale &locale, const icu::TimeZone &timeZone) 15344514f5e3Sopenharmony_ci{ 15354514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 15364514f5e3Sopenharmony_ci std::unique_ptr<icu::Calendar> calendar(icu::Calendar::createInstance(timeZone, locale, status)); 15374514f5e3Sopenharmony_ci if (U_FAILURE(status) || calendar == nullptr) { 15384514f5e3Sopenharmony_ci return nullptr; 15394514f5e3Sopenharmony_ci } 15404514f5e3Sopenharmony_ci ASSERT_PRINT(U_SUCCESS(status), "buildCalendar failed"); 15414514f5e3Sopenharmony_ci ASSERT_PRINT(calendar.get() != nullptr, "calendar is nullptr"); 15424514f5e3Sopenharmony_ci 15434514f5e3Sopenharmony_ci /** 15444514f5e3Sopenharmony_ci * Return the class ID for this class. 15454514f5e3Sopenharmony_ci * 15464514f5e3Sopenharmony_ci * This is useful only for comparing to a return value from getDynamicClassID(). For example: 15474514f5e3Sopenharmony_ci * 15484514f5e3Sopenharmony_ci * Base* polymorphic_pointer = createPolymorphicObject(); 15494514f5e3Sopenharmony_ci * if (polymorphic_pointer->getDynamicClassID() == 15504514f5e3Sopenharmony_ci * Derived::getStaticClassID()) ... 15514514f5e3Sopenharmony_ci */ 15524514f5e3Sopenharmony_ci if (calendar->getDynamicClassID() == icu::GregorianCalendar::getStaticClassID()) { 15534514f5e3Sopenharmony_ci auto gregorianCalendar = static_cast<icu::GregorianCalendar *>(calendar.get()); 15544514f5e3Sopenharmony_ci // ECMAScript start time, value = -(2**53) 15554514f5e3Sopenharmony_ci const double beginTime = -9007199254740992; 15564514f5e3Sopenharmony_ci gregorianCalendar->setGregorianChange(beginTime, status); 15574514f5e3Sopenharmony_ci ASSERT(U_SUCCESS(status)); 15584514f5e3Sopenharmony_ci } 15594514f5e3Sopenharmony_ci return calendar; 15604514f5e3Sopenharmony_ci} 15614514f5e3Sopenharmony_ci 15624514f5e3Sopenharmony_cistd::unique_ptr<icu::TimeZone> JSDateTimeFormat::ConstructTimeZone(const std::string &timezone) 15634514f5e3Sopenharmony_ci{ 15644514f5e3Sopenharmony_ci if (timezone.empty()) { 15654514f5e3Sopenharmony_ci return std::unique_ptr<icu::TimeZone>(); 15664514f5e3Sopenharmony_ci } 15674514f5e3Sopenharmony_ci std::string canonicalized = ConstructFormattedTimeZoneID(timezone); 15684514f5e3Sopenharmony_ci 15694514f5e3Sopenharmony_ci std::unique_ptr<icu::TimeZone> tz(icu::TimeZone::createTimeZone(canonicalized.c_str())); 15704514f5e3Sopenharmony_ci if (!JSLocale::IsValidTimeZoneName(*tz)) { 15714514f5e3Sopenharmony_ci return std::unique_ptr<icu::TimeZone>(); 15724514f5e3Sopenharmony_ci } 15734514f5e3Sopenharmony_ci return tz; 15744514f5e3Sopenharmony_ci} 15754514f5e3Sopenharmony_ci 15764514f5e3Sopenharmony_cistd::map<std::string, std::string> JSDateTimeFormat::GetSpecialTimeZoneMap() 15774514f5e3Sopenharmony_ci{ 15784514f5e3Sopenharmony_ci std::vector<std::string> specialTimeZones = { 15794514f5e3Sopenharmony_ci "America/Argentina/ComodRivadavia", 15804514f5e3Sopenharmony_ci "America/Knox_IN", 15814514f5e3Sopenharmony_ci "Antarctica/McMurdo", 15824514f5e3Sopenharmony_ci "Australia/ACT", 15834514f5e3Sopenharmony_ci "Australia/LHI", 15844514f5e3Sopenharmony_ci "Australia/NSW", 15854514f5e3Sopenharmony_ci "Antarctica/DumontDUrville", 15864514f5e3Sopenharmony_ci "Brazil/DeNoronha", 15874514f5e3Sopenharmony_ci "CET", 15884514f5e3Sopenharmony_ci "CST6CDT", 15894514f5e3Sopenharmony_ci "Chile/EasterIsland", 15904514f5e3Sopenharmony_ci "EET", 15914514f5e3Sopenharmony_ci "EST", 15924514f5e3Sopenharmony_ci "EST5EDT", 15934514f5e3Sopenharmony_ci "GB", 15944514f5e3Sopenharmony_ci "GB-Eire", 15954514f5e3Sopenharmony_ci "HST", 15964514f5e3Sopenharmony_ci "MET", 15974514f5e3Sopenharmony_ci "MST", 15984514f5e3Sopenharmony_ci "MST7MDT", 15994514f5e3Sopenharmony_ci "Mexico/BajaNorte", 16004514f5e3Sopenharmony_ci "Mexico/BajaSur", 16014514f5e3Sopenharmony_ci "NZ", 16024514f5e3Sopenharmony_ci "NZ-CHAT", 16034514f5e3Sopenharmony_ci "PRC", 16044514f5e3Sopenharmony_ci "PST8PDT", 16054514f5e3Sopenharmony_ci "ROC", 16064514f5e3Sopenharmony_ci "ROK", 16074514f5e3Sopenharmony_ci "UCT", 16084514f5e3Sopenharmony_ci "W-SU", 16094514f5e3Sopenharmony_ci "WET"}; 16104514f5e3Sopenharmony_ci std::map<std::string, std::string> map; 16114514f5e3Sopenharmony_ci for (const auto &item : specialTimeZones) { 16124514f5e3Sopenharmony_ci std::string upper(item); 16134514f5e3Sopenharmony_ci transform(upper.begin(), upper.end(), upper.begin(), toupper); 16144514f5e3Sopenharmony_ci map.emplace(upper, item); 16154514f5e3Sopenharmony_ci } 16164514f5e3Sopenharmony_ci return map; 16174514f5e3Sopenharmony_ci} 16184514f5e3Sopenharmony_ci 16194514f5e3Sopenharmony_cistd::string JSDateTimeFormat::ConstructFormattedTimeZoneID(const std::string &input) 16204514f5e3Sopenharmony_ci{ 16214514f5e3Sopenharmony_ci std::string result = input; 16224514f5e3Sopenharmony_ci transform(result.begin(), result.end(), result.begin(), toupper); 16234514f5e3Sopenharmony_ci std::map<std::string, std::string> map = JSDateTimeFormat::GetSpecialTimeZoneMap(); 16244514f5e3Sopenharmony_ci auto it = map.find(result); 16254514f5e3Sopenharmony_ci if (it != map.end()) { 16264514f5e3Sopenharmony_ci return it->second; 16274514f5e3Sopenharmony_ci } 16284514f5e3Sopenharmony_ci static const std::vector<std::string> tzStyleEntry = { 16294514f5e3Sopenharmony_ci "GMT", "ETC/UTC", "ETC/UCT", "GMT0", "ETC/GMT", "GMT+0", "GMT-0" 16304514f5e3Sopenharmony_ci }; 16314514f5e3Sopenharmony_ci if (result.find("SYSTEMV/") == 0) { 16324514f5e3Sopenharmony_ci result.replace(0, STRING_LENGTH_8, "SystemV/"); 16334514f5e3Sopenharmony_ci } else if (result.find("US/") == 0) { 16344514f5e3Sopenharmony_ci result = (result.length() == STRING_LENGTH_3) ? result : "US/" + ToTitleCaseTimezonePosition( 16354514f5e3Sopenharmony_ci input.substr(STRING_LENGTH_3)); 16364514f5e3Sopenharmony_ci } else if (result.find("ETC/GMT") == 0 && result.length() > STRING_LENGTH_7) { 16374514f5e3Sopenharmony_ci result = ConstructGMTTimeZoneID(input); 16384514f5e3Sopenharmony_ci } else if (count(tzStyleEntry.begin(), tzStyleEntry.end(), result)) { 16394514f5e3Sopenharmony_ci result = "UTC"; 16404514f5e3Sopenharmony_ci } else if (result.length() == STRING_LENGTH_3) { 16414514f5e3Sopenharmony_ci return result; 16424514f5e3Sopenharmony_ci } else { 16434514f5e3Sopenharmony_ci return ToTitleCaseTimezonePosition(result); 16444514f5e3Sopenharmony_ci } 16454514f5e3Sopenharmony_ci 16464514f5e3Sopenharmony_ci return result; 16474514f5e3Sopenharmony_ci} 16484514f5e3Sopenharmony_ci 16494514f5e3Sopenharmony_cistd::string JSDateTimeFormat::ToTitleCaseFunction(const std::string &input) 16504514f5e3Sopenharmony_ci{ 16514514f5e3Sopenharmony_ci std::string result(input); 16524514f5e3Sopenharmony_ci transform(result.begin(), result.end(), result.begin(), tolower); 16534514f5e3Sopenharmony_ci result[0] = static_cast<int8_t>(toupper(result[0])); 16544514f5e3Sopenharmony_ci return result; 16554514f5e3Sopenharmony_ci} 16564514f5e3Sopenharmony_ci 16574514f5e3Sopenharmony_cibool JSDateTimeFormat::IsValidTimeZoneInput(const std::string &input) 16584514f5e3Sopenharmony_ci{ 16594514f5e3Sopenharmony_ci std::regex r("[a-zA-Z_\\-/]*"); 16604514f5e3Sopenharmony_ci bool isValid = regex_match(input, r); 16614514f5e3Sopenharmony_ci return isValid; 16624514f5e3Sopenharmony_ci} 16634514f5e3Sopenharmony_ci 16644514f5e3Sopenharmony_cistd::string JSDateTimeFormat::ToTitleCaseTimezonePosition(const std::string &input) 16654514f5e3Sopenharmony_ci{ 16664514f5e3Sopenharmony_ci if (!IsValidTimeZoneInput(input)) { 16674514f5e3Sopenharmony_ci return std::string(); 16684514f5e3Sopenharmony_ci } 16694514f5e3Sopenharmony_ci std::vector<std::string> titleEntry; 16704514f5e3Sopenharmony_ci std::vector<std::string> charEntry; 16714514f5e3Sopenharmony_ci int32_t leftPosition = 0; 16724514f5e3Sopenharmony_ci int32_t titleLength = 0; 16734514f5e3Sopenharmony_ci for (int32_t i = 0; i < static_cast<int>(input.length()); i++) { 16744514f5e3Sopenharmony_ci if (input[i] == '_' || input[i] == '-' || input[i] == '/') { 16754514f5e3Sopenharmony_ci std::string s(1, input[i]); 16764514f5e3Sopenharmony_ci charEntry.emplace_back(s); 16774514f5e3Sopenharmony_ci titleLength = i - leftPosition; 16784514f5e3Sopenharmony_ci titleEntry.emplace_back(input.substr(leftPosition, titleLength)); 16794514f5e3Sopenharmony_ci leftPosition = i + 1; 16804514f5e3Sopenharmony_ci } else { 16814514f5e3Sopenharmony_ci continue; 16824514f5e3Sopenharmony_ci } 16834514f5e3Sopenharmony_ci } 16844514f5e3Sopenharmony_ci ASSERT(input.length() >= static_cast<size_t>(leftPosition)); 16854514f5e3Sopenharmony_ci titleEntry.emplace_back(input.substr(leftPosition, input.length() - leftPosition)); 16864514f5e3Sopenharmony_ci std::string result; 16874514f5e3Sopenharmony_ci size_t len = titleEntry.size(); 16884514f5e3Sopenharmony_ci if (len == 0) { 16894514f5e3Sopenharmony_ci return ToTitleCaseFunction(input); 16904514f5e3Sopenharmony_ci } 16914514f5e3Sopenharmony_ci for (size_t i = 0; i < len - 1; i++) { 16924514f5e3Sopenharmony_ci std::string titleValue = ToTitleCaseFunction(titleEntry[i]); 16934514f5e3Sopenharmony_ci if (titleValue == "Of" || titleValue == "Es" || titleValue == "Au") { 16944514f5e3Sopenharmony_ci titleValue[0] = static_cast<int8_t>(tolower(titleValue[0])); 16954514f5e3Sopenharmony_ci } 16964514f5e3Sopenharmony_ci result = result + titleValue + charEntry[i]; 16974514f5e3Sopenharmony_ci } 16984514f5e3Sopenharmony_ci result = result + ToTitleCaseFunction(titleEntry[len - 1]); 16994514f5e3Sopenharmony_ci return result; 17004514f5e3Sopenharmony_ci} 17014514f5e3Sopenharmony_ci 17024514f5e3Sopenharmony_cistd::string JSDateTimeFormat::ConstructGMTTimeZoneID(const std::string &input) 17034514f5e3Sopenharmony_ci{ 17044514f5e3Sopenharmony_ci if (input.length() < STRING_LENGTH_8 || input.length() > STRING_LENGTH_10) { 17054514f5e3Sopenharmony_ci return ""; 17064514f5e3Sopenharmony_ci } 17074514f5e3Sopenharmony_ci std::string ret = "Etc/GMT"; 17084514f5e3Sopenharmony_ci int timeZoneOffsetFlag = 7; // The offset of time zone flag, to match RegExp starting with the correct string 17094514f5e3Sopenharmony_ci if (regex_match(input.substr(timeZoneOffsetFlag), std::regex("[+-][1][0-4]")) || 17104514f5e3Sopenharmony_ci (regex_match(input.substr(timeZoneOffsetFlag), std::regex("[+-][0-9]")) || 17114514f5e3Sopenharmony_ci input.substr(timeZoneOffsetFlag) == "0")) { 17124514f5e3Sopenharmony_ci return ret + input.substr(timeZoneOffsetFlag); 17134514f5e3Sopenharmony_ci } 17144514f5e3Sopenharmony_ci return ""; 17154514f5e3Sopenharmony_ci} 17164514f5e3Sopenharmony_ci 17174514f5e3Sopenharmony_cistd::string JSDateTimeFormat::ToHourCycleString(HourCycleOption hc) 17184514f5e3Sopenharmony_ci{ 17194514f5e3Sopenharmony_ci auto mapIter = std::find_if(TO_HOUR_CYCLE_MAP.begin(), TO_HOUR_CYCLE_MAP.end(), 17204514f5e3Sopenharmony_ci [hc](const std::map<std::string, HourCycleOption>::value_type item) { 17214514f5e3Sopenharmony_ci return item.second == hc; 17224514f5e3Sopenharmony_ci }); 17234514f5e3Sopenharmony_ci if (mapIter != TO_HOUR_CYCLE_MAP.end()) { 17244514f5e3Sopenharmony_ci return mapIter->first; 17254514f5e3Sopenharmony_ci } 17264514f5e3Sopenharmony_ci return ""; 17274514f5e3Sopenharmony_ci} 17284514f5e3Sopenharmony_ci 17294514f5e3Sopenharmony_ciHourCycleOption JSDateTimeFormat::OptionToHourCycle(const std::string &hc) 17304514f5e3Sopenharmony_ci{ 17314514f5e3Sopenharmony_ci auto iter = TO_HOUR_CYCLE_MAP.find(hc); 17324514f5e3Sopenharmony_ci if (iter != TO_HOUR_CYCLE_MAP.end()) { 17334514f5e3Sopenharmony_ci return iter->second; 17344514f5e3Sopenharmony_ci } 17354514f5e3Sopenharmony_ci return HourCycleOption::UNDEFINED; 17364514f5e3Sopenharmony_ci} 17374514f5e3Sopenharmony_ci 17384514f5e3Sopenharmony_ciHourCycleOption JSDateTimeFormat::OptionToHourCycle(UDateFormatHourCycle hc) 17394514f5e3Sopenharmony_ci{ 17404514f5e3Sopenharmony_ci HourCycleOption hcOption = HourCycleOption::UNDEFINED; 17414514f5e3Sopenharmony_ci switch (hc) { 17424514f5e3Sopenharmony_ci case UDAT_HOUR_CYCLE_11: 17434514f5e3Sopenharmony_ci hcOption = HourCycleOption::H11; 17444514f5e3Sopenharmony_ci break; 17454514f5e3Sopenharmony_ci case UDAT_HOUR_CYCLE_12: 17464514f5e3Sopenharmony_ci hcOption = HourCycleOption::H12; 17474514f5e3Sopenharmony_ci break; 17484514f5e3Sopenharmony_ci case UDAT_HOUR_CYCLE_23: 17494514f5e3Sopenharmony_ci hcOption = HourCycleOption::H23; 17504514f5e3Sopenharmony_ci break; 17514514f5e3Sopenharmony_ci case UDAT_HOUR_CYCLE_24: 17524514f5e3Sopenharmony_ci hcOption = HourCycleOption::H24; 17534514f5e3Sopenharmony_ci break; 17544514f5e3Sopenharmony_ci default: 17554514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 17564514f5e3Sopenharmony_ci UNREACHABLE(); 17574514f5e3Sopenharmony_ci } 17584514f5e3Sopenharmony_ci return hcOption; 17594514f5e3Sopenharmony_ci} 17604514f5e3Sopenharmony_ci 17614514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSDateTimeFormat::ConvertFieldIdToDateType(JSThread *thread, int32_t fieldId) 17624514f5e3Sopenharmony_ci{ 17634514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 17644514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 17654514f5e3Sopenharmony_ci if (fieldId == -1) { 17664514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledLiteralString().GetTaggedValue()); 17674514f5e3Sopenharmony_ci } else if (fieldId == UDAT_YEAR_FIELD || fieldId == UDAT_EXTENDED_YEAR_FIELD) { 17684514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledYearString().GetTaggedValue()); 17694514f5e3Sopenharmony_ci } else if (fieldId == UDAT_YEAR_NAME_FIELD) { 17704514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledYearNameString().GetTaggedValue()); 17714514f5e3Sopenharmony_ci } else if (fieldId == UDAT_MONTH_FIELD || fieldId == UDAT_STANDALONE_MONTH_FIELD) { 17724514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledMonthString().GetTaggedValue()); 17734514f5e3Sopenharmony_ci } else if (fieldId == UDAT_DATE_FIELD) { 17744514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledDayString().GetTaggedValue()); 17754514f5e3Sopenharmony_ci } else if (fieldId == UDAT_HOUR_OF_DAY1_FIELD || 17764514f5e3Sopenharmony_ci fieldId == UDAT_HOUR_OF_DAY0_FIELD || fieldId == UDAT_HOUR1_FIELD || fieldId == UDAT_HOUR0_FIELD) { 17774514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledHourString().GetTaggedValue()); 17784514f5e3Sopenharmony_ci } else if (fieldId == UDAT_MINUTE_FIELD) { 17794514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledMinuteString().GetTaggedValue()); 17804514f5e3Sopenharmony_ci } else if (fieldId == UDAT_SECOND_FIELD) { 17814514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledSecondString().GetTaggedValue()); 17824514f5e3Sopenharmony_ci } else if (fieldId == UDAT_DAY_OF_WEEK_FIELD || fieldId == UDAT_DOW_LOCAL_FIELD || 17834514f5e3Sopenharmony_ci fieldId == UDAT_STANDALONE_DAY_FIELD) { 17844514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledWeekdayString().GetTaggedValue()); 17854514f5e3Sopenharmony_ci } else if (fieldId == UDAT_AM_PM_FIELD || fieldId == UDAT_AM_PM_MIDNIGHT_NOON_FIELD || 17864514f5e3Sopenharmony_ci fieldId == UDAT_FLEXIBLE_DAY_PERIOD_FIELD) { 17874514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledDayPeriodString().GetTaggedValue()); 17884514f5e3Sopenharmony_ci } else if (fieldId == UDAT_TIMEZONE_FIELD || fieldId == UDAT_TIMEZONE_RFC_FIELD || 17894514f5e3Sopenharmony_ci fieldId == UDAT_TIMEZONE_GENERIC_FIELD || fieldId == UDAT_TIMEZONE_SPECIAL_FIELD || 17904514f5e3Sopenharmony_ci fieldId == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD || fieldId == UDAT_TIMEZONE_ISO_FIELD || 17914514f5e3Sopenharmony_ci fieldId == UDAT_TIMEZONE_ISO_LOCAL_FIELD) { 17924514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledTimeZoneNameString().GetTaggedValue()); 17934514f5e3Sopenharmony_ci } else if (fieldId == UDAT_ERA_FIELD) { 17944514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledEraString().GetTaggedValue()); 17954514f5e3Sopenharmony_ci } else if (fieldId == UDAT_FRACTIONAL_SECOND_FIELD) { 17964514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledFractionalSecondString().GetTaggedValue()); 17974514f5e3Sopenharmony_ci } else if (fieldId == UDAT_RELATED_YEAR_FIELD) { 17984514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledRelatedYearString().GetTaggedValue()); 17994514f5e3Sopenharmony_ci } else if (fieldId == UDAT_QUARTER_FIELD || fieldId == UDAT_STANDALONE_QUARTER_FIELD) { 18004514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 18014514f5e3Sopenharmony_ci UNREACHABLE(); 18024514f5e3Sopenharmony_ci } 18034514f5e3Sopenharmony_ci return result; 18044514f5e3Sopenharmony_ci} 18054514f5e3Sopenharmony_ci 18064514f5e3Sopenharmony_cistd::unique_ptr<icu::DateIntervalFormat> JSDateTimeFormat::ConstructDateIntervalFormat( 18074514f5e3Sopenharmony_ci const JSHandle<JSDateTimeFormat> &dtf) 18084514f5e3Sopenharmony_ci{ 18094514f5e3Sopenharmony_ci icu::SimpleDateFormat *icuSimpleDateFormat = dtf->GetIcuSimpleDateFormat(); 18104514f5e3Sopenharmony_ci icu::Locale locale = *(dtf->GetIcuLocale()); 18114514f5e3Sopenharmony_ci std::string hcString = ToHourCycleString(dtf->GetHourCycle()); 18124514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 18134514f5e3Sopenharmony_ci // Sets the Unicode value for a Unicode keyword. 18144514f5e3Sopenharmony_ci if (!hcString.empty()) { 18154514f5e3Sopenharmony_ci locale.setUnicodeKeywordValue("hc", hcString, status); 18164514f5e3Sopenharmony_ci } 18174514f5e3Sopenharmony_ci icu::UnicodeString pattern; 18184514f5e3Sopenharmony_ci // Return a pattern string describing this date format. 18194514f5e3Sopenharmony_ci pattern = icuSimpleDateFormat->toPattern(pattern); 18204514f5e3Sopenharmony_ci // Utility to return a unique skeleton from a given pattern. 18214514f5e3Sopenharmony_ci icu::UnicodeString skeleton = icu::DateTimePatternGenerator::staticGetSkeleton(pattern, status); 18224514f5e3Sopenharmony_ci // Construct a DateIntervalFormat from skeleton and a given locale. 18234514f5e3Sopenharmony_ci std::unique_ptr<icu::DateIntervalFormat> dateIntervalFormat( 18244514f5e3Sopenharmony_ci icu::DateIntervalFormat::createInstance(skeleton, locale, status)); 18254514f5e3Sopenharmony_ci if (U_FAILURE(status)) { 18264514f5e3Sopenharmony_ci return nullptr; 18274514f5e3Sopenharmony_ci } 18284514f5e3Sopenharmony_ci dateIntervalFormat->setTimeZone(icuSimpleDateFormat->getTimeZone()); 18294514f5e3Sopenharmony_ci return dateIntervalFormat; 18304514f5e3Sopenharmony_ci} 18314514f5e3Sopenharmony_ci} // namespace panda::ecmascript 1832