• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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