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