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_relative_time_format.h"
174514f5e3Sopenharmony_ci#include "ecmascript/js_function.h"
184514f5e3Sopenharmony_ci#include "ecmascript/object_factory-inl.h"
194514f5e3Sopenharmony_ci
204514f5e3Sopenharmony_cinamespace panda::ecmascript {
214514f5e3Sopenharmony_ci// 14.1.1 InitializeRelativeTimeFormat ( relativeTimeFormat, locales, options )
224514f5e3Sopenharmony_ciJSHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::InitializeRelativeTimeFormat(
234514f5e3Sopenharmony_ci    JSThread *thread, const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat, const JSHandle<JSTaggedValue> &locales,
244514f5e3Sopenharmony_ci    const JSHandle<JSTaggedValue> &options)
254514f5e3Sopenharmony_ci{
264514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
274514f5e3Sopenharmony_ci    ObjectFactory *factory = ecmaVm->GetFactory();
284514f5e3Sopenharmony_ci
294514f5e3Sopenharmony_ci    // 1.Let requestedLocales be ? CanonicalizeLocaleList(locales).
304514f5e3Sopenharmony_ci    JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales);
314514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread);
324514f5e3Sopenharmony_ci
334514f5e3Sopenharmony_ci    // 2&3. If options is undefined, then Let options be ObjectCreate(null). else Let options be ? ToObject(options).
344514f5e3Sopenharmony_ci    JSHandle<JSObject> rtfOptions;
354514f5e3Sopenharmony_ci    if (!options->IsUndefined()) {
364514f5e3Sopenharmony_ci        rtfOptions = JSTaggedValue::ToObject(thread, options);
374514f5e3Sopenharmony_ci        RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread);
384514f5e3Sopenharmony_ci    } else {
394514f5e3Sopenharmony_ci        rtfOptions = factory->CreateNullJSObject();
404514f5e3Sopenharmony_ci    }
414514f5e3Sopenharmony_ci
424514f5e3Sopenharmony_ci    // 5. Let matcher be ? GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
434514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
444514f5e3Sopenharmony_ci    LocaleMatcherOption matcher =
454514f5e3Sopenharmony_ci        JSLocale::GetOptionOfString(thread, rtfOptions, globalConst->GetHandledLocaleMatcherString(),
464514f5e3Sopenharmony_ci                                    {LocaleMatcherOption::LOOKUP, LocaleMatcherOption::BEST_FIT},
474514f5e3Sopenharmony_ci                                    {"lookup", "best fit"}, LocaleMatcherOption::BEST_FIT);
484514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread);
494514f5e3Sopenharmony_ci
504514f5e3Sopenharmony_ci    // 7. Let numberingSystem be ? GetOption(options, "numberingSystem", "string", undefined, undefined).
514514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> property = globalConst->GetHandledNumberingSystemString();
524514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> undefinedValue(thread, JSTaggedValue::Undefined());
534514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> numberingSystemValue =
544514f5e3Sopenharmony_ci        JSLocale::GetOption(thread, rtfOptions, property, OptionType::STRING, undefinedValue, undefinedValue);
554514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread);
564514f5e3Sopenharmony_ci
574514f5e3Sopenharmony_ci    // Check whether numberingSystem is well formed and set to %RelativeTimeFormat%.[[numberingSystem]]
584514f5e3Sopenharmony_ci    std::string numberingSystemStdStr;
594514f5e3Sopenharmony_ci    if (!numberingSystemValue->IsUndefined()) {
604514f5e3Sopenharmony_ci        JSHandle<EcmaString> numberingSystemString = JSHandle<EcmaString>::Cast(numberingSystemValue);
614514f5e3Sopenharmony_ci        if (EcmaStringAccessor(numberingSystemString).IsUtf16()) {
624514f5e3Sopenharmony_ci            THROW_RANGE_ERROR_AND_RETURN(thread, "invalid numberingSystem", relativeTimeFormat);
634514f5e3Sopenharmony_ci        }
644514f5e3Sopenharmony_ci        numberingSystemStdStr = intl::LocaleHelper::ConvertToStdString(numberingSystemString);
654514f5e3Sopenharmony_ci        if (!JSLocale::IsNormativeNumberingSystem(numberingSystemStdStr)) {
664514f5e3Sopenharmony_ci            THROW_RANGE_ERROR_AND_RETURN(thread, "invalid numberingSystem", relativeTimeFormat);
674514f5e3Sopenharmony_ci        }
684514f5e3Sopenharmony_ci    }
694514f5e3Sopenharmony_ci
704514f5e3Sopenharmony_ci    // 10. Let localeData be %RelativeTimeFormat%.[[LocaleData]].
714514f5e3Sopenharmony_ci    // 11. Let r be ResolveLocale(%RelativeTimeFormat%.[[AvailableLocales]], requestedLocales, opt,
724514f5e3Sopenharmony_ci    // %RelativeTimeFormat%.[[RelevantExtensionKeys]], localeData).
734514f5e3Sopenharmony_ci    JSHandle<TaggedArray> availableLocales;
744514f5e3Sopenharmony_ci    if (requestedLocales->GetLength() == 0) {
754514f5e3Sopenharmony_ci        availableLocales = factory->EmptyArray();
764514f5e3Sopenharmony_ci    } else {
774514f5e3Sopenharmony_ci        std::vector<std::string> availableStringLocales =
784514f5e3Sopenharmony_ci            intl::LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr);
794514f5e3Sopenharmony_ci        availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
804514f5e3Sopenharmony_ci    }
814514f5e3Sopenharmony_ci    std::set<std::string> relevantExtensionKeys{"nu"};
824514f5e3Sopenharmony_ci    ResolvedLocale r =
834514f5e3Sopenharmony_ci        JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, relevantExtensionKeys);
844514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread);
854514f5e3Sopenharmony_ci    icu::Locale icuLocale = r.localeData;
864514f5e3Sopenharmony_ci
874514f5e3Sopenharmony_ci    // 12. Let locale be r.[[Locale]].
884514f5e3Sopenharmony_ci    JSHandle<EcmaString> localeStr = intl::LocaleHelper::ToLanguageTag(thread, icuLocale);
894514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread);
904514f5e3Sopenharmony_ci
914514f5e3Sopenharmony_ci    // 13. Set relativeTimeFormat.[[Locale]] to locale.
924514f5e3Sopenharmony_ci    relativeTimeFormat->SetLocale(thread, localeStr.GetTaggedValue());
934514f5e3Sopenharmony_ci
944514f5e3Sopenharmony_ci    // 15. Set relativeTimeFormat.[[NumberingSystem]] to r.[[nu]].
954514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
964514f5e3Sopenharmony_ci    if (!numberingSystemStdStr.empty()) {
974514f5e3Sopenharmony_ci        if (JSLocale::IsWellNumberingSystem(numberingSystemStdStr)) {
984514f5e3Sopenharmony_ci            icuLocale.setUnicodeKeywordValue("nu", numberingSystemStdStr, status);
994514f5e3Sopenharmony_ci            ASSERT(U_SUCCESS(status));
1004514f5e3Sopenharmony_ci        }
1014514f5e3Sopenharmony_ci    }
1024514f5e3Sopenharmony_ci
1034514f5e3Sopenharmony_ci    // 16. Let s be ? GetOption(options, "style", "string", «"long", "short", "narrow"», "long").
1044514f5e3Sopenharmony_ci    property = globalConst->GetHandledStyleString();
1054514f5e3Sopenharmony_ci    RelativeStyleOption styleOption = JSLocale::GetOptionOfString(thread, rtfOptions, property,
1064514f5e3Sopenharmony_ci        {RelativeStyleOption::LONG, RelativeStyleOption::SHORT, RelativeStyleOption::NARROW},
1074514f5e3Sopenharmony_ci        {"long", "short", "narrow"}, RelativeStyleOption::LONG);
1084514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread);
1094514f5e3Sopenharmony_ci
1104514f5e3Sopenharmony_ci    // 17. Set relativeTimeFormat.[[Style]] to s.
1114514f5e3Sopenharmony_ci    relativeTimeFormat->SetStyle(styleOption);
1124514f5e3Sopenharmony_ci
1134514f5e3Sopenharmony_ci    // 18. Let numeric be ? GetOption(options, "numeric", "string", ?"always", "auto"?, "always").
1144514f5e3Sopenharmony_ci    property = globalConst->GetHandledNumericString();
1154514f5e3Sopenharmony_ci    NumericOption numericOption =
1164514f5e3Sopenharmony_ci        JSLocale::GetOptionOfString(thread, rtfOptions, property, {NumericOption::ALWAYS, NumericOption::AUTO},
1174514f5e3Sopenharmony_ci                                    {"always", "auto"}, NumericOption::ALWAYS);
1184514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread);
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_ci    // 19. Set relativeTimeFormat.[[Numeric]] to numeric.
1214514f5e3Sopenharmony_ci    relativeTimeFormat->SetNumeric(numericOption);
1224514f5e3Sopenharmony_ci
1234514f5e3Sopenharmony_ci    // 20. Let relativeTimeFormat.[[NumberFormat]] be ! Construct(%NumberFormat%, « locale »).
1244514f5e3Sopenharmony_ci    icu::NumberFormat *icuNumberFormat = icu::NumberFormat::createInstance(icuLocale, UNUM_DECIMAL, status);
1254514f5e3Sopenharmony_ci    if (U_FAILURE(status) != 0) {
1264514f5e3Sopenharmony_ci        delete icuNumberFormat;
1274514f5e3Sopenharmony_ci        if (status == UErrorCode::U_MISSING_RESOURCE_ERROR) {
1284514f5e3Sopenharmony_ci            THROW_REFERENCE_ERROR_AND_RETURN(thread, "can not find icu data resources", relativeTimeFormat);
1294514f5e3Sopenharmony_ci        }
1304514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "create icu::NumberFormat failed", relativeTimeFormat);
1314514f5e3Sopenharmony_ci    }
1324514f5e3Sopenharmony_ci    // Display grouping using the default strategy for all locales
1334514f5e3Sopenharmony_ci    if (icuNumberFormat->getDynamicClassID() == icu::DecimalFormat::getStaticClassID()) {
1344514f5e3Sopenharmony_ci        icu::DecimalFormat* icuDecimalFormat = static_cast<icu::DecimalFormat*>(icuNumberFormat);
1354514f5e3Sopenharmony_ci        icuDecimalFormat->setMinimumGroupingDigits(UNUM_MINIMUM_GROUPING_DIGITS_AUTO);
1364514f5e3Sopenharmony_ci    }
1374514f5e3Sopenharmony_ci
1384514f5e3Sopenharmony_ci    // Trans RelativeStyleOption to ICU Style
1394514f5e3Sopenharmony_ci    UDateRelativeDateTimeFormatterStyle uStyle;
1404514f5e3Sopenharmony_ci    switch (styleOption) {
1414514f5e3Sopenharmony_ci        case RelativeStyleOption::LONG:
1424514f5e3Sopenharmony_ci            uStyle = UDAT_STYLE_LONG;
1434514f5e3Sopenharmony_ci            break;
1444514f5e3Sopenharmony_ci        case RelativeStyleOption::SHORT:
1454514f5e3Sopenharmony_ci            uStyle = UDAT_STYLE_SHORT;
1464514f5e3Sopenharmony_ci            break;
1474514f5e3Sopenharmony_ci        case RelativeStyleOption::NARROW:
1484514f5e3Sopenharmony_ci            uStyle = UDAT_STYLE_NARROW;
1494514f5e3Sopenharmony_ci            break;
1504514f5e3Sopenharmony_ci        default:
1514514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
1524514f5e3Sopenharmony_ci            UNREACHABLE();
1534514f5e3Sopenharmony_ci    }
1544514f5e3Sopenharmony_ci    icu::RelativeDateTimeFormatter rtfFormatter(icuLocale, icuNumberFormat, uStyle, UDISPCTX_CAPITALIZATION_NONE,
1554514f5e3Sopenharmony_ci                                                status);
1564514f5e3Sopenharmony_ci    if (U_FAILURE(status) != 0) {
1574514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "icu Formatter Error", relativeTimeFormat);
1584514f5e3Sopenharmony_ci    }
1594514f5e3Sopenharmony_ci
1604514f5e3Sopenharmony_ci    std::string numberingSystem = JSLocale::GetNumberingSystem(icuLocale);
1614514f5e3Sopenharmony_ci    auto result = factory->NewFromStdString(numberingSystem);
1624514f5e3Sopenharmony_ci    relativeTimeFormat->SetNumberingSystem(thread, result);
1634514f5e3Sopenharmony_ci
1644514f5e3Sopenharmony_ci    // Set RelativeTimeFormat.[[IcuRelativeTimeFormatter]]
1654514f5e3Sopenharmony_ci    factory->NewJSIntlIcuData(relativeTimeFormat, rtfFormatter, JSRelativeTimeFormat::FreeIcuRTFFormatter);
1664514f5e3Sopenharmony_ci
1674514f5e3Sopenharmony_ci    // 22. Return relativeTimeFormat.
1684514f5e3Sopenharmony_ci    return relativeTimeFormat;
1694514f5e3Sopenharmony_ci}
1704514f5e3Sopenharmony_ci
1714514f5e3Sopenharmony_ci// 14.1.2  SingularRelativeTimeUnit ( unit )
1724514f5e3Sopenharmony_cibool SingularUnitToIcuUnit(JSThread *thread, const JSHandle<EcmaString> &unit, URelativeDateTimeUnit *unitEnum)
1734514f5e3Sopenharmony_ci{
1744514f5e3Sopenharmony_ci    // 1. Assert: Type(unit) is String.
1754514f5e3Sopenharmony_ci    ASSERT(JSHandle<JSTaggedValue>::Cast(unit)->IsString());
1764514f5e3Sopenharmony_ci
1774514f5e3Sopenharmony_ci    // 2. If unit is "seconds" or "second", return "second".
1784514f5e3Sopenharmony_ci    // 3. If unit is "minutes" or "minute", return "minute".
1794514f5e3Sopenharmony_ci    // 4. If unit is "hours" or "hour", return "hour".
1804514f5e3Sopenharmony_ci    // 5. If unit is "days" or "day", return "day".
1814514f5e3Sopenharmony_ci    // 6. If unit is "weeks" or "week", return "week".
1824514f5e3Sopenharmony_ci    // 7. If unit is "months" or "month", return "month".
1834514f5e3Sopenharmony_ci    // 8. If unit is "quarters" or "quarter", return "quarter".
1844514f5e3Sopenharmony_ci    // 9. If unit is "years" or "year", return "year".
1854514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
1864514f5e3Sopenharmony_ci    JSHandle<EcmaString> second = JSHandle<EcmaString>::Cast(globalConst->GetHandledSecondString());
1874514f5e3Sopenharmony_ci    JSHandle<EcmaString> minute = JSHandle<EcmaString>::Cast(globalConst->GetHandledMinuteString());
1884514f5e3Sopenharmony_ci    JSHandle<EcmaString> hour = JSHandle<EcmaString>::Cast(globalConst->GetHandledHourString());
1894514f5e3Sopenharmony_ci    JSHandle<EcmaString> day = JSHandle<EcmaString>::Cast(globalConst->GetHandledDayString());
1904514f5e3Sopenharmony_ci    JSHandle<EcmaString> week = JSHandle<EcmaString>::Cast(globalConst->GetHandledWeekString());
1914514f5e3Sopenharmony_ci    JSHandle<EcmaString> month = JSHandle<EcmaString>::Cast(globalConst->GetHandledMonthString());
1924514f5e3Sopenharmony_ci    JSHandle<EcmaString> quarter = JSHandle<EcmaString>::Cast(globalConst->GetHandledQuarterString());
1934514f5e3Sopenharmony_ci    JSHandle<EcmaString> year = JSHandle<EcmaString>::Cast(globalConst->GetHandledYearString());
1944514f5e3Sopenharmony_ci
1954514f5e3Sopenharmony_ci    JSHandle<EcmaString> seconds = JSHandle<EcmaString>::Cast(globalConst->GetHandledSecondsString());
1964514f5e3Sopenharmony_ci    JSHandle<EcmaString> minutes = JSHandle<EcmaString>::Cast(globalConst->GetHandledMinutesString());
1974514f5e3Sopenharmony_ci    JSHandle<EcmaString> hours = JSHandle<EcmaString>::Cast(globalConst->GetHandledHoursString());
1984514f5e3Sopenharmony_ci    JSHandle<EcmaString> days = JSHandle<EcmaString>::Cast(globalConst->GetHandledDaysString());
1994514f5e3Sopenharmony_ci    JSHandle<EcmaString> weeks = JSHandle<EcmaString>::Cast(globalConst->GetHandledWeeksString());
2004514f5e3Sopenharmony_ci    JSHandle<EcmaString> months = JSHandle<EcmaString>::Cast(globalConst->GetHandledMonthsString());
2014514f5e3Sopenharmony_ci    JSHandle<EcmaString> quarters = JSHandle<EcmaString>::Cast(globalConst->GetHandledQuartersString());
2024514f5e3Sopenharmony_ci    JSHandle<EcmaString> years = JSHandle<EcmaString>::Cast(globalConst->GetHandledYearsString());
2034514f5e3Sopenharmony_ci
2044514f5e3Sopenharmony_ci    if (EcmaStringAccessor::StringsAreEqual(*second, *unit) ||
2054514f5e3Sopenharmony_ci        EcmaStringAccessor::StringsAreEqual(*seconds, *unit)) {
2064514f5e3Sopenharmony_ci        *unitEnum = UDAT_REL_UNIT_SECOND;
2074514f5e3Sopenharmony_ci    } else if (EcmaStringAccessor::StringsAreEqual(*minute, *unit) ||
2084514f5e3Sopenharmony_ci        EcmaStringAccessor::StringsAreEqual(*minutes, *unit)) {
2094514f5e3Sopenharmony_ci        *unitEnum = UDAT_REL_UNIT_MINUTE;
2104514f5e3Sopenharmony_ci    } else if (EcmaStringAccessor::StringsAreEqual(*hour, *unit) ||
2114514f5e3Sopenharmony_ci        EcmaStringAccessor::StringsAreEqual(*hours, *unit)) {
2124514f5e3Sopenharmony_ci        *unitEnum = UDAT_REL_UNIT_HOUR;
2134514f5e3Sopenharmony_ci    } else if (EcmaStringAccessor::StringsAreEqual(*day, *unit) ||
2144514f5e3Sopenharmony_ci        EcmaStringAccessor::StringsAreEqual(*days, *unit)) {
2154514f5e3Sopenharmony_ci        *unitEnum = UDAT_REL_UNIT_DAY;
2164514f5e3Sopenharmony_ci    } else if (EcmaStringAccessor::StringsAreEqual(*week, *unit) ||
2174514f5e3Sopenharmony_ci        EcmaStringAccessor::StringsAreEqual(*weeks, *unit)) {
2184514f5e3Sopenharmony_ci        *unitEnum = UDAT_REL_UNIT_WEEK;
2194514f5e3Sopenharmony_ci    } else if (EcmaStringAccessor::StringsAreEqual(*month, *unit) ||
2204514f5e3Sopenharmony_ci        EcmaStringAccessor::StringsAreEqual(*months, *unit)) {
2214514f5e3Sopenharmony_ci        *unitEnum = UDAT_REL_UNIT_MONTH;
2224514f5e3Sopenharmony_ci    } else if (EcmaStringAccessor::StringsAreEqual(*quarter, *unit) ||
2234514f5e3Sopenharmony_ci        EcmaStringAccessor::StringsAreEqual(*quarters, *unit)) {
2244514f5e3Sopenharmony_ci        *unitEnum = UDAT_REL_UNIT_QUARTER;
2254514f5e3Sopenharmony_ci    } else if (EcmaStringAccessor::StringsAreEqual(*year, *unit) ||
2264514f5e3Sopenharmony_ci        EcmaStringAccessor::StringsAreEqual(*years, *unit)) {
2274514f5e3Sopenharmony_ci        *unitEnum = UDAT_REL_UNIT_YEAR;
2284514f5e3Sopenharmony_ci    } else {
2294514f5e3Sopenharmony_ci        return false;
2304514f5e3Sopenharmony_ci    }
2314514f5e3Sopenharmony_ci    // 11. else return unit.
2324514f5e3Sopenharmony_ci    return true;
2334514f5e3Sopenharmony_ci}
2344514f5e3Sopenharmony_ci
2354514f5e3Sopenharmony_ci// Unwrap RelativeTimeFormat
2364514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSRelativeTimeFormat::UnwrapRelativeTimeFormat(JSThread *thread,
2374514f5e3Sopenharmony_ci                                                                       const JSHandle<JSTaggedValue> &rtf)
2384514f5e3Sopenharmony_ci{
2394514f5e3Sopenharmony_ci    ASSERT_PRINT(rtf->IsJSObject(), "rtf is not a JSObject");
2404514f5e3Sopenharmony_ci
2414514f5e3Sopenharmony_ci    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
2424514f5e3Sopenharmony_ci    bool isInstanceOf = JSFunction::InstanceOf(thread, rtf, env->GetRelativeTimeFormatFunction());
2434514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, rtf);
2444514f5e3Sopenharmony_ci    if (!rtf->IsJSRelativeTimeFormat() && isInstanceOf) {
2454514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> key(thread, JSHandle<JSIntl>::Cast(env->GetIntlFunction())->GetFallbackSymbol());
2464514f5e3Sopenharmony_ci        OperationResult operationResult = JSTaggedValue::GetProperty(thread, rtf, key);
2474514f5e3Sopenharmony_ci        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, rtf);
2484514f5e3Sopenharmony_ci        return operationResult.GetValue();
2494514f5e3Sopenharmony_ci    }
2504514f5e3Sopenharmony_ci
2514514f5e3Sopenharmony_ci    // Perform ? RequireInternalSlot(relativeTimeFormat, [[InitializedRelativeTimeFormat]]).
2524514f5e3Sopenharmony_ci    if (!rtf->IsJSRelativeTimeFormat()) {
2534514f5e3Sopenharmony_ci        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, rtf);
2544514f5e3Sopenharmony_ci    }
2554514f5e3Sopenharmony_ci    return rtf;
2564514f5e3Sopenharmony_ci}
2574514f5e3Sopenharmony_ci
2584514f5e3Sopenharmony_ci// CommonFormat
2594514f5e3Sopenharmony_ciicu::FormattedRelativeDateTime GetIcuFormatted(JSThread *thread,
2604514f5e3Sopenharmony_ci                                               const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat,
2614514f5e3Sopenharmony_ci                                               double value, const JSHandle<EcmaString> &unit)
2624514f5e3Sopenharmony_ci{
2634514f5e3Sopenharmony_ci    icu::RelativeDateTimeFormatter *formatter = relativeTimeFormat->GetIcuRTFFormatter();
2644514f5e3Sopenharmony_ci    ASSERT_PRINT(formatter != nullptr, "rtfFormatter is null");
2654514f5e3Sopenharmony_ci
2664514f5e3Sopenharmony_ci    // If isFinite(value) is false, then throw a RangeError exception.
2674514f5e3Sopenharmony_ci    if (!std::isfinite(value)) {
2684514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "", icu::FormattedRelativeDateTime());
2694514f5e3Sopenharmony_ci    }
2704514f5e3Sopenharmony_ci
2714514f5e3Sopenharmony_ci    // 10. If unit is not one of "second", "minute", "hour", "day", "week", "month", "quarter", or "year", throw a
2724514f5e3Sopenharmony_ci    // RangeError exception.
2734514f5e3Sopenharmony_ci    URelativeDateTimeUnit unitEnum;
2744514f5e3Sopenharmony_ci    if (!SingularUnitToIcuUnit(thread, unit, &unitEnum)) {
2754514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "", icu::FormattedRelativeDateTime());
2764514f5e3Sopenharmony_ci    }
2774514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
2784514f5e3Sopenharmony_ci    NumericOption numeric = relativeTimeFormat->GetNumeric();
2794514f5e3Sopenharmony_ci
2804514f5e3Sopenharmony_ci    icu::FormattedRelativeDateTime formatted;
2814514f5e3Sopenharmony_ci    switch (numeric) {
2824514f5e3Sopenharmony_ci        case NumericOption::ALWAYS:
2834514f5e3Sopenharmony_ci            formatted = formatter->formatNumericToValue(value, unitEnum, status);
2844514f5e3Sopenharmony_ci            ASSERT_PRINT(U_SUCCESS(status), "icu format to value error");
2854514f5e3Sopenharmony_ci            break;
2864514f5e3Sopenharmony_ci        case NumericOption::AUTO:
2874514f5e3Sopenharmony_ci            formatted = formatter->formatToValue(value, unitEnum, status);
2884514f5e3Sopenharmony_ci            ASSERT_PRINT(U_SUCCESS(status), "icu format to value error");
2894514f5e3Sopenharmony_ci            break;
2904514f5e3Sopenharmony_ci        default:
2914514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
2924514f5e3Sopenharmony_ci            UNREACHABLE();
2934514f5e3Sopenharmony_ci    }
2944514f5e3Sopenharmony_ci    return formatted;
2954514f5e3Sopenharmony_ci}
2964514f5e3Sopenharmony_ci
2974514f5e3Sopenharmony_ci// 14.1.2 SingularRelativeTimeUnit ( unit )
2984514f5e3Sopenharmony_ciJSHandle<EcmaString> SingularUnitString(JSThread *thread, const JSHandle<EcmaString> &unit)
2994514f5e3Sopenharmony_ci{
3004514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
3014514f5e3Sopenharmony_ci    JSHandle<EcmaString> second = JSHandle<EcmaString>::Cast(globalConst->GetHandledSecondString());
3024514f5e3Sopenharmony_ci    JSHandle<EcmaString> minute = JSHandle<EcmaString>::Cast(globalConst->GetHandledMinuteString());
3034514f5e3Sopenharmony_ci    JSHandle<EcmaString> hour = JSHandle<EcmaString>::Cast(globalConst->GetHandledHourString());
3044514f5e3Sopenharmony_ci    JSHandle<EcmaString> day = JSHandle<EcmaString>::Cast(globalConst->GetHandledDayString());
3054514f5e3Sopenharmony_ci    JSHandle<EcmaString> week = JSHandle<EcmaString>::Cast(globalConst->GetHandledWeekString());
3064514f5e3Sopenharmony_ci    JSHandle<EcmaString> month = JSHandle<EcmaString>::Cast(globalConst->GetHandledMonthString());
3074514f5e3Sopenharmony_ci    JSHandle<EcmaString> quarter = JSHandle<EcmaString>::Cast(globalConst->GetHandledQuarterString());
3084514f5e3Sopenharmony_ci    JSHandle<EcmaString> year = JSHandle<EcmaString>::Cast(globalConst->GetHandledYearString());
3094514f5e3Sopenharmony_ci    JSHandle<EcmaString> seconds = JSHandle<EcmaString>::Cast(globalConst->GetHandledSecondsString());
3104514f5e3Sopenharmony_ci    JSHandle<EcmaString> minutes = JSHandle<EcmaString>::Cast(globalConst->GetHandledMinutesString());
3114514f5e3Sopenharmony_ci    JSHandle<EcmaString> hours = JSHandle<EcmaString>::Cast(globalConst->GetHandledHoursString());
3124514f5e3Sopenharmony_ci    JSHandle<EcmaString> days = JSHandle<EcmaString>::Cast(globalConst->GetHandledDaysString());
3134514f5e3Sopenharmony_ci    JSHandle<EcmaString> weeks = JSHandle<EcmaString>::Cast(globalConst->GetHandledWeeksString());
3144514f5e3Sopenharmony_ci    JSHandle<EcmaString> months = JSHandle<EcmaString>::Cast(globalConst->GetHandledMonthsString());
3154514f5e3Sopenharmony_ci    JSHandle<EcmaString> quarters = JSHandle<EcmaString>::Cast(globalConst->GetHandledQuartersString());
3164514f5e3Sopenharmony_ci    JSHandle<EcmaString> years = JSHandle<EcmaString>::Cast(globalConst->GetHandledYearsString());
3174514f5e3Sopenharmony_ci
3184514f5e3Sopenharmony_ci    // 2. If unit is "seconds" or "second", return "second".
3194514f5e3Sopenharmony_ci    if (EcmaStringAccessor::StringsAreEqual(*second, *unit) || EcmaStringAccessor::StringsAreEqual(*seconds, *unit)) {
3204514f5e3Sopenharmony_ci        return second;
3214514f5e3Sopenharmony_ci    }
3224514f5e3Sopenharmony_ci    // 3. If unit is "minutes" or "minute", return "minute".
3234514f5e3Sopenharmony_ci    if (EcmaStringAccessor::StringsAreEqual(*minute, *unit) || EcmaStringAccessor::StringsAreEqual(*minutes, *unit)) {
3244514f5e3Sopenharmony_ci        return minute;
3254514f5e3Sopenharmony_ci    }
3264514f5e3Sopenharmony_ci    // 4. If unit is "hours" or "hour", return "hour".
3274514f5e3Sopenharmony_ci    if (EcmaStringAccessor::StringsAreEqual(*hour, *unit) || EcmaStringAccessor::StringsAreEqual(*hours, *unit)) {
3284514f5e3Sopenharmony_ci        return hour;
3294514f5e3Sopenharmony_ci    }
3304514f5e3Sopenharmony_ci    // 5. If unit is "days" or "day", return "day".
3314514f5e3Sopenharmony_ci    if (EcmaStringAccessor::StringsAreEqual(*day, *unit) || EcmaStringAccessor::StringsAreEqual(*days, *unit)) {
3324514f5e3Sopenharmony_ci        return day;
3334514f5e3Sopenharmony_ci    }
3344514f5e3Sopenharmony_ci    // 6. If unit is "weeks" or "week", return "week".
3354514f5e3Sopenharmony_ci    if (EcmaStringAccessor::StringsAreEqual(*week, *unit) || EcmaStringAccessor::StringsAreEqual(*weeks, *unit)) {
3364514f5e3Sopenharmony_ci        return week;
3374514f5e3Sopenharmony_ci    }
3384514f5e3Sopenharmony_ci    // 7. If unit is "months" or "month", return "month".
3394514f5e3Sopenharmony_ci    if (EcmaStringAccessor::StringsAreEqual(*month, *unit) || EcmaStringAccessor::StringsAreEqual(*months, *unit)) {
3404514f5e3Sopenharmony_ci        return month;
3414514f5e3Sopenharmony_ci    }
3424514f5e3Sopenharmony_ci    // 8. If unit is "quarters" or "quarter", return "quarter".
3434514f5e3Sopenharmony_ci    if (EcmaStringAccessor::StringsAreEqual(*quarter, *unit) || EcmaStringAccessor::StringsAreEqual(*quarters, *unit)) {
3444514f5e3Sopenharmony_ci        return quarter;
3454514f5e3Sopenharmony_ci    }
3464514f5e3Sopenharmony_ci    // 9. If unit is "years" or "year", return "year".
3474514f5e3Sopenharmony_ci    if (EcmaStringAccessor::StringsAreEqual(*year, *unit) || EcmaStringAccessor::StringsAreEqual(*years, *unit)) {
3484514f5e3Sopenharmony_ci        return year;
3494514f5e3Sopenharmony_ci    }
3504514f5e3Sopenharmony_ci
3514514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> undefinedValue(thread, JSTaggedValue::Undefined());
3524514f5e3Sopenharmony_ci    return JSHandle<EcmaString>::Cast(undefinedValue);
3534514f5e3Sopenharmony_ci}
3544514f5e3Sopenharmony_ci
3554514f5e3Sopenharmony_ci// 14.1.5 FormatRelativeTime ( relativeTimeFormat, value, unit )
3564514f5e3Sopenharmony_ciJSHandle<EcmaString> JSRelativeTimeFormat::Format(JSThread *thread, double value, const JSHandle<EcmaString> &unit,
3574514f5e3Sopenharmony_ci                                                  const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat)
3584514f5e3Sopenharmony_ci{
3594514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
3604514f5e3Sopenharmony_ci    icu::FormattedRelativeDateTime formatted = GetIcuFormatted(thread, relativeTimeFormat, value, unit);
3614514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread);
3624514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
3634514f5e3Sopenharmony_ci    icu::UnicodeString uString = formatted.toString(status);
3644514f5e3Sopenharmony_ci    if (U_FAILURE(status) != 0) {
3654514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "icu formatted toString error", factory->GetEmptyString());
3664514f5e3Sopenharmony_ci    }
3674514f5e3Sopenharmony_ci    JSHandle<EcmaString> string =
3684514f5e3Sopenharmony_ci        factory->NewFromUtf16(reinterpret_cast<const uint16_t *>(uString.getBuffer()), uString.length());
3694514f5e3Sopenharmony_ci    return string;
3704514f5e3Sopenharmony_ci}
3714514f5e3Sopenharmony_ci
3724514f5e3Sopenharmony_civoid FormatToArray(JSThread *thread, const JSHandle<JSArray> &array,
3734514f5e3Sopenharmony_ci                   const icu::FormattedRelativeDateTime &formatted, double value,
3744514f5e3Sopenharmony_ci                   const JSHandle<EcmaString> &unit)
3754514f5e3Sopenharmony_ci{
3764514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
3774514f5e3Sopenharmony_ci    icu::UnicodeString formattedText = formatted.toString(status);
3784514f5e3Sopenharmony_ci    if (U_FAILURE(status)) {
3794514f5e3Sopenharmony_ci        THROW_TYPE_ERROR(thread, "formattedRelativeDateTime toString failed");
3804514f5e3Sopenharmony_ci    }
3814514f5e3Sopenharmony_ci
3824514f5e3Sopenharmony_ci    icu::ConstrainedFieldPosition cfpo;
3834514f5e3Sopenharmony_ci    // Set constrainCategory to UFIELD_CATEGORY_NUMBER which is specified for UNumberFormatFields
3844514f5e3Sopenharmony_ci    cfpo.constrainCategory(UFIELD_CATEGORY_NUMBER);
3854514f5e3Sopenharmony_ci    int32_t index = 0;
3864514f5e3Sopenharmony_ci    int32_t previousLimit = 0;
3874514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
3884514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> taggedValue(thread, JSTaggedValue(value));
3894514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> typeString(thread, JSTaggedValue::Undefined());
3904514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> unitString = globalConst->GetHandledUnitString();
3914514f5e3Sopenharmony_ci    std::vector<std::pair<int32_t, int32_t>> separatorFields;
3924514f5e3Sopenharmony_ci    /**
3934514f5e3Sopenharmony_ci     * From ICU header file document @unumberformatter.h
3944514f5e3Sopenharmony_ci     * Sets a constraint on the field category.
3954514f5e3Sopenharmony_ci     *
3964514f5e3Sopenharmony_ci     * When this instance of ConstrainedFieldPosition is passed to FormattedValue#nextPosition,
3974514f5e3Sopenharmony_ci     * positions are skipped unless they have the given category.
3984514f5e3Sopenharmony_ci     *
3994514f5e3Sopenharmony_ci     * Any previously set constraints are cleared.
4004514f5e3Sopenharmony_ci     *
4014514f5e3Sopenharmony_ci     * For example, to loop over only the number-related fields:
4024514f5e3Sopenharmony_ci     *
4034514f5e3Sopenharmony_ci     *     ConstrainedFieldPosition cfpo;
4044514f5e3Sopenharmony_ci     *     cfpo.constrainCategory(UFIELDCATEGORY_NUMBER_FORMAT);
4054514f5e3Sopenharmony_ci     *     while (fmtval.nextPosition(cfpo, status)) {
4064514f5e3Sopenharmony_ci     *         // handle the number-related field position
4074514f5e3Sopenharmony_ci     *     }
4084514f5e3Sopenharmony_ci     */
4094514f5e3Sopenharmony_ci    while ((formatted.nextPosition(cfpo, status) != 0)) {
4104514f5e3Sopenharmony_ci        int32_t fieldId = cfpo.getField();
4114514f5e3Sopenharmony_ci        int32_t start = cfpo.getStart();
4124514f5e3Sopenharmony_ci        int32_t limit = cfpo.getLimit();
4134514f5e3Sopenharmony_ci        // Special case when fieldId is UNUM_GROUPING_SEPARATOR_FIELD
4144514f5e3Sopenharmony_ci        if (static_cast<UNumberFormatFields>(fieldId) == UNUM_GROUPING_SEPARATOR_FIELD) {
4154514f5e3Sopenharmony_ci            separatorFields.push_back(std::pair<int32_t, int32_t>(start, limit));
4164514f5e3Sopenharmony_ci            continue;
4174514f5e3Sopenharmony_ci        }
4184514f5e3Sopenharmony_ci        // If start greater than previousLimit, means a literal type exists before number fields
4194514f5e3Sopenharmony_ci        // so add a literal type with value of formattedText.sub(0, start)
4204514f5e3Sopenharmony_ci        if (start > previousLimit) {
4214514f5e3Sopenharmony_ci            typeString.Update(globalConst->GetLiteralString());
4224514f5e3Sopenharmony_ci            JSHandle<EcmaString> substring =
4234514f5e3Sopenharmony_ci                intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, start);
4244514f5e3Sopenharmony_ci            JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(substring));
4254514f5e3Sopenharmony_ci            RETURN_IF_ABRUPT_COMPLETION(thread);
4264514f5e3Sopenharmony_ci        }
4274514f5e3Sopenharmony_ci        // Add part when type is unit
4284514f5e3Sopenharmony_ci        // Iterate former grouping separator vector and add unit element to array
4294514f5e3Sopenharmony_ci        for (auto it = separatorFields.begin(); it != separatorFields.end(); it++) {
4304514f5e3Sopenharmony_ci            if (it->first > start) {
4314514f5e3Sopenharmony_ci                // Add Integer type element
4324514f5e3Sopenharmony_ci                JSHandle<EcmaString> resString =
4334514f5e3Sopenharmony_ci                    intl::LocaleHelper::UStringToString(thread, formattedText, start, it->first);
4344514f5e3Sopenharmony_ci                typeString.Update(
4354514f5e3Sopenharmony_ci                    JSLocale::GetNumberFieldType(thread, taggedValue.GetTaggedValue(), fieldId).GetTaggedValue());
4364514f5e3Sopenharmony_ci                JSHandle<JSObject> record =
4374514f5e3Sopenharmony_ci                    JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(resString));
4384514f5e3Sopenharmony_ci                RETURN_IF_ABRUPT_COMPLETION(thread);
4394514f5e3Sopenharmony_ci                JSObject::CreateDataPropertyOrThrow(thread, record, unitString, JSHandle<JSTaggedValue>::Cast(unit));
4404514f5e3Sopenharmony_ci                RETURN_IF_ABRUPT_COMPLETION(thread);
4414514f5e3Sopenharmony_ci                // Add Group type element
4424514f5e3Sopenharmony_ci                resString = intl::LocaleHelper::UStringToString(thread, formattedText, it->first, it->second);
4434514f5e3Sopenharmony_ci                typeString.Update(JSLocale::GetNumberFieldType(thread, taggedValue.GetTaggedValue(),
4444514f5e3Sopenharmony_ci                    UNUM_GROUPING_SEPARATOR_FIELD).GetTaggedValue());
4454514f5e3Sopenharmony_ci                record =
4464514f5e3Sopenharmony_ci                    JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(resString));
4474514f5e3Sopenharmony_ci                RETURN_IF_ABRUPT_COMPLETION(thread);
4484514f5e3Sopenharmony_ci                JSObject::CreateDataPropertyOrThrow(thread, record, unitString, JSHandle<JSTaggedValue>::Cast(unit));
4494514f5e3Sopenharmony_ci                RETURN_IF_ABRUPT_COMPLETION(thread);
4504514f5e3Sopenharmony_ci                start = it->second;
4514514f5e3Sopenharmony_ci            }
4524514f5e3Sopenharmony_ci        }
4534514f5e3Sopenharmony_ci        // Add current field unit
4544514f5e3Sopenharmony_ci        JSHandle<EcmaString> subString = intl::LocaleHelper::UStringToString(thread, formattedText, start, limit);
4554514f5e3Sopenharmony_ci        typeString.Update(JSLocale::GetNumberFieldType(thread, taggedValue.GetTaggedValue(), fieldId).GetTaggedValue());
4564514f5e3Sopenharmony_ci        JSHandle<JSObject> record =
4574514f5e3Sopenharmony_ci            JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(subString));
4584514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
4594514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, record, unitString, JSHandle<JSTaggedValue>::Cast(unit));
4604514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
4614514f5e3Sopenharmony_ci        previousLimit = limit;
4624514f5e3Sopenharmony_ci    }
4634514f5e3Sopenharmony_ci    // If iterated length is smaller than formattedText.length, means a literal type exists after number fields
4644514f5e3Sopenharmony_ci    // so add a literal type with value of formattedText.sub(previousLimit, formattedText.length)
4654514f5e3Sopenharmony_ci    if (formattedText.length() > previousLimit) {
4664514f5e3Sopenharmony_ci        typeString.Update(globalConst->GetLiteralString());
4674514f5e3Sopenharmony_ci        JSHandle<EcmaString> substring =
4684514f5e3Sopenharmony_ci            intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, formattedText.length());
4694514f5e3Sopenharmony_ci        JSLocale::PutElement(thread, index, array, typeString, JSHandle<JSTaggedValue>::Cast(substring));
4704514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
4714514f5e3Sopenharmony_ci    }
4724514f5e3Sopenharmony_ci}
4734514f5e3Sopenharmony_ci
4744514f5e3Sopenharmony_ci// 14.1.6 FormatRelativeTimeToParts ( relativeTimeFormat, value, unit )
4754514f5e3Sopenharmony_ciJSHandle<JSArray> JSRelativeTimeFormat::FormatToParts(JSThread *thread, double value, const JSHandle<EcmaString> &unit,
4764514f5e3Sopenharmony_ci                                                      const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat)
4774514f5e3Sopenharmony_ci{
4784514f5e3Sopenharmony_ci    icu::FormattedRelativeDateTime formatted = GetIcuFormatted(thread, relativeTimeFormat, value, unit);
4794514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread);
4804514f5e3Sopenharmony_ci    JSHandle<EcmaString> singularUnit = SingularUnitString(thread, unit);
4814514f5e3Sopenharmony_ci    JSHandle<JSArray> array = JSHandle<JSArray>::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
4824514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread);
4834514f5e3Sopenharmony_ci    FormatToArray(thread, array, formatted, value, singularUnit);
4844514f5e3Sopenharmony_ci    return array;
4854514f5e3Sopenharmony_ci}
4864514f5e3Sopenharmony_ci
4874514f5e3Sopenharmony_civoid JSRelativeTimeFormat::ResolvedOptions(JSThread *thread, const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat,
4884514f5e3Sopenharmony_ci                                           const JSHandle<JSObject> &options)
4894514f5e3Sopenharmony_ci{
4904514f5e3Sopenharmony_ci    if (relativeTimeFormat->GetIcuRTFFormatter() != nullptr) {
4914514f5e3Sopenharmony_ci        [[maybe_unused]] icu::RelativeDateTimeFormatter *formatter = relativeTimeFormat->GetIcuRTFFormatter();
4924514f5e3Sopenharmony_ci    } else {
4934514f5e3Sopenharmony_ci        THROW_ERROR(thread, ErrorType::RANGE_ERROR, "rtf is not initialized");
4944514f5e3Sopenharmony_ci    }
4954514f5e3Sopenharmony_ci
4964514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
4974514f5e3Sopenharmony_ci    // [[locale]]
4984514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> property = globalConst->GetHandledLocaleString();
4994514f5e3Sopenharmony_ci    JSHandle<EcmaString> locale(thread, relativeTimeFormat->GetLocale());
5004514f5e3Sopenharmony_ci    PropertyDescriptor localeDesc(thread, JSHandle<JSTaggedValue>::Cast(locale), true, true, true);
5014514f5e3Sopenharmony_ci    JSObject::DefineOwnProperty(thread, options, property, localeDesc);
5024514f5e3Sopenharmony_ci
5034514f5e3Sopenharmony_ci    // [[Style]]
5044514f5e3Sopenharmony_ci    property = globalConst->GetHandledStyleString();
5054514f5e3Sopenharmony_ci    RelativeStyleOption style = relativeTimeFormat->GetStyle();
5064514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> styleValue;
5074514f5e3Sopenharmony_ci    if (style == RelativeStyleOption::LONG) {
5084514f5e3Sopenharmony_ci        styleValue = globalConst->GetHandledLongString();
5094514f5e3Sopenharmony_ci    } else if (style == RelativeStyleOption::SHORT) {
5104514f5e3Sopenharmony_ci        styleValue = globalConst->GetHandledShortString();
5114514f5e3Sopenharmony_ci    } else if (style == RelativeStyleOption::NARROW) {
5124514f5e3Sopenharmony_ci        styleValue = globalConst->GetHandledNarrowString();
5134514f5e3Sopenharmony_ci    }
5144514f5e3Sopenharmony_ci    PropertyDescriptor styleDesc(thread, styleValue, true, true, true);
5154514f5e3Sopenharmony_ci    JSObject::DefineOwnProperty(thread, options, property, styleDesc);
5164514f5e3Sopenharmony_ci
5174514f5e3Sopenharmony_ci    // [[Numeric]]
5184514f5e3Sopenharmony_ci    property = globalConst->GetHandledNumericString();
5194514f5e3Sopenharmony_ci    NumericOption numeric = relativeTimeFormat->GetNumeric();
5204514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> numericValue;
5214514f5e3Sopenharmony_ci    if (numeric == NumericOption::ALWAYS) {
5224514f5e3Sopenharmony_ci        numericValue = globalConst->GetHandledAlwaysString();
5234514f5e3Sopenharmony_ci    } else if (numeric == NumericOption::AUTO) {
5244514f5e3Sopenharmony_ci        numericValue = globalConst->GetHandledAutoString();
5254514f5e3Sopenharmony_ci    } else {
5264514f5e3Sopenharmony_ci        THROW_ERROR(thread, ErrorType::RANGE_ERROR, "numeric is exception");
5274514f5e3Sopenharmony_ci    }
5284514f5e3Sopenharmony_ci    PropertyDescriptor numericDesc(thread, numericValue, true, true, true);
5294514f5e3Sopenharmony_ci    JSObject::DefineOwnProperty(thread, options, property, numericDesc);
5304514f5e3Sopenharmony_ci
5314514f5e3Sopenharmony_ci    // [[NumberingSystem]]
5324514f5e3Sopenharmony_ci    property = JSHandle<JSTaggedValue>::Cast(globalConst->GetHandledNumberingSystemString());
5334514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> numberingSystem(thread, relativeTimeFormat->GetNumberingSystem());
5344514f5e3Sopenharmony_ci    PropertyDescriptor numberingSystemDesc(thread, numberingSystem, true, true, true);
5354514f5e3Sopenharmony_ci    JSObject::DefineOwnProperty(thread, options, property, numberingSystemDesc);
5364514f5e3Sopenharmony_ci}
5374514f5e3Sopenharmony_ci}  // namespace panda::ecmascript