1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/builtins/builtins_date.h" 17 18#include "ecmascript/global_env.h" 19#include "ecmascript/interpreter/interpreter.h" 20#include "ecmascript/js_function.h" 21 22#ifdef ARK_SUPPORT_INTL 23#include "ecmascript/js_date.h" 24#include "ecmascript/js_date_time_format.h" 25#else 26#ifndef ARK_NOT_SUPPORT_INTL_GLOBAL 27#include "ecmascript/intl/global_intl_helper.h" 28#endif 29#endif 30 31namespace panda::ecmascript::builtins { 32// constructor 33JSTaggedValue BuiltinsDate::DateConstructor(EcmaRuntimeCallInfo *argv) 34{ 35 BUILTINS_ENTRY_DEBUG_LOG(); 36 BUILTINS_API_TRACE(argv->GetThread(), Date, Constructor); 37 JSThread *thread = argv->GetThread(); 38 [[maybe_unused]] EcmaHandleScope handleScope(thread); 39 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 40 if (newTarget->IsUndefined()) { 41 double now = JSDate::Now().GetDouble(); 42 CString str = JSDate::ToDateString(now); 43 return GetTaggedString(thread, str.c_str()); 44 } 45 46 JSTaggedValue timeValue(0.0); 47 uint32_t length = argv->GetArgsNumber(); 48 if (length == 0) { // no value 49 timeValue = JSDate::Now(); 50 } else if (length == 1) { // one value 51 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 52 if (value->IsDate()) { // The value is a date object. 53 JSHandle<JSDate> jsDate(thread, JSDate::Cast(value->GetTaggedObject())); 54 timeValue = jsDate->GetTimeValue(); 55 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 56 } else { 57 JSHandle<JSTaggedValue> objValue(thread, JSTaggedValue::ToPrimitive(thread, value)); 58 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 59 if (objValue->IsString()) { // The value is a string object. 60 timeValue = JSDate::Parse(argv); 61 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 62 } else { // The value is a number. 63 JSTaggedNumber val = JSTaggedValue::ToNumber(thread, objValue); 64 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 65 timeValue = JSTaggedValue(val.GetNumber()); 66 } 67 timeValue = JSTaggedValue(JSDate::TimeClip(timeValue.GetDouble())); 68 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 69 } 70 } else { // two or more values 71 timeValue = ExtractDateFields(thread, length, argv, timeValue); 72 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 73 } 74 75 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 76 JSHandle<JSFunction> constructor(GetConstructor(argv)); 77 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(constructor, newTarget); 78 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 79 JSHandle<JSDate> dateObject = JSHandle<JSDate>::Cast(obj); 80 dateObject->SetTimeValue(thread, timeValue); 81 return dateObject.GetTaggedValue(); 82} 83 84// 20.4.3.1 85JSTaggedValue BuiltinsDate::Now([[maybe_unused]] EcmaRuntimeCallInfo *argv) 86{ 87 BUILTINS_API_TRACE(argv->GetThread(), Date, Now); 88 return JSDate::Now(); 89} 90 91// 20.4.3.2 92JSTaggedValue BuiltinsDate::Parse(EcmaRuntimeCallInfo *argv) 93{ 94 BUILTINS_API_TRACE(argv->GetThread(), Date, Parse); 95 [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread()); 96 return JSDate::Parse(argv); 97} 98 99// 20.4.3.4 100JSTaggedValue BuiltinsDate::UTC(EcmaRuntimeCallInfo *argv) 101{ 102 BUILTINS_API_TRACE(argv->GetThread(), Date, UTC); 103 [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread()); 104 return JSDate::UTC(argv); 105} 106 107// 20.4.4.10 108JSTaggedValue BuiltinsDate::GetTime(EcmaRuntimeCallInfo *argv) 109{ 110 ASSERT(argv); 111 BUILTINS_API_TRACE(argv->GetThread(), Date, GetTime); 112 JSThread *thread = argv->GetThread(); 113 JSHandle<JSTaggedValue> msg = GetThis(argv); 114 if (!msg->IsDate()) { 115 [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread()); 116 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); 117 } 118 return JSDate::Cast(msg->GetTaggedObject())->GetTime(); 119} 120 121JSTaggedValue BuiltinsDate::SetTime(EcmaRuntimeCallInfo *argv) 122{ 123 ASSERT(argv); 124 BUILTINS_API_TRACE(argv->GetThread(), Date, SetTime); 125 JSThread *thread = argv->GetThread(); 126 [[maybe_unused]] EcmaHandleScope handleScope(thread); 127 128 JSHandle<JSTaggedValue> msg = GetThis(argv); 129 if (!msg->IsDate()) { 130 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); 131 } 132 JSHandle<JSDate> jsDate(thread, JSDate::Cast(msg->GetTaggedObject())); 133 JSTaggedNumber res = JSTaggedValue::ToNumber(thread, GetCallArg(argv, 0)); 134 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread()); 135 double number = res.GetNumber(); 136 double value = JSDate::TimeClip(number); 137 jsDate->SetTimeValue(thread, JSTaggedValue(value)); 138 return GetTaggedDouble(value); 139} 140 141// 20.4.4.37 142JSTaggedValue BuiltinsDate::ToJSON(EcmaRuntimeCallInfo *argv) 143{ 144 ASSERT(argv); 145 BUILTINS_API_TRACE(argv->GetThread(), Date, ToJSON); 146 JSThread *thread = argv->GetThread(); 147 [[maybe_unused]] EcmaHandleScope handleScope(thread); 148 149 // 1. Let O be ToObject(this value). 150 JSHandle<JSTaggedValue> msg = GetThis(argv); 151 JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, msg); 152 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 153 154 // 2. Let tv be ToPrimitive(hint Number) 155 JSHandle<JSTaggedValue> objectHandle = JSHandle<JSTaggedValue>::Cast(object); 156 JSHandle<JSTaggedValue> tv(thread, 157 JSTaggedValue::ToPrimitive(thread, objectHandle, PreferredPrimitiveType::PREFER_NUMBER)); 158 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 159 // 3. If Type(tv) is Number and tv is not finite, return null 160 if (tv->IsNumber()) { 161 if (tv->IsDouble() && !std::isfinite(tv->GetDouble())) { 162 return JSTaggedValue::Null(); 163 } 164 } 165 JSHandle<JSTaggedValue> calleeKey(thread->GetEcmaVM()->GetFactory()->NewFromASCII("toISOString")); 166 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 167 EcmaRuntimeCallInfo *info = 168 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, objectHandle, undefined, 0); 169 return JSFunction::Invoke(info, calleeKey); 170} 171 172// 20.4.4.44 173JSTaggedValue BuiltinsDate::ValueOf(EcmaRuntimeCallInfo *argv) 174{ 175 ASSERT(argv); 176 BUILTINS_API_TRACE(argv->GetThread(), Date, ValueOf); 177 JSThread *thread = argv->GetThread(); 178 JSHandle<JSTaggedValue> msg = GetThis(argv); 179 if (!msg->IsDate()) { 180 [[maybe_unused]] EcmaHandleScope handleScope(thread); 181 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); 182 } 183 return JSDate::Cast(msg->GetTaggedObject())->ValueOf(); 184} 185 186// 20.4.4.45 187JSTaggedValue BuiltinsDate::ToPrimitive(EcmaRuntimeCallInfo *argv) 188{ 189 ASSERT(argv); 190 BUILTINS_API_TRACE(argv->GetThread(), Date, ToPrimitive); 191 JSThread *thread = argv->GetThread(); 192 auto vm = thread->GetEcmaVM(); 193 [[maybe_unused]] EcmaHandleScope handleScope(thread); 194 195 JSHandle<JSTaggedValue> object = GetThis(argv); 196 if (!object->IsECMAObject()) { 197 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a JSObject", JSTaggedValue::Exception()); 198 } 199 JSHandle<JSTaggedValue> hint = GetCallArg(argv, 0); 200 PreferredPrimitiveType tryFirst = PREFER_STRING; 201 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 202 if (hint->IsString()) { 203 JSHandle<EcmaString> numberStrHandle = JSHandle<EcmaString>::Cast(globalConst->GetHandledNumberString()); 204 if (EcmaStringAccessor::StringsAreEqual(vm, JSHandle<EcmaString>(hint), numberStrHandle)) { 205 tryFirst = PREFER_NUMBER; 206 } else { 207 JSHandle<EcmaString> stringStrHandle = JSHandle<EcmaString>::Cast(globalConst->GetHandledStringString()); 208 JSHandle<EcmaString> defaultStrHandle = JSHandle<EcmaString>::Cast(globalConst->GetHandledDefaultString()); 209 if (EcmaStringAccessor::StringsAreEqual(vm, JSHandle<EcmaString>(hint), stringStrHandle) || 210 EcmaStringAccessor::StringsAreEqual(vm, JSHandle<EcmaString>(hint), defaultStrHandle)) { 211 tryFirst = PREFER_STRING; 212 } else { 213 THROW_TYPE_ERROR_AND_RETURN(thread, "This is not a primitiveType.", JSTaggedValue::Exception()); 214 } 215 } 216 } else { 217 THROW_TYPE_ERROR_AND_RETURN(thread, "This is not an primitiveType.", JSTaggedValue::Exception()); 218 } 219 return JSTaggedValue::OrdinaryToPrimitive(thread, object, tryFirst); 220} 221 222// ecma 402 16.4.1 Date.prototype.toLocaleString ( [ locales [ , options ] ] ) 223JSTaggedValue BuiltinsDate::ToLocaleString(EcmaRuntimeCallInfo *argv) 224{ 225 ASSERT(argv); 226 JSThread *thread = argv->GetThread(); 227 BUILTINS_API_TRACE(thread, Date, ToLocaleString); 228 EcmaVM *ecmaVm = thread->GetEcmaVM(); 229 [[maybe_unused]] ObjectFactory *factory = ecmaVm->GetFactory(); 230 [[maybe_unused]] EcmaHandleScope handleScope(thread); 231 232 // Let x be ? thisTimeValue(this value). 233 JSHandle<JSTaggedValue> msg = GetThis(argv); 234 if (!msg->IsDate()) { 235 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); 236 } 237 JSTaggedValue value = JSDate::Cast(msg->GetTaggedObject())->GetTime(); 238 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 239 240 // If x is NaN, return "Invalid Date". 241 double x = value.GetNumber(); 242 if (std::isnan(x)) { 243 return thread->GlobalConstants()->GetInvalidDateString(); 244 } 245 246 // Let options be ? ToDateTimeOptions(options, "any", "all"). 247 JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 248 JSHandle<JSTaggedValue> options = GetCallArg(argv, 1); 249 [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined(); 250#ifdef ARK_SUPPORT_INTL 251 if (cacheable) { 252 auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales, 253 IcuFormatterType::SIMPLE_DATE_FORMAT_DEFAULT); 254 if (simpleDateFormat != nullptr) { 255 JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x); 256 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 257 return result.GetTaggedValue(); 258 } 259 } 260 JSHandle<JSObject> dateTimeOptions = 261 JSDateTimeFormat::ToDateTimeOptions(thread, options, RequiredOption::ANY, DefaultsOption::ALL); 262 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 263 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 264 // Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »). 265 JSHandle<JSFunction> ctor(env->GetDateTimeFormatFunction()); 266 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor); 267 IcuCacheType type = cacheable ? IcuCacheType::DEFAULT : IcuCacheType::NOT_CACHE; 268 JSHandle<JSDateTimeFormat> dtf = JSDateTimeFormat::InitializeDateTimeFormat(thread, 269 JSHandle<JSDateTimeFormat>::Cast(obj), locales, JSHandle<JSTaggedValue>::Cast(dateTimeOptions), type); 270 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 271 if (cacheable) { 272 auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales, 273 IcuFormatterType::SIMPLE_DATE_FORMAT_DEFAULT); 274 ASSERT(simpleDateFormat != nullptr); 275 JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x); 276 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 277 return result.GetTaggedValue(); 278 } 279 280 // Return ? FormatDateTime(dateFormat, x). 281 JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, dtf, x); 282 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 283 return result.GetTaggedValue(); 284#else 285#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL 286 ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "ToLocaleString"); 287#else 288 intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::DateFormatter); 289 auto dateFormatter = gh.GetGlobalObject<intl::GlobalDateFormatter>(thread, 290 locales, options, intl::GlobalFormatterType::DateFormatter, cacheable); 291 if (dateFormatter == nullptr) { 292 LOG_ECMA(ERROR) << "BuiltinsDate::ToLocaleString:dateFormatter is nullptr"; 293 } 294 ASSERT(dateFormatter != nullptr); 295 std::string result = dateFormatter->Format(intl::GlobalIntlHelper::DoubleToInt64(x)); 296 JSHandle returnValue = factory->NewFromStdString(result); 297 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 298 return returnValue.GetTaggedValue(); 299#endif 300#endif 301} 302 303// ecma 402 16.4.1 Date.prototype.toLocaleString ( [ locales [ , options ] ] ) 304JSTaggedValue BuiltinsDate::ToLocaleDateString(EcmaRuntimeCallInfo *argv) 305{ 306 ASSERT(argv); 307 JSThread *thread = argv->GetThread(); 308 BUILTINS_API_TRACE(thread, Date, ToLocaleDateString); 309 EcmaVM *ecmaVm = thread->GetEcmaVM(); 310 [[maybe_unused]] ObjectFactory *factory = ecmaVm->GetFactory(); 311 [[maybe_unused]] EcmaHandleScope handleScope(thread); 312 313 // Let x be ? thisTimeValue(this value). 314 JSHandle<JSTaggedValue> msg = GetThis(argv); 315 if (!msg->IsDate()) { 316 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); 317 } 318 JSTaggedValue value = JSDate::Cast(msg->GetTaggedObject())->GetTime(); 319 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 320 321 // If x is NaN, return "Invalid Date". 322 double x = value.GetNumber(); 323 if (std::isnan(x)) { 324 return thread->GlobalConstants()->GetInvalidDateString(); 325 } 326 327 // Let options be ? ToDateTimeOptions(options, "any", "all"). 328 JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 329 JSHandle<JSTaggedValue> options = GetCallArg(argv, 1); 330 [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined(); 331#ifdef ARK_SUPPORT_INTL 332 if (cacheable) { 333 auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales, 334 IcuFormatterType::SIMPLE_DATE_FORMAT_DATE); 335 if (simpleDateFormat != nullptr) { 336 JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x); 337 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 338 return result.GetTaggedValue(); 339 } 340 } 341 JSHandle<JSObject> dateTimeOptions = 342 JSDateTimeFormat::ToDateTimeOptions(thread, options, RequiredOption::DATE, DefaultsOption::DATE); 343 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 344 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 345 // Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »). 346 JSHandle<JSFunction> ctor(env->GetDateTimeFormatFunction()); 347 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor); 348 IcuCacheType type = cacheable ? IcuCacheType::DATE : IcuCacheType::NOT_CACHE; 349 JSHandle<JSDateTimeFormat> dtf = JSDateTimeFormat::InitializeDateTimeFormat(thread, 350 JSHandle<JSDateTimeFormat>::Cast(obj), locales, JSHandle<JSTaggedValue>::Cast(dateTimeOptions), type); 351 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 352 if (cacheable) { 353 auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales, 354 IcuFormatterType::SIMPLE_DATE_FORMAT_DATE); 355 ASSERT(simpleDateFormat != nullptr); 356 JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x); 357 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 358 return result.GetTaggedValue(); 359 } 360 361 // Return ? FormatDateTime(dateFormat, x). 362 JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, dtf, x); 363 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 364 return result.GetTaggedValue(); 365#else 366#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL 367 ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare"); 368#else 369 intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::SimpleDateFormatDate); 370 auto dateFormatter = gh.GetGlobalObject<intl::GlobalDateFormatter>(thread, 371 locales, options, intl::GlobalFormatterType::SimpleDateFormatDate, cacheable); 372 if (dateFormatter == nullptr) { 373 LOG_ECMA(ERROR) << "BuiltinsDate::ToLocaleDateString:dateFormatter is nullptr"; 374 } 375 ASSERT(dateFormatter != nullptr); 376 std::string result = dateFormatter->Format(intl::GlobalIntlHelper::DoubleToInt64(x)); 377 JSHandle returnValue = factory->NewFromStdString(result); 378 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 379 return returnValue.GetTaggedValue(); 380#endif 381#endif 382} 383 384// ecma 402 16.4.1 Date.prototype.toLocaleString ( [ locales [ , options ] ] ) 385JSTaggedValue BuiltinsDate::ToLocaleTimeString(EcmaRuntimeCallInfo *argv) 386{ 387 ASSERT(argv); 388 JSThread *thread = argv->GetThread(); 389 BUILTINS_API_TRACE(thread, Date, ToLocaleTimeString); 390 EcmaVM *ecmaVm = thread->GetEcmaVM(); 391 [[maybe_unused]] ObjectFactory *factory = ecmaVm->GetFactory(); 392 [[maybe_unused]] EcmaHandleScope handleScope(thread); 393 394 // Let x be ? thisTimeValue(this value). 395 JSHandle<JSTaggedValue> msg = GetThis(argv); 396 if (!msg->IsDate()) { 397 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); 398 } 399 JSTaggedValue value = JSDate::Cast(msg->GetTaggedObject())->GetTime(); 400 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 401 402 // If x is NaN, return "Invalid Date". 403 double x = value.GetNumber(); 404 if (std::isnan(x)) { 405 return thread->GlobalConstants()->GetInvalidDateString(); 406 } 407 408 // Let options be ? ToDateTimeOptions(options, "any", "all"). 409 JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 410 JSHandle<JSTaggedValue> options = GetCallArg(argv, 1); 411 [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined(); 412#ifdef ARK_SUPPORT_INTL 413 if (cacheable) { 414 auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales, 415 IcuFormatterType::SIMPLE_DATE_FORMAT_TIME); 416 if (simpleDateFormat != nullptr) { 417 JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x); 418 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 419 return result.GetTaggedValue(); 420 } 421 } 422 JSHandle<JSObject> dateTimeOptions = 423 JSDateTimeFormat::ToDateTimeOptions(thread, options, RequiredOption::TIME, DefaultsOption::TIME); 424 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 425 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 426 // Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »). 427 JSHandle<JSFunction> ctor(env->GetDateTimeFormatFunction()); 428 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor); 429 IcuCacheType type = cacheable ? IcuCacheType::TIME : IcuCacheType::NOT_CACHE; 430 JSHandle<JSDateTimeFormat> dtf = JSDateTimeFormat::InitializeDateTimeFormat(thread, 431 JSHandle<JSDateTimeFormat>::Cast(obj), locales, JSHandle<JSTaggedValue>::Cast(dateTimeOptions), type); 432 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 433 if (cacheable) { 434 auto simpleDateFormat = JSDateTimeFormat::GetCachedIcuSimpleDateFormat(thread, locales, 435 IcuFormatterType::SIMPLE_DATE_FORMAT_TIME); 436 ASSERT(simpleDateFormat != nullptr); 437 JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, simpleDateFormat, x); 438 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 439 return result.GetTaggedValue(); 440 } 441 442 // Return ? FormatDateTime(dateFormat, x). 443 JSHandle<EcmaString> result = JSDateTimeFormat::FormatDateTime(thread, dtf, x); 444 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 445 return result.GetTaggedValue(); 446#else 447#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL 448 ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare"); 449#else 450 intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::SimpleDateFormatTime); 451 auto dateFormatter = gh.GetGlobalObject<intl::GlobalDateFormatter>(thread, 452 locales, options, intl::GlobalFormatterType::SimpleDateFormatTime, cacheable); 453 if (dateFormatter == nullptr) { 454 LOG_ECMA(ERROR) << "BuiltinsDate::ToLocaleTimeString:dateFormatter is nullptr"; 455 } 456 ASSERT(dateFormatter != nullptr); 457 std::string result = dateFormatter->Format(intl::GlobalIntlHelper::DoubleToInt64(x)); 458 JSHandle returnValue = factory->NewFromStdString(result); 459 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 460 return returnValue.GetTaggedValue(); 461#endif 462#endif 463} 464 465JSTaggedValue BuiltinsDate::ExtractDateFields(JSThread *thread, uint32_t &length, EcmaRuntimeCallInfo *argv, 466 JSTaggedValue &timeValue) 467{ 468 std::array<int64_t, DATE_LENGTH> fields = {0, 0, 1, 0, 0, 0, 0, 0, 0}; 469 if (length > CONSTRUCTOR_MAX_LENGTH) { // The max length is 7. 470 length = CONSTRUCTOR_MAX_LENGTH; 471 } 472 uint32_t i = 0; 473 for (; i < length; ++i) { 474 JSHandle<JSTaggedValue> value = GetCallArg(argv, i); 475 JSTaggedNumber res = JSTaggedValue::ToNumber(thread, value); 476 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 477 double temp = JSDate::TimeClip(res.GetNumber()); 478 if (std::isnan(temp) || !std::isfinite(temp)) { // Check the double value is finite. 479 break; 480 } 481 fields[i] = static_cast<int64_t>(temp); 482 if (i == 0 && fields[0] >= 0 && fields[0] < JSDate::HUNDRED) { 483 fields[0] += JSDate::NINETEEN_HUNDRED_YEAR; 484 } 485 } 486 timeValue = JSTaggedValue((i == length) ? JSDate::SetDateValues(&fields, true) : base::NAN_VALUE); 487 return timeValue; 488} 489} // namespace panda::ecmascript::builtins 490