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