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