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