• 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/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