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