1 /*
2 * Copyright (c) 2022 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/intl/locale_helper.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/js_date.h"
19 #include "ecmascript/js_date_time_format.h"
20 #include "ecmascript/js_locale.h"
21 #include "ecmascript/object_factory-inl.h"
22 #include "ecmascript/tests/test_helper.h"
23
24 using namespace panda;
25 using namespace panda::ecmascript;
26 using namespace panda::ecmascript::base;
27 using LocaleHelper = panda::ecmascript::intl::LocaleHelper;
28
29 namespace panda::test {
30 class JSDateTimeFormatTest : public testing::Test {
31 public:
SetUpTestCase()32 static void SetUpTestCase()
33 {
34 GTEST_LOG_(INFO) << "SetUpTestCase";
35 }
36
TearDownTestCase()37 static void TearDownTestCase()
38 {
39 GTEST_LOG_(INFO) << "TearDownCase";
40 }
41
SetUp()42 void SetUp() override
43 {
44 JSRuntimeOptions options;
45 #if PANDA_TARGET_LINUX
46 // for consistency requirement, use ohos_icu4j/data as icu-data-path
47 options.SetIcuDataPath(ICU_PATH);
48 #endif
49 options.SetEnableForceGC(true);
50 instance = JSNApi::CreateEcmaVM(options);
51 instance->SetEnableForceGC(true);
52 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
53 thread = instance->GetJSThread();
54 scope = new EcmaHandleScope(thread);
55 }
56
TearDown()57 void TearDown() override
58 {
59 TestHelper::DestroyEcmaVMWithScope(instance, scope);
60 }
61
62 EcmaVM *instance {nullptr};
63 EcmaHandleScope *scope {nullptr};
64 JSThread *thread {nullptr};
65 };
66
SetDateOptionsTest(JSThread * thread,JSHandle<JSObject> & optionsObj,std::map<std::string,std::string> & dateOptions)67 void SetDateOptionsTest(JSThread *thread, JSHandle<JSObject> &optionsObj,
68 std::map<std::string, std::string> &dateOptions)
69 {
70 auto vm = thread->GetEcmaVM();
71 auto factory = vm->GetFactory();
72 auto globalConst = thread->GlobalConstants();
73 // Date options keys.
74 JSHandle<JSTaggedValue> weekdayKey = globalConst->GetHandledWeekdayString();
75 JSHandle<JSTaggedValue> yearKey = globalConst->GetHandledYearString();
76 JSHandle<JSTaggedValue> monthKey = globalConst->GetHandledMonthString();
77 JSHandle<JSTaggedValue> dayKey = globalConst->GetHandledDayString();
78 // Date options values.
79 JSHandle<JSTaggedValue> weekdayValue(factory->NewFromASCII(dateOptions["weekday"].c_str()));
80 JSHandle<JSTaggedValue> yearValue(factory->NewFromASCII(dateOptions["year"].c_str()));
81 JSHandle<JSTaggedValue> monthValue(factory->NewFromASCII(dateOptions["month"].c_str()));
82 JSHandle<JSTaggedValue> dayValue(factory->NewFromASCII(dateOptions["day"].c_str()));
83 // Set date options.
84 JSObject::SetProperty(thread, optionsObj, weekdayKey, weekdayValue);
85 JSObject::SetProperty(thread, optionsObj, yearKey, yearValue);
86 JSObject::SetProperty(thread, optionsObj, monthKey, monthValue);
87 JSObject::SetProperty(thread, optionsObj, dayKey, dayValue);
88 }
89
SetTimeOptionsTest(JSThread * thread,JSHandle<JSObject> & optionsObj,std::map<std::string,std::string> & timeOptionsMap)90 void SetTimeOptionsTest(JSThread *thread, JSHandle<JSObject> &optionsObj,
91 std::map<std::string, std::string> &timeOptionsMap)
92 {
93 auto vm = thread->GetEcmaVM();
94 auto factory = vm->GetFactory();
95 auto globalConst = thread->GlobalConstants();
96 // Time options keys.
97 JSHandle<JSTaggedValue> dayPeriodKey = globalConst->GetHandledDayPeriodString();
98 JSHandle<JSTaggedValue> hourKey = globalConst->GetHandledHourString();
99 JSHandle<JSTaggedValue> minuteKey = globalConst->GetHandledMinuteString();
100 JSHandle<JSTaggedValue> secondKey = globalConst->GetHandledSecondString();
101 JSHandle<JSTaggedValue> fractionalSecondDigitsKey = globalConst->GetHandledFractionalSecondDigitsString();
102 // Time options values.
103 JSHandle<JSTaggedValue> dayPeriodValue(factory->NewFromASCII(timeOptionsMap["dayPeriod"].c_str()));
104 JSHandle<JSTaggedValue> hourValue(factory->NewFromASCII(timeOptionsMap["hour"].c_str()));
105 JSHandle<JSTaggedValue> minuteValue(factory->NewFromASCII(timeOptionsMap["minute"].c_str()));
106 JSHandle<JSTaggedValue> secondValue(factory->NewFromASCII(timeOptionsMap["second"].c_str()));
107 JSHandle<JSTaggedValue> fractionalSecondDigitsValue(
108 factory->NewFromASCII(timeOptionsMap["fractionalSecond"].c_str()));
109 // Set time options.
110 JSObject::SetProperty(thread, optionsObj, dayPeriodKey, dayPeriodValue);
111 JSObject::SetProperty(thread, optionsObj, hourKey, hourValue);
112 JSObject::SetProperty(thread, optionsObj, minuteKey, minuteValue);
113 JSObject::SetProperty(thread, optionsObj, secondKey, secondValue);
114 JSObject::SetProperty(thread, optionsObj, fractionalSecondDigitsKey, fractionalSecondDigitsValue);
115 }
116
117 /**
118 * @tc.name: GetIcuLocale & SetIcuLocale
119 * @tc.desc: Set and obtain localization labels compatible with ICU Libraries.
120 * @tc.type: FUNC
121 * @tc.require:
122 */
HWTEST_F_L0(JSDateTimeFormatTest,Set_Get_IcuLocale)123 HWTEST_F_L0(JSDateTimeFormatTest, Set_Get_IcuLocale)
124 {
125 auto vm = thread->GetEcmaVM();
126 auto factory = vm->GetFactory();
127 auto env = vm->GetGlobalEnv();
128 JSHandle<JSTaggedValue> ctor = env->GetDateTimeFormatFunction();
129 JSHandle<JSDateTimeFormat> dtf =
130 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
131
132 icu::Locale locale1("ko", "Kore", "KR");
133 JSDateTimeFormat::SetIcuLocale(thread, dtf, locale1, JSDateTimeFormat::FreeIcuLocale);
134 icu::Locale *resLocale1 = dtf->GetIcuLocale();
135 EXPECT_STREQ(resLocale1->getBaseName(), "ko_Kore_KR");
136
137 icu::Locale locale2("zh", "Hans", "Cn");
138 JSDateTimeFormat::SetIcuLocale(thread, dtf, locale2, JSDateTimeFormat::FreeIcuLocale);
139 icu::Locale *resLocale2 = dtf->GetIcuLocale();
140 EXPECT_STREQ(resLocale2->getBaseName(), "zh_Hans_CN");
141 }
142
143 /**
144 * @tc.name: SetIcuSimpleDateFormat & GetIcuSimpleDateFormat
145 * @tc.desc: Set and obtain a simple time and date format compatible with ICU Libraries.
146 * @tc.type: FUNC
147 * @tc.require:
148 */
HWTEST_F_L0(JSDateTimeFormatTest,Set_Get_IcuSimpleDateFormat)149 HWTEST_F_L0(JSDateTimeFormatTest, Set_Get_IcuSimpleDateFormat)
150 {
151 auto vm = thread->GetEcmaVM();
152 auto factory = vm->GetFactory();
153 auto env = vm->GetGlobalEnv();
154 const icu::UnicodeString timeZoneId("Asia/Shanghai");
155 icu::TimeZone *tz = icu::TimeZone::createTimeZone(timeZoneId);
156 icu::TimeZone::adoptDefault(tz);
157 JSHandle<JSTaggedValue> ctor = env->GetDateTimeFormatFunction();
158 JSHandle<JSDateTimeFormat> dtf =
159 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
160 UErrorCode status = UErrorCode::U_ZERO_ERROR;
161 icu::UnicodeString dateTime1("2022.05.25 11:09:34");
162 icu::UnicodeString dateTime2("2022.May.25 11:09:34");
163 icu::UnicodeString dateTime3("2022.May.25 AD 11:09:34 AM");
164
165 icu::UnicodeString pattern("yyyy.MM.dd HH:mm:ss");
166 icu::SimpleDateFormat sdf(pattern, status);
167 JSDateTimeFormat::SetIcuSimpleDateFormat(thread, dtf, sdf, JSDateTimeFormat::FreeSimpleDateFormat);
168 icu::SimpleDateFormat *resSdf = dtf->GetIcuSimpleDateFormat();
169 UDate timeStamp = resSdf->parse(dateTime1, status);
170 EXPECT_EQ(timeStamp, 1653448174000);
171 status = UErrorCode::U_ZERO_ERROR;
172 timeStamp = resSdf->parse(dateTime2, status);
173 EXPECT_EQ(timeStamp, 1653448174000);
174 status = UErrorCode::U_ZERO_ERROR;
175 timeStamp = resSdf->parse(dateTime3, status);
176 EXPECT_EQ(timeStamp, 0);
177
178 status = UErrorCode::U_ZERO_ERROR;
179 icu::UnicodeString pattern2("yyyyy.MMMMM.dd GGG hh:mm::ss aaa");
180 icu::SimpleDateFormat sdf2(pattern2, status);
181 JSDateTimeFormat::SetIcuSimpleDateFormat(thread, dtf, sdf2, JSDateTimeFormat::FreeSimpleDateFormat);
182 icu::SimpleDateFormat *resSdf2 = dtf->GetIcuSimpleDateFormat();
183 timeStamp = resSdf2->parse(dateTime1, status);
184 EXPECT_EQ(timeStamp, 0);
185 status = UErrorCode::U_ZERO_ERROR;
186 timeStamp = resSdf2->parse(dateTime2, status);
187 EXPECT_EQ(timeStamp, 0);
188 status = UErrorCode::U_ZERO_ERROR;
189 timeStamp = resSdf2->parse(dateTime3, status);
190 EXPECT_EQ(timeStamp, 1653448174000);
191 }
192
193 /**
194 * @tc.name: InitializeDateTimeFormat
195 * @tc.desc: Initialize the time and date format through localization label locales and options.
196 * Options can include year, month, day, hour, minute, second, time zone and weekday, etc.
197 * @tc.type: FUNC
198 * @tc.require:
199 */
HWTEST_F_L0(JSDateTimeFormatTest,InitializeDateTimeFormat)200 HWTEST_F_L0(JSDateTimeFormatTest, InitializeDateTimeFormat)
201 {
202 auto vm = thread->GetEcmaVM();
203 auto factory = vm->GetFactory();
204 auto env = vm->GetGlobalEnv();
205 // Create locales.
206 JSHandle<JSTaggedValue> localeCtor = env->GetLocaleFunction();
207 JSHandle<JSLocale> locales =
208 JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(localeCtor), localeCtor));
209 icu::Locale icuLocale("zh", "Hans", "Cn", "calendar=chinese");
210 factory->NewJSIntlIcuData(locales, icuLocale, JSLocale::FreeIcuLocale);
211 // Create options.
212 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
213 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
214 options = JSDateTimeFormat::ToDateTimeOptions(
215 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
216 // Initialize DateTimeFormat.
217 JSHandle<JSTaggedValue> dtfCtor = env->GetDateTimeFormatFunction();
218 JSHandle<JSDateTimeFormat> dtf =
219 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(dtfCtor), dtfCtor));
220 dtf = JSDateTimeFormat::InitializeDateTimeFormat(
221 thread, dtf, JSHandle<JSTaggedValue>::Cast(locales), JSHandle<JSTaggedValue>::Cast(options));
222
223 JSHandle<JSTaggedValue> localeTagVal(thread, dtf->GetLocale());
224 JSHandle<EcmaString> localeEcmaStr = JSHandle<EcmaString>::Cast(localeTagVal);
225 std::string localeStr = LocaleHelper::ConvertToStdString(localeEcmaStr);
226 EXPECT_STREQ(localeStr.c_str(), "zh-Hans-CN-u-ca-chinese");
227 }
228
229 /**
230 * @tc.name: ToDateTimeOptions
231 * @tc.desc: Empty or incomplete option objects are supplemented according to the required option and default option.
232 * @tc.type: FUNC
233 * @tc.require:
234 */
HWTEST_F_L0(JSDateTimeFormatTest,ToDateTimeOptions_001)235 HWTEST_F_L0(JSDateTimeFormatTest, ToDateTimeOptions_001)
236 {
237 auto vm = thread->GetEcmaVM();
238 auto factory = vm->GetFactory();
239 auto env = vm->GetGlobalEnv();
240 auto globalConst = thread->GlobalConstants();
241
242 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
243 JSHandle<JSTaggedValue> yearKey = globalConst->GetHandledYearString();
244 JSHandle<JSTaggedValue> monthKey = globalConst->GetHandledMonthString();
245 JSHandle<JSTaggedValue> dayKey = globalConst->GetHandledDayString();
246 JSHandle<JSTaggedValue> hourKey = globalConst->GetHandledHourString();
247 JSHandle<JSTaggedValue> minuteKey = globalConst->GetHandledMinuteString();
248 JSHandle<JSTaggedValue> secondKey = globalConst->GetHandledSecondString();
249
250 // When the option value is blank, it will be set according to the default option,
251 // including the year, month, day, hour, minute and second, and the values are all numeric.
252 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
253 options = JSDateTimeFormat::ToDateTimeOptions(
254 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL); // test "ALL"
255 auto yearEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, yearKey).GetValue());
256 EXPECT_STREQ(LocaleHelper::ConvertToStdString(yearEcmaStr).c_str(), "numeric");
257 auto monthEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, monthKey).GetValue());
258 EXPECT_STREQ(LocaleHelper::ConvertToStdString(monthEcmaStr).c_str(), "numeric");
259 auto dayEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayKey).GetValue());
260 EXPECT_STREQ(LocaleHelper::ConvertToStdString(dayEcmaStr).c_str(), "numeric");
261 auto hourEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, hourKey).GetValue());
262 EXPECT_STREQ(LocaleHelper::ConvertToStdString(hourEcmaStr).c_str(), "numeric");
263 auto minuteEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, minuteKey).GetValue());
264 EXPECT_STREQ(LocaleHelper::ConvertToStdString(minuteEcmaStr).c_str(), "numeric");
265 auto secondEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, secondKey).GetValue());
266 EXPECT_STREQ(LocaleHelper::ConvertToStdString(secondEcmaStr).c_str(), "numeric");
267 }
268
HWTEST_F_L0(JSDateTimeFormatTest,ToDateTimeOptions_002)269 HWTEST_F_L0(JSDateTimeFormatTest, ToDateTimeOptions_002)
270 {
271 auto vm = thread->GetEcmaVM();
272 auto factory = vm->GetFactory();
273 auto env = vm->GetGlobalEnv();
274 auto globalConst = thread->GlobalConstants();
275
276 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
277 JSHandle<JSTaggedValue> weekdayKey = globalConst->GetHandledWeekdayString();
278 JSHandle<JSTaggedValue> yearKey = globalConst->GetHandledYearString();
279 JSHandle<JSTaggedValue> monthKey = globalConst->GetHandledMonthString();
280 JSHandle<JSTaggedValue> dayKey = globalConst->GetHandledDayString();
281 JSHandle<JSTaggedValue> dayPeriodKey = globalConst->GetHandledDayPeriodString();
282 JSHandle<JSTaggedValue> hourKey = globalConst->GetHandledHourString();
283 JSHandle<JSTaggedValue> minuteKey = globalConst->GetHandledMinuteString();
284 JSHandle<JSTaggedValue> secondKey = globalConst->GetHandledSecondString();
285 JSHandle<JSTaggedValue> fracSecKey = globalConst->GetHandledFractionalSecondDigitsString();
286
287 // When the option value is not empty, it will be set according to the required options.
288 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
289 std::map<std::string, std::string> dateOptionsMap {
290 { "weekday", "narrow" },
291 { "year", "2-digit" },
292 { "month", "2-digit" },
293 { "day", "2-digit" }
294 };
295 std::map<std::string, std::string> timeOptionsMap {
296 { "dayPeriod", "narrow" },
297 { "hour", "2-digit" },
298 { "minute", "2-digit" },
299 { "second", "2-digit" },
300 { "fractionalSecond", "1" }
301 };
302 SetDateOptionsTest(thread, options, dateOptionsMap);
303 SetTimeOptionsTest(thread, options, timeOptionsMap);
304 options = JSDateTimeFormat::ToDateTimeOptions(
305 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL); // test "ANY"
306 auto weekdayStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, weekdayKey).GetValue());
307 EXPECT_STREQ(LocaleHelper::ConvertToStdString(weekdayStr).c_str(), "narrow");
308 auto yearStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, yearKey).GetValue());
309 EXPECT_STREQ(LocaleHelper::ConvertToStdString(yearStr).c_str(), "2-digit");
310 auto monthStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, monthKey).GetValue());
311 EXPECT_STREQ(LocaleHelper::ConvertToStdString(monthStr).c_str(), "2-digit");
312 auto dayStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayKey).GetValue());
313 EXPECT_STREQ(LocaleHelper::ConvertToStdString(dayStr).c_str(), "2-digit");
314
315 auto dayPeriodStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayPeriodKey).GetValue());
316 EXPECT_STREQ(LocaleHelper::ConvertToStdString(dayPeriodStr).c_str(), "narrow");
317 auto hourStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, hourKey).GetValue());
318 EXPECT_STREQ(LocaleHelper::ConvertToStdString(hourStr).c_str(), "2-digit");
319 auto minuteStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, minuteKey).GetValue());
320 EXPECT_STREQ(LocaleHelper::ConvertToStdString(minuteStr).c_str(), "2-digit");
321 auto secondStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, secondKey).GetValue());
322 EXPECT_STREQ(LocaleHelper::ConvertToStdString(secondStr).c_str(), "2-digit");
323 auto fracSecStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, fracSecKey).GetValue());
324 EXPECT_STREQ(LocaleHelper::ConvertToStdString(fracSecStr).c_str(), "1");
325 }
326
CreateDateTimeFormatTest(JSThread * thread,icu::Locale icuLocale,JSHandle<JSObject> options)327 JSHandle<JSDateTimeFormat> CreateDateTimeFormatTest(JSThread *thread, icu::Locale icuLocale, JSHandle<JSObject> options)
328 {
329 auto vm = thread->GetEcmaVM();
330 auto factory = vm->GetFactory();
331 auto env = vm->GetGlobalEnv();
332
333 JSHandle<JSTaggedValue> localeCtor = env->GetLocaleFunction();
334 JSHandle<JSTaggedValue> dtfCtor = env->GetDateTimeFormatFunction();
335 JSHandle<JSLocale> locales =
336 JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(localeCtor), localeCtor));
337 JSHandle<JSDateTimeFormat> dtf =
338 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(dtfCtor), dtfCtor));
339
340 JSHandle<JSTaggedValue> optionsVal = JSHandle<JSTaggedValue>::Cast(options);
341 factory->NewJSIntlIcuData(locales, icuLocale, JSLocale::FreeIcuLocale);
342 dtf = JSDateTimeFormat::InitializeDateTimeFormat(thread, dtf, JSHandle<JSTaggedValue>::Cast(locales), optionsVal);
343 return dtf;
344 }
345
346 /**
347 * @tc.name: FormatDateTime
348 * @tc.desc: Convert floating-point timestamp to fixed format time date through time date format.
349 * @tc.type: FUNC
350 * @tc.require:
351 */
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTime_001)352 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_001)
353 {
354 auto vm = thread->GetEcmaVM();
355 auto factory = vm->GetFactory();
356 auto env = vm->GetGlobalEnv();
357 auto globalConst = thread->GlobalConstants();
358
359 icu::Locale icuLocale("zh", "Hans", "Cn");
360 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
361 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
362 JSHandle<JSTaggedValue> hourCycleKey = globalConst->GetHandledHourCycleString();
363 JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h12"));
364 JSHandle<JSTaggedValue> timeZoneKey = globalConst->GetHandledTimeZoneString();
365 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("ETC/GMT-8"));
366 JSObject::SetProperty(thread, options, timeZoneKey, timeZoneValue);
367 JSObject::SetProperty(thread, options, hourCycleKey, hourCycleValue);
368 JSHandle<JSDateTimeFormat> dtf = CreateDateTimeFormatTest(thread, icuLocale, options);
369
370 double timeStamp1 = 1653448174000; // test "2022-05-25 11:09:34.000"
371 double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
372
373 // When the option is blank, the default format is "yyyy/MM/dd", the year, month and day are all numeric,
374 // because the default option in initialization is "DefaultsOption::DATE".
375 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
376 EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25");
377 JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
378 EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr2).c_str(), "2022/5/30");
379 }
380 } // namespace panda::test
381