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