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/global_env.h"
17 #include "ecmascript/js_date.h"
18 #include "ecmascript/js_date_time_format.h"
19 #include "ecmascript/js_locale.h"
20 #include "ecmascript/tests/test_helper.h"
21
22 using namespace panda;
23 using namespace panda::ecmascript;
24
25 namespace panda::test {
26 class JSDateTimeFormatTest : public testing::Test {
27 public:
SetUpTestCase()28 static void SetUpTestCase()
29 {
30 GTEST_LOG_(INFO) << "SetUpTestCase";
31 }
32
TearDownTestCase()33 static void TearDownTestCase()
34 {
35 GTEST_LOG_(INFO) << "TearDownCase";
36 }
37
SetUp()38 void SetUp() override
39 {
40 JSRuntimeOptions options;
41 #if PANDA_TARGET_LINUX
42 // for consistency requirement, use ohos_icu4j/data as icu-data-path
43 options.SetIcuDataPath(ICU_PATH);
44 #endif
45 options.SetEnableForceGC(true);
46 instance = JSNApi::CreateEcmaVM(options);
47 instance->SetEnableForceGC(true);
48 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
49 thread = instance->GetJSThread();
50 scope = new EcmaHandleScope(thread);
51 }
52
TearDown()53 void TearDown() override
54 {
55 TestHelper::DestroyEcmaVMWithScope(instance, scope);
56 }
57
58 EcmaVM *instance {nullptr};
59 EcmaHandleScope *scope {nullptr};
60 JSThread *thread {nullptr};
61 };
62
SetDateOptionsTest(JSThread * thread,JSHandle<JSObject> & optionsObj,std::map<std::string,std::string> & dateOptions)63 void SetDateOptionsTest(JSThread *thread, JSHandle<JSObject> &optionsObj,
64 std::map<std::string, std::string> &dateOptions)
65 {
66 auto vm = thread->GetEcmaVM();
67 auto factory = vm->GetFactory();
68 auto globalConst = thread->GlobalConstants();
69 // Date options keys.
70 JSHandle<JSTaggedValue> weekdayKey = globalConst->GetHandledWeekdayString();
71 JSHandle<JSTaggedValue> yearKey = globalConst->GetHandledYearString();
72 JSHandle<JSTaggedValue> monthKey = globalConst->GetHandledMonthString();
73 JSHandle<JSTaggedValue> dayKey = globalConst->GetHandledDayString();
74 // Date options values.
75 JSHandle<JSTaggedValue> weekdayValue(factory->NewFromASCII(dateOptions["weekday"].c_str()));
76 JSHandle<JSTaggedValue> yearValue(factory->NewFromASCII(dateOptions["year"].c_str()));
77 JSHandle<JSTaggedValue> monthValue(factory->NewFromASCII(dateOptions["month"].c_str()));
78 JSHandle<JSTaggedValue> dayValue(factory->NewFromASCII(dateOptions["day"].c_str()));
79 // Set date options.
80 JSObject::SetProperty(thread, optionsObj, weekdayKey, weekdayValue);
81 JSObject::SetProperty(thread, optionsObj, yearKey, yearValue);
82 JSObject::SetProperty(thread, optionsObj, monthKey, monthValue);
83 JSObject::SetProperty(thread, optionsObj, dayKey, dayValue);
84 }
85
SetTimeOptionsTest(JSThread * thread,JSHandle<JSObject> & optionsObj,std::map<std::string,std::string> & timeOptionsMap)86 void SetTimeOptionsTest(JSThread *thread, JSHandle<JSObject> &optionsObj,
87 std::map<std::string, std::string> &timeOptionsMap)
88 {
89 auto vm = thread->GetEcmaVM();
90 auto factory = vm->GetFactory();
91 auto globalConst = thread->GlobalConstants();
92 // Time options keys.
93 JSHandle<JSTaggedValue> dayPeriodKey = globalConst->GetHandledDayPeriodString();
94 JSHandle<JSTaggedValue> hourKey = globalConst->GetHandledHourString();
95 JSHandle<JSTaggedValue> minuteKey = globalConst->GetHandledMinuteString();
96 JSHandle<JSTaggedValue> secondKey = globalConst->GetHandledSecondString();
97 JSHandle<JSTaggedValue> fractionalSecondDigitsKey = globalConst->GetHandledFractionalSecondDigitsString();
98 // Time options values.
99 JSHandle<JSTaggedValue> dayPeriodValue(factory->NewFromASCII(timeOptionsMap["dayPeriod"].c_str()));
100 JSHandle<JSTaggedValue> hourValue(factory->NewFromASCII(timeOptionsMap["hour"].c_str()));
101 JSHandle<JSTaggedValue> minuteValue(factory->NewFromASCII(timeOptionsMap["minute"].c_str()));
102 JSHandle<JSTaggedValue> secondValue(factory->NewFromASCII(timeOptionsMap["second"].c_str()));
103 JSHandle<JSTaggedValue> fractionalSecondDigitsValue(
104 factory->NewFromASCII(timeOptionsMap["fractionalSecond"].c_str()));
105 // Set time options.
106 JSObject::SetProperty(thread, optionsObj, dayPeriodKey, dayPeriodValue);
107 JSObject::SetProperty(thread, optionsObj, hourKey, hourValue);
108 JSObject::SetProperty(thread, optionsObj, minuteKey, minuteValue);
109 JSObject::SetProperty(thread, optionsObj, secondKey, secondValue);
110 JSObject::SetProperty(thread, optionsObj, fractionalSecondDigitsKey, fractionalSecondDigitsValue);
111 }
112
113 /**
114 * @tc.name: GetIcuLocale & SetIcuLocale
115 * @tc.desc: Set and obtain localization labels compatible with ICU Libraries.
116 * @tc.type: FUNC
117 * @tc.require:
118 */
HWTEST_F_L0(JSDateTimeFormatTest,Set_Get_IcuLocale)119 HWTEST_F_L0(JSDateTimeFormatTest, Set_Get_IcuLocale)
120 {
121 auto vm = thread->GetEcmaVM();
122 auto factory = vm->GetFactory();
123 auto env = vm->GetGlobalEnv();
124 JSHandle<JSTaggedValue> ctor = env->GetDateTimeFormatFunction();
125 JSHandle<JSDateTimeFormat> dtf =
126 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
127
128 icu::Locale locale1("ko", "Kore", "KR");
129 JSDateTimeFormat::SetIcuLocale(thread, dtf, locale1, JSDateTimeFormat::FreeIcuLocale);
130 icu::Locale *resLocale1 = dtf->GetIcuLocale();
131 EXPECT_STREQ(resLocale1->getBaseName(), "ko_Kore_KR");
132
133 icu::Locale locale2("zh", "Hans", "Cn");
134 JSDateTimeFormat::SetIcuLocale(thread, dtf, locale2, JSDateTimeFormat::FreeIcuLocale);
135 icu::Locale *resLocale2 = dtf->GetIcuLocale();
136 EXPECT_STREQ(resLocale2->getBaseName(), "zh_Hans_CN");
137 }
138
139 /**
140 * @tc.name: SetIcuSimpleDateFormat & GetIcuSimpleDateFormat
141 * @tc.desc: Set and obtain a simple time and date format compatible with ICU Libraries.
142 * @tc.type: FUNC
143 * @tc.require:
144 */
HWTEST_F_L0(JSDateTimeFormatTest,Set_Get_IcuSimpleDateFormat)145 HWTEST_F_L0(JSDateTimeFormatTest, Set_Get_IcuSimpleDateFormat)
146 {
147 auto vm = thread->GetEcmaVM();
148 auto factory = vm->GetFactory();
149 auto env = vm->GetGlobalEnv();
150 const icu::UnicodeString timeZoneId("Asia/Shanghai");
151 icu::TimeZone *tz = icu::TimeZone::createTimeZone(timeZoneId);
152 icu::TimeZone::adoptDefault(tz);
153 JSHandle<JSTaggedValue> ctor = env->GetDateTimeFormatFunction();
154 JSHandle<JSDateTimeFormat> dtf =
155 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
156 UErrorCode status = UErrorCode::U_ZERO_ERROR;
157 icu::UnicodeString dateTime1("2022.05.25 11:09:34");
158 icu::UnicodeString dateTime2("2022.May.25 11:09:34");
159 icu::UnicodeString dateTime3("2022.May.25 AD 11:09:34 AM");
160
161 icu::UnicodeString pattern("yyyy.MM.dd HH:mm:ss");
162 icu::SimpleDateFormat sdf(pattern, status);
163 JSDateTimeFormat::SetIcuSimpleDateFormat(thread, dtf, sdf, JSDateTimeFormat::FreeSimpleDateFormat);
164 icu::SimpleDateFormat *resSdf = dtf->GetIcuSimpleDateFormat();
165 UDate timeStamp = resSdf->parse(dateTime1, status);
166 EXPECT_EQ(timeStamp, 1653448174000);
167 status = UErrorCode::U_ZERO_ERROR;
168 timeStamp = resSdf->parse(dateTime2, status);
169 EXPECT_EQ(timeStamp, 1653448174000);
170 status = UErrorCode::U_ZERO_ERROR;
171 timeStamp = resSdf->parse(dateTime3, status);
172 EXPECT_EQ(timeStamp, 0);
173
174 status = UErrorCode::U_ZERO_ERROR;
175 icu::UnicodeString pattern2("yyyyy.MMMMM.dd GGG hh:mm::ss aaa");
176 icu::SimpleDateFormat sdf2(pattern2, status);
177 JSDateTimeFormat::SetIcuSimpleDateFormat(thread, dtf, sdf2, JSDateTimeFormat::FreeSimpleDateFormat);
178 icu::SimpleDateFormat *resSdf2 = dtf->GetIcuSimpleDateFormat();
179 timeStamp = resSdf2->parse(dateTime1, status);
180 EXPECT_EQ(timeStamp, 0);
181 status = UErrorCode::U_ZERO_ERROR;
182 timeStamp = resSdf2->parse(dateTime2, status);
183 EXPECT_EQ(timeStamp, 0);
184 status = UErrorCode::U_ZERO_ERROR;
185 timeStamp = resSdf2->parse(dateTime3, status);
186 EXPECT_EQ(timeStamp, 1653448174000);
187 }
188
189 /**
190 * @tc.name: InitializeDateTimeFormat
191 * @tc.desc: Initialize the time and date format through localization label locales and options.
192 * Options can include year, month, day, hour, minute, second, time zone and weekday, etc.
193 * @tc.type: FUNC
194 * @tc.require:
195 */
HWTEST_F_L0(JSDateTimeFormatTest,InitializeDateTimeFormat)196 HWTEST_F_L0(JSDateTimeFormatTest, InitializeDateTimeFormat)
197 {
198 auto vm = thread->GetEcmaVM();
199 auto factory = vm->GetFactory();
200 auto env = vm->GetGlobalEnv();
201 // Create locales.
202 JSHandle<JSTaggedValue> localeCtor = env->GetLocaleFunction();
203 JSHandle<JSLocale> locales =
204 JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(localeCtor), localeCtor));
205 icu::Locale icuLocale("zh", "Hans", "Cn", "calendar=chinese");
206 factory->NewJSIntlIcuData(locales, icuLocale, JSLocale::FreeIcuLocale);
207 // Create options.
208 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
209 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
210 options = JSDateTimeFormat::ToDateTimeOptions(
211 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
212 // Initialize DateTimeFormat.
213 JSHandle<JSTaggedValue> dtfCtor = env->GetDateTimeFormatFunction();
214 JSHandle<JSDateTimeFormat> dtf =
215 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(dtfCtor), dtfCtor));
216 dtf = JSDateTimeFormat::InitializeDateTimeFormat(
217 thread, dtf, JSHandle<JSTaggedValue>::Cast(locales), JSHandle<JSTaggedValue>::Cast(options));
218
219 JSHandle<JSTaggedValue> localeTagVal(thread, dtf->GetLocale());
220 JSHandle<EcmaString> localeEcmaStr = JSHandle<EcmaString>::Cast(localeTagVal);
221 std::string localeStr = JSLocale::ConvertToStdString(localeEcmaStr);
222 EXPECT_STREQ(localeStr.c_str(), "zh-Hans-CN-u-ca-chinese");
223 }
224
225 /**
226 * @tc.name: ToDateTimeOptions
227 * @tc.desc: Empty or incomplete option objects are supplemented according to the required option and default option.
228 * @tc.type: FUNC
229 * @tc.require:
230 */
HWTEST_F_L0(JSDateTimeFormatTest,ToDateTimeOptions_001)231 HWTEST_F_L0(JSDateTimeFormatTest, ToDateTimeOptions_001)
232 {
233 auto vm = thread->GetEcmaVM();
234 auto factory = vm->GetFactory();
235 auto env = vm->GetGlobalEnv();
236 auto globalConst = thread->GlobalConstants();
237
238 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
239 JSHandle<JSTaggedValue> yearKey = globalConst->GetHandledYearString();
240 JSHandle<JSTaggedValue> monthKey = globalConst->GetHandledMonthString();
241 JSHandle<JSTaggedValue> dayKey = globalConst->GetHandledDayString();
242 JSHandle<JSTaggedValue> hourKey = globalConst->GetHandledHourString();
243 JSHandle<JSTaggedValue> minuteKey = globalConst->GetHandledMinuteString();
244 JSHandle<JSTaggedValue> secondKey = globalConst->GetHandledSecondString();
245
246 // When the option value is blank, it will be set according to the default option,
247 // including the year, month, day, hour, minute and second, and the values are all numeric.
248 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
249 options = JSDateTimeFormat::ToDateTimeOptions(
250 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL); // test "ALL"
251 auto yearEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, yearKey).GetValue());
252 EXPECT_STREQ(JSLocale::ConvertToStdString(yearEcmaStr).c_str(), "numeric");
253 auto monthEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, monthKey).GetValue());
254 EXPECT_STREQ(JSLocale::ConvertToStdString(monthEcmaStr).c_str(), "numeric");
255 auto dayEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayKey).GetValue());
256 EXPECT_STREQ(JSLocale::ConvertToStdString(dayEcmaStr).c_str(), "numeric");
257 auto hourEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, hourKey).GetValue());
258 EXPECT_STREQ(JSLocale::ConvertToStdString(hourEcmaStr).c_str(), "numeric");
259 auto minuteEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, minuteKey).GetValue());
260 EXPECT_STREQ(JSLocale::ConvertToStdString(minuteEcmaStr).c_str(), "numeric");
261 auto secondEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, secondKey).GetValue());
262 EXPECT_STREQ(JSLocale::ConvertToStdString(secondEcmaStr).c_str(), "numeric");
263 }
264
HWTEST_F_L0(JSDateTimeFormatTest,ToDateTimeOptions_002)265 HWTEST_F_L0(JSDateTimeFormatTest, ToDateTimeOptions_002)
266 {
267 auto vm = thread->GetEcmaVM();
268 auto factory = vm->GetFactory();
269 auto env = vm->GetGlobalEnv();
270 auto globalConst = thread->GlobalConstants();
271
272 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
273 JSHandle<JSTaggedValue> weekdayKey = globalConst->GetHandledWeekdayString();
274 JSHandle<JSTaggedValue> yearKey = globalConst->GetHandledYearString();
275 JSHandle<JSTaggedValue> monthKey = globalConst->GetHandledMonthString();
276 JSHandle<JSTaggedValue> dayKey = globalConst->GetHandledDayString();
277 JSHandle<JSTaggedValue> dayPeriodKey = globalConst->GetHandledDayPeriodString();
278 JSHandle<JSTaggedValue> hourKey = globalConst->GetHandledHourString();
279 JSHandle<JSTaggedValue> minuteKey = globalConst->GetHandledMinuteString();
280 JSHandle<JSTaggedValue> secondKey = globalConst->GetHandledSecondString();
281 JSHandle<JSTaggedValue> fracSecKey = globalConst->GetHandledFractionalSecondDigitsString();
282
283 // When the option value is not empty, it will be set according to the required options.
284 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
285 std::map<std::string, std::string> dateOptionsMap {
286 { "weekday", "narrow" },
287 { "year", "2-digit" },
288 { "month", "2-digit" },
289 { "day", "2-digit" }
290 };
291 std::map<std::string, std::string> timeOptionsMap {
292 { "dayPeriod", "narrow" },
293 { "hour", "2-digit" },
294 { "minute", "2-digit" },
295 { "second", "2-digit" },
296 { "fractionalSecond", "1" }
297 };
298 SetDateOptionsTest(thread, options, dateOptionsMap);
299 SetTimeOptionsTest(thread, options, timeOptionsMap);
300 options = JSDateTimeFormat::ToDateTimeOptions(
301 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL); // test "ANY"
302 auto weekdayStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, weekdayKey).GetValue());
303 EXPECT_STREQ(JSLocale::ConvertToStdString(weekdayStr).c_str(), "narrow");
304 auto yearStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, yearKey).GetValue());
305 EXPECT_STREQ(JSLocale::ConvertToStdString(yearStr).c_str(), "2-digit");
306 auto monthStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, monthKey).GetValue());
307 EXPECT_STREQ(JSLocale::ConvertToStdString(monthStr).c_str(), "2-digit");
308 auto dayStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayKey).GetValue());
309 EXPECT_STREQ(JSLocale::ConvertToStdString(dayStr).c_str(), "2-digit");
310
311 auto dayPeriodStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayPeriodKey).GetValue());
312 EXPECT_STREQ(JSLocale::ConvertToStdString(dayPeriodStr).c_str(), "narrow");
313 auto hourStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, hourKey).GetValue());
314 EXPECT_STREQ(JSLocale::ConvertToStdString(hourStr).c_str(), "2-digit");
315 auto minuteStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, minuteKey).GetValue());
316 EXPECT_STREQ(JSLocale::ConvertToStdString(minuteStr).c_str(), "2-digit");
317 auto secondStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, secondKey).GetValue());
318 EXPECT_STREQ(JSLocale::ConvertToStdString(secondStr).c_str(), "2-digit");
319 auto fracSecStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, fracSecKey).GetValue());
320 EXPECT_STREQ(JSLocale::ConvertToStdString(fracSecStr).c_str(), "1");
321 }
322
CreateDateTimeFormatTest(JSThread * thread,icu::Locale icuLocale,JSHandle<JSObject> options)323 JSHandle<JSDateTimeFormat> CreateDateTimeFormatTest(JSThread *thread, icu::Locale icuLocale, JSHandle<JSObject> options)
324 {
325 auto vm = thread->GetEcmaVM();
326 auto factory = vm->GetFactory();
327 auto env = vm->GetGlobalEnv();
328
329 JSHandle<JSTaggedValue> localeCtor = env->GetLocaleFunction();
330 JSHandle<JSTaggedValue> dtfCtor = env->GetDateTimeFormatFunction();
331 JSHandle<JSLocale> locales =
332 JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(localeCtor), localeCtor));
333 JSHandle<JSDateTimeFormat> dtf =
334 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(dtfCtor), dtfCtor));
335
336 JSHandle<JSTaggedValue> optionsVal = JSHandle<JSTaggedValue>::Cast(options);
337 factory->NewJSIntlIcuData(locales, icuLocale, JSLocale::FreeIcuLocale);
338 dtf = JSDateTimeFormat::InitializeDateTimeFormat(thread, dtf, JSHandle<JSTaggedValue>::Cast(locales), optionsVal);
339 return dtf;
340 }
341 /**
342 * @tc.name: FormatDateTime
343 * @tc.desc: Convert floating-point timestamp to fixed format time date through time date format.
344 * @tc.type: FUNC
345 * @tc.require:
346 */
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTime_001)347 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_001)
348 {
349 auto vm = thread->GetEcmaVM();
350 auto factory = vm->GetFactory();
351 auto env = vm->GetGlobalEnv();
352 auto globalConst = thread->GlobalConstants();
353
354 icu::Locale icuLocale("zh", "Hans", "Cn");
355 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
356 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
357 JSHandle<JSTaggedValue> hourCycleKey = globalConst->GetHandledHourCycleString();
358 JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h12"));
359 JSHandle<JSTaggedValue> timeZoneKey = globalConst->GetHandledTimeZoneString();
360 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("ETC/GMT-8"));
361 JSObject::SetProperty(thread, options, timeZoneKey, timeZoneValue);
362 JSObject::SetProperty(thread, options, hourCycleKey, hourCycleValue);
363 JSHandle<JSDateTimeFormat> dtf = CreateDateTimeFormatTest(thread, icuLocale, options);
364
365 double timeStamp1 = 1653448174000; // test "2022-05-25 11:09:34.000"
366 double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
367
368 // When the option is blank, the default format is "yyyy/MM/dd", the year, month and day are all numeric,
369 // because the default option in initialization is "DefaultsOption::DATE".
370 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
371 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25");
372 JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
373 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr2).c_str(), "2022/5/30");
374 }
375
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTime_002)376 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_002)
377 {
378 auto vm = thread->GetEcmaVM();
379 auto factory = vm->GetFactory();
380 auto env = vm->GetGlobalEnv();
381 auto globalConst = thread->GlobalConstants();
382
383 icu::Locale icuLocale("zh", "Hans", "Cn");
384 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
385 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
386 JSHandle<JSTaggedValue> hourCycleKey = globalConst->GetHandledHourCycleString();
387 JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h12"));
388 JSHandle<JSTaggedValue> timeZoneKey = globalConst->GetHandledTimeZoneString();
389 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("ETC/GMT-8"));
390 JSObject::SetProperty(thread, options, timeZoneKey, timeZoneValue);
391 JSObject::SetProperty(thread, options, hourCycleKey, hourCycleValue);
392 options = JSDateTimeFormat::ToDateTimeOptions(
393 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
394 JSHandle<JSDateTimeFormat> dtf = CreateDateTimeFormatTest(thread, icuLocale, options);
395
396 double timeStamp1 = 1653448174000; // test "2022-05-25 11:09:34.000"
397 double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
398
399 // Format to include all options by "DefaultsOption::ALL".
400 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
401 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25 上午11:09:34");
402 JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
403 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr2).c_str(), "2022/5/30 下午10:30:12");
404 }
405
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTime_003)406 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_003)
407 {
408 auto vm = thread->GetEcmaVM();
409 auto factory = vm->GetFactory();
410 auto env = vm->GetGlobalEnv();
411 auto globalConst = thread->GlobalConstants();
412
413 icu::Locale icuLocale("zh", "Hans", "Cn");
414 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
415 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
416 JSHandle<JSTaggedValue> hourCycleKey = globalConst->GetHandledHourCycleString();
417 JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h12"));
418 JSHandle<JSTaggedValue> timeZoneKey = globalConst->GetHandledTimeZoneString();
419 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("ETC/GMT-8"));
420 JSObject::SetProperty(thread, options, timeZoneKey, timeZoneValue);
421 JSObject::SetProperty(thread, options, hourCycleKey, hourCycleValue);
422
423 // Set custom date time format.
424 std::map<std::string, std::string> dateOptionsMap {
425 { "weekday", "long" },
426 { "year", "2-digit" },
427 { "month", "2-digit" },
428 { "day", "2-digit" }
429 };
430 std::map<std::string, std::string> timeOptionsMap {
431 { "dayPeriod", "long" },
432 { "hour", "2-digit" },
433 { "minute", "2-digit" },
434 { "second", "2-digit" },
435 { "fractionalSecond", "3" }
436 };
437 SetDateOptionsTest(thread, options, dateOptionsMap);
438 SetTimeOptionsTest(thread, options, timeOptionsMap);
439 options = JSDateTimeFormat::ToDateTimeOptions(
440 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
441 JSHandle<JSDateTimeFormat> dtf = CreateDateTimeFormatTest(thread, icuLocale, options);
442
443 double timeStamp1 = 1653448174000; // test "2022-05-25 11:09:34.000"
444 double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
445
446 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
447 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(), "22年05月25日星期三 上午11:09:34.000");
448 JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
449 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr2).c_str(), "22年05月30日星期一 晚上10:30:12.999");
450 }
451
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTime_004)452 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_004)
453 {
454 auto vm = thread->GetEcmaVM();
455 auto factory = vm->GetFactory();
456 auto env = vm->GetGlobalEnv();
457 auto globalConst = thread->GlobalConstants();
458
459 icu::Locale icuLocale("en", "Latn", "US");
460 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
461 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
462 JSHandle<JSTaggedValue> hourCycleKey = globalConst->GetHandledHourCycleString();
463 JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h12"));
464 JSHandle<JSTaggedValue> timeZoneKey = globalConst->GetHandledTimeZoneString();
465 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("ETC/GMT-8"));
466 JSObject::SetProperty(thread, options, timeZoneKey, timeZoneValue);
467 JSObject::SetProperty(thread, options, hourCycleKey, hourCycleValue);
468
469 // Set custom date time format.
470 std::map<std::string, std::string> dateOptionsMap {
471 { "weekday", "long" },
472 { "year", "2-digit" },
473 { "month", "2-digit" },
474 { "day", "2-digit" }
475 };
476 std::map<std::string, std::string> timeOptionsMap {
477 { "dayPeriod", "long" },
478 { "hour", "2-digit" },
479 { "minute", "2-digit" },
480 { "second", "2-digit" },
481 { "fractionalSecond", "3" }
482 };
483 SetDateOptionsTest(thread, options, dateOptionsMap);
484 SetTimeOptionsTest(thread, options, timeOptionsMap);
485 options = JSDateTimeFormat::ToDateTimeOptions(
486 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
487 JSHandle<JSDateTimeFormat> dtf = CreateDateTimeFormatTest(thread, icuLocale, options);
488
489 double timeStamp1 = 1653448174000; // test "2022-05-25 11:09:34.000"
490 double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
491
492 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
493 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(),
494 "Wednesday, 05/25/22, 11:09:34.000 in the morning");
495 JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
496 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr2).c_str(),
497 "Monday, 05/30/22, 10:30:12.999 at night");
498 }
499
GetDateTimePartStringTest(JSThread * thread,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> part)500 std::string GetDateTimePartStringTest(JSThread *thread, JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> part)
501 {
502 JSHandle<JSObject> partObj = JSHandle<JSObject>::Cast(part);
503 JSHandle<JSTaggedValue> partValue = JSObject::GetProperty(thread, partObj, key).GetValue();
504 JSHandle<EcmaString> partEcmaStr = JSHandle<EcmaString>::Cast(partValue);
505 std::string partStr = JSLocale::ConvertToStdString(partEcmaStr);
506 return partStr;
507 }
508
509 /**
510 * @tc.name: FormatDateTimeToParts
511 * @tc.desc: Convert floating-point timestamp to fixed format time date through time date format.
512 * The "FormatDateTimeToParts" method converts the output result into an array containing various time and
513 * date attributes.
514 * @tc.type: FUNC
515 * @tc.require:
516 */
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTimeToParts_001)517 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTimeToParts_001)
518 {
519 auto vm = thread->GetEcmaVM();
520 auto factory = vm->GetFactory();
521 auto env = vm->GetGlobalEnv();
522 auto globalConst = thread->GlobalConstants();
523
524 JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledTypeString();
525 JSHandle<JSTaggedValue> valueKey = globalConst->GetHandledValueString();
526
527 icu::Locale icuLocale("zh", "Hans", "Cn");
528 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
529 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
530 JSHandle<JSTaggedValue> hourCycleKey = globalConst->GetHandledHourCycleString();
531 JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h12"));
532 JSHandle<JSTaggedValue> timeZoneKey = globalConst->GetHandledTimeZoneString();
533 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("ETC/GMT-8"));
534 JSObject::SetProperty(thread, options, timeZoneKey, timeZoneValue);
535 JSObject::SetProperty(thread, options, hourCycleKey, hourCycleValue);
536 JSHandle<JSDateTimeFormat> dtf = CreateDateTimeFormatTest(thread, icuLocale, options);
537
538 double timeStamp = 1653448174123; // test "2022-05-25 11:09:34.123"
539 // Use default date time format and format date and time to parts.
540 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp);
541 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25");
542 JSHandle<JSArray> dateTimeArray1 = JSDateTimeFormat::FormatDateTimeToParts(thread, dtf, timeStamp);
543 auto year = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 0).GetValue();
544 auto literal1 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 1).GetValue();
545 auto month = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 2).GetValue();
546 auto literal2 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 3).GetValue();
547 auto day = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 4).GetValue();
548 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, year).c_str(), "year");
549 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, year).c_str(), "2022");
550 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal1).c_str(), "literal");
551 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal1).c_str(), "/");
552 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, month).c_str(), "month");
553 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, month).c_str(), "5");
554 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal2).c_str(), "literal");
555 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal2).c_str(), "/");
556 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, day).c_str(), "day");
557 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, day).c_str(), "25");
558 }
559
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTimeToParts_002)560 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTimeToParts_002)
561 {
562 auto vm = thread->GetEcmaVM();
563 auto factory = vm->GetFactory();
564 auto env = vm->GetGlobalEnv();
565 auto globalConst = thread->GlobalConstants();
566
567 JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledTypeString();
568 JSHandle<JSTaggedValue> valueKey = globalConst->GetHandledValueString();
569 icu::Locale icuLocale("zh", "Hans", "Cn");
570 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
571 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
572 JSHandle<JSTaggedValue> hourCycleKey = globalConst->GetHandledHourCycleString();
573 JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h12"));
574 JSHandle<JSTaggedValue> timeZoneKey = globalConst->GetHandledTimeZoneString();
575 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("ETC/GMT-8"));
576 JSObject::SetProperty(thread, options, timeZoneKey, timeZoneValue);
577 JSObject::SetProperty(thread, options, hourCycleKey, hourCycleValue);
578
579 double timeStamp = 1653448174123; // test "2022-05-25 11:09:34.123"
580 // Set custom date time format and format date and time to parts.
581 std::map<std::string, std::string> dateOptionsMap {
582 { "weekday", "long" },
583 { "year", "2-digit" },
584 { "month", "2-digit" },
585 { "day", "2-digit" }
586 };
587 std::map<std::string, std::string> timeOptionsMap {
588 { "dayPeriod", "long" },
589 { "hour", "2-digit" },
590 { "minute", "2-digit" },
591 { "second", "2-digit" },
592 { "fractionalSecond", "3" }
593 };
594 SetDateOptionsTest(thread, options, dateOptionsMap);
595 SetTimeOptionsTest(thread, options, timeOptionsMap);
596 options = JSDateTimeFormat::ToDateTimeOptions(
597 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
598 JSHandle<JSDateTimeFormat> dtf = CreateDateTimeFormatTest(thread, icuLocale, options);
599 JSHandle<EcmaString> dateTimeEcamStr = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp);
600 EXPECT_STREQ(JSLocale::ConvertToStdString(dateTimeEcamStr).c_str(), "22年05月25日星期三 上午11:09:34.123");
601
602 JSHandle<JSArray> dateTimeArray = JSDateTimeFormat::FormatDateTimeToParts(thread, dtf, timeStamp);
603 auto year = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 0).GetValue();
604 auto literal1 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 1).GetValue();
605 auto month = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 2).GetValue();
606 auto literal2 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 3).GetValue();
607 auto day = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 4).GetValue();
608 auto literal3 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 5).GetValue();
609 auto weekday = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 6).GetValue();
610 auto literal4 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 7).GetValue();
611 auto dayPeriod = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 8).GetValue();
612 auto hour = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 9).GetValue();
613 auto literal5 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 10).GetValue();
614 auto minute = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 11).GetValue();
615 auto literal6 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 12).GetValue();
616 auto second = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 13).GetValue();
617 auto literal7 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 14).GetValue();
618 auto fracSec = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 15).GetValue();
619 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, year).c_str(), "year");
620 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, year).c_str(), "22");
621 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal1).c_str(), "literal");
622 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal1).c_str(), "年");
623 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, month).c_str(), "month");
624 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, month).c_str(), "05");
625 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal2).c_str(), "literal");
626 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal2).c_str(), "月");
627 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, day).c_str(), "day");
628 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, day).c_str(), "25");
629 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal3).c_str(), "literal");
630 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal3).c_str(), "日");
631 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, weekday).c_str(), "weekday");
632 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, weekday).c_str(), "星期三");
633 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal4).c_str(), "literal");
634 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal4).c_str(), " ");
635 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, dayPeriod).c_str(), "dayPeriod");
636 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, dayPeriod).c_str(), "上午");
637 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, hour).c_str(), "hour");
638 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, hour).c_str(), "11");
639 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal5).c_str(), "literal");
640 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal5).c_str(), ":");
641 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, minute).c_str(), "minute");
642 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, minute).c_str(), "09");
643 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal6).c_str(), "literal");
644 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal6).c_str(), ":");
645 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, second).c_str(), "second");
646 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, second).c_str(), "34");
647 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal7).c_str(), "literal");
648 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal7).c_str(), ".");
649 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, fracSec).c_str(), "fractionalSecond");
650 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, fracSec).c_str(), "123");
651 }
652 /**
653 * @tc.name: GainAvailableLocales
654 * @tc.desc: Get the available localized label array. If the global time date localized label is not set, return an
655 * array containing all available labels. Otherwise, return an array containing self-defined labels.
656 * @tc.type: FUNC
657 * @tc.require:
658 */
HWTEST_F_L0(JSDateTimeFormatTest,GainAvailableLocales)659 HWTEST_F_L0(JSDateTimeFormatTest, GainAvailableLocales)
660 {
661 auto vm = thread->GetEcmaVM();
662 auto factory = vm->GetFactory();
663 auto env = vm->GetGlobalEnv();
664
665 // The date and time format locales is not initialized,
666 // then get all available locales and save them in a 'TaggedArray'.
667 JSHandle<JSTaggedValue> dateTimeFormatLocales = env->GetDateTimeFormatLocales();
668 EXPECT_EQ(dateTimeFormatLocales.GetTaggedValue(), JSTaggedValue::Undefined());
669
670 const char *key = "calendar";
671 const char *path = nullptr;
672 JSHandle<TaggedArray> availableLocales = JSLocale::GetAvailableLocales(thread, key, path);
673 env->SetDateTimeFormatLocales(thread, availableLocales);
674 JSHandle<TaggedArray> gainLocales1 = JSDateTimeFormat::GainAvailableLocales(thread);
675 EXPECT_EQ(JSHandle<JSTaggedValue>::Cast(gainLocales1).GetTaggedValue().GetRawData(),
676 JSHandle<JSTaggedValue>::Cast(availableLocales).GetTaggedValue().GetRawData());
677
678 // The date and time format locales has already been initialized,
679 // then get custom locale and save it in a 'TaggedArray'.
680 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
681 JSHandle<JSTaggedValue> localeCtor = env->GetLocaleFunction();
682 JSHandle<JSTaggedValue> dtfCtor = env->GetDateTimeFormatFunction();
683
684 JSHandle<JSLocale> locales =
685 JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(localeCtor), localeCtor));
686 icu::Locale icuLocale("zh", "Hans", "Cn", "calendar=chinese");
687 factory->NewJSIntlIcuData(locales, icuLocale, JSLocale::FreeIcuLocale);
688 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
689 options = JSDateTimeFormat::ToDateTimeOptions(
690 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
691 JSHandle<JSDateTimeFormat> dtf =
692 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(dtfCtor), dtfCtor));
693 dtf = JSDateTimeFormat::InitializeDateTimeFormat(
694 thread, dtf, JSHandle<JSTaggedValue>::Cast(locales), JSHandle<JSTaggedValue>::Cast(options));
695
696 JSHandle<JSTaggedValue> localeTagVal(thread, dtf->GetLocale());
697 JSHandle<TaggedArray> localesTagArr = factory->NewTaggedArray(1);
698 localesTagArr->Set(thread, 0, localeTagVal);
699 env->SetDateTimeFormatLocales(thread, localesTagArr);
700 JSHandle<TaggedArray> gainLocales2 = JSDateTimeFormat::GainAvailableLocales(thread);
701 EXPECT_EQ(gainLocales2->GetLength(), 1U);
702 EXPECT_STREQ(EcmaStringAccessor(gainLocales2->Get(0)).ToCString().c_str(),
703 "zh-Hans-CN-u-ca-chinese");
704 }
705 } // namespace panda::test
706