• 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/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 
31 namespace panda::ecmascript::builtins {
32 // constructor
DateConstructor(EcmaRuntimeCallInfo * argv)33 JSTaggedValue 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(thread, 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
Now(EcmaRuntimeCallInfo * argv)85 JSTaggedValue 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
Parse(EcmaRuntimeCallInfo * argv)92 JSTaggedValue 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
UTC(EcmaRuntimeCallInfo * argv)100 JSTaggedValue 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
GetTime(EcmaRuntimeCallInfo * argv)108 JSTaggedValue 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 
SetTime(EcmaRuntimeCallInfo * argv)121 JSTaggedValue 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
ToJSON(EcmaRuntimeCallInfo * argv)142 JSTaggedValue 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
ValueOf(EcmaRuntimeCallInfo * argv)173 JSTaggedValue 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
ToPrimitive(EcmaRuntimeCallInfo * argv)187 JSTaggedValue 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 ] ] )
ToLocaleString(EcmaRuntimeCallInfo * argv)223 JSTaggedValue 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 ] ] )
ToLocaleDateString(EcmaRuntimeCallInfo * argv)304 JSTaggedValue 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 ] ] )
ToLocaleTimeString(EcmaRuntimeCallInfo * argv)385 JSTaggedValue 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 
ExtractDateFields(JSThread * thread,uint32_t & length,EcmaRuntimeCallInfo * argv,JSTaggedValue & timeValue)465 JSTaggedValue 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