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