14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021 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/builtins/builtins_date.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/global_env.h"
194514f5e3Sopenharmony_ci#include "ecmascript/interpreter/interpreter.h"
204514f5e3Sopenharmony_ci#include "ecmascript/js_function.h"
214514f5e3Sopenharmony_ci
224514f5e3Sopenharmony_ci#ifdef ARK_SUPPORT_INTL
234514f5e3Sopenharmony_ci#include "ecmascript/js_date.h"
244514f5e3Sopenharmony_ci#include "ecmascript/js_date_time_format.h"
254514f5e3Sopenharmony_ci#else
264514f5e3Sopenharmony_ci#ifndef ARK_NOT_SUPPORT_INTL_GLOBAL
274514f5e3Sopenharmony_ci#include "ecmascript/intl/global_intl_helper.h"
284514f5e3Sopenharmony_ci#endif
294514f5e3Sopenharmony_ci#endif
304514f5e3Sopenharmony_ci
314514f5e3Sopenharmony_cinamespace panda::ecmascript::builtins {
324514f5e3Sopenharmony_ci// constructor
334514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::DateConstructor(EcmaRuntimeCallInfo *argv)
344514f5e3Sopenharmony_ci{
354514f5e3Sopenharmony_ci    BUILTINS_ENTRY_DEBUG_LOG();
364514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Date, Constructor);
374514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
384514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
394514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
404514f5e3Sopenharmony_ci    if (newTarget->IsUndefined()) {
414514f5e3Sopenharmony_ci        double now = JSDate::Now().GetDouble();
424514f5e3Sopenharmony_ci        CString str = JSDate::ToDateString(now);
434514f5e3Sopenharmony_ci        return GetTaggedString(thread, str.c_str());
444514f5e3Sopenharmony_ci    }
454514f5e3Sopenharmony_ci
464514f5e3Sopenharmony_ci    JSTaggedValue timeValue(0.0);
474514f5e3Sopenharmony_ci    uint32_t length = argv->GetArgsNumber();
484514f5e3Sopenharmony_ci    if (length == 0) {  // no value
494514f5e3Sopenharmony_ci        timeValue = JSDate::Now();
504514f5e3Sopenharmony_ci    } else if (length == 1) {  // one value
514514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
524514f5e3Sopenharmony_ci        if (value->IsDate()) {  // The value is a date object.
534514f5e3Sopenharmony_ci            JSHandle<JSDate> jsDate(thread, JSDate::Cast(value->GetTaggedObject()));
544514f5e3Sopenharmony_ci            timeValue = jsDate->GetTimeValue();
554514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
564514f5e3Sopenharmony_ci        } else {
574514f5e3Sopenharmony_ci            JSHandle<JSTaggedValue> objValue(thread, JSTaggedValue::ToPrimitive(thread, value));
584514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
594514f5e3Sopenharmony_ci            if (objValue->IsString()) {  // The value is a string object.
604514f5e3Sopenharmony_ci                timeValue = JSDate::Parse(argv);
614514f5e3Sopenharmony_ci                RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
624514f5e3Sopenharmony_ci            } else {  // The value is a number.
634514f5e3Sopenharmony_ci                JSTaggedNumber val = JSTaggedValue::ToNumber(thread, objValue);
644514f5e3Sopenharmony_ci                RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
654514f5e3Sopenharmony_ci                timeValue = JSTaggedValue(val.GetNumber());
664514f5e3Sopenharmony_ci            }
674514f5e3Sopenharmony_ci            timeValue = JSTaggedValue(JSDate::TimeClip(timeValue.GetDouble()));
684514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
694514f5e3Sopenharmony_ci        }
704514f5e3Sopenharmony_ci    } else {  // two or more values
714514f5e3Sopenharmony_ci        timeValue = ExtractDateFields(thread, length, argv, timeValue);
724514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
734514f5e3Sopenharmony_ci    }
744514f5e3Sopenharmony_ci
754514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
764514f5e3Sopenharmony_ci    JSHandle<JSFunction> constructor(GetConstructor(argv));
774514f5e3Sopenharmony_ci    JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(constructor, newTarget);
784514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
794514f5e3Sopenharmony_ci    JSHandle<JSDate> dateObject = JSHandle<JSDate>::Cast(obj);
804514f5e3Sopenharmony_ci    dateObject->SetTimeValue(thread, timeValue);
814514f5e3Sopenharmony_ci    return dateObject.GetTaggedValue();
824514f5e3Sopenharmony_ci}
834514f5e3Sopenharmony_ci
844514f5e3Sopenharmony_ci// 20.4.3.1
854514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::Now([[maybe_unused]] EcmaRuntimeCallInfo *argv)
864514f5e3Sopenharmony_ci{
874514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Date, Now);
884514f5e3Sopenharmony_ci    return JSDate::Now();
894514f5e3Sopenharmony_ci}
904514f5e3Sopenharmony_ci
914514f5e3Sopenharmony_ci// 20.4.3.2
924514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::Parse(EcmaRuntimeCallInfo *argv)
934514f5e3Sopenharmony_ci{
944514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Date, Parse);
954514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
964514f5e3Sopenharmony_ci    return JSDate::Parse(argv);
974514f5e3Sopenharmony_ci}
984514f5e3Sopenharmony_ci
994514f5e3Sopenharmony_ci// 20.4.3.4
1004514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::UTC(EcmaRuntimeCallInfo *argv)
1014514f5e3Sopenharmony_ci{
1024514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Date, UTC);
1034514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
1044514f5e3Sopenharmony_ci    return JSDate::UTC(argv);
1054514f5e3Sopenharmony_ci}
1064514f5e3Sopenharmony_ci
1074514f5e3Sopenharmony_ci// 20.4.4.10
1084514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::GetTime(EcmaRuntimeCallInfo *argv)
1094514f5e3Sopenharmony_ci{
1104514f5e3Sopenharmony_ci    ASSERT(argv);
1114514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Date, GetTime);
1124514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
1134514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> msg = GetThis(argv);
1144514f5e3Sopenharmony_ci    if (!msg->IsDate()) {
1154514f5e3Sopenharmony_ci        [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
1164514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception());
1174514f5e3Sopenharmony_ci    }
1184514f5e3Sopenharmony_ci    return JSDate::Cast(msg->GetTaggedObject())->GetTime();
1194514f5e3Sopenharmony_ci}
1204514f5e3Sopenharmony_ci
1214514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::SetTime(EcmaRuntimeCallInfo *argv)
1224514f5e3Sopenharmony_ci{
1234514f5e3Sopenharmony_ci    ASSERT(argv);
1244514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Date, SetTime);
1254514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
1264514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
1274514f5e3Sopenharmony_ci
1284514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> msg = GetThis(argv);
1294514f5e3Sopenharmony_ci    if (!msg->IsDate()) {
1304514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception());
1314514f5e3Sopenharmony_ci    }
1324514f5e3Sopenharmony_ci    JSHandle<JSDate> jsDate(thread, JSDate::Cast(msg->GetTaggedObject()));
1334514f5e3Sopenharmony_ci    JSTaggedNumber res = JSTaggedValue::ToNumber(thread, GetCallArg(argv, 0));
1344514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
1354514f5e3Sopenharmony_ci    double number = res.GetNumber();
1364514f5e3Sopenharmony_ci    double value = JSDate::TimeClip(number);
1374514f5e3Sopenharmony_ci    jsDate->SetTimeValue(thread, JSTaggedValue(value));
1384514f5e3Sopenharmony_ci    return GetTaggedDouble(value);
1394514f5e3Sopenharmony_ci}
1404514f5e3Sopenharmony_ci
1414514f5e3Sopenharmony_ci// 20.4.4.37
1424514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::ToJSON(EcmaRuntimeCallInfo *argv)
1434514f5e3Sopenharmony_ci{
1444514f5e3Sopenharmony_ci    ASSERT(argv);
1454514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Date, ToJSON);
1464514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
1474514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
1484514f5e3Sopenharmony_ci
1494514f5e3Sopenharmony_ci    // 1. Let O be ToObject(this value).
1504514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> msg = GetThis(argv);
1514514f5e3Sopenharmony_ci    JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, msg);
1524514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1534514f5e3Sopenharmony_ci
1544514f5e3Sopenharmony_ci    // 2. Let tv be ToPrimitive(hint Number)
1554514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> objectHandle = JSHandle<JSTaggedValue>::Cast(object);
1564514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> tv(thread,
1574514f5e3Sopenharmony_ci                               JSTaggedValue::ToPrimitive(thread, objectHandle, PreferredPrimitiveType::PREFER_NUMBER));
1584514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1594514f5e3Sopenharmony_ci    // 3. If Type(tv) is Number and tv is not finite, return null
1604514f5e3Sopenharmony_ci    if (tv->IsNumber()) {
1614514f5e3Sopenharmony_ci        if (tv->IsDouble() && !std::isfinite(tv->GetDouble())) {
1624514f5e3Sopenharmony_ci            return JSTaggedValue::Null();
1634514f5e3Sopenharmony_ci        }
1644514f5e3Sopenharmony_ci    }
1654514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> calleeKey(thread->GetEcmaVM()->GetFactory()->NewFromASCII("toISOString"));
1664514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1674514f5e3Sopenharmony_ci    EcmaRuntimeCallInfo *info =
1684514f5e3Sopenharmony_ci        EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, objectHandle, undefined, 0);
1694514f5e3Sopenharmony_ci    return JSFunction::Invoke(info, calleeKey);
1704514f5e3Sopenharmony_ci}
1714514f5e3Sopenharmony_ci
1724514f5e3Sopenharmony_ci// 20.4.4.44
1734514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::ValueOf(EcmaRuntimeCallInfo *argv)
1744514f5e3Sopenharmony_ci{
1754514f5e3Sopenharmony_ci    ASSERT(argv);
1764514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Date, ValueOf);
1774514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
1784514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> msg = GetThis(argv);
1794514f5e3Sopenharmony_ci    if (!msg->IsDate()) {
1804514f5e3Sopenharmony_ci        [[maybe_unused]] EcmaHandleScope handleScope(thread);
1814514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception());
1824514f5e3Sopenharmony_ci    }
1834514f5e3Sopenharmony_ci    return JSDate::Cast(msg->GetTaggedObject())->ValueOf();
1844514f5e3Sopenharmony_ci}
1854514f5e3Sopenharmony_ci
1864514f5e3Sopenharmony_ci// 20.4.4.45
1874514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::ToPrimitive(EcmaRuntimeCallInfo *argv)
1884514f5e3Sopenharmony_ci{
1894514f5e3Sopenharmony_ci    ASSERT(argv);
1904514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Date, ToPrimitive);
1914514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
1924514f5e3Sopenharmony_ci    auto vm = thread->GetEcmaVM();
1934514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
1944514f5e3Sopenharmony_ci
1954514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> object = GetThis(argv);
1964514f5e3Sopenharmony_ci    if (!object->IsECMAObject()) {
1974514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "Not a JSObject", JSTaggedValue::Exception());
1984514f5e3Sopenharmony_ci    }
1994514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> hint = GetCallArg(argv, 0);
2004514f5e3Sopenharmony_ci    PreferredPrimitiveType tryFirst = PREFER_STRING;
2014514f5e3Sopenharmony_ci    const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2024514f5e3Sopenharmony_ci    if (hint->IsString()) {
2034514f5e3Sopenharmony_ci        JSHandle<EcmaString> numberStrHandle = JSHandle<EcmaString>::Cast(globalConst->GetHandledNumberString());
2044514f5e3Sopenharmony_ci        if (EcmaStringAccessor::StringsAreEqual(vm, JSHandle<EcmaString>(hint), numberStrHandle)) {
2054514f5e3Sopenharmony_ci            tryFirst = PREFER_NUMBER;
2064514f5e3Sopenharmony_ci        } else {
2074514f5e3Sopenharmony_ci            JSHandle<EcmaString> stringStrHandle = JSHandle<EcmaString>::Cast(globalConst->GetHandledStringString());
2084514f5e3Sopenharmony_ci            JSHandle<EcmaString> defaultStrHandle = JSHandle<EcmaString>::Cast(globalConst->GetHandledDefaultString());
2094514f5e3Sopenharmony_ci            if (EcmaStringAccessor::StringsAreEqual(vm, JSHandle<EcmaString>(hint), stringStrHandle) ||
2104514f5e3Sopenharmony_ci                EcmaStringAccessor::StringsAreEqual(vm, JSHandle<EcmaString>(hint), defaultStrHandle)) {
2114514f5e3Sopenharmony_ci                tryFirst = PREFER_STRING;
2124514f5e3Sopenharmony_ci            } else {
2134514f5e3Sopenharmony_ci                THROW_TYPE_ERROR_AND_RETURN(thread, "This is not a primitiveType.", JSTaggedValue::Exception());
2144514f5e3Sopenharmony_ci            }
2154514f5e3Sopenharmony_ci        }
2164514f5e3Sopenharmony_ci    } else {
2174514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "This is not an primitiveType.", JSTaggedValue::Exception());
2184514f5e3Sopenharmony_ci    }
2194514f5e3Sopenharmony_ci    return JSTaggedValue::OrdinaryToPrimitive(thread, object, tryFirst);
2204514f5e3Sopenharmony_ci}
2214514f5e3Sopenharmony_ci
2224514f5e3Sopenharmony_ci// ecma 402 16.4.1 Date.prototype.toLocaleString ( [ locales [ , options ] ] )
2234514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::ToLocaleString(EcmaRuntimeCallInfo *argv)
2244514f5e3Sopenharmony_ci{
2254514f5e3Sopenharmony_ci    ASSERT(argv);
2264514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
2274514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, Date, ToLocaleString);
2284514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
2294514f5e3Sopenharmony_ci    [[maybe_unused]] ObjectFactory *factory = ecmaVm->GetFactory();
2304514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
2314514f5e3Sopenharmony_ci
2324514f5e3Sopenharmony_ci    // Let x be ? thisTimeValue(this value).
2334514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> msg = GetThis(argv);
2344514f5e3Sopenharmony_ci    if (!msg->IsDate()) {
2354514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception());
2364514f5e3Sopenharmony_ci    }
2374514f5e3Sopenharmony_ci    JSTaggedValue value = JSDate::Cast(msg->GetTaggedObject())->GetTime();
2384514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2394514f5e3Sopenharmony_ci
2404514f5e3Sopenharmony_ci    // If x is NaN, return "Invalid Date".
2414514f5e3Sopenharmony_ci    double x = value.GetNumber();
2424514f5e3Sopenharmony_ci    if (std::isnan(x)) {
2434514f5e3Sopenharmony_ci        return thread->GlobalConstants()->GetInvalidDateString();
2444514f5e3Sopenharmony_ci    }
2454514f5e3Sopenharmony_ci
2464514f5e3Sopenharmony_ci    // Let options be ? ToDateTimeOptions(options, "any", "all").
2474514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
2484514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
2494514f5e3Sopenharmony_ci    [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined();
2504514f5e3Sopenharmony_ci#ifdef ARK_SUPPORT_INTL
2514514f5e3Sopenharmony_ci    if (cacheable) {
2524514f5e3Sopenharmony_ci        auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales,
2534514f5e3Sopenharmony_ci            IcuFormatterType::SIMPLE_DATE_FORMAT_DEFAULT);
2544514f5e3Sopenharmony_ci        if (simpleDateFormat != nullptr) {
2554514f5e3Sopenharmony_ci            JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x);
2564514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2574514f5e3Sopenharmony_ci            return result.GetTaggedValue();
2584514f5e3Sopenharmony_ci        }
2594514f5e3Sopenharmony_ci    }
2604514f5e3Sopenharmony_ci    JSHandle<JSObject> dateTimeOptions =
2614514f5e3Sopenharmony_ci        JSDateTimeFormat::ToDateTimeOptions(thread, options, RequiredOption::ANY, DefaultsOption::ALL);
2624514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2634514f5e3Sopenharmony_ci    JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
2644514f5e3Sopenharmony_ci    // Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »).
2654514f5e3Sopenharmony_ci    JSHandle<JSFunction> ctor(env->GetDateTimeFormatFunction());
2664514f5e3Sopenharmony_ci    JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor);
2674514f5e3Sopenharmony_ci    IcuCacheType type = cacheable ? IcuCacheType::DEFAULT : IcuCacheType::NOT_CACHE;
2684514f5e3Sopenharmony_ci    JSHandle<JSDateTimeFormat> dtf = JSDateTimeFormat::InitializeDateTimeFormat(thread,
2694514f5e3Sopenharmony_ci        JSHandle<JSDateTimeFormat>::Cast(obj), locales, JSHandle<JSTaggedValue>::Cast(dateTimeOptions), type);
2704514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2714514f5e3Sopenharmony_ci    if (cacheable) {
2724514f5e3Sopenharmony_ci        auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales,
2734514f5e3Sopenharmony_ci            IcuFormatterType::SIMPLE_DATE_FORMAT_DEFAULT);
2744514f5e3Sopenharmony_ci        ASSERT(simpleDateFormat != nullptr);
2754514f5e3Sopenharmony_ci        JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x);
2764514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2774514f5e3Sopenharmony_ci        return result.GetTaggedValue();
2784514f5e3Sopenharmony_ci    }
2794514f5e3Sopenharmony_ci
2804514f5e3Sopenharmony_ci    // Return ? FormatDateTime(dateFormat, x).
2814514f5e3Sopenharmony_ci    JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, dtf, x);
2824514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2834514f5e3Sopenharmony_ci    return result.GetTaggedValue();
2844514f5e3Sopenharmony_ci#else
2854514f5e3Sopenharmony_ci#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL
2864514f5e3Sopenharmony_ci    ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "ToLocaleString");
2874514f5e3Sopenharmony_ci#else
2884514f5e3Sopenharmony_ci    intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::DateFormatter);
2894514f5e3Sopenharmony_ci    auto dateFormatter = gh.GetGlobalObject<intl::GlobalDateFormatter>(thread,
2904514f5e3Sopenharmony_ci        locales, options, intl::GlobalFormatterType::DateFormatter, cacheable);
2914514f5e3Sopenharmony_ci    if (dateFormatter == nullptr) {
2924514f5e3Sopenharmony_ci        LOG_ECMA(ERROR) << "BuiltinsDate::ToLocaleString:dateFormatter is nullptr";
2934514f5e3Sopenharmony_ci    }
2944514f5e3Sopenharmony_ci    ASSERT(dateFormatter != nullptr);
2954514f5e3Sopenharmony_ci    std::string result = dateFormatter->Format(intl::GlobalIntlHelper::DoubleToInt64(x));
2964514f5e3Sopenharmony_ci    JSHandle returnValue = factory->NewFromStdString(result);
2974514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2984514f5e3Sopenharmony_ci    return returnValue.GetTaggedValue();
2994514f5e3Sopenharmony_ci#endif
3004514f5e3Sopenharmony_ci#endif
3014514f5e3Sopenharmony_ci}
3024514f5e3Sopenharmony_ci
3034514f5e3Sopenharmony_ci// ecma 402 16.4.1 Date.prototype.toLocaleString ( [ locales [ , options ] ] )
3044514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::ToLocaleDateString(EcmaRuntimeCallInfo *argv)
3054514f5e3Sopenharmony_ci{
3064514f5e3Sopenharmony_ci    ASSERT(argv);
3074514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
3084514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, Date, ToLocaleDateString);
3094514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
3104514f5e3Sopenharmony_ci    [[maybe_unused]] ObjectFactory *factory = ecmaVm->GetFactory();
3114514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
3124514f5e3Sopenharmony_ci
3134514f5e3Sopenharmony_ci    // Let x be ? thisTimeValue(this value).
3144514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> msg = GetThis(argv);
3154514f5e3Sopenharmony_ci    if (!msg->IsDate()) {
3164514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception());
3174514f5e3Sopenharmony_ci    }
3184514f5e3Sopenharmony_ci    JSTaggedValue value = JSDate::Cast(msg->GetTaggedObject())->GetTime();
3194514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3204514f5e3Sopenharmony_ci
3214514f5e3Sopenharmony_ci    // If x is NaN, return "Invalid Date".
3224514f5e3Sopenharmony_ci    double x = value.GetNumber();
3234514f5e3Sopenharmony_ci    if (std::isnan(x)) {
3244514f5e3Sopenharmony_ci        return thread->GlobalConstants()->GetInvalidDateString();
3254514f5e3Sopenharmony_ci    }
3264514f5e3Sopenharmony_ci
3274514f5e3Sopenharmony_ci    // Let options be ? ToDateTimeOptions(options, "any", "all").
3284514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
3294514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
3304514f5e3Sopenharmony_ci    [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined();
3314514f5e3Sopenharmony_ci#ifdef ARK_SUPPORT_INTL
3324514f5e3Sopenharmony_ci    if (cacheable) {
3334514f5e3Sopenharmony_ci        auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales,
3344514f5e3Sopenharmony_ci            IcuFormatterType::SIMPLE_DATE_FORMAT_DATE);
3354514f5e3Sopenharmony_ci        if (simpleDateFormat != nullptr) {
3364514f5e3Sopenharmony_ci            JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x);
3374514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3384514f5e3Sopenharmony_ci            return result.GetTaggedValue();
3394514f5e3Sopenharmony_ci        }
3404514f5e3Sopenharmony_ci    }
3414514f5e3Sopenharmony_ci    JSHandle<JSObject> dateTimeOptions =
3424514f5e3Sopenharmony_ci        JSDateTimeFormat::ToDateTimeOptions(thread, options, RequiredOption::DATE, DefaultsOption::DATE);
3434514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3444514f5e3Sopenharmony_ci    JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
3454514f5e3Sopenharmony_ci    // Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »).
3464514f5e3Sopenharmony_ci    JSHandle<JSFunction> ctor(env->GetDateTimeFormatFunction());
3474514f5e3Sopenharmony_ci    JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor);
3484514f5e3Sopenharmony_ci    IcuCacheType type = cacheable ? IcuCacheType::DATE : IcuCacheType::NOT_CACHE;
3494514f5e3Sopenharmony_ci    JSHandle<JSDateTimeFormat> dtf = JSDateTimeFormat::InitializeDateTimeFormat(thread,
3504514f5e3Sopenharmony_ci        JSHandle<JSDateTimeFormat>::Cast(obj), locales, JSHandle<JSTaggedValue>::Cast(dateTimeOptions), type);
3514514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3524514f5e3Sopenharmony_ci    if (cacheable) {
3534514f5e3Sopenharmony_ci        auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales,
3544514f5e3Sopenharmony_ci            IcuFormatterType::SIMPLE_DATE_FORMAT_DATE);
3554514f5e3Sopenharmony_ci        ASSERT(simpleDateFormat != nullptr);
3564514f5e3Sopenharmony_ci        JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x);
3574514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3584514f5e3Sopenharmony_ci        return result.GetTaggedValue();
3594514f5e3Sopenharmony_ci    }
3604514f5e3Sopenharmony_ci
3614514f5e3Sopenharmony_ci    // Return ? FormatDateTime(dateFormat, x).
3624514f5e3Sopenharmony_ci    JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, dtf, x);
3634514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3644514f5e3Sopenharmony_ci    return result.GetTaggedValue();
3654514f5e3Sopenharmony_ci#else
3664514f5e3Sopenharmony_ci#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL
3674514f5e3Sopenharmony_ci    ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare");
3684514f5e3Sopenharmony_ci#else
3694514f5e3Sopenharmony_ci    intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::SimpleDateFormatDate);
3704514f5e3Sopenharmony_ci    auto dateFormatter = gh.GetGlobalObject<intl::GlobalDateFormatter>(thread,
3714514f5e3Sopenharmony_ci        locales, options, intl::GlobalFormatterType::SimpleDateFormatDate, cacheable);
3724514f5e3Sopenharmony_ci    if (dateFormatter == nullptr) {
3734514f5e3Sopenharmony_ci        LOG_ECMA(ERROR) << "BuiltinsDate::ToLocaleDateString:dateFormatter is nullptr";
3744514f5e3Sopenharmony_ci    }
3754514f5e3Sopenharmony_ci    ASSERT(dateFormatter != nullptr);
3764514f5e3Sopenharmony_ci    std::string result = dateFormatter->Format(intl::GlobalIntlHelper::DoubleToInt64(x));
3774514f5e3Sopenharmony_ci    JSHandle returnValue = factory->NewFromStdString(result);
3784514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3794514f5e3Sopenharmony_ci    return returnValue.GetTaggedValue();
3804514f5e3Sopenharmony_ci#endif
3814514f5e3Sopenharmony_ci#endif
3824514f5e3Sopenharmony_ci}
3834514f5e3Sopenharmony_ci
3844514f5e3Sopenharmony_ci// ecma 402 16.4.1 Date.prototype.toLocaleString ( [ locales [ , options ] ] )
3854514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::ToLocaleTimeString(EcmaRuntimeCallInfo *argv)
3864514f5e3Sopenharmony_ci{
3874514f5e3Sopenharmony_ci    ASSERT(argv);
3884514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
3894514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, Date, ToLocaleTimeString);
3904514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
3914514f5e3Sopenharmony_ci    [[maybe_unused]] ObjectFactory *factory = ecmaVm->GetFactory();
3924514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
3934514f5e3Sopenharmony_ci
3944514f5e3Sopenharmony_ci    // Let x be ? thisTimeValue(this value).
3954514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> msg = GetThis(argv);
3964514f5e3Sopenharmony_ci    if (!msg->IsDate()) {
3974514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception());
3984514f5e3Sopenharmony_ci    }
3994514f5e3Sopenharmony_ci    JSTaggedValue value = JSDate::Cast(msg->GetTaggedObject())->GetTime();
4004514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
4014514f5e3Sopenharmony_ci
4024514f5e3Sopenharmony_ci    // If x is NaN, return "Invalid Date".
4034514f5e3Sopenharmony_ci    double x = value.GetNumber();
4044514f5e3Sopenharmony_ci    if (std::isnan(x)) {
4054514f5e3Sopenharmony_ci        return thread->GlobalConstants()->GetInvalidDateString();
4064514f5e3Sopenharmony_ci    }
4074514f5e3Sopenharmony_ci
4084514f5e3Sopenharmony_ci    // Let options be ? ToDateTimeOptions(options, "any", "all").
4094514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
4104514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
4114514f5e3Sopenharmony_ci    [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined();
4124514f5e3Sopenharmony_ci#ifdef ARK_SUPPORT_INTL
4134514f5e3Sopenharmony_ci    if (cacheable) {
4144514f5e3Sopenharmony_ci        auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales,
4154514f5e3Sopenharmony_ci            IcuFormatterType::SIMPLE_DATE_FORMAT_TIME);
4164514f5e3Sopenharmony_ci        if (simpleDateFormat != nullptr) {
4174514f5e3Sopenharmony_ci            JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x);
4184514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
4194514f5e3Sopenharmony_ci            return result.GetTaggedValue();
4204514f5e3Sopenharmony_ci        }
4214514f5e3Sopenharmony_ci    }
4224514f5e3Sopenharmony_ci    JSHandle<JSObject> dateTimeOptions =
4234514f5e3Sopenharmony_ci        JSDateTimeFormat::ToDateTimeOptions(thread, options, RequiredOption::TIME, DefaultsOption::TIME);
4244514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
4254514f5e3Sopenharmony_ci    JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
4264514f5e3Sopenharmony_ci    // Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »).
4274514f5e3Sopenharmony_ci    JSHandle<JSFunction> ctor(env->GetDateTimeFormatFunction());
4284514f5e3Sopenharmony_ci    JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor);
4294514f5e3Sopenharmony_ci    IcuCacheType type = cacheable ? IcuCacheType::TIME : IcuCacheType::NOT_CACHE;
4304514f5e3Sopenharmony_ci    JSHandle<JSDateTimeFormat> dtf = JSDateTimeFormat::InitializeDateTimeFormat(thread,
4314514f5e3Sopenharmony_ci        JSHandle<JSDateTimeFormat>::Cast(obj), locales, JSHandle<JSTaggedValue>::Cast(dateTimeOptions), type);
4324514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
4334514f5e3Sopenharmony_ci    if (cacheable) {
4344514f5e3Sopenharmony_ci        auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales,
4354514f5e3Sopenharmony_ci            IcuFormatterType::SIMPLE_DATE_FORMAT_TIME);
4364514f5e3Sopenharmony_ci        ASSERT(simpleDateFormat != nullptr);
4374514f5e3Sopenharmony_ci        JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x);
4384514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
4394514f5e3Sopenharmony_ci        return result.GetTaggedValue();
4404514f5e3Sopenharmony_ci    }
4414514f5e3Sopenharmony_ci
4424514f5e3Sopenharmony_ci    // Return ? FormatDateTime(dateFormat, x).
4434514f5e3Sopenharmony_ci    JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, dtf, x);
4444514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
4454514f5e3Sopenharmony_ci    return result.GetTaggedValue();
4464514f5e3Sopenharmony_ci#else
4474514f5e3Sopenharmony_ci#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL
4484514f5e3Sopenharmony_ci    ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare");
4494514f5e3Sopenharmony_ci#else
4504514f5e3Sopenharmony_ci    intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::SimpleDateFormatTime);
4514514f5e3Sopenharmony_ci    auto dateFormatter = gh.GetGlobalObject<intl::GlobalDateFormatter>(thread,
4524514f5e3Sopenharmony_ci        locales, options, intl::GlobalFormatterType::SimpleDateFormatTime, cacheable);
4534514f5e3Sopenharmony_ci    if (dateFormatter == nullptr) {
4544514f5e3Sopenharmony_ci        LOG_ECMA(ERROR) << "BuiltinsDate::ToLocaleTimeString:dateFormatter is nullptr";
4554514f5e3Sopenharmony_ci    }
4564514f5e3Sopenharmony_ci    ASSERT(dateFormatter != nullptr);
4574514f5e3Sopenharmony_ci    std::string result = dateFormatter->Format(intl::GlobalIntlHelper::DoubleToInt64(x));
4584514f5e3Sopenharmony_ci    JSHandle returnValue = factory->NewFromStdString(result);
4594514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
4604514f5e3Sopenharmony_ci    return returnValue.GetTaggedValue();
4614514f5e3Sopenharmony_ci#endif
4624514f5e3Sopenharmony_ci#endif
4634514f5e3Sopenharmony_ci}
4644514f5e3Sopenharmony_ci
4654514f5e3Sopenharmony_ciJSTaggedValue BuiltinsDate::ExtractDateFields(JSThread *thread, uint32_t &length, EcmaRuntimeCallInfo *argv,
4664514f5e3Sopenharmony_ci    JSTaggedValue &timeValue)
4674514f5e3Sopenharmony_ci{
4684514f5e3Sopenharmony_ci    std::array<int64_t, DATE_LENGTH> fields = {0, 0, 1, 0, 0, 0, 0, 0, 0};
4694514f5e3Sopenharmony_ci    if (length > CONSTRUCTOR_MAX_LENGTH) {  // The max length is 7.
4704514f5e3Sopenharmony_ci        length = CONSTRUCTOR_MAX_LENGTH;
4714514f5e3Sopenharmony_ci    }
4724514f5e3Sopenharmony_ci    uint32_t i = 0;
4734514f5e3Sopenharmony_ci    for (; i < length; ++i) {
4744514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> value = GetCallArg(argv, i);
4754514f5e3Sopenharmony_ci        JSTaggedNumber res = JSTaggedValue::ToNumber(thread, value);
4764514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
4774514f5e3Sopenharmony_ci        double temp = JSDate::TimeClip(res.GetNumber());
4784514f5e3Sopenharmony_ci        if (std::isnan(temp) || !std::isfinite(temp)) {  // Check the double value is finite.
4794514f5e3Sopenharmony_ci            break;
4804514f5e3Sopenharmony_ci        }
4814514f5e3Sopenharmony_ci        fields[i] = static_cast<int64_t>(temp);
4824514f5e3Sopenharmony_ci        if (i == 0 && fields[0] >= 0 && fields[0] < JSDate::HUNDRED) {
4834514f5e3Sopenharmony_ci            fields[0] += JSDate::NINETEEN_HUNDRED_YEAR;
4844514f5e3Sopenharmony_ci        }
4854514f5e3Sopenharmony_ci    }
4864514f5e3Sopenharmony_ci    timeValue = JSTaggedValue((i == length) ? JSDate::SetDateValues(&fields, true) : base::NAN_VALUE);
4874514f5e3Sopenharmony_ci    return timeValue;
4884514f5e3Sopenharmony_ci}
4894514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::builtins
490