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