1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 2008-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8
9 #include "unicode/utypes.h"
10
11 #if !UCONFIG_NO_FORMATTING
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include "dtptngts.h"
16
17 #include "unicode/calendar.h"
18 #include "unicode/smpdtfmt.h"
19 #include "unicode/dtfmtsym.h"
20 #include "unicode/dtptngen.h"
21 #include "unicode/ustring.h"
22 #include "unicode/datefmt.h"
23 #include "cmemory.h"
24 #include "cstring.h"
25 #include "loctest.h"
26
27
28 // This is an API test, not a unit test. It doesn't test very many cases, and doesn't
29 // try to test the full functionality. It just calls each function in the class and
30 // verifies that it works on a basic level.
31
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)32 void IntlTestDateTimePatternGeneratorAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
33 {
34 if (exec) logln("TestSuite DateTimePatternGeneratorAPI");
35 switch (index) {
36 TESTCASE(0, testAPI);
37 TESTCASE(1, testOptions);
38 TESTCASE(2, testAllFieldPatterns);
39 TESTCASE(3, testStaticGetSkeleton);
40 TESTCASE(4, testC);
41 TESTCASE(5, testSkeletonsWithDayPeriods);
42 TESTCASE(6, testGetFieldDisplayNames);
43 TESTCASE(7, testJjMapping);
44 TESTCASE(8, test20640_HourCyclArsEnNH);
45 TESTCASE(9, testFallbackWithDefaultRootLocale);
46 default: name = ""; break;
47 }
48 }
49
50 #define MAX_LOCALE 12
51
52 /**
53 * Test various generic API methods of DateTimePatternGenerator for API coverage.
54 */
testAPI()55 void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/)
56 {
57 UnicodeString patternData[] = {
58 UnicodeString("yM"), // 00
59 UnicodeString("yMMM"), // 01
60 UnicodeString("yMd"), // 02
61 UnicodeString("yMMMd"), // 03
62 UnicodeString("Md"), // 04
63 UnicodeString("MMMd"), // 05
64 UnicodeString("MMMMd"), // 06
65 UnicodeString("yQQQ"), // 07
66 UnicodeString("hhmm"), // 08
67 UnicodeString("HHmm"), // 09
68 UnicodeString("jjmm"), // 10
69 UnicodeString("mmss"), // 11
70 UnicodeString("yyyyMMMM"), // 12
71 UnicodeString("MMMEd"), // 13
72 UnicodeString("Ed"), // 14
73 UnicodeString("jmmssSSS"), // 15
74 UnicodeString("JJmm"), // 16
75 UnicodeString(),
76 };
77
78 const char* testLocale[MAX_LOCALE][4] = {
79 {"en", "US", "", ""}, // 0
80 {"en", "US", "", "calendar=japanese"}, // 1
81 {"de", "DE", "", ""}, // 2
82 {"fi", "", "", ""}, // 3
83 {"es", "", "", ""}, // 4
84 {"ja", "", "", ""}, // 5
85 {"ja", "", "", "calendar=japanese"}, // 6
86 {"zh", "Hans", "CN", ""}, // 7
87 {"zh", "TW", "", "calendar=roc"}, // 8
88 {"ru", "", "", ""}, // 9
89 {"zh", "", "", "calendar=chinese"}, // 10
90 {"ja", "JP", "TRADITIONAL", ""}, // 11
91 };
92
93 // For Weds, Jan 13, 1999, 23:58:59
94 UnicodeString patternResults_en_US[] = {
95 // en_US // 0 en_US
96 UnicodeString("1/1999"), // 00: yM
97 UnicodeString("Jan 1999"), // 01: yMMM
98 UnicodeString("1/13/1999"), // 02: yMd
99 UnicodeString("Jan 13, 1999"), // 03: yMMMd
100 UnicodeString("1/13"), // 04: Md
101 UnicodeString("Jan 13"), // 05: MMMd
102 UnicodeString("January 13"), // 06: MMMMd
103 UnicodeString("Q1 1999"), // 07: yQQQ
104 UnicodeString("11:58 PM"), // 08: hhmm
105 UnicodeString("23:58"), // 09: HHmm
106 UnicodeString("11:58 PM"), // 10: jjmm
107 UnicodeString("58:59"), // 11: mmss
108 UnicodeString("January 1999"), // 12: yyyyMMMM
109 UnicodeString("Wed, Jan 13"), // 13: MMMEd -> EEE, MMM d
110 UnicodeString("13 Wed"), // 14: Ed -> d EEE
111 UnicodeString("11:58:59.123 PM"), // 15: jmmssSSS -> "h:mm:ss.SSS a"
112 UnicodeString("11:58"), // 16: JJmm
113 };
114
115 UnicodeString patternResults_en_US_japanese[] = {
116 // en_US@calendar=japanese // 1 en_US@calendar=japanese
117 UnicodeString("1/11 H"), // 0: yM
118 UnicodeString("Jan 11 Heisei"), // 1: yMMM
119 UnicodeString("1/13/11 H"), // 2: yMd
120 UnicodeString("Jan 13, 11 Heisei"), // 3: yMMMd
121 UnicodeString("1/13"), // 4: Md
122 UnicodeString("Jan 13"), // 5: MMMd
123 UnicodeString("January 13"), // 6: MMMMd
124 UnicodeString("Q1 11 Heisei"), // 7: yQQQ
125 UnicodeString("11:58 PM"), // 8: hhmm
126 UnicodeString("23:58"), // 9: HHmm
127 UnicodeString("11:58 PM"), // 10: jjmm
128 UnicodeString("58:59"), // 11: mmss
129 UnicodeString("January 11 Heisei"), // 12: yyyyMMMM
130 UnicodeString("Wed, Jan 13"), // 13: MMMEd -> EEE, MMM d"
131 UnicodeString("13 Wed"), // 14: Ed -> d EEE
132 UnicodeString("11:58:59.123 PM"), // 15: jmmssSSS -> "h:mm:ss.SSS a"
133 UnicodeString("11:58"), // 16: JJmm
134 };
135
136 UnicodeString patternResults_de_DE[] = {
137 // de_DE // 2 de_DE
138 UnicodeString("1.1999"), // 00: yM
139 UnicodeString("Jan. 1999"), // 01: yMMM
140 UnicodeString("13.1.1999"), // 02: yMd
141 UnicodeString("13. Jan. 1999"), // 03: yMMMd
142 UnicodeString("13.1."), // 04: Md
143 UnicodeString("13. Jan."), // 05: MMMd
144 UnicodeString("13. Januar"), // 06: MMMMd
145 UnicodeString("Q1 1999"), // 07: yQQQ
146 UnicodeString("11:58 PM"), // 08: hhmm
147 UnicodeString("23:58"), // 09: HHmm
148 UnicodeString("23:58"), // 10: jjmm
149 UnicodeString("58:59"), // 11: mmss
150 UnicodeString("Januar 1999"), // 12: yyyyMMMM
151 UnicodeString("Mi., 13. Jan."), // 13: MMMEd -> EEE, d. MMM
152 UnicodeString("Mi., 13."), // 14: Ed -> EEE d.
153 UnicodeString("23:58:59,123"), // 15: jmmssSSS -> "HH:mm:ss,SSS"
154 UnicodeString("23:58"), // 16: JJmm
155 };
156
157 UnicodeString patternResults_fi[] = {
158 // fi // 3 fi
159 UnicodeString("1.1999"), // 00: yM (fixed expected result per ticket:6626:)
160 UnicodeString("tammi 1999"), // 01: yMMM
161 UnicodeString("13.1.1999"), // 02: yMd
162 UnicodeString("13. tammik. 1999"), // 03: yMMMd
163 UnicodeString("13.1."), // 04: Md
164 UnicodeString("13. tammik."), // 05: MMMd
165 UnicodeString("13. tammikuuta"), // 06: MMMMd
166 UnicodeString("1. nelj. 1999"), // 07: yQQQ
167 UnicodeString("11.58 ip."), // 08: hhmm
168 UnicodeString("23.58"), // 09: HHmm
169 UnicodeString("23.58"), // 10: jjmm
170 UnicodeString("58.59"), // 11: mmss
171 UnicodeString("tammikuu 1999"), // 12: yyyyMMMM
172 UnicodeString("ke 13. tammik."), // 13: MMMEd -> EEE d. MMM
173 UnicodeString("ke 13."), // 14: Ed -> ccc d.
174 UnicodeString("23.58.59,123"), // 15: jmmssSSS -> "H.mm.ss,SSS"
175 UnicodeString("23.58"), // 16: JJmm
176 };
177
178 UnicodeString patternResults_es[] = {
179 // es // 4 es
180 UnicodeString("1/1999"), // 00: yM -> "M/y"
181 UnicodeString("ene. 1999"), // 01: yMMM -> "MMM y"
182 UnicodeString("13/1/1999"), // 02: yMd -> "d/M/y"
183 UnicodeString("13 ene. 1999"), // 03: yMMMd -> "d MMM y"
184 UnicodeString("13/1"), // 04: Md -> "d/M"
185 UnicodeString("13 ene."), // 05: MMMd -> "d 'de' MMM"
186 UnicodeString("13 de enero"), // 06: MMMMd -> "d 'de' MMMM"
187 UnicodeString("T1 1999"), // 07: yQQQ -> "QQQ y"
188 CharsToUnicodeString("11:58 p.\\u00A0m."), // 08: hhmm -> "hh:mm a"
189 UnicodeString("23:58"), // 09: HHmm -> "HH:mm"
190 UnicodeString("23:58"), // 10: jjmm -> "HH:mm"
191 UnicodeString("58:59"), // 11: mmss -> "mm:ss"
192 UnicodeString("enero de 1999"), // 12: yyyyMMMM -> "MMMM 'de' yyyy"
193 CharsToUnicodeString("mi\\u00E9., 13 ene."), // 13: MMMEd -> "E, d MMM"
194 CharsToUnicodeString("mi\\u00E9. 13"), // 14: Ed -> "EEE d"
195 UnicodeString("23:58:59,123"), // 15: jmmssSSS -> "H:mm:ss,SSS"
196 UnicodeString("23:58"), // 16: JJmm
197 };
198
199 UnicodeString patternResults_ja[] = {
200 // ja // 5 ja
201 UnicodeString("1999/1"), // 00: yM -> y/M
202 CharsToUnicodeString("1999\\u5E741\\u6708"), // 01: yMMM -> y\u5E74M\u6708
203 UnicodeString("1999/1/13"), // 02: yMd -> y/M/d
204 CharsToUnicodeString("1999\\u5E741\\u670813\\u65E5"), // 03: yMMMd -> y\u5E74M\u6708d\u65E5
205 UnicodeString("1/13"), // 04: Md -> M/d
206 CharsToUnicodeString("1\\u670813\\u65E5"), // 05: MMMd -> M\u6708d\u65E5
207 CharsToUnicodeString("1\\u670813\\u65E5"), // 06: MMMMd -> M\u6708d\u65E5
208 CharsToUnicodeString("1999/Q1"), // 07: yQQQ -> y/QQQ
209 CharsToUnicodeString("\\u5348\\u5F8C11:58"), // 08: hhmm
210 UnicodeString("23:58"), // 09: HHmm -> HH:mm
211 UnicodeString("23:58"), // 10: jjmm
212 UnicodeString("58:59"), // 11: mmss -> mm:ss
213 CharsToUnicodeString("1999\\u5E741\\u6708"), // 12: yyyyMMMM -> y\u5E74M\u6708
214 CharsToUnicodeString("1\\u670813\\u65E5(\\u6C34)"), // 13: MMMEd -> M\u6708d\u65E5(EEE)
215 CharsToUnicodeString("13\\u65E5(\\u6C34)"), // 14: Ed -> d\u65E5(EEE)
216 UnicodeString("23:58:59.123"), // 15: jmmssSSS -> "H:mm:ss.SSS"
217 UnicodeString("23:58"), // 16: JJmm
218 };
219
220 UnicodeString patternResults_ja_japanese[] = {
221 // ja@calendar=japanese // 6 ja@calendar=japanese
222 UnicodeString("H11/1"), // 00: yM -> GGGGGy/m
223 CharsToUnicodeString("\\u5E73\\u621011\\u5E741\\u6708"), // 01: yMMM -> Gy\u5E74M\u6708
224 UnicodeString("H11/1/13"), // 02: yMd -> GGGGGy/m/d
225 CharsToUnicodeString("\\u5E73\\u621011\\u5E741\\u670813\\u65E5"), // 03: yMMMd -> Gy\u5E74M\u6708d\u65E5
226 UnicodeString("1/13"), // 04: Md -> M/d
227 CharsToUnicodeString("1\\u670813\\u65E5"), // 05: MMMd -> M\u6708d\u65E5
228 CharsToUnicodeString("1\\u670813\\u65E5"), // 06: MMMMd -> M\u6708d\u65E5
229 CharsToUnicodeString("\\u5E73\\u621011/Q1"), // 07: yQQQ -> Gy/QQQ
230 CharsToUnicodeString("\\u5348\\u5F8C11:58"), // 08: hhmm ->
231 UnicodeString("23:58"), // 09: HHmm -> HH:mm (as for ja)
232 UnicodeString("23:58"), // 10: jjmm
233 UnicodeString("58:59"), // 11: mmss -> mm:ss (as for ja)
234 CharsToUnicodeString("\\u5E73\\u621011\\u5E741\\u6708"), // 12: yyyyMMMM -> Gyyyy\u5E74M\u6708
235 CharsToUnicodeString("1\\u670813\\u65E5(\\u6C34)"), // 13: MMMEd -> M\u6708d\u65E5(EEE)
236 CharsToUnicodeString("13\\u65E5(\\u6C34)"), // 14: Ed -> d\u65E5(EEE)
237 UnicodeString("23:58:59.123"), // 15: jmmssSSS -> "H:mm:ss.SSS"
238 UnicodeString("23:58"), // 16: JJmm
239 };
240
241 UnicodeString patternResults_zh_Hans_CN[] = {
242 // zh_Hans_CN // 7 zh_Hans_CN
243 CharsToUnicodeString("1999\\u5E741\\u6708"), // 00: yM -> y\u5E74M\u6708
244 CharsToUnicodeString("1999\\u5E741\\u6708"), // 01: yMMM -> yyyy\u5E74MMM (fixed expected result per ticket:6626:)
245 CharsToUnicodeString("1999/1/13"), // 02: yMd
246 CharsToUnicodeString("1999\\u5E741\\u670813\\u65E5"), // 03: yMMMd -> yyyy\u5E74MMMd\u65E5 (fixed expected result per ticket:6626:)
247 UnicodeString("1/13"), // 04: Md
248 CharsToUnicodeString("1\\u670813\\u65E5"), // 05: MMMd -> M\u6708d\u65E5 (fixed expected result per ticket:6626:)
249 CharsToUnicodeString("1\\u670813\\u65E5"), // 06: MMMMd -> M\u6708d\u65E5
250 CharsToUnicodeString("1999\\u5E74\\u7B2C1\\u5B63\\u5EA6"), // 07: yQQQ
251 CharsToUnicodeString("\\u4E0B\\u534811:58"), // 08: hhmm
252 UnicodeString("23:58"), // 09: HHmm
253 CharsToUnicodeString("\\u4E0B\\u534811:58"), // 10: jjmm
254 UnicodeString("58:59"), // 11: mmss
255 CharsToUnicodeString("1999\\u5E741\\u6708"), // 12: yyyyMMMM -> yyyy\u5E74MMM
256 CharsToUnicodeString("1\\u670813\\u65E5\\u5468\\u4E09"), // 13: MMMEd -> MMMd\u65E5EEE
257 CharsToUnicodeString("13\\u65E5\\u5468\\u4E09"), // 14: Ed -> d\u65E5EEE
258 CharsToUnicodeString("\\u4E0B\\u534811:58:59.123"), // 15: jmmssSSS -> "ah:mm:ss.SSS"
259 UnicodeString("11:58"), // 16: JJmm
260 };
261
262 UnicodeString patternResults_zh_TW_roc[] = {
263 // zh_TW@calendar=roc // 8 zh_TW@calendar=roc
264 CharsToUnicodeString("\\u6C11\\u570B88/1"), // 00: yM -> Gy/M
265 CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u6708"), // 01: yMMM -> Gy\u5E74M\u6708
266 CharsToUnicodeString("\\u6C11\\u570B88/1/13"), // 02: yMd -> Gy/M/d
267 CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u670813\\u65E5"), // 03: yMMMd -> Gy\u5E74M\u6708d\u65E5
268 UnicodeString("1/13"), // 04: Md -> M/d
269 CharsToUnicodeString("1\\u670813\\u65E5"), // 05: MMMd ->M\u6708d\u65E5
270 CharsToUnicodeString("1\\u670813\\u65E5"), // 06: MMMMd ->M\u6708d\u65E5
271 CharsToUnicodeString("\\u6C11\\u570B88\\u5E74\\u7B2C1\\u5B63"), // 07: yQQQ -> Gy QQQ
272 CharsToUnicodeString("\\u4E0B\\u534811:58"), // 08: hhmm ->
273 UnicodeString("23:58"), // 09: HHmm ->
274 CharsToUnicodeString("\\u4E0B\\u534811:58"), // 10: jjmm
275 UnicodeString("58:59"), // 11: mmss ->
276 CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u6708"), // 12: yyyyMMMM -> Gy\u5E74M\u670
277 CharsToUnicodeString("1\\u670813\\u65E5\\u9031\\u4E09"), // 13: MMMEd -> M\u6708d\u65E5EEE
278 CharsToUnicodeString("13 \\u9031\\u4E09"), // 14: Ed -> d E
279 CharsToUnicodeString("\\u4E0B\\u534811:58:59.123"), // 15: jmmssSSS -> "ah:mm:ss.SSS"
280 UnicodeString("11:58"), // 16: JJmm
281 };
282
283 UnicodeString patternResults_ru[] = {
284 // ru // 9 ru
285 UnicodeString("01.1999"), // 00: yM -> MM.y
286 CharsToUnicodeString("\\u044F\\u043D\\u0432. 1999 \\u0433."), // 01: yMMM -> LLL y
287 UnicodeString("13.01.1999"), // 02: yMd -> dd.MM.y
288 CharsToUnicodeString("13 \\u044F\\u043D\\u0432. 1999 \\u0433."), // 03: yMMMd -> d MMM y
289 UnicodeString("13.01"), // 04: Md -> dd.MM
290 CharsToUnicodeString("13 \\u044F\\u043D\\u0432."), // 05: MMMd -> d MMM
291 CharsToUnicodeString("13 \\u044F\\u043D\\u0432\\u0430\\u0440\\u044F"), // 06: MMMMd -> d MMMM
292 CharsToUnicodeString("1-\\u0439 \\u043A\\u0432. 1999 \\u0433."), // 07: yQQQ -> y QQQ
293 CharsToUnicodeString("11:58 PM"), // 08: hhmm -> hh:mm a
294 UnicodeString("23:58"), // 09: HHmm -> HH:mm
295 UnicodeString("23:58"), // 10: jjmm -> HH:mm
296 UnicodeString("58:59"), // 11: mmss -> mm:ss
297 CharsToUnicodeString("\\u044F\\u043D\\u0432\\u0430\\u0440\\u044C 1999 \\u0433."), // 12: yyyyMMMM -> LLLL y
298 CharsToUnicodeString("\\u0441\\u0440, 13 \\u044F\\u043D\\u0432."), // 13: MMMEd -> ccc, d MMM
299 CharsToUnicodeString("\\u0441\\u0440, 13"), // 14: Ed -> EEE, d
300 UnicodeString("23:58:59,123"), // 15: jmmssSSS -> "H:mm:ss,SSS"
301 UnicodeString("23:58"), // 16: JJmm
302 };
303
304 UnicodeString patternResults_zh_chinese[] = {
305 // zh@calendar=chinese // 10 zh@calendar=chinese
306 CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u5341\\u4E00\\u6708"), // 00: yMMM
307 CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u5341\\u4E00\\u6708"), // 01: yMMM
308 CharsToUnicodeString("1998\\u5E74\\u5341\\u4E00\\u670826"), // 02: yMMMd
309 CharsToUnicodeString("1998\\u5E74\\u5341\\u4E00\\u670826"), // 03: yMMMd
310 UnicodeString("11-26"), // 04: Md
311 CharsToUnicodeString("\\u5341\\u4E00\\u670826\\u65E5"), // 05: MMMd
312 CharsToUnicodeString("\\u5341\\u4E00\\u670826\\u65E5"), // 06: MMMMd
313 CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u7b2c\\u56db\\u5B63\\u5EA6"), // 07: yQQQ
314 CharsToUnicodeString("\\u4E0B\\u534811:58"), // 08: hhmm
315 UnicodeString("23:58"), // 09: HHmm
316 CharsToUnicodeString("\\u4E0B\\u534811:58"), // 10: jjmm
317 UnicodeString("58:59"), // 11: mmss
318 CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u5341\\u4E00\\u6708"), // 12: yyyyMMMM
319 CharsToUnicodeString("\\u5341\\u4E00\\u670826\\u65E5\\u5468\\u4E09"), // 13: MMMEd
320 CharsToUnicodeString("26\\u65E5\\u5468\\u4E09"), // 14: Ed -> d\u65E5EEE
321 CharsToUnicodeString("\\u4E0B\\u534811:58:59.123"), // 15: jmmssSS
322 UnicodeString("11:58"), // 16: JJmm
323 };
324
325 UnicodeString patternResults_ja_jp_traditional[] = {
326 // ja_JP_TRADITIONAL // 11 ja_JP_TRADITIONAL
327 u"AD1999/1", // 00: yM
328 u"西暦1999年1月", // 01: yMMM
329 u"1999年1月13日", // 02: yMd
330 u"西暦1999年1月13日", // 03: yMMMd
331 u"1/13", // 04: Md
332 u"1月13日", // 05: MMMd
333 u"1月13日", // 06: MMMMd
334 u"西暦1999/Q1", // 07: yQQQ
335 u"午後11:58", // 08: hhmm
336 u"23:58", // 09: HHmm
337 u"23:58", // 10: jjmm
338 u"58:59", // 11: mmss
339 u"西暦1999年1月", // 12: yyyyMMMM
340 u"1月13日(水)", // 13: MMMEd
341 u"13日(水)", // 14: Ed
342 u"23:58:59.123", // 15: jmmssSSS
343 u"23:58", // 16: JJmm
344 };
345
346 UnicodeString* patternResults[] = {
347 patternResults_en_US, // 0
348 patternResults_en_US_japanese, // 1
349 patternResults_de_DE, // 2
350 patternResults_fi, // 3
351 patternResults_es, // 4
352 patternResults_ja, // 5
353 patternResults_ja_japanese, // 6
354 patternResults_zh_Hans_CN, // 7
355 patternResults_zh_TW_roc, // 8
356 patternResults_ru, // 9
357 patternResults_zh_chinese, // 10
358 patternResults_ja_jp_traditional, // 11
359 };
360
361 UnicodeString patternTests2[] = {
362 UnicodeString("yyyyMMMdd"),
363 UnicodeString("yyyyqqqq"),
364 UnicodeString("yMMMdd"),
365 UnicodeString("EyyyyMMMdd"),
366 UnicodeString("yyyyMMdd"),
367 UnicodeString("yyyyMMM"),
368 UnicodeString("yyyyMM"),
369 UnicodeString("yyMM"),
370 UnicodeString("yMMMMMd"),
371 UnicodeString("EEEEEMMMMMd"),
372 UnicodeString("MMMd"),
373 UnicodeString("MMMdhmm"),
374 UnicodeString("EMMMdhmms"),
375 UnicodeString("MMdhmm"),
376 UnicodeString("EEEEMMMdhmms"),
377 UnicodeString("yyyyMMMddhhmmss"),
378 UnicodeString("EyyyyMMMddhhmmss"),
379 UnicodeString("hmm"),
380 UnicodeString("hhmm"),
381 UnicodeString("hhmmVVVV"),
382 UnicodeString(""),
383 };
384 UnicodeString patternResults2[] = {
385 UnicodeString("Oct 14, 1999"),
386 UnicodeString("4th quarter 1999"),
387 UnicodeString("Oct 14, 1999"),
388 UnicodeString("Thu, Oct 14, 1999"),
389 UnicodeString("10/14/1999"),
390 UnicodeString("Oct 1999"),
391 UnicodeString("10/1999"),
392 UnicodeString("10/99"),
393 UnicodeString("O 14, 1999"),
394 UnicodeString("T, O 14"),
395 UnicodeString("Oct 14"),
396 UnicodeString("Oct 14, 6:58 AM"),
397 UnicodeString("Thu, Oct 14, 6:58:59 AM"),
398 UnicodeString("10/14, 6:58 AM"),
399 UnicodeString("Thursday, Oct 14, 6:58:59 AM"),
400 UnicodeString("Oct 14, 1999, 6:58:59 AM"),
401 UnicodeString("Thu, Oct 14, 1999, 6:58:59 AM"),
402 UnicodeString("6:58 AM"),
403 UnicodeString("6:58 AM"),
404 UnicodeString("6:58 AM GMT"),
405 UnicodeString(""),
406 };
407
408 // results for getSkeletons() and getPatternForSkeleton()
409 const UnicodeString testSkeletonsResults[] = {
410 UnicodeString("HH:mm"),
411 UnicodeString("MMMMd"),
412 UnicodeString("MMMMMdd"),
413 };
414
415 const UnicodeString testBaseSkeletonsResults[] = {
416 UnicodeString("Hm"),
417 UnicodeString("MMMMd"),
418 UnicodeString("MMMMMd"),
419 };
420
421 const char* testGetSkeletonAndBase[][3] = {
422 // pattern skeleton baseSkeleton
423 { "dd-MMM", "MMMdd", "MMMd" },
424 { "dd/MMMM/yy", "yyMMMMdd", "yMMMMd" },
425 { "h", "h", "h" },
426 { "ah", "ah", "ah" },
427 { "aaaah", "aaaah", "aaaah" },
428 { "Bh", "Bh", "Bh" }
429 };
430
431 UnicodeString newDecimal(" "); // space
432 UnicodeString newAppendItemName("hrs.");
433 UnicodeString newAppendItemFormat("{1} {0}");
434 UnicodeString newDateTimeFormat("{1} {0}");
435 UErrorCode status = U_ZERO_ERROR;
436 UnicodeString conflictingPattern;
437 UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
438 (void)conflictingStatus; // Suppress set but not used warning.
439
440 // ======= Test CreateInstance with default locale
441 logln("Testing DateTimePatternGenerator createInstance from default locale");
442
443 DateTimePatternGenerator *instFromDefaultLocale=DateTimePatternGenerator::createInstance(status);
444 if (U_FAILURE(status)) {
445 dataerrln("ERROR: Could not create DateTimePatternGenerator (default) - exitting");
446 return;
447 }
448 else {
449 delete instFromDefaultLocale;
450 }
451
452 // ======= Test CreateInstance with given locale
453 logln("Testing DateTimePatternGenerator createInstance from French locale");
454 status = U_ZERO_ERROR;
455 DateTimePatternGenerator *instFromLocale=DateTimePatternGenerator::createInstance(Locale::getFrench(), status);
456 if (U_FAILURE(status)) {
457 dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getFrench()) - exitting");
458 return;
459 }
460
461 // ======= Test clone DateTimePatternGenerator
462 logln("Testing DateTimePatternGenerator::clone()");
463 status = U_ZERO_ERROR;
464
465
466 UnicodeString decimalSymbol = instFromLocale->getDecimal();
467 UnicodeString newDecimalSymbol = UnicodeString("*");
468 decimalSymbol = instFromLocale->getDecimal();
469 instFromLocale->setDecimal(newDecimalSymbol);
470 DateTimePatternGenerator *cloneDTPatternGen=instFromLocale->clone();
471 decimalSymbol = cloneDTPatternGen->getDecimal();
472 if (decimalSymbol != newDecimalSymbol) {
473 errln("ERROR: inconsistency is found in cloned object.");
474 }
475 if ( !(*cloneDTPatternGen == *instFromLocale) ) {
476 errln("ERROR: inconsistency is found in cloned object.");
477 }
478
479 if ( *cloneDTPatternGen != *instFromLocale ) {
480 errln("ERROR: inconsistency is found in cloned object.");
481 }
482
483 delete instFromLocale;
484 delete cloneDTPatternGen;
485
486 // ======= Test simple use cases
487 logln("Testing simple use cases");
488 status = U_ZERO_ERROR;
489 Locale deLocale=Locale::getGermany();
490 UDate sampleDate=LocaleTest::date(99, 9, 13, 23, 58, 59);
491 DateTimePatternGenerator *gen = DateTimePatternGenerator::createInstance(deLocale, status);
492 if (U_FAILURE(status)) {
493 dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getGermany()) - exitting");
494 return;
495 }
496 UnicodeString findPattern = gen->getBestPattern(UnicodeString("MMMddHmm"), status);
497 SimpleDateFormat *format = new SimpleDateFormat(findPattern, deLocale, status);
498 if (U_FAILURE(status)) {
499 dataerrln("ERROR: Could not create SimpleDateFormat (Locale::getGermany())");
500 delete gen;
501 return;
502 }
503 TimeZone *zone = TimeZone::createTimeZone(UnicodeString("ECT"));
504 if (zone==NULL) {
505 dataerrln("ERROR: Could not create TimeZone ECT");
506 delete gen;
507 delete format;
508 return;
509 }
510 format->setTimeZone(*zone);
511 UnicodeString dateReturned, expectedResult;
512 dateReturned.remove();
513 dateReturned = format->format(sampleDate, dateReturned, status);
514 expectedResult=UnicodeString("14. Okt., 08:58", -1, US_INV);
515 if ( dateReturned != expectedResult ) {
516 errln("ERROR: Simple test in getBestPattern with Locale::getGermany()).");
517 }
518 // add new pattern
519 status = U_ZERO_ERROR;
520 conflictingStatus = gen->addPattern(UnicodeString("d'. von' MMMM", -1, US_INV), true, conflictingPattern, status);
521 if (U_FAILURE(status)) {
522 errln("ERROR: Could not addPattern - d\'. von\' MMMM");
523 }
524 status = U_ZERO_ERROR;
525 UnicodeString testPattern=gen->getBestPattern(UnicodeString("MMMMdd"), status);
526 testPattern=gen->getBestPattern(UnicodeString("MMMddHmm"), status);
527 format->applyPattern(gen->getBestPattern(UnicodeString("MMMMdHmm"), status));
528 dateReturned.remove();
529 dateReturned = format->format(sampleDate, dateReturned, status);
530 expectedResult=UnicodeString("14. von Oktober, 08:58", -1, US_INV);
531 if ( dateReturned != expectedResult ) {
532 errln(UnicodeString("ERROR: Simple test addPattern failed!: d\'. von\' MMMM Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult);
533 }
534 delete format;
535
536 // get a pattern and modify it
537 format = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull,
538 deLocale);
539 format->setTimeZone(*zone);
540 UnicodeString pattern;
541 pattern = format->toPattern(pattern);
542 dateReturned.remove();
543 dateReturned = format->format(sampleDate, dateReturned, status);
544 expectedResult=CharsToUnicodeString("Donnerstag, 14. Oktober 1999 um 08:58:59 Mitteleurop\\u00E4ische Sommerzeit");
545 if ( dateReturned != expectedResult ) {
546 errln("ERROR: Simple test uses full date format.");
547 errln(UnicodeString(" Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult);
548 }
549
550 // modify it to change the zone.
551 UnicodeString newPattern = gen->replaceFieldTypes(pattern, UnicodeString("vvvv"), status);
552 format->applyPattern(newPattern);
553 dateReturned.remove();
554 dateReturned = format->format(sampleDate, dateReturned, status);
555 expectedResult=CharsToUnicodeString("Donnerstag, 14. Oktober 1999 um 08:58:59 Mitteleurop\\u00E4ische Zeit");
556 if ( dateReturned != expectedResult ) {
557 errln("ERROR: Simple test modify the timezone!");
558 errln(UnicodeString(" Got: ")+ dateReturned + UnicodeString(" Expected: ") + expectedResult);
559 }
560
561 // setDeciaml(), getDeciaml()
562 gen->setDecimal(newDecimal);
563 if (newDecimal != gen->getDecimal()) {
564 errln("ERROR: unexpected result from setDecimal() and getDecimal()!.\n");
565 }
566
567 // setAppenItemName() , getAppendItemName()
568 gen->setAppendItemName(UDATPG_HOUR_FIELD, newAppendItemName);
569 if (newAppendItemName != gen->getAppendItemName(UDATPG_HOUR_FIELD)) {
570 errln("ERROR: unexpected result from setAppendItemName() and getAppendItemName()!.\n");
571 }
572
573 // setAppenItemFormat() , getAppendItemFormat()
574 gen->setAppendItemFormat(UDATPG_HOUR_FIELD, newAppendItemFormat);
575 if (newAppendItemFormat != gen->getAppendItemFormat(UDATPG_HOUR_FIELD)) {
576 errln("ERROR: unexpected result from setAppendItemFormat() and getAppendItemFormat()!.\n");
577 }
578
579 // setDateTimeFormat() , getDateTimeFormat()
580 gen->setDateTimeFormat(newDateTimeFormat);
581 if (newDateTimeFormat != gen->getDateTimeFormat()) {
582 errln("ERROR: unexpected result from setDateTimeFormat() and getDateTimeFormat()!.\n");
583 }
584
585 // ======== Test getSkeleton and getBaseSkeleton
586
587 int32_t i, count = UPRV_LENGTHOF(testGetSkeletonAndBase);
588 for (i = 0; i < count; i++) {
589 status = U_ZERO_ERROR;
590 pattern = UnicodeString(testGetSkeletonAndBase[i][0]);
591 UnicodeString expectedSkeleton = UnicodeString(testGetSkeletonAndBase[i][1]);
592 UnicodeString expectedBaseSkeleton = UnicodeString(testGetSkeletonAndBase[i][2]);
593 UnicodeString retSkeleton = gen->getSkeleton(pattern, status);
594 if(U_FAILURE(status) || retSkeleton != expectedSkeleton ) {
595 errln("ERROR: Unexpected result from getSkeleton().\n");
596 errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected: ") + expectedSkeleton );
597 }
598 retSkeleton = gen->getBaseSkeleton(pattern, status);
599 if(U_FAILURE(status) || retSkeleton != expectedBaseSkeleton) {
600 errln("ERROR: Unexpected result from getBaseSkeleton().\n");
601 errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected:")+ expectedBaseSkeleton);
602 }
603 }
604
605 delete format;
606 delete zone;
607 delete gen;
608
609 {
610 // Trac# 6104
611 status = U_ZERO_ERROR;
612 pattern = UnicodeString("YYYYMMM");
613 UnicodeString expR = CharsToUnicodeString("1999\\u5E741\\u6708"); // fixed expected result per ticket:6626:
614 Locale loc("ja");
615 UDate testDate1= LocaleTest::date(99, 0, 13, 23, 58, 59);
616 DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
617 if(U_FAILURE(status)) {
618 dataerrln("ERROR: Could not create DateTimePatternGenerator");
619 return;
620 }
621 UnicodeString bPattern = patGen->getBestPattern(pattern, status);
622 UnicodeString rDate;
623 SimpleDateFormat sdf(bPattern, loc, status);
624 rDate.remove();
625 rDate = sdf.format(testDate1, rDate);
626
627 logln(UnicodeString(" ja locale with skeleton: YYYYMMM Best Pattern:") + bPattern);
628 logln(UnicodeString(" Formatted date:") + rDate);
629
630 if ( expR!= rDate ) {
631 errln(UnicodeString("\nERROR: Test Japanese month hack Got: ") + rDate +
632 UnicodeString(" Expected: ") + expR );
633 }
634
635 delete patGen;
636 }
637 { // Trac# 6104
638 Locale loc("zh");
639 UnicodeString expR = CharsToUnicodeString("1999\\u5E741\\u6708"); // fixed expected result per ticket:6626:
640 UDate testDate1= LocaleTest::date(99, 0, 13, 23, 58, 59);
641 DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
642 if(U_FAILURE(status)) {
643 dataerrln("ERROR: Could not create DateTimePatternGenerator");
644 return;
645 }
646 UnicodeString bPattern = patGen->getBestPattern(pattern, status);
647 UnicodeString rDate;
648 SimpleDateFormat sdf(bPattern, loc, status);
649 rDate.remove();
650 rDate = sdf.format(testDate1, rDate);
651
652 logln(UnicodeString(" zh locale with skeleton: YYYYMMM Best Pattern:") + bPattern);
653 logln(UnicodeString(" Formatted date:") + rDate);
654 if ( expR!= rDate ) {
655 errln(UnicodeString("\nERROR: Test Chinese month hack Got: ") + rDate +
656 UnicodeString(" Expected: ") + expR );
657 }
658 delete patGen;
659 }
660
661 {
662 // Trac# 6172 duplicate time pattern
663 status = U_ZERO_ERROR;
664 pattern = UnicodeString("hmv");
665 UnicodeString expR = UnicodeString("h:mm a v"); // avail formats has hm -> "h:mm a" (fixed expected result per ticket:6626:)
666 Locale loc("en");
667 DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
668 if(U_FAILURE(status)) {
669 dataerrln("ERROR: Could not create DateTimePatternGenerator");
670 return;
671 }
672 UnicodeString bPattern = patGen->getBestPattern(pattern, status);
673 logln(UnicodeString(" en locale with skeleton: hmv Best Pattern:") + bPattern);
674
675 if ( expR!= bPattern ) {
676 errln(UnicodeString("\nERROR: Test EN time format Got: ") + bPattern +
677 UnicodeString(" Expected: ") + expR );
678 }
679
680 delete patGen;
681 }
682
683
684 // ======= Test various skeletons.
685 logln("Testing DateTimePatternGenerator with various skeleton");
686
687 status = U_ZERO_ERROR;
688 int32_t localeIndex=0;
689 int32_t resultIndex=0;
690 UnicodeString resultDate;
691 UDate testDate= LocaleTest::date(99, 0, 13, 23, 58, 59) + 123.0;
692 while (localeIndex < MAX_LOCALE )
693 {
694 resultIndex=0;
695 int32_t dataIndex=0;
696 UnicodeString bestPattern;
697
698 Locale loc(testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2], testLocale[localeIndex][3]);
699 logln("\n\n Locale: %s_%s_%s@%s", testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2], testLocale[localeIndex][3]);
700 DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
701 if(U_FAILURE(status)) {
702 dataerrln("ERROR: Could not create DateTimePatternGenerator with locale index:%d . - exitting\n", localeIndex);
703 return;
704 }
705 while (patternData[dataIndex].length() > 0) {
706 log(patternData[dataIndex]);
707 bestPattern = patGen->getBestPattern(patternData[dataIndex++], status);
708 logln(UnicodeString(" -> ") + bestPattern);
709
710 SimpleDateFormat sdf(bestPattern, loc, status);
711 resultDate.remove();
712 resultDate = sdf.format(testDate, resultDate);
713 if ( resultDate != patternResults[localeIndex][resultIndex] ) {
714 auto* calendar = sdf.getCalendar();
715 errln(UnicodeString("\nERROR: Test various skeletons[") + (dataIndex-1) + UnicodeString("], localeIndex ") + localeIndex +
716 u". Got: \"" + resultDate +
717 u"\" with calendar " + calendar->getType() +
718 u" Expected: \"" + patternResults[localeIndex][resultIndex] + u"\"");
719 }
720
721 resultIndex++;
722 }
723 delete patGen;
724 localeIndex++;
725 }
726
727 // ======= More tests ticket#6110
728 logln("Testing DateTimePatternGenerator with various skeleton");
729
730 status = U_ZERO_ERROR;
731 localeIndex=0;
732 resultIndex=0;
733 testDate= LocaleTest::date(99, 9, 13, 23, 58, 59);
734 {
735 int32_t dataIndex=0;
736 UnicodeString bestPattern;
737 logln("\n\n Test various skeletons for English locale...");
738 DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(Locale::getEnglish(), status);
739 if(U_FAILURE(status)) {
740 dataerrln("ERROR: Could not create DateTimePatternGenerator with locale English . - exitting\n");
741 return;
742 }
743 TimeZone *enZone = TimeZone::createTimeZone(UnicodeString("ECT/GMT"));
744 if (enZone==NULL) {
745 dataerrln("ERROR: Could not create TimeZone ECT");
746 delete patGen;
747 return;
748 }
749 SimpleDateFormat *enFormat = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull,
750 DateFormat::kFull, Locale::getEnglish());
751 enFormat->setTimeZone(*enZone);
752 while (patternTests2[dataIndex].length() > 0) {
753 logln(patternTests2[dataIndex]);
754 bestPattern = patGen->getBestPattern(patternTests2[dataIndex], status);
755 logln(UnicodeString(" -> ") + bestPattern);
756 enFormat->applyPattern(bestPattern);
757 resultDate.remove();
758 resultDate = enFormat->format(testDate, resultDate);
759 if ( resultDate != patternResults2[resultIndex] ) {
760 errln(UnicodeString("\nERROR: Test various skeletons[") + dataIndex
761 + UnicodeString("]. Got: ") + resultDate + UnicodeString(" Expected: ") +
762 patternResults2[resultIndex] );
763 }
764 dataIndex++;
765 resultIndex++;
766 }
767 delete patGen;
768 delete enZone;
769 delete enFormat;
770 }
771
772
773
774 // ======= Test random skeleton
775 DateTimePatternGenerator *randDTGen= DateTimePatternGenerator::createInstance(status);
776 if (U_FAILURE(status)) {
777 dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getFrench()) - exitting");
778 return;
779 }
780 UChar newChar;
781 for (i=0; i<10; ++i) {
782 UnicodeString randomSkeleton;
783 int32_t len = rand() % 20;
784 for (int32_t j=0; j<len; ++j ) {
785 while ((newChar = (UChar)(rand()%0x7f))>=(UChar)0x20) {
786 randomSkeleton += newChar;
787 }
788 }
789 UnicodeString bestPattern = randDTGen->getBestPattern(randomSkeleton, status);
790 }
791 delete randDTGen;
792
793 // UnicodeString randomString=Unicode
794 // ======= Test getStaticClassID()
795
796 logln("Testing getStaticClassID()");
797 status = U_ZERO_ERROR;
798 DateTimePatternGenerator *test= DateTimePatternGenerator::createInstance(status);
799
800 if(test->getDynamicClassID() != DateTimePatternGenerator::getStaticClassID()) {
801 errln("ERROR: getDynamicClassID() didn't return the expected value");
802 }
803 delete test;
804
805 // ====== Test createEmptyInstance()
806
807 logln("Testing createEmptyInstance()");
808 status = U_ZERO_ERROR;
809
810 test = DateTimePatternGenerator::createEmptyInstance(status);
811 if(U_FAILURE(status)) {
812 errln("ERROR: Fail to create an empty instance ! - exitting.\n");
813 delete test;
814 return;
815 }
816
817 conflictingStatus = test->addPattern(UnicodeString("MMMMd"), true, conflictingPattern, status);
818 status = U_ZERO_ERROR;
819 testPattern=test->getBestPattern(UnicodeString("MMMMdd"), status);
820 conflictingStatus = test->addPattern(UnicodeString("HH:mm"), true, conflictingPattern, status);
821 conflictingStatus = test->addPattern(UnicodeString("MMMMMdd"), true, conflictingPattern, status); //duplicate pattern
822 StringEnumeration *output=NULL;
823 output = test->getRedundants(status);
824 expectedResult=UnicodeString("MMMMd");
825 if (output != NULL) {
826 output->reset(status);
827 const UnicodeString *dupPattern=output->snext(status);
828 if ( (dupPattern==NULL) || (*dupPattern != expectedResult) ) {
829 errln("ERROR: Fail in getRedundants !\n");
830 }
831 }
832
833 // ======== Test getSkeletons and getBaseSkeletons
834 StringEnumeration* ptrSkeletonEnum = test->getSkeletons(status);
835 if(U_FAILURE(status)) {
836 errln("ERROR: Fail to get skeletons !\n");
837 }
838 UnicodeString returnPattern, *ptrSkeleton;
839 ptrSkeletonEnum->reset(status);
840 count=ptrSkeletonEnum->count(status);
841 for (i=0; i<count; ++i) {
842 ptrSkeleton = (UnicodeString *)ptrSkeletonEnum->snext(status);
843 returnPattern = test->getPatternForSkeleton(*ptrSkeleton);
844 if ( returnPattern != testSkeletonsResults[i] ) {
845 errln(UnicodeString("ERROR: Unexpected result from getSkeletons and getPatternForSkeleton\nGot: ") + returnPattern
846 + UnicodeString("\nExpected: ") + testSkeletonsResults[i]
847 + UnicodeString("\n"));
848 }
849 }
850 StringEnumeration* ptrBaseSkeletonEnum = test->getBaseSkeletons(status);
851 if(U_FAILURE(status)) {
852 errln("ERROR: Fail to get base skeletons !\n");
853 }
854 count=ptrBaseSkeletonEnum->count(status);
855 for (i=0; i<count; ++i) {
856 ptrSkeleton = (UnicodeString *)ptrBaseSkeletonEnum->snext(status);
857 if ( *ptrSkeleton != testBaseSkeletonsResults[i] ) {
858 errln("ERROR: Unexpected result from getBaseSkeletons() !\n");
859 }
860 }
861
862 // ========= DateTimePatternGenerator sample code in Userguide
863 // set up the generator
864 Locale locale = Locale::getFrench();
865 status = U_ZERO_ERROR;
866 DateTimePatternGenerator *generator = DateTimePatternGenerator::createInstance( locale, status);
867
868 // get a pattern for an abbreviated month and day
869 pattern = generator->getBestPattern(UnicodeString("MMMd"), status);
870 SimpleDateFormat formatter(pattern, locale, status);
871
872 zone = TimeZone::createTimeZone(UnicodeString("GMT"));
873 formatter.setTimeZone(*zone);
874 // use it to format (or parse)
875 UnicodeString formatted;
876 formatted = formatter.format(Calendar::getNow(), formatted, status);
877 // for French, the result is "13 sept."
878 formatted.remove();
879 // cannot use the result from getNow() because the value change evreyday.
880 testDate= LocaleTest::date(99, 0, 13, 23, 58, 59);
881 formatted = formatter.format(testDate, formatted, status);
882 expectedResult=UnicodeString("14 janv.");
883 if ( formatted != expectedResult ) {
884 errln("ERROR: Userguide sample code result!");
885 errln(UnicodeString(" Got: ")+ formatted + UnicodeString(" Expected: ") + expectedResult);
886 }
887
888 delete zone;
889 delete output;
890 delete ptrSkeletonEnum;
891 delete ptrBaseSkeletonEnum;
892 delete test;
893 delete generator;
894 }
895
896 /**
897 * Test handling of options
898 *
899 * For reference, as of ICU 4.3.3,
900 * root/gregorian has
901 * Hm{"H:mm"}
902 * Hms{"H:mm:ss"}
903 * hm{"h:mm a"}
904 * hms{"h:mm:ss a"}
905 * en/gregorian has
906 * Hm{"H:mm"}
907 * Hms{"H:mm:ss"}
908 * hm{"h:mm a"}
909 * be/gregorian has
910 * HHmmss{"HH.mm.ss"}
911 * Hm{"HH.mm"}
912 * hm{"h.mm a"}
913 * hms{"h.mm.ss a"}
914 */
915 typedef struct DTPtnGenOptionsData {
916 const char *locale;
917 const char *skel;
918 const char *expectedPattern;
919 UDateTimePatternMatchOptions options;
920 } DTPtnGenOptionsData;
testOptions()921 void IntlTestDateTimePatternGeneratorAPI::testOptions(/*char *par*/)
922 {
923 DTPtnGenOptionsData testData[] = {
924 // locale skel expectedPattern options
925 { "en", "Hmm", "HH:mm", UDATPG_MATCH_NO_OPTIONS },
926 { "en", "HHmm", "HH:mm", UDATPG_MATCH_NO_OPTIONS },
927 { "en", "hhmm", "h:mm a", UDATPG_MATCH_NO_OPTIONS },
928 { "en", "Hmm", "HH:mm", UDATPG_MATCH_HOUR_FIELD_LENGTH },
929 { "en", "HHmm", "HH:mm", UDATPG_MATCH_HOUR_FIELD_LENGTH },
930 { "en", "hhmm", "hh:mm a", UDATPG_MATCH_HOUR_FIELD_LENGTH },
931 { "da", "Hmm", "HH.mm", UDATPG_MATCH_NO_OPTIONS },
932 { "da", "HHmm", "HH.mm", UDATPG_MATCH_NO_OPTIONS },
933 { "da", "hhmm", "h.mm a", UDATPG_MATCH_NO_OPTIONS },
934 { "da", "Hmm", "H.mm", UDATPG_MATCH_HOUR_FIELD_LENGTH },
935 { "da", "HHmm", "HH.mm", UDATPG_MATCH_HOUR_FIELD_LENGTH },
936 { "da", "hhmm", "hh.mm a", UDATPG_MATCH_HOUR_FIELD_LENGTH },
937 //
938 { "en", "yyyy", "yyyy", UDATPG_MATCH_NO_OPTIONS },
939 { "en", "YYYY", "YYYY", UDATPG_MATCH_NO_OPTIONS },
940 { "en", "U", "y", UDATPG_MATCH_NO_OPTIONS },
941 { "en@calendar=japanese", "yyyy", "y G", UDATPG_MATCH_NO_OPTIONS },
942 { "en@calendar=japanese", "YYYY", "Y G", UDATPG_MATCH_NO_OPTIONS },
943 { "en@calendar=japanese", "U", "y G", UDATPG_MATCH_NO_OPTIONS },
944 { "en@calendar=chinese", "yyyy", "r(U)", UDATPG_MATCH_NO_OPTIONS },
945 { "en@calendar=chinese", "YYYY", "Y(Y)", UDATPG_MATCH_NO_OPTIONS }, // not a good result, want r(Y) or r(U)
946 { "en@calendar=chinese", "U", "r(U)", UDATPG_MATCH_NO_OPTIONS },
947 { "en@calendar=chinese", "Gy", "r(U)", UDATPG_MATCH_NO_OPTIONS },
948 { "en@calendar=chinese", "GU", "r(U)", UDATPG_MATCH_NO_OPTIONS },
949 { "en@calendar=chinese", "ULLL", "MMM U", UDATPG_MATCH_NO_OPTIONS },
950 { "en@calendar=chinese", "yMMM", "MMM r(U)", UDATPG_MATCH_NO_OPTIONS },
951 { "en@calendar=chinese", "GUMMM", "MMM r(U)", UDATPG_MATCH_NO_OPTIONS },
952 { "zh@calendar=chinese", "yyyy", "rU\\u5E74", UDATPG_MATCH_NO_OPTIONS },
953 { "zh@calendar=chinese", "YYYY", "YY\\u5E74", UDATPG_MATCH_NO_OPTIONS }, // not a good result, may want r(Y) or r(U)
954 { "zh@calendar=chinese", "U", "rU\\u5E74", UDATPG_MATCH_NO_OPTIONS },
955 { "zh@calendar=chinese", "Gy", "rU\\u5E74", UDATPG_MATCH_NO_OPTIONS },
956 { "zh@calendar=chinese", "GU", "rU\\u5E74", UDATPG_MATCH_NO_OPTIONS },
957 { "zh@calendar=chinese", "ULLL", "U\\u5E74MMM", UDATPG_MATCH_NO_OPTIONS },
958 { "zh@calendar=chinese", "yMMM", "rU\\u5E74MMM", UDATPG_MATCH_NO_OPTIONS },
959 { "zh@calendar=chinese", "GUMMM", "rU\\u5E74MMM", UDATPG_MATCH_NO_OPTIONS },
960 };
961
962 int count = UPRV_LENGTHOF(testData);
963 const DTPtnGenOptionsData * testDataPtr = testData;
964
965 for (; count-- > 0; ++testDataPtr) {
966 UErrorCode status = U_ZERO_ERROR;
967
968 Locale locale(testDataPtr->locale);
969 UnicodeString skel(testDataPtr->skel);
970 UnicodeString expectedPattern(UnicodeString(testDataPtr->expectedPattern).unescape());
971 UDateTimePatternMatchOptions options = testDataPtr->options;
972
973 DateTimePatternGenerator * dtpgen = DateTimePatternGenerator::createInstance(locale, status);
974 if (U_FAILURE(status)) {
975 dataerrln("Unable to create DateTimePatternGenerator instance for locale(%s): %s", locale.getName(), u_errorName(status));
976 delete dtpgen;
977 continue;
978 }
979 UnicodeString pattern = dtpgen->getBestPattern(skel, options, status);
980 if (pattern.compare(expectedPattern) != 0) {
981 errln( UnicodeString("ERROR in getBestPattern, locale ") + UnicodeString(testDataPtr->locale) +
982 UnicodeString(", skeleton ") + skel +
983 ((options)?UnicodeString(", options!=0"):UnicodeString(", options==0")) +
984 UnicodeString(", expected pattern ") + expectedPattern +
985 UnicodeString(", got ") + pattern );
986 }
987 delete dtpgen;
988 }
989 }
990
991 /**
992 * Test that DTPG can handle all valid pattern character / length combinations
993 *
994 */
995 #define FIELD_LENGTHS_COUNT 6
996 #define FIELD_LENGTH_MAX 8
997 #define MUST_INCLUDE_COUNT 5
998
999 typedef struct AllFieldsTestItem {
1000 char patternChar;
1001 int8_t fieldLengths[FIELD_LENGTHS_COUNT+1]; // up to FIELD_LENGTHS_COUNT lengths to try
1002 // (length <=FIELD_LENGTH_MAX) plus 0 terminator
1003 char mustIncludeOneOf[MUST_INCLUDE_COUNT+1];// resulting pattern must include at least one of
1004 // these as a pattern char (0-terminated list)
1005 } AllFieldsTestItem;
1006
testAllFieldPatterns()1007 void IntlTestDateTimePatternGeneratorAPI::testAllFieldPatterns(/*char *par*/)
1008 {
1009 const char * localeNames[] = {
1010 "root",
1011 "root@calendar=japanese",
1012 "root@calendar=chinese",
1013 "en",
1014 "en@calendar=japanese",
1015 "en@calendar=chinese",
1016 NULL // terminator
1017 };
1018 AllFieldsTestItem testData[] = {
1019 //pat fieldLengths generated pattern must
1020 //chr to test include one of these
1021 { 'G', {1,2,3,4,5,0}, "G" }, // era
1022 // year
1023 { 'y', {1,2,3,4,0}, "yU" }, // year
1024 { 'Y', {1,2,3,4,0}, "Y" }, // year for week of year
1025 { 'u', {1,2,3,4,5,0}, "yuU" }, // extended year
1026 { 'U', {1,2,3,4,5,0}, "yU" }, // cyclic year name
1027 // quarter
1028 { 'Q', {1,2,3,4,0}, "Qq" }, // x
1029 { 'q', {1,2,3,4,0}, "Qq" }, // standalone
1030 // month
1031 { 'M', {1,2,3,4,5,0}, "ML" }, // x
1032 { 'L', {1,2,3,4,5,0}, "ML" }, // standalone
1033 // week
1034 { 'w', {1,2,0}, "w" }, // week of year
1035 { 'W', {1,0}, "W" }, // week of month
1036 // day
1037 { 'd', {1,2,0}, "d" }, // day of month
1038 { 'D', {1,2,3,0}, "D" }, // day of year
1039 { 'F', {1,0}, "F" }, // day of week in month
1040 { 'g', {7,0}, "g" }, // modified julian day
1041 // weekday
1042 { 'E', {1,2,3,4,5,6}, "Eec" }, // day of week
1043 { 'e', {1,2,3,4,5,6}, "Eec" }, // local day of week
1044 { 'c', {1,2,3,4,5,6}, "Eec" }, // standalone local day of week
1045 // day period
1046 { 'a', {1,2,3,4,5,0}, "a" }, // am or pm
1047 { 'b', {1,2,3,4,5,0}, "b" }, // dayPeriod AM/PM/noon
1048 { 'B', {1,2,3,4,5,0}, "B" }, // dayPeriod ranges
1049 // hour
1050 { 'h', {1,2,0}, "hK" }, // 12 (1-12)
1051 { 'H', {1,2,0}, "Hk" }, // 24 (0-23)
1052 { 'K', {1,2,0}, "hK" }, // 12 (0-11)
1053 { 'k', {1,2,0}, "Hk" }, // 24 (1-24)
1054 { 'j', {1,2,0}, "hHKk" }, // locale default
1055 { 'J', {1,2,0}, "hHKk" }, // locale default, without any dayPeriod
1056 { 'C', {1,2,0}, "hHKk" }, // locale allowed first entry, possibly with b or B
1057 // minute
1058 { 'm', {1,2,0}, "m" }, // x
1059 // second & fractions
1060 { 's', {1,2,0}, "s" }, // x
1061 { 'S', {1,2,3,4,0}, "S" }, // fractional second
1062 { 'A', {8,0}, "A" }, // milliseconds in day
1063 // zone
1064 { 'z', {1,2,3,4,0}, "z" }, // x
1065 { 'Z', {1,2,3,4,5,0}, "Z" }, // x
1066 { 'O', {1,4,0}, "O" }, // x
1067 { 'v', {1,4,0}, "v" }, // x
1068 { 'V', {1,2,3,4,0}, "V" }, // x
1069 { 'X', {1,2,3,4,5,0}, "X" }, // x
1070 { 'x', {1,2,3,4,5,0}, "x" }, // x
1071 };
1072
1073 const char ** localeNamesPtr = localeNames;
1074 const char * localeName;
1075 while ( (localeName = *localeNamesPtr++) != NULL) {
1076 UErrorCode status = U_ZERO_ERROR;
1077 Locale locale = Locale::createFromName(localeName);
1078 DateTimePatternGenerator * dtpg = DateTimePatternGenerator::createInstance(locale, status);
1079 if (U_SUCCESS(status)) {
1080 const AllFieldsTestItem * testDataPtr = testData;
1081 int itemCount = UPRV_LENGTHOF(testData);
1082 for (; itemCount-- > 0; ++testDataPtr) {
1083 char skelBuf[FIELD_LENGTH_MAX];
1084 int32_t chrIndx, lenIndx;
1085 for (chrIndx = 0; chrIndx < FIELD_LENGTH_MAX; chrIndx++) {
1086 skelBuf[chrIndx] = testDataPtr->patternChar;
1087 }
1088 for (lenIndx = 0; lenIndx < FIELD_LENGTHS_COUNT; lenIndx++) {
1089 int32_t skelLen = testDataPtr->fieldLengths[lenIndx];
1090 if (skelLen <= 0) {
1091 break;
1092 }
1093 if (skelLen > FIELD_LENGTH_MAX) {
1094 continue;
1095 }
1096 UnicodeString skeleton(skelBuf, skelLen, US_INV);
1097 UnicodeString pattern = dtpg->getBestPattern(skeleton, status);
1098 if (U_FAILURE(status)) {
1099 errln("DateTimePatternGenerator getBestPattern for locale %s, skelChar %c skelLength %d fails: %s",
1100 locale.getName(), testDataPtr->patternChar, skelLen, u_errorName(status));
1101 } else if (pattern.length() <= 0) {
1102 errln("DateTimePatternGenerator getBestPattern for locale %s, skelChar %c skelLength %d produces 0-length pattern",
1103 locale.getName(), testDataPtr->patternChar, skelLen);
1104 } else {
1105 // test that resulting pattern has at least one char in mustIncludeOneOf
1106 UnicodeString mustIncludeOneOf(testDataPtr->mustIncludeOneOf, -1, US_INV);
1107 int32_t patIndx, patLen = pattern.length();
1108 UBool inQuoted = FALSE;
1109 for (patIndx = 0; patIndx < patLen; patIndx++) {
1110 UChar c = pattern.charAt(patIndx);
1111 if (c == 0x27) {
1112 inQuoted = !inQuoted;
1113 } else if (!inQuoted && c <= 0x007A && c >= 0x0041) {
1114 if (mustIncludeOneOf.indexOf(c) >= 0) {
1115 break;
1116 }
1117 }
1118 }
1119 if (patIndx >= patLen) {
1120 errln(UnicodeString("DateTimePatternGenerator getBestPattern for locale ") +
1121 UnicodeString(locale.getName(),-1,US_INV) +
1122 ", skeleton " + skeleton +
1123 ", produces pattern without required chars: " + pattern);
1124 }
1125
1126 }
1127 }
1128 }
1129 delete dtpg;
1130 } else {
1131 dataerrln("Create DateTimePatternGenerator instance for locale(%s) fails: %s",
1132 locale.getName(), u_errorName(status));
1133 }
1134 }
1135 }
1136
testStaticGetSkeleton()1137 void IntlTestDateTimePatternGeneratorAPI::testStaticGetSkeleton(/*char *par*/)
1138 {
1139 // Verify that staticGetSkeleton() doesn't mangle skeletons. (Ticket #11985)
1140 static const char* const testData[] = {
1141 "jmm",
1142 "jjmm",
1143 "Jmm",
1144 "JJmm"
1145 };
1146
1147 for (size_t i = 0; i < UPRV_LENGTHOF(testData); i++) {
1148 UErrorCode status = U_ZERO_ERROR;
1149 UnicodeString skeleton = DateTimePatternGenerator::staticGetSkeleton(testData[i], status);
1150 if (!assertSuccess("staticGetSkeleton", status)) {
1151 return;
1152 }
1153 assertEquals("Skeleton", testData[i], skeleton);
1154 }
1155 }
1156
testC()1157 void IntlTestDateTimePatternGeneratorAPI::testC() {
1158 const char* tests[][3] = {
1159 // These may change with actual data for Bhmm/bhmm skeletons
1160 {"zh", "Cm", "Bh:mm"},
1161 {"zh", "CCm", "Bhh:mm"},
1162 {"zh", "CCCm", "BBBBh:mm"},
1163 {"zh", "CCCCm", "BBBBhh:mm"},
1164 {"zh", "CCCCCm", "BBBBBh:mm"},
1165 {"zh", "CCCCCCm", "BBBBBhh:mm"},
1166 {"de", "Cm", "HH:mm"},
1167 {"de", "CCm", "HH:mm"},
1168 {"de", "CCCm", "HH:mm"},
1169 {"de", "CCCCm", "HH:mm"},
1170 {"en", "Cm", "h:mm a"},
1171 {"en", "CCm", "hh:mm a"},
1172 {"en", "CCCm", "h:mm aaaa"},
1173 {"en", "CCCCm", "hh:mm aaaa"},
1174 {"en", "CCCCCm", "h:mm aaaaa"},
1175 {"en", "CCCCCCm", "hh:mm aaaaa"},
1176 {"en-BN", "Cm", "h:mm b"},
1177 {"gu-IN", "Cm", "h:mm B"},
1178 {"und-IN", "Cm", "h:mm B"}
1179 };
1180
1181 UErrorCode status = U_ZERO_ERROR;
1182 int32_t numTests = UPRV_LENGTHOF(tests);
1183 for (int32_t i = 0; i < numTests; ++i) {
1184 DateTimePatternGenerator *gen = DateTimePatternGenerator::createInstance(
1185 Locale::forLanguageTag(tests[i][0], status), status);
1186 if (gen == NULL) {
1187 dataerrln("FAIL: DateTimePatternGenerator::createInstance failed for %s", tests[i][0]);
1188 return;
1189 }
1190 UDateTimePatternMatchOptions options = UDATPG_MATCH_HOUR_FIELD_LENGTH;
1191 UnicodeString pattern = gen->getBestPattern(tests[i][1], options, status);
1192 UnicodeString expectedPattern = tests[i][2];
1193
1194 char message[100] = "\0";
1195 strcat(message, tests[i][0]);
1196 strcat(message, "/");
1197 strcat(message, tests[i][1]);
1198 assertEquals(message, expectedPattern, pattern);
1199 delete gen;
1200 }
1201 }
1202
1203 enum { kCharBufMax = 31 };
testSkeletonsWithDayPeriods()1204 void IntlTestDateTimePatternGeneratorAPI::testSkeletonsWithDayPeriods() {
1205 const char * patterns[] = {
1206 // since icu4c getEmptyInstance does not call addCanonicalItems (unlike J), set these here:
1207 "a", // should get internal skeleton a
1208 "H", // should get internalskeleton H
1209 "m", // should get internalskeleton m
1210 "s", // should get internalskeleton s
1211 // patterns from which to construct sample data for a locale
1212 //"H", // should get internalskeleton H
1213 "h a", // should get internalskeleton ah
1214 "B h", // should get internalskeleton Bh
1215 };
1216 const char* testItems[][2] = {
1217 // sample requested skeletons and results
1218 // skel pattern
1219 { "H", "H"},
1220 { "HH", "HH"},
1221 { "aH", "H"},
1222 { "aHH", "HH"},
1223 { "BH", "H"},
1224 { "BHH", "HH"},
1225 { "BBBBH", "H"},
1226 { "h", "h a"},
1227 { "hh", "hh a"},
1228 { "ah", "h a"},
1229 { "ahh", "hh a"},
1230 { "aaaah", "h aaaa"},
1231 { "aaaahh", "hh aaaa"},
1232 { "bh", "h b"},
1233 { "bhh", "hh b"},
1234 { "bbbbh", "h bbbb"},
1235 { "Bh", "B h"},
1236 { "Bhh", "B hh"},
1237 { "BBBBh", "BBBB h"},
1238 { "BBBBhh", "BBBB hh"},
1239 { "a", "a"},
1240 { "aaaaa", "aaaaa"},
1241 { "b", "b"},
1242 { "bbbb", "bbbb"},
1243 { "B", "B"},
1244 { "BBBB", "BBBB"},
1245 };
1246 UErrorCode status = U_ZERO_ERROR;
1247 DateTimePatternGenerator *gen = DateTimePatternGenerator::createEmptyInstance(status);
1248 if (U_FAILURE(status)) {
1249 errln("ERROR: createEmptyInstance fails, status: %s", u_errorName(status));
1250 } else {
1251 int32_t i, len = UPRV_LENGTHOF(patterns);
1252 for (i = 0; i < len; i++) {
1253 UnicodeString conflictingPattern;
1254 (void)gen->addPattern(UnicodeString(patterns[i]), TRUE, conflictingPattern, status);
1255 if (U_FAILURE(status)) {
1256 errln("ERROR: addPattern %s fail, status: %s", patterns[i], u_errorName(status));
1257 break;
1258 }
1259 }
1260 if (U_SUCCESS(status)) {
1261 len = UPRV_LENGTHOF(testItems);
1262 for (i = 0; i < len; i++) {
1263 status = U_ZERO_ERROR;
1264 UDateTimePatternMatchOptions options = UDATPG_MATCH_HOUR_FIELD_LENGTH;
1265 UnicodeString result = gen->getBestPattern(UnicodeString(testItems[i][0]), options, status);
1266 if (U_FAILURE(status)) {
1267 errln("ERROR: getBestPattern %s fail, status: %s", testItems[i][0], u_errorName(status));
1268 } else if (result != UnicodeString(testItems[i][1])) {
1269 char charResult[kCharBufMax+1];
1270 result.extract(0, result.length(), charResult, kCharBufMax);
1271 charResult[kCharBufMax] = 0; // ensure termination
1272 errln("ERROR: getBestPattern %s, expected %s, got %s", testItems[i][0], testItems[i][1], charResult);
1273 }
1274 }
1275 }
1276 }
1277 delete gen;
1278 }
1279
1280 typedef struct FieldDisplayNameData {
1281 const char * locale;
1282 UDateTimePatternField field;
1283 UDateTimePGDisplayWidth width;
1284 const char * expected; // can have escapes such as \\u00E0
1285 } FieldDisplayNameData;
1286 enum { kFieldDisplayNameMax = 32 };
1287
testGetFieldDisplayNames()1288 void IntlTestDateTimePatternGeneratorAPI::testGetFieldDisplayNames() {
1289 const FieldDisplayNameData testData[] = {
1290 /*loc field width expectedName */
1291 { "de", UDATPG_QUARTER_FIELD, UDATPG_WIDE, "Quartal" },
1292 { "de", UDATPG_QUARTER_FIELD, UDATPG_ABBREVIATED, "Quart." },
1293 { "de", UDATPG_QUARTER_FIELD, UDATPG_NARROW, "Q" },
1294 { "en", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_WIDE, "weekday of the month" },
1295 { "en", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_ABBREVIATED, "wkday. of mo." },
1296 { "en", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_NARROW, "wkday. of mo." }, // fallback
1297 { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_WIDE, "weekday of the month" },
1298 { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_ABBREVIATED, "wkday of mo" }, // override
1299 { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_NARROW, "wkday of mo" },
1300 { "it", UDATPG_SECOND_FIELD, UDATPG_WIDE, "secondo" },
1301 { "it", UDATPG_SECOND_FIELD, UDATPG_ABBREVIATED, "s" },
1302 { "it", UDATPG_SECOND_FIELD, UDATPG_NARROW, "s" },
1303 };
1304
1305 int count = UPRV_LENGTHOF(testData);
1306 const FieldDisplayNameData * testDataPtr = testData;
1307 for (; count-- > 0; ++testDataPtr) {
1308 UErrorCode status = U_ZERO_ERROR;
1309 Locale locale(testDataPtr->locale);
1310 DateTimePatternGenerator * dtpg = DateTimePatternGenerator::createInstance(locale, status);
1311 if (U_FAILURE(status)) {
1312 dataerrln("FAIL: DateTimePatternGenerator::createInstance failed for locale %s", testDataPtr->locale);
1313 } else {
1314 UChar expName[kFieldDisplayNameMax+1];
1315 u_unescape(testDataPtr->expected, expName, kFieldDisplayNameMax);
1316 expName[kFieldDisplayNameMax] = 0; // ensure 0 termination
1317 UnicodeString getName = dtpg->getFieldDisplayName(testDataPtr->field, testDataPtr->width);
1318 if (getName.compare(expName, u_strlen(expName)) != 0) {
1319 errln("ERROR: locale %s field %d width %d, expected %s\n",
1320 testDataPtr->locale, testDataPtr->field, testDataPtr->width, testDataPtr->expected);
1321 }
1322 delete dtpg;
1323 }
1324 }
1325 }
1326
1327 static const UChar timeCycleChars[] = { (UChar)0x0048, (UChar)0x0068, (UChar)0x004B, (UChar)0x006B, (UChar)0 };
1328
testJjMapping()1329 void IntlTestDateTimePatternGeneratorAPI::testJjMapping() {
1330 // Android patch: b/145129186 Disable failing tests
1331 #ifndef ANDROID
1332 UErrorCode status = U_ZERO_ERROR;
1333 UnicodeString jSkeleton("j");
1334 // First test that j maps correctly by region in a locale for which we do not have data.
1335 {
1336 const char* testLocaleID = "de_US"; // short patterns from fallback locale "de" have "HH"
1337 Locale testLocale(testLocaleID);
1338 LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(testLocale, status));
1339 if (U_FAILURE(status)) {
1340 dataerrln("FAIL: DateTimePatternGenerator::createInstance failed for locale %s: %s", testLocaleID, u_errorName(status));
1341 } else {
1342 UnicodeString jPattern = dtpg->getBestPattern(jSkeleton, UDATPG_MATCH_ALL_FIELDS_LENGTH, status); // get pattern with h e.g. "h 'Uhr' a"
1343 if (U_FAILURE(status)) {
1344 errln("FAIL: DateTimePatternGenerator::getBestPattern locale %s, pattern j: %s", testLocaleID, u_errorName(status));
1345 } else {
1346 UnicodeString jPatSkeleton = DateTimePatternGenerator::staticGetSkeleton(jPattern, status); // strip literals, get e.g. "ah"
1347 if (U_FAILURE(status)) {
1348 errln("FAIL: DateTimePatternGenerator::staticGetSkeleton locale %s: %s", testLocaleID, u_errorName(status));
1349 } else if (jPatSkeleton.indexOf(u'h') < 0) { // expect US preferred cycle 'h', not H or other cycle
1350 errln("ERROR: DateTimePatternGenerator::getBestPattern locale %s, pattern j did not use 'h'", testLocaleID);
1351 }
1352 }
1353 }
1354 }
1355
1356 // Next test that in all available Locales, the actual short time pattern uses the same cycle as produced by 'j'
1357 int32_t locCount;
1358 const Locale* localePtr = DateFormat::getAvailableLocales(locCount);
1359 for (; locCount-- > 0; localePtr++) {
1360 const char* localeID = localePtr->getName();
1361 status = U_ZERO_ERROR;
1362 LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(*localePtr, status));
1363 if (U_FAILURE(status)) {
1364 dataerrln("FAIL: DateTimePatternGenerator::createInstance failed for locale %s: %s", localeID, u_errorName(status));
1365 continue;
1366 }
1367 LocalPointer<DateFormat> dfmt(DateFormat::createTimeInstance(DateFormat::kShort, *localePtr));
1368 if (U_FAILURE(status)) {
1369 dataerrln("FAIL: DateFormat::createTimeInstance kShort failed for locale %s: %s", localeID, u_errorName(status));
1370 continue;
1371 }
1372 const SimpleDateFormat* sdfmt;
1373 if ((sdfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(dfmt.getAlias()))) == NULL) {
1374 continue;
1375 }
1376 UnicodeString shortPattern;
1377 shortPattern = sdfmt->toPattern(shortPattern);
1378 UnicodeString jPattern = dtpg->getBestPattern(jSkeleton, status);
1379 if (U_FAILURE(status)) {
1380 errln("FAIL: DateTimePatternGenerator::getBestPattern locale %s, pattern j: %s", localeID, u_errorName(status));
1381 continue;
1382 }
1383 // Now check that shortPattern and jPattern use the same hour cycle
1384 UnicodeString jPatSkeleton = DateTimePatternGenerator::staticGetSkeleton(jPattern, status);
1385 UnicodeString shortPatSkeleton = DateTimePatternGenerator::staticGetSkeleton(shortPattern, status);
1386 if (U_FAILURE(status)) {
1387 errln("FAIL: DateTimePatternGenerator::staticGetSkeleton locale %s: %s", localeID, u_errorName(status));
1388 continue;
1389 }
1390 const UChar* charPtr = timeCycleChars;
1391 for (; *charPtr != (UChar)0; charPtr++) {
1392 if (jPatSkeleton.indexOf(*charPtr) >= 0) {
1393 if (shortPatSkeleton.indexOf(*charPtr) < 0) {
1394 char jcBuf[2], spBuf[32], jpBuf[32];
1395 u_austrncpy(jcBuf, charPtr, 1);
1396 jcBuf[1] = 0;
1397 shortPattern.extract(0, shortPattern.length(), spBuf, 32);
1398 jPattern.extract(0, jPattern.length(), jpBuf, 32);
1399 const char* dfmtCalType = (dfmt->getCalendar())->getType();
1400 errln("ERROR: locale %s, expected j resolved char %s to occur in short time pattern '%s' for %s (best pattern: '%s')", localeID, jcBuf, spBuf, dfmtCalType, jpBuf);
1401 }
1402 break;
1403 }
1404 }
1405 }
1406 #endif /* ANDROID */
1407 }
1408
test20640_HourCyclArsEnNH()1409 void IntlTestDateTimePatternGeneratorAPI::test20640_HourCyclArsEnNH() {
1410 IcuTestErrorCode status(*this, "test20640_HourCyclArsEnNH");
1411
1412 const struct TestCase {
1413 const char* localeName;
1414 const char16_t* expectedDtpgPattern;
1415 const char16_t* expectedTimePattern;
1416 } cases[] = {
1417 // ars is interesting because it does not have a region, but it aliases
1418 // to ar_SA, which has a region.
1419 {"ars", u"h a", u"h:mm a"},
1420 // en_NH is interesting because NH is a deprecated region code;
1421 // formerly New Hebrides, now Vanuatu => VU => h.
1422 {"en_NH", u"h a", u"h:mm a"},
1423 // ch_ZH is a typo (should be zh_CN), but we should fail gracefully.
1424 // {"cn_ZH", u"HH", u"H:mm"}, // TODO(ICU-20653): Desired behavior
1425 {"cn_ZH", u"HH", u"h:mm a"}, // Actual behavior
1426 // a non-BCP47 locale without a country code should not fail
1427 {"ja_TRADITIONAL", u"H時", u"H:mm"},
1428 };
1429
1430 for (auto& cas : cases) {
1431 status.setScope(cas.localeName);
1432
1433 Locale loc(cas.localeName);
1434 LocalPointer<DateFormat> dtf(DateFormat::createTimeInstance(DateFormat::kShort, loc), status);
1435 LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(loc, status));
1436 if (status.errIfFailureAndReset()) {
1437 return;
1438 }
1439
1440 UnicodeString timePattern;
1441 dynamic_cast<SimpleDateFormat*>(dtf.getAlias())->toPattern(timePattern);
1442 UnicodeString dtpgPattern = dtpg->getBestPattern(u"j", status);
1443 if (status.errIfFailureAndReset()) {
1444 return;
1445 }
1446
1447 assertEquals(UnicodeString("dtpgPattern ") + cas.localeName,
1448 cas.expectedDtpgPattern, dtpgPattern);
1449 assertEquals(UnicodeString("timePattern ") + cas.localeName,
1450 cas.expectedTimePattern, timePattern);
1451 }
1452
1453 }
1454
testFallbackWithDefaultRootLocale()1455 void IntlTestDateTimePatternGeneratorAPI::testFallbackWithDefaultRootLocale() {
1456 UErrorCode status = U_ZERO_ERROR;
1457 char original[ULOC_FULLNAME_CAPACITY];
1458
1459 uprv_strcpy(original, uloc_getDefault());
1460 uloc_setDefault("root", &status);
1461 if (U_FAILURE(status)) {
1462 errln("ERROR: Failed to change the default locale to root! Default is: %s\n", uloc_getDefault());
1463 }
1464
1465 DateTimePatternGenerator* dtpg = icu::DateTimePatternGenerator::createInstance("abcdedf", status);
1466
1467 if (U_FAILURE(status)) {
1468 errln("ERROR: expected createInstance with invalid locale to succeed. Status: %s", u_errorName(status));
1469 }
1470 if (status != U_USING_DEFAULT_WARNING) {
1471 errln("ERROR: expected createInstance to return U_USING_DEFAULT_WARNING for invalid locale and default root locale. Status: %s", u_errorName(status));
1472 }
1473
1474 delete dtpg;
1475
1476 uloc_setDefault(original, &status);
1477 if (U_FAILURE(status)) {
1478 errln("ERROR: Failed to change the default locale back to %s\n", original);
1479 }
1480 }
1481
1482 #endif /* #if !UCONFIG_NO_FORMATTING */
1483