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