2 *******************************************************************************
3 * Copyright (C) 2006-2013, Google, International Business Machines Corporation *
4 * and others. All Rights Reserved. *
5 *******************************************************************************
8 package com.ibm.icu.dev.test.format;
10 import java.text.ParsePosition;
11 import java.util.Collection;
12 import java.util.Date;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.LinkedHashMap;
16 import java.util.LinkedHashSet;
17 import java.util.List;
19 import java.util.Random;
22 import com.ibm.icu.dev.test.TestFmwk;
23 import com.ibm.icu.impl.PatternTokenizer;
24 import com.ibm.icu.impl.Utility;
25 import com.ibm.icu.text.DateFormat;
26 import com.ibm.icu.text.DateTimePatternGenerator;
27 import com.ibm.icu.text.DateTimePatternGenerator.FormatParser;
28 import com.ibm.icu.text.DateTimePatternGenerator.VariableField;
29 import com.ibm.icu.text.SimpleDateFormat;
30 import com.ibm.icu.text.UTF16;
31 import com.ibm.icu.text.UnicodeSet;
32 import com.ibm.icu.util.Calendar;
33 import com.ibm.icu.util.GregorianCalendar;
34 import com.ibm.icu.util.SimpleTimeZone;
35 import com.ibm.icu.util.TimeZone;
36 import com.ibm.icu.util.ULocale;
38 public class DateTimeGeneratorTest extends TestFmwk {
39 public static boolean GENERATE_TEST_DATA;
42 GENERATE_TEST_DATA = System.getProperty("GENERATE_TEST_DATA") != null;
43 } catch (SecurityException e) {
44 GENERATE_TEST_DATA = false;
47 public static int RANDOM_COUNT = 1000;
48 public static boolean DEBUG = false;
50 public static void main(String[] args) throws Exception {
51 new DateTimeGeneratorTest().run(args);
54 public void TestSimple() {
55 // some simple use cases
56 ULocale locale = ULocale.GERMANY;
57 TimeZone zone = TimeZone.getTimeZone("Europe/Paris");
60 DateTimePatternGenerator gen = DateTimePatternGenerator.getInstance(locale);
61 SimpleDateFormat format = new SimpleDateFormat(gen.getBestPattern("MMMddHmm"), locale);
62 format.setTimeZone(zone);
63 assertEquals("simple format: MMMddHmm", "14. Okt. 08:58", format.format(sampleDate)); // (fixed expected result per ticket 6872<-7180)
64 // (a generator can be built from scratch, but that is not a typical use case)
66 // modify the generator by adding patterns
67 DateTimePatternGenerator.PatternInfo returnInfo = new DateTimePatternGenerator.PatternInfo();
68 gen.addPattern("d'. von' MMMM", true, returnInfo);
69 // the returnInfo is mostly useful for debugging problem cases
70 format.applyPattern(gen.getBestPattern("MMMMdHmm"));
71 assertEquals("modified format: MMMdHmm", "14. von Oktober 08:58", format.format(sampleDate)); // (fixed expected result per ticket 6872<-7180)
73 // get a pattern and modify it
74 format = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, locale);
75 format.setTimeZone(zone);
76 String pattern = format.toPattern();
77 assertEquals("full-date", "Donnerstag, 14. Oktober 1999 08:58:59 Mitteleurop\u00E4ische Sommerzeit", format.format(sampleDate));
79 // modify it to change the zone.
80 String newPattern = gen.replaceFieldTypes(pattern, "vvvv");
81 format.applyPattern(newPattern);
82 assertEquals("full-date: modified zone", "Donnerstag, 14. Oktober 1999 08:58:59 Mitteleurop\u00E4ische Zeit", format.format(sampleDate));
84 // add test of basic cases
86 //lang YYYYMMM MMMd MMMdhmm hmm hhmm Full Date-Time
87 // en Mar 2007 Mar 4 6:05 PM Mar 4 6:05 PM 06:05 PM Sunday, March 4, 2007 6:05:05 PM PT
88 DateTimePatternGenerator enGen = DateTimePatternGenerator.getInstance(ULocale.ENGLISH);
89 TimeZone enZone = TimeZone.getTimeZone("Etc/GMT");
90 SimpleDateFormat enFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, ULocale.ENGLISH);
91 enFormat.setTimeZone(enZone);
93 {"yyyyMMMdd", "Oct 14, 1999"},
94 {"yyyyqqqq", "4th quarter 1999"},
95 {"yMMMdd", "Oct 14, 1999"},
96 {"EyyyyMMMdd", "Thu, Oct 14, 1999"},
97 {"yyyyMMdd", "10/14/1999"},
98 {"yyyyMMM", "Oct 1999"},
99 {"yyyyMM", "10/1999"},
101 {"yMMMMMd", "O 14, 1999"}, // narrow format
102 {"EEEEEMMMMMd", "T, O 14"}, // narrow format
104 {"MMMdhmm", "Oct 14, 6:58 AM"},
105 {"EMMMdhmms", "Thu, Oct 14, 6:58:59 AM"},
106 {"MMdhmm", "10/14, 6:58 AM"},
107 {"EEEEMMMdhmms", "Thursday, Oct 14, 6:58:59 AM"},
108 {"yyyyMMMddhhmmss", "Oct 14, 1999, 6:58:59 AM"}, // (fixed expected result per ticket 6872<-7180)
109 {"EyyyyMMMddhhmmss", "Thu, Oct 14, 1999, 6:58:59 AM"}, // (fixed expected result per ticket 6872<-7180)
111 {"hhmm", "6:58 AM"}, // (fixed expected result per ticket 6872<-7180)
112 {"hhmmVVVV", "6:58 AM GMT"}, // (fixed expected result per ticket 6872<-7180)
114 for (int i = 0; i < tests.length; ++i) {
115 final String testSkeleton = tests[i][0];
116 String pat = enGen.getBestPattern(testSkeleton);
117 enFormat.applyPattern(pat);
118 String formattedDate = enFormat.format(sampleDate);
119 assertEquals("Testing skeleton '" + testSkeleton + "' with " + sampleDate, tests[i][1], formattedDate);
123 public void TestRoot() {
124 DateTimePatternGenerator rootGen = DateTimePatternGenerator.getInstance(ULocale.ROOT);
125 SimpleDateFormat rootFormat = new SimpleDateFormat(rootGen.getBestPattern("yMdHms"), ULocale.ROOT);
126 rootFormat.setTimeZone(gmt);
127 // *** expected result should be "1999-10-14 6:58:59" with current data, changed test temporarily to match current result, needs investigation
128 assertEquals("root format: yMdHms", "1999-10-14 06:58:59", rootFormat.format(sampleDate));
131 public void TestEmpty() {
133 DateTimePatternGenerator nullGen = DateTimePatternGenerator.getEmptyInstance();
134 SimpleDateFormat format = new SimpleDateFormat(nullGen.getBestPattern("yMdHms"), ULocale.ROOT);
135 TimeZone rootZone = TimeZone.getTimeZone("Etc/GMT");
136 format.setTimeZone(rootZone);
139 public void TestPatternParser() {
140 StringBuffer buffer = new StringBuffer();
141 PatternTokenizer pp = new PatternTokenizer()
142 .setIgnorableCharacters(new UnicodeSet("[-]"))
143 .setSyntaxCharacters(new UnicodeSet("[a-zA-Z]"))
144 .setEscapeCharacters(new UnicodeSet("[b#]"))
145 .setUsingQuote(true);
146 logln("Using Quote");
147 for (int i = 0; i < patternTestData.length; ++i) {
148 String patternTest = (String) patternTestData[i];
149 CheckPattern(buffer, pp, patternTest);
151 String[] randomSet = {"abcdef", "$12!@#-", "'\\"};
152 for (int i = 0; i < RANDOM_COUNT; ++i) {
153 String patternTest = getRandomString(randomSet, 0, 10);
154 CheckPattern(buffer, pp, patternTest);
156 logln("Using Backslash");
157 pp.setUsingQuote(false).setUsingSlash(true);
158 for (int i = 0; i < patternTestData.length; ++i) {
159 String patternTest = (String) patternTestData[i];
160 CheckPattern(buffer, pp, patternTest);
162 for (int i = 0; i < RANDOM_COUNT; ++i) {
163 String patternTest = getRandomString(randomSet, 0, 10);
164 CheckPattern(buffer, pp, patternTest);
168 Random random = new java.util.Random(-1);
170 private String getRandomString(String[] randomList, int minLen, int maxLen) {
171 StringBuffer result = new StringBuffer();
172 int len = random.nextInt(maxLen + 1 - minLen) + minLen;
173 for (int i = minLen; i < len; ++ i) {
174 String source = randomList[random.nextInt(randomList.length)]; // don't bother with surrogates
175 char ch = source.charAt(random.nextInt(source.length()));
176 UTF16.append(result, ch);
178 return result.toString();
181 private void CheckPattern(StringBuffer buffer, PatternTokenizer pp, String patternTest) {
182 pp.setPattern(patternTest);
183 if (DEBUG && isVerbose()) {
184 showItems(buffer, pp, patternTest);
186 String normalized = pp.setStart(0).normalize();
187 logln("input:\t<" + patternTest + ">" + "\tnormalized:\t<" + normalized + ">");
188 String doubleNormalized = pp.setPattern(normalized).normalize();
189 if (!normalized.equals(doubleNormalized)) {
190 errln("Normalization not idempotent:\t" + patternTest + "\tnormalized: " + normalized + "\tnormalized2: " + doubleNormalized);
191 // allow for debugging at the point of failure
193 pp.setPattern(patternTest);
194 normalized = pp.setStart(0).normalize();
195 pp.setPattern(normalized);
196 showItems(buffer, pp, normalized);
197 doubleNormalized = pp.normalize();
202 private void showItems(StringBuffer buffer, PatternTokenizer pp, String patternTest) {
203 logln("input:\t<" + patternTest + ">");
206 int status = pp.next(buffer);
207 if (status == PatternTokenizer.DONE) break;
209 if (status != PatternTokenizer.SYNTAX ) {
210 lit = "\t<" + pp.quoteLiteral(buffer) + ">";
212 logln("\t" + statusName[status] + "\t<" + buffer + ">" + lit);
216 static final String[] statusName = {"DONE", "SYNTAX", "LITERAL", "BROKEN_QUOTE", "BROKEN_ESCAPE", "UNKNOWN"};
218 public void TestBasic() {
219 ULocale uLocale = null;
220 DateTimePatternGenerator dtfg = null;
222 for (int i = 0; i < dateTestData.length; ++i) {
223 if (dateTestData[i] instanceof ULocale) {
224 uLocale = (ULocale) dateTestData[i];
225 dtfg = DateTimePatternGenerator.getInstance(uLocale);
226 if (GENERATE_TEST_DATA) logln("new ULocale(\"" + uLocale.toString() + "\"),");
227 } else if (dateTestData[i] instanceof Date) {
228 date = (Date) dateTestData[i];
229 if (GENERATE_TEST_DATA) logln("new Date(" + date.getTime()+ "L),");
230 } else if (dateTestData[i] instanceof String) {
231 String testSkeleton = (String) dateTestData[i];
232 String pattern = dtfg.getBestPattern(testSkeleton);
233 SimpleDateFormat sdf = new SimpleDateFormat(pattern, uLocale);
234 String formatted = sdf.format(date);
235 if (GENERATE_TEST_DATA) logln("new String[] {\"" + testSkeleton + "\", \"" + Utility.escape(formatted) + "\"},");
236 //logln(uLocale + "\t" + testSkeleton + "\t" + pattern + "\t" + sdf.format(date));
238 String[] testPair = (String[]) dateTestData[i];
239 String testSkeleton = testPair[0];
240 String testFormatted = testPair[1];
241 String pattern = dtfg.getBestPattern(testSkeleton);
242 SimpleDateFormat sdf = new SimpleDateFormat(pattern, uLocale);
243 String formatted = sdf.format(date);
244 if (GENERATE_TEST_DATA) {
245 logln("new String[] {\"" + testSkeleton + "\", \"" + Utility.escape(formatted) + "\"},");
246 } else if (!formatted.equals(testFormatted)) {
247 errln(uLocale + "\tformatted string doesn't match test case: " + testSkeleton + "\t generated: " + pattern + "\t expected: " + testFormatted + "\t got: " + formatted);
249 pattern = dtfg.getBestPattern(testSkeleton);
250 sdf = new SimpleDateFormat(pattern, uLocale);
251 formatted = sdf.format(date);
254 //logln(uLocale + "\t" + testSkeleton + "\t" + pattern + "\t" + sdf.format(date));
259 static final Object[] patternTestData = {
268 // can be generated by using GENERATE_TEST_DATA. Must be reviewed before adding
269 static final Object[] dateTestData = {
270 new Date(916300739123L), // 1999-01-13T23:58:59.123,0-0800
272 new ULocale("en_US"),
273 new String[] {"yM", "1/1999"},
274 new String[] {"yMMM", "Jan 1999"},
275 new String[] {"yMd", "1/13/1999"},
276 new String[] {"yMMMd", "Jan 13, 1999"},
277 new String[] {"Md", "1/13"},
278 new String[] {"MMMd", "Jan 13"},
279 new String[] {"MMMMd", "January 13"},
280 new String[] {"yQQQ", "Q1 1999"},
281 new String[] {"hhmm", "11:58 PM"},
282 new String[] {"HHmm", "23:58"},
283 new String[] {"jjmm", "11:58 PM"},
284 new String[] {"mmss", "58:59"},
285 new String[] {"yyyyMMMM", "January 1999"}, // (new item for testing 6872<-5702)
286 new String[] {"MMMEd", "Wed, Jan 13"},
287 new String[] {"Ed", "13 Wed"},
288 new String[] {"jmmssSSS", "11:58:59.123 PM"},
289 new String[] {"JJmm", "11:58"},
291 new ULocale("en_US@calendar=japanese"), // (new locale for testing ticket 6872<-5702)
292 new String[] {"yM", "1/11 H"},
293 new String[] {"yMMM", "Jan 11 Heisei"},
294 new String[] {"yMd", "1/13/11 H"},
295 new String[] {"yMMMd", "Jan 13, 11 Heisei"},
296 new String[] {"Md", "1/13"},
297 new String[] {"MMMd", "Jan 13"},
298 new String[] {"MMMMd", "January 13"},
299 new String[] {"yQQQ", "Q1 11 Heisei"},
300 new String[] {"hhmm", "11:58 PM"},
301 new String[] {"HHmm", "23:58"},
302 new String[] {"jjmm", "11:58 PM"},
303 new String[] {"mmss", "58:59"},
304 new String[] {"yyyyMMMM", "January 11 Heisei"},
305 new String[] {"MMMEd", "Wed, Jan 13"},
306 new String[] {"Ed", "13 Wed"},
307 new String[] {"jmmssSSS", "11:58:59.123 PM"},
308 new String[] {"JJmm", "11:58"},
310 new ULocale("de_DE"),
311 new String[] {"yM", "1.1999"},
312 new String[] {"yMMM", "Jan. 1999"},
313 new String[] {"yMd", "13.1.1999"},
314 new String[] {"yMMMd", "13. Jan. 1999"},
315 new String[] {"Md", "13.1."}, // 13.1
316 new String[] {"MMMd", "13. Jan."},
317 new String[] {"MMMMd", "13. Januar"},
318 new String[] {"yQQQ", "Q1 1999"},
319 new String[] {"hhmm", "11:58 nachm."},
320 new String[] {"HHmm", "23:58"},
321 new String[] {"jjmm", "23:58"},
322 new String[] {"mmss", "58:59"},
323 new String[] {"yyyyMMMM", "Januar 1999"}, // (new item for testing 6872<-5702)
324 new String[] {"MMMEd", "Mi., 13. Jan."},
325 new String[] {"Ed", "Mi., 13."},
326 new String[] {"jmmssSSS", "23:58:59,123"},
327 new String[] {"JJmm", "23:58"},
330 new String[] {"yM", "1.1999"}, // (fixed expected result per ticket 6872<-6626)
331 new String[] {"yMMM", "tammi 1999"}, // (fixed expected result per ticket 6872<-7007)
332 new String[] {"yMd", "13.1.1999"},
333 new String[] {"yMMMd", "13. tammikuuta 1999"},
334 new String[] {"Md", "13.1."},
335 new String[] {"MMMd", "13. tammikuuta"},
336 new String[] {"MMMMd", "13. tammikuuta"},
337 new String[] {"yQQQ", "1. nelj. 1999"},
338 new String[] {"hhmm", "11.58 ip."},
339 new String[] {"HHmm", "23.58"},
340 new String[] {"jjmm", "23.58"},
341 new String[] {"mmss", "58.59"},
342 new String[] {"yyyyMMMM", "tammikuu 1999"}, // (new item for testing 6872<-5702,7007)
343 new String[] {"MMMEd", "ke 13. tammikuuta"},
344 new String[] {"Ed", "ke 13."},
345 new String[] {"jmmssSSS", "23.58.59,123"},
346 new String[] {"JJmm", "23.58"},
349 new String[] {"yM", "1/1999"},
350 new String[] {"yMMM", "ene. de 1999"},
351 new String[] {"yMd", "13/1/1999"},
352 new String[] {"yMMMd", "13 de ene. de 1999"},
353 new String[] {"Md", "13/1"},
354 new String[] {"MMMd", "13 de ene."},
355 new String[] {"MMMMd", "13 de enero"},
356 new String[] {"yQQQ", "T1 1999"},
357 new String[] {"hhmm", "11:58 p. m."},
358 new String[] {"HHmm", "23:58"},
359 new String[] {"jjmm", "23:58"},
360 new String[] {"mmss", "58:59"},
361 new String[] {"yyyyMMMM", "enero de 1999"},
362 new String[] {"MMMEd", "mi\u00E9. 13 de ene."},
363 new String[] {"Ed", "mi\u00E9. 13"},
364 new String[] {"jmmssSSS", "23:58:59,123"},
365 new String[] {"JJmm", "23:58"},
367 new ULocale("ja"), // (new locale for testing ticket 6872<-6626)
368 new String[] {"yM", "1999/1"},
369 new String[] {"yMMM", "1999\u5E741\u6708"},
370 new String[] {"yMd", "1999/1/13"},
371 new String[] {"yMMMd", "1999\u5E741\u670813\u65E5"},
372 new String[] {"Md", "1/13"},
373 new String[] {"MMMd", "1\u670813\u65E5"},
374 new String[] {"MMMMd", "1\u670813\u65E5"},
375 new String[] {"yQQQ", "1999/Q1"},
376 new String[] {"hhmm", "\u5348\u5F8C11:58"},
377 new String[] {"HHmm", "23:58"},
378 new String[] {"jjmm", "23:58"},
379 new String[] {"mmss", "58:59"},
380 new String[] {"yyyyMMMM", "1999\u5E741\u6708"}, // (new item for testing 6872<-5702)
381 new String[] {"MMMEd", "1\u670813\u65E5(\u6C34)"},
382 new String[] {"Ed", "13\u65E5(\u6C34)"},
383 new String[] {"jmmssSSS", "23:58:59.123"},
384 new String[] {"JJmm", "23:58"},
386 new ULocale("ja@calendar=japanese"), // (new locale for testing ticket 6872<-5702)
387 new String[] {"yM", "\u5E73\u621011/1"},
388 new String[] {"yMMM", "\u5E73\u621011\u5E741\u6708"},
389 new String[] {"yMd", "\u5E73\u621011/1/13"},
390 new String[] {"yMMMd", "\u5E73\u621011\u5E741\u670813\u65E5"},
391 new String[] {"Md", "1/13"},
392 new String[] {"MMMd", "1\u670813\u65E5"},
393 new String[] {"MMMMd", "1\u670813\u65E5"},
394 new String[] {"yQQQ", "\u5E73\u6210 11 Q1"},
395 new String[] {"hhmm", "\u5348\u5F8C11:58"},
396 new String[] {"HHmm", "23:58"},
397 new String[] {"jjmm", "23:58"},
398 new String[] {"mmss", "58:59"},
399 new String[] {"yyyyMMMM", "\u5E73\u621011\u5E741\u6708"},
400 new String[] {"MMMEd", "1\u670813\u65E5(\u6C34)"},
401 new String[] {"Ed", "13\u65E5(\u6C34)"},
402 new String[] {"jmmssSSS", "23:58:59.123"},
403 new String[] {"JJmm", "23:58"},
405 new ULocale("zh_Hans_CN"),
406 new String[] {"yM", "1999/1"},
407 new String[] {"yMMM", "1999\u5E741\u6708"}, // (fixed expected result per ticket 6872<-6626)
408 new String[] {"yMd", "1999/1/13"},
409 new String[] {"yMMMd", "1999\u5E741\u670813\u65E5"}, // (fixed expected result per ticket 6872<-6626)
410 new String[] {"Md", "1/13"},
411 new String[] {"MMMd", "1\u670813\u65E5"}, // (fixed expected result per ticket 6872<-6626)
412 new String[] {"MMMMd", "1\u670813\u65E5"},
413 new String[] {"yQQQ", "1999\u5E74\u7B2C1\u5B63\u5EA6"},
414 new String[] {"hhmm", "\u4E0B\u534811:58"},
415 new String[] {"HHmm", "23:58"},
416 new String[] {"jjmm", "\u4E0B\u534811:58"},
417 new String[] {"mmss", "58:59"},
418 new String[] {"yyyyMMMM", "1999\u5E741\u6708"}, // (new item for testing 6872<-5702)
419 new String[] {"MMMEd", "1\u670813\u65E5\u5468\u4E09"},
420 new String[] {"Ed", "13\u65E5\u5468\u4E09"},
421 new String[] {"jmmssSSS", "\u4E0B\u534811:58:59.123"},
422 new String[] {"JJmm", "11:58"},
424 new ULocale("zh_TW@calendar=roc"), // (new locale for testing ticket 6872<-5702)
425 new String[] {"yM", "\u6C11\u570B88/1"},
426 new String[] {"yMMM", "\u6C11\u570B88\u5E741\u6708"},
427 new String[] {"yMd", "\u6C11\u570B88/1/13"},
428 new String[] {"yMMMd", "\u6C11\u570B88\u5E741\u670813\u65E5"},
429 new String[] {"Md", "1/13"},
430 new String[] {"MMMd", "1\u670813\u65E5"},
431 new String[] {"MMMMd", "1\u670813\u65E5"},
432 new String[] {"yQQQ", "\u6C11\u570B88\u5E741\u5B63"},
433 new String[] {"hhmm", "\u4E0B\u534811:58"},
434 new String[] {"HHmm", "23:58"},
435 new String[] {"jjmm", "\u4E0B\u534811:58"},
436 new String[] {"mmss", "58:59"},
437 new String[] {"yyyyMMMM", "\u6C11\u570B88\u5E741\u6708"},
438 new String[] {"MMMEd", "1\u670813\u65E5\u9031\u4E09"},
439 new String[] {"Ed", "13\u65E5\uFF08\u9031\u4E09\uFF09"},
440 new String[] {"jmmssSSS", "\u4E0B\u534811:58:59.123"},
441 new String[] {"JJmm", "11:58"},
444 new String[] {"yM", "01.1999"},
445 new String[] {"yMMM", "\u042F\u043D\u0432. 1999"},
446 new String[] {"yMd", "13.01.1999"},
447 new String[] {"yMMMd", "13 \u044F\u043D\u0432. 1999 \u0433."},
448 new String[] {"Md", "13.01"},
449 new String[] {"MMMd", "13 \u044F\u043D\u0432."},
450 new String[] {"MMMMd", "13 \u044F\u043D\u0432\u0430\u0440\u044F"},
451 new String[] {"yQQQ", "1-\u0439 \u043A\u0432. 1999 \u0433."},
452 new String[] {"hhmm", "11:58 \u043F\u043E\u0441\u043B\u0435 \u043F\u043E\u043B\u0443\u0434\u043D\u044F"},
453 new String[] {"HHmm", "23:58"},
454 new String[] {"jjmm", "23:58"},
455 new String[] {"mmss", "58:59"},
456 new String[] {"yyyyMMMM", "\u042F\u043D\u0432\u0430\u0440\u044C 1999"},
457 new String[] {"MMMEd", "\u0421\u0440, 13 \u044F\u043D\u0432."},
458 new String[] {"Ed", "\u0421\u0440, 13"},
459 new String[] {"jmmssSSS", "23:58:59,123"},
460 new String[] {"JJmm", "23:58"},
462 new ULocale("zh@calendar=chinese"),
463 new String[] {"yM", "\u620A\u5BC5\u5E7411\u6708"},
464 new String[] {"yMMM", "\u620A\u5BC5\u5E74\u5341\u4E00\u6708"},
465 new String[] {"yMd", "\u620A\u5BC5\u5E7411\u670826\u65E5"},
466 new String[] {"yMMMd", "\u620A\u5BC5\u5E74\u5341\u4E00\u670826\u65E5"},
467 new String[] {"Md", "11-26"},
468 new String[] {"MMMd", "\u5341\u4E00\u670826\u65E5"},
469 new String[] {"MMMMd", "\u5341\u4E00\u670826\u65E5"},
470 new String[] {"yQQQ", "\u620A\u5BC5\u5E74\u7B2C\u56DB\u5B63\u5EA6"},
471 new String[] {"hhmm", "\u4E0B\u534811:58"},
472 new String[] {"HHmm", "23:58"},
473 new String[] {"jjmm", "\u4E0B\u534811:58"},
474 new String[] {"mmss", "58:59"},
475 new String[] {"yyyyMMMM", "\u620A\u5BC5\u5E74\u5341\u4E00\u6708"},
476 new String[] {"MMMEd", "\u5341\u4E00\u670826\u65E5\u5468\u4E09"},
477 new String[] {"Ed", "26\u65E5\u5468\u4E09"},
478 new String[] {"jmmssSSS", "\u4E0B\u534811:58:59.123"},
479 new String[] {"JJmm", "11:58"},
482 public void DayMonthTest() {
483 final ULocale locale = ULocale.FRANCE;
485 // set up the generator
486 DateTimePatternGenerator dtpgen
487 = DateTimePatternGenerator.getInstance(locale);
489 // get a pattern for an abbreviated month and day
490 final String pattern = dtpgen.getBestPattern("MMMd");
491 SimpleDateFormat formatter = new SimpleDateFormat(pattern, locale);
493 // use it to format (or parse)
494 String formatted = formatter.format(new Date());
495 logln("formatted=" + formatted);
496 // for French, the result is "13 sept."
499 public void TestOrdering() {
500 ULocale[] locales = ULocale.getAvailableLocales();
501 for (int i = 0; i < locales.length; ++i) {
502 for (int style1 = DateFormat.FULL; style1 <= DateFormat.SHORT; ++style1) {
503 for (int style2 = DateFormat.FULL; style2 < style1; ++style2) {
504 checkCompatible(style1, style2, locales[i]);
510 public void TestReplacingZoneString() {
511 Date testDate = new Date();
512 TimeZone testTimeZone = TimeZone.getTimeZone("America/New_York");
513 TimeZone bogusTimeZone = new SimpleTimeZone(1234, "Etc/Unknown");
514 Calendar calendar = Calendar.getInstance();
515 ParsePosition parsePosition = new ParsePosition(0);
517 ULocale[] locales = ULocale.getAvailableLocales();
519 for (int i = 0; i < locales.length; ++i) {
520 // skip the country locales unless we are doing exhaustive tests
521 if (getInclusion() < 6) {
522 if (locales[i].getCountry().length() > 0) {
527 // Skipping some test case in the non-exhaustive mode to reduce the test time
529 if(params.inclusion<=5 && count%3!=0){
532 logln(locales[i].toString());
533 DateTimePatternGenerator dtpgen
534 = DateTimePatternGenerator.getInstance(locales[i]);
536 for (int style1 = DateFormat.FULL; style1 <= DateFormat.SHORT; ++style1) {
537 final SimpleDateFormat oldFormat = (SimpleDateFormat) DateFormat.getTimeInstance(style1, locales[i]);
538 String pattern = oldFormat.toPattern();
539 String newPattern = dtpgen.replaceFieldTypes(pattern, "VVVV"); // replaceZoneString(pattern, "VVVV");
540 if (newPattern.equals(pattern)) {
543 // verify that it roundtrips parsing
544 SimpleDateFormat newFormat = new SimpleDateFormat(newPattern, locales[i]);
545 newFormat.setTimeZone(testTimeZone);
546 String formatted = newFormat.format(testDate);
547 calendar.setTimeZone(bogusTimeZone);
548 parsePosition.setIndex(0);
549 newFormat.parse(formatted, calendar, parsePosition);
550 if (parsePosition.getErrorIndex() >= 0) {
551 errln("Failed parse with VVVV:\t" + locales[i] + ",\t\"" + pattern + "\",\t\"" + newPattern + "\",\t\"" + formatted.substring(0,parsePosition.getErrorIndex()) + "{}" + formatted.substring(parsePosition.getErrorIndex()) + "\"");
552 } else if (!calendar.getTimeZone().getID().equals(testTimeZone.getID())) {
553 errln("Failed timezone roundtrip with VVVV:\t" + locales[i] + ",\t\"" + pattern + "\",\t\"" + newPattern + "\",\t\"" + formatted + "\",\t" + calendar.getTimeZone().getID() + " != " + testTimeZone.getID());
555 logln(locales[i] + ":\t\"" + pattern + "\" => \t\"" + newPattern + "\"\t" + formatted);
561 public void TestVariableCharacters() {
562 UnicodeSet valid = new UnicodeSet("[G y Y u U Q q M L l w W d D F g E e c a h H K k m s S A z Z O v V X x]");
563 for (char c = 0; c < 0xFF; ++c) {
564 boolean works = false;
566 VariableField vf = new VariableField(String.valueOf(c), true);
567 logln("VariableField " + vf.toString());
569 } catch (Exception e) {}
570 if (works != valid.contains(c)) {
572 errln("VariableField can be created with illegal character: " + c);
574 errln("VariableField can't be created with legal character: " + c);
580 static String[] DATE_STYLE_NAMES = {
581 "FULL", "LONG", "MEDIUM", "SHORT"
588 private void checkCompatible(int style1, int style2, ULocale uLocale) {
589 DateOrder order1 = getOrdering(style1, uLocale);
590 DateOrder order2 = getOrdering(style2, uLocale);
591 if (!order1.hasSameOrderAs(order2)) {
592 // Note: This test case was updated by #6806 and no longer reports
593 // ordering difference as an error case.
594 logln(showOrderComparison(uLocale, style1, style2, order1, order2));
598 private String showOrderComparison(ULocale uLocale, int style1, int style2, DateOrder order1, DateOrder order2) {
599 String pattern1 = ((SimpleDateFormat) DateFormat.getDateInstance(style1, uLocale)).toPattern();
600 String pattern2 = ((SimpleDateFormat) DateFormat.getDateInstance(style2, uLocale)).toPattern();
601 return "Mismatch in in ordering for " + uLocale + ": " + DATE_STYLE_NAMES[style1] + ": " + order1 + ", <" + pattern1
603 + DATE_STYLE_NAMES[style2] + ": " + order2 + ", <" + pattern2 + ">; " ;
607 * Main date fields -- Poor-man's enum -- change to real enum when we get JDK 1.5
609 public static class DateFieldType {
611 private DateFieldType(String string) {
615 public static DateFieldType
616 YEAR = new DateFieldType("YEAR"),
617 MONTH = new DateFieldType("MONTH"),
618 DAY = new DateFieldType("DAY");
620 public String toString() {
626 * Simple struct for output from getOrdering
628 static class DateOrder {
630 DateFieldType[] fields = new DateFieldType[3];
632 public boolean isCompatible(DateOrder other) {
633 return monthLength == other.monthLength;
639 public boolean hasSameOrderAs(DateOrder other) {
640 // TODO Auto-generated method stub
641 return fields[0] == other.fields[0] && fields[1] == other.fields[1] && fields[2] == other.fields[2];
643 public String toString() {
644 return "{" + monthLength + ", " + fields[0] + ", " + fields[1] + ", " + fields[2] + "}";
646 public boolean equals(Object that) {
647 DateOrder other = (DateOrder) that;
648 return monthLength == other.monthLength && fields[0] == other.fields[0] && fields[1] == other.fields[1] && fields[2] == other.fields[2];
652 DateTimePatternGenerator.FormatParser formatParser = new DateTimePatternGenerator.FormatParser ();
653 DateTimePatternGenerator generator = DateTimePatternGenerator.getEmptyInstance();
655 private Calendar sampleCalendar;
657 sampleCalendar = new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles"));
658 sampleCalendar.set(1999, Calendar.OCTOBER, 13, 23, 58, 59);
661 private Date sampleDate = sampleCalendar.getTime();
662 private TimeZone gmt = TimeZone.getTimeZone("Etc/GMT");
665 * Replace the zone string with a different type, eg v's for z's, etc. <p>Called with a pattern, such as one gotten from
667 * String pattern = ((SimpleDateFormat) DateFormat.getTimeInstance(style, locale)).toPattern();
669 * @param pattern original pattern to change, such as "HH:mm zzzz"
670 * @param newZone Must be: z, zzzz, Z, ZZZZ, v, vvvv, V, or VVVV
673 public String replaceZoneString(String pattern, String newZone) {
674 final List itemList = formatParser.set(pattern).getItems();
675 boolean changed = false;
676 for (int i = 0; i < itemList.size(); ++i) {
677 Object item = itemList.get(i);
678 if (item instanceof VariableField) {
679 VariableField variableField = (VariableField) item;
680 if (variableField.getType() == DateTimePatternGenerator.ZONE) {
681 if (!variableField.toString().equals(newZone)) {
683 itemList.set(i, new VariableField(newZone, true));
688 return changed ? formatParser.toString() : pattern;
691 public boolean containsZone(String pattern) {
692 for (Iterator it = formatParser.set(pattern).getItems().iterator(); it.hasNext();) {
693 Object item = it.next();
694 if (item instanceof VariableField) {
695 VariableField variableField = (VariableField) item;
696 if (variableField.getType() == DateTimePatternGenerator.ZONE) {
705 * Get the ordering from a particular date format. Best is to use
706 * DateFormat.FULL to get the format with String form month (like "January")
707 * and DateFormat.SHORT for the numeric format order. They may be different.
708 * (Theoretically all 4 formats could be different but that never happens in
712 * DateFormat.FULL..DateFormat.SHORT
716 * @return list of ordered items DateFieldType (I
717 * didn't know what form you really wanted so this is just a
720 private DateOrder getOrdering(int style, ULocale locale) {
721 // and the date pattern
722 String pattern = ((SimpleDateFormat) DateFormat.getDateInstance(style, locale)).toPattern();
724 DateOrder result = new DateOrder();
726 for (Iterator it = formatParser.set(pattern).getItems().iterator(); it.hasNext();) {
727 Object item = it.next();
728 if (!(item instanceof String)) {
729 // the first character of the variable field determines the type,
730 // according to CLDR.
731 String variableField = item.toString();
732 switch (variableField.charAt(0)) {
733 case 'y': case 'Y': case 'u':
734 result.fields[count++] = DateFieldType.YEAR;
737 result.monthLength = variableField.length();
738 if (result.monthLength < 2) {
739 result.monthLength = 2;
741 result.fields[count++] = DateFieldType.MONTH;
743 case 'd': case 'D': case 'F': case 'g':
744 result.fields[count++] = DateFieldType.DAY;
752 * public static DateTimePatternGenerator getInstance()
754 public void TestGetInstance(){
756 DateTimePatternGenerator.getInstance();
757 } catch(Exception e){
758 errln("DateTimePatternGenerator.getInstance() was not suppose to " +
759 "return an exception.");
764 * public String getSkeleton(String pattern)
766 public void TestGetSkeleton(){
767 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
768 String[] cases = {"MMDD","MMMDD","MMM-DD","DD/MMM","ddM","MMMMd"};
769 String[] results = {"MMDD","MMMDD","MMMDD","MMMDD","Mdd","MMMMd"};
770 for(int i=0; i<cases.length; i++){
771 if(!dtpg.getSkeleton(cases[i]).equals(results[i])){
772 errln("DateTimePatternGenerator.getSkeleton(String) did " +
773 "return the expected result when passing " + cases[i] +
774 " and expected " + results[i] + " but got " +
775 dtpg.getSkeleton(cases[i]));
781 * public String getBaseSkeleton(String pattern)
783 public void TestGetBaseSkeleton(){
784 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
785 String[] cases = {"MMDD","MMMDD","MMM-DD","DD/MMM","ddM","MMMMd"};
786 String[] results = {"MD","MMMD","MMMD","MMMD","Md","MMMMd"};
787 for(int i=0; i<cases.length; i++){
788 if(!dtpg.getBaseSkeleton(cases[i]).equals(results[i])){
789 errln("DateTimePatternGenerator.getSkeleton(String) did " +
790 "return the expected result when passing " + cases[i] +
791 " and expected " + results[i] + " but got " +
792 dtpg.getBaseSkeleton(cases[i]));
798 * public Map<String, String> getSkeletons(Map<String, String> result)
800 public void TestGetSkeletons(){
801 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
802 // Tests when "if (result == null)" is true
804 dtpg.getSkeletons(null);
805 } catch(Exception e){
806 errln("DateTimePatternGenerator.getSkeletons(Map) was suppose to " +
807 "return a new LinkedHashMap for a null parameter.");
810 // Tests when "if (result == null)" is false
811 Map<String,String> mm = new LinkedHashMap<String, String>();
813 dtpg.getSkeletons(mm);
814 } catch(Exception e){
815 errln("DateTimePatternGenerator.getSkeletons(Map) was suppose to " +
816 "return a new LinkedHashMap for a LinkedHashMap parameter.");
821 * public Set<String> getBaseSkeletons(Set<String> result)
823 public void TestGetBaseSkeletons(){
824 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
825 // Tests when "if (result == null)" is true
827 dtpg.getBaseSkeletons(null);
828 } catch(Exception e){
829 errln("DateTimePatternGenerator.getBaseSkeletons(Map) was suppose to " +
830 "return a new LinkedHashMap for a null parameter.");
833 // Tests when "if (result == null)" is false
834 Set<String> mm = new HashSet<String>();
836 dtpg.getBaseSkeletons(mm);
837 } catch(Exception e){
838 errln("DateTimePatternGenerator.getBaseSkeletons(Map) was suppose to " +
839 "return a new LinkedHashMap for a HashSet parameter.");
844 * public String getDecimal()
846 public void TestGetDecimal(){
847 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
848 if(!dtpg.getDecimal().equals(".")){
849 errln("DateTimePatternGenerator.getDecimal() was to return '.' " +
850 "when the object gets a new instance.");
853 String[] cases = {",","-","","*","&","a","0"};
854 for(int i=0; i<cases.length; i++){
855 dtpg.setDecimal(cases[i]);
856 if(!dtpg.getDecimal().equals(cases[i])){
857 errln("DateTimePatternGenerator.getDecimal() was to return " + cases[i] +
858 "when setting decimal with " + cases[i]);
864 * public Collection<String> getRedundants(Collection<String> output)
866 public void TestGetRedundants(){
867 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
869 // Tests when "if (output == null)" is true
871 dtpg.getRedundants(null);
872 } catch(Exception e){
873 errln("DateTimeGenerator.getRedundants was not suppose to return " +
874 "an exception when passing a null parameter.");
877 // Tests when "if (output == null)" is false
879 Collection<String> out = new LinkedHashSet<String>();
880 dtpg.getRedundants(out);
881 } catch(Exception e){
882 errln("DateTimeGenerator.getRedundants was not suppose to return " +
883 "an exception when passing a new LinkedHashSet<String>() parameter.");
889 * public String getAppendItemFormat(int field)
891 public void TestGetAppendItemFormat(){
892 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
893 String[] cases = {"d","u","m","m","y"};
894 for(int i=0; i<cases.length; i++){
895 dtpg.setAppendItemFormat(i, cases[i]);
896 if(!dtpg.getAppendItemFormat(i).equals(cases[i])){
897 errln("DateTimePatternGeneratorgetAppendItemFormat(int field) " +
898 "did not return as expected. Value set at " + i + " was " +
899 cases[i] + " but got back " + dtpg.getAppendItemFormat(i));
905 * public String getAppendItemName(int field)
907 private final class AppendItemName {
910 public AppendItemName(int f, String n) {
916 public void TestGetAppendItemName(){
917 final AppendItemName[] appendItemNames = {
918 new AppendItemName( DateTimePatternGenerator.YEAR, "vuosi" ),
919 new AppendItemName( DateTimePatternGenerator.MONTH, "kuukausi" ),
920 new AppendItemName( DateTimePatternGenerator.WEEKDAY, "viikonp\u00E4iv\u00E4" ),
921 new AppendItemName( DateTimePatternGenerator.DAY, "p\u00E4iv\u00E4" ),
922 new AppendItemName( DateTimePatternGenerator.HOUR, "tunti" ),
925 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
926 String[] cases = {"d","u","m","m","y"};
927 for(int i=0; i<cases.length; i++){
928 dtpg.setAppendItemName(i, cases[i]);
929 if(!dtpg.getAppendItemName(i).equals(cases[i])){
930 errln("DateTimePatternGenerator.getAppendItemFormat(int field) " +
931 "did not return as expected. Value set at " + i + " was " +
932 cases[i] + " but got back " + dtpg.getAppendItemName(i));
936 DateTimePatternGenerator dtpgfi = DateTimePatternGenerator.getInstance(ULocale.forLanguageTag("fi"));
937 for (AppendItemName appendItemName: appendItemNames) {
938 String name = dtpgfi.getAppendItemName(appendItemName.field);
939 if (!name.equals(appendItemName.name)) {
940 errln("DateTimePatternGenerator.getAppendItemName returns invalid name for field " + appendItemName.field);
946 * public static boolean isSingleField(String skeleton)
948 @SuppressWarnings("static-access")
949 public void TestIsSingleField(){
950 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
951 String[] cases = {" ", "m","mm","md","mmd","mmdd"};
952 boolean[] results = {true,true,true,false,false,false};
953 for(int i=0; i<cases.length; i++){
954 if(dtpg.isSingleField(cases[i]) != results[i]){
955 errln("DateTimePatternGenerator.isSingleField(String skeleton) " +
956 "did not return as expected. Value passed was " + cases[i] +
957 " but got back " + dtpg.isSingleField(cases[i]));
963 * public Object freeze()
964 * public Object cloneAsThawed()
966 public void TestFreezeAndCloneAsThawed(){
967 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
969 if(dtpg.isFrozen() != false){
970 errln("DateTimePatternGenerator.isFrozen() is suppose to return false " +
971 "for a DateTimePatternGenerator object that was just " +
976 if(dtpg.isFrozen() != true){
977 errln("DateTimePatternGenerator.isFrozen() is suppose to return true " +
978 "for a DateTimePatternGenerator object that was just " +
979 "created and freeze.");
982 DateTimePatternGenerator dtpg2 = (DateTimePatternGenerator) dtpg.cloneAsThawed();
983 if(dtpg.isFrozen() != false){
984 errln("DateTimePatternGenerator.isFrozen() is suppose to return false " +
985 "for a DateTimePatternGenerator object that was just " +
988 if(dtpg2.isFrozen() != false){
989 errln("DateTimePatternGenerator.isFrozen() is suppose to return false " +
990 "for a second DateTimePatternGenerator object that was just " +
996 * public Object clone()
998 public void TestClone(){
999 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
1000 DateTimePatternGenerator dtpg2 = (DateTimePatternGenerator) dtpg.clone();
1001 dtpg = (DateTimePatternGenerator) dtpg2.clone();
1004 /* Tests the constructor
1005 * public VariableField(String string)
1007 @SuppressWarnings("unused")
1008 public void TestVariableField_String(){
1009 String[] cases = {"d","mm","aa"};
1010 String[] invalid = {null,"","dummy"};
1011 for(int i=0; i<cases.length; i++){
1013 VariableField vf = new VariableField(cases[i]);
1014 } catch(Exception e){
1015 errln("VariableField constructor was not suppose to return " +
1016 "an exception when created when passing " + cases[i]);
1019 for(int i=0; i<invalid.length; i++){
1021 VariableField vf = new VariableField(invalid[i]);
1022 errln("VariableField constructor was suppose to return " +
1023 "an exception when created when passing " + invalid[i]);
1024 } catch(Exception e){}
1029 * public FormatParser set(String string, boolean strict)
1031 public void TestSet(){
1032 FormatParser fp = new FormatParser();
1033 //Tests when "if (string.length() == 0)" is true
1036 }catch(Exception e){
1037 errln("FormatParser.set(String,boolean) was not suppose to " +
1038 "return an exception.");
1043 * public String toString()
1045 public void TestToString(){
1046 FormatParser fp = new FormatParser();
1047 if(!fp.toString().equals("")){
1048 errln("FormatParser.toString() was suppose to return an " +
1049 "empty string for a new FormatParser object.");
1052 String[] cases = {"m","d","y","mm","mmm","mm dd","mm':'dd","mm-dd-yyyy"};
1053 String[] results = {"m","d","y","mm","mmm","mm dd","mm:dd","mm-dd-yyyy"};
1054 for(int i=0; i<cases.length; i++){
1056 if(!fp.toString().equals(results[i])){
1057 errln("FormatParser.toString() was suppose to return " + results[i] +
1058 " after setting the object. Got: " + fp.toString());
1064 * public boolean hasDateAndTimeFields()
1066 public void TestHasDateAndTimeFields(){
1067 FormatParser fp = new FormatParser();
1068 if(fp.hasDateAndTimeFields() != false){
1069 errln("FormatParser.hasDateAndTimeFields() was suppose to return " +
1070 "false when a new object is created.");
1073 String[] cases = {"MMDDYY", "HHMMSS", "", "MM/DD/YYYY HH:MM:SS",
1074 "MMDDYY HHMMSS", "HHMMSS MMDDYYYY", "HMS MDY"};
1075 boolean[] results = {false,true,false,true,true,true,true};
1076 for(int i=0; i<cases.length; i++){
1078 if(fp.hasDateAndTimeFields() != results[i]){
1079 errln("FormatParser.hasDateAndTimeFields() was suppose to " +
1080 "return " + results[i] + " but returned " +
1081 fp.hasDateAndTimeFields() + " for parameter " +
1082 cases[i] + " that is set to FormatParser.");
1088 * private void checkFrozen()
1089 * from public void setDateTimeFormat(String dateTimeFormat)
1091 public void TestCheckFrozen(){
1092 // Tests when "if (isFrozen())" is true
1093 DateTimePatternGenerator dt = DateTimePatternGenerator.getInstance();
1096 dt.setDateTimeFormat("MMDDYYYY");
1097 errln("DateTimePatternGenerator.checkFrozen() was suppose to " +
1098 "return an exception when trying to setDateTimeFormat " +
1099 "for a frozen object.");
1100 } catch(Exception e){}
1101 dt = (DateTimePatternGenerator) dt.cloneAsThawed();
1105 * public String getFields(String pattern)
1107 public void TestGetFields(){
1108 DateTimePatternGenerator dt = DateTimePatternGenerator.getInstance();
1109 String[] cases = {"MMDDYY", "HHMMSS", "", "MM/DD/YYYY HH:MM:SS",
1110 "MMDDYY HHMMSS", "HHMMSS MMDDYYYY", "HMS MDY"};
1111 String[] results = {"{Month:N}{Day_Of_Year:N}{Year:N}",
1112 "{Hour:N}{Month:N}{Fractional_Second:N}","",
1113 "{Month:N}/{Day_Of_Year:N}/{Year:N} {Hour:N}:{Month:N}:{Fractional_Second:N}",
1114 "{Month:N}{Day_Of_Year:N}{Year:N} {Hour:N}{Month:N}{Fractional_Second:N}",
1115 "{Hour:N}{Month:N}{Fractional_Second:N} {Month:N}{Day_Of_Year:N}{Year:N}",
1116 "{Hour:N}{Month:N}{Fractional_Second:N} {Month:N}{Day_Of_Year:N}{Year:N}"};
1117 for(int i=0; i<cases.length; i++){
1119 if(!dt.getFields(cases[i]).equals(results[i]));
1120 } catch(Exception e){
1121 errln("DateTimePatternGenerator.getFields(String) did not " +
1122 "not return an expected result when passing " + cases[i] +
1123 ". Got " + dt.getFields(cases[i]) + " but expected " +
1130 * Test case for DateFormatPatternGenerator threading problem #7169
1132 public void TestT7169() {
1133 Thread[] workers = new Thread[10];
1134 for (int i = 0 ; i < workers.length; i++) {
1135 workers[i] = new Thread(new Runnable() {
1138 for (int i = 0; i < 50; i++) {
1139 DateTimePatternGenerator patternGenerator =
1140 DateTimePatternGenerator.getFrozenInstance(ULocale.US);
1141 patternGenerator.getBestPattern("MMMMd");
1143 } catch (Exception e) {
1144 errln("FAIL: Caught an exception (frozen)" + e);
1147 for (int i = 0; i < 50; i++) {
1148 DateTimePatternGenerator patternGenerator =
1149 DateTimePatternGenerator.getInstance(ULocale.US);
1150 patternGenerator.getBestPattern("MMMMd");
1152 } catch (Exception e) {
1153 errln("FAIL: Caught an exception " + e);
1158 for (Thread wk : workers) {
1161 for (Thread wk : workers) {
1164 } catch (InterruptedException ie) {
1171 * Test handling of options
1173 * For reference, as of ICU 4.3.3,
1174 * root/gregorian has
1184 * HHmmss{"HH.mm.ss"}
1189 private final class TestOptionsItem {
1190 public String locale;
1191 public String skeleton;
1192 public String expectedPattern;
1194 // Simple constructor
1195 public TestOptionsItem(String loc, String skel, String expectedPat, int opts) {
1198 expectedPattern = expectedPat;
1202 public void TestOptions() {
1203 final TestOptionsItem[] testOptionsData = {
1204 new TestOptionsItem( "en", "Hmm", "HH:mm", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1205 new TestOptionsItem( "en", "HHmm", "HH:mm", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1206 new TestOptionsItem( "en", "hhmm", "h:mm a", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1207 new TestOptionsItem( "en", "Hmm", "HH:mm", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),
1208 new TestOptionsItem( "en", "HHmm", "HH:mm", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),
1209 new TestOptionsItem( "en", "hhmm", "hh:mm a", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),
1210 new TestOptionsItem( "be", "Hmm", "HH.mm", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1211 new TestOptionsItem( "be", "HHmm", "HH.mm", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1212 new TestOptionsItem( "be", "hhmm", "h.mm a", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1213 new TestOptionsItem( "be", "Hmm", "H.mm", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),
1214 new TestOptionsItem( "be", "HHmm", "HH.mm", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),
1215 new TestOptionsItem( "be", "hhmm", "hh.mm a", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),
1217 new TestOptionsItem( "en", "yyyy", "yyyy", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1218 new TestOptionsItem( "en", "YYYY", "YYYY", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1219 new TestOptionsItem( "en", "U", "y", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1220 new TestOptionsItem( "en@calendar=japanese", "yyyy", "y G", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1221 new TestOptionsItem( "en@calendar=japanese", "YYYY", "Y G", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1222 new TestOptionsItem( "en@calendar=japanese", "U", "y G", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1223 new TestOptionsItem( "en@calendar=chinese", "yyyy", "U", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1224 new TestOptionsItem( "en@calendar=chinese", "YYYY", "Y", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1225 new TestOptionsItem( "en@calendar=chinese", "U", "U", DateTimePatternGenerator.MATCH_NO_OPTIONS ),
1228 for (int i = 0; i < testOptionsData.length; ++i) {
1229 ULocale uloc = new ULocale(testOptionsData[i].locale);
1230 DateTimePatternGenerator dtpgen = DateTimePatternGenerator.getInstance(uloc);
1231 String pattern = dtpgen.getBestPattern(testOptionsData[i].skeleton, testOptionsData[i].options);
1232 if (pattern.compareTo(testOptionsData[i].expectedPattern) != 0) {
1233 errln("Locale " + testOptionsData[i].locale + ", skeleton " + testOptionsData[i].skeleton +
1234 ", options " + ((testOptionsData[i].options != 0)? "!=0": "==0") +
1235 ", expected pattern " + testOptionsData[i].expectedPattern + ", got " + pattern);
1241 * Test that DTPG can handle all valid pattern character / length combinations
1243 private final class AllFieldsTestItem {
1244 public char patternChar;
1245 public int[] fieldLengths;
1246 public String mustIncludeOneOf;
1247 // Simple constructor
1248 public AllFieldsTestItem(char pC, int[] fL, String mI) {
1251 mustIncludeOneOf = mI;
1254 public void TestAllFieldPatterns() {
1255 String[] localeNames = {
1257 "root@calendar=japanese",
1258 "root@calendar=chinese",
1260 "en@calendar=japanese",
1261 "en@calendar=chinese",
1263 final AllFieldsTestItem[] testItems = {
1264 // pat fieldLengths generated pattern must
1265 // chr to test include one of these
1266 new AllFieldsTestItem( 'G', new int[]{1,2,3,4,5}, "G" ), // era
1268 new AllFieldsTestItem( 'y', new int[]{1,2,3,4}, "yU" ), // year
1269 new AllFieldsTestItem( 'Y', new int[]{1,2,3,4}, "Y" ), // year for week of year
1270 new AllFieldsTestItem( 'u', new int[]{1,2,3,4,5}, "yuU" ), // extended year
1271 new AllFieldsTestItem( 'U', new int[]{1,2,3,4,5}, "yU" ), // cyclic year name
1273 new AllFieldsTestItem( 'Q', new int[]{1,2,3,4}, "Qq" ), // x
1274 new AllFieldsTestItem( 'q', new int[]{1,2,3,4}, "Qq" ), // standalone
1276 new AllFieldsTestItem( 'M', new int[]{1,2,3,4,5}, "ML" ), // x
1277 new AllFieldsTestItem( 'L', new int[]{1,2,3,4,5}, "ML" ), // standalone
1279 new AllFieldsTestItem( 'w', new int[]{1,2}, "w" ), // week of year
1280 new AllFieldsTestItem( 'W', new int[]{1}, "W" ), // week of month
1282 new AllFieldsTestItem( 'd', new int[]{1,2}, "d" ), // day of month
1283 new AllFieldsTestItem( 'D', new int[]{1,2,3}, "D" ), // day of year
1284 new AllFieldsTestItem( 'F', new int[]{1}, "F" ), // day of week in month
1285 new AllFieldsTestItem( 'g', new int[]{7}, "g" ), // modified julian day
1287 new AllFieldsTestItem( 'E', new int[]{1,2,3,4,5,6}, "Eec" ), // day of week
1288 new AllFieldsTestItem( 'e', new int[]{1,2,3,4,5,6}, "Eec" ), // local day of week
1289 new AllFieldsTestItem( 'c', new int[]{1,2,3,4,5,6}, "Eec" ), // standalone local day of week
1291 // new AllFieldsTestItem( 'a', new int[]{1}, "a" ), // am or pm // not clear this one is supposed to work (it doesn't)
1293 new AllFieldsTestItem( 'h', new int[]{1,2}, "hK" ), // 12 (1-12)
1294 new AllFieldsTestItem( 'H', new int[]{1,2}, "Hk" ), // 24 (0-23)
1295 new AllFieldsTestItem( 'K', new int[]{1,2}, "hK" ), // 12 (0-11)
1296 new AllFieldsTestItem( 'k', new int[]{1,2}, "Hk" ), // 24 (1-24)
1297 new AllFieldsTestItem( 'j', new int[]{1,2}, "hHKk" ), // locale default
1299 new AllFieldsTestItem( 'm', new int[]{1,2}, "m" ), // x
1300 // second & fractions
1301 new AllFieldsTestItem( 's', new int[]{1,2}, "s" ), // x
1302 new AllFieldsTestItem( 'S', new int[]{1,2,3,4}, "S" ), // fractional second
1303 new AllFieldsTestItem( 'A', new int[]{8}, "A" ), // milliseconds in day
1305 new AllFieldsTestItem( 'z', new int[]{1,2,3,4}, "z" ), // x
1306 new AllFieldsTestItem( 'Z', new int[]{1,2,3,4,5}, "Z" ), // x
1307 new AllFieldsTestItem( 'O', new int[]{1,4}, "O" ), // x
1308 new AllFieldsTestItem( 'v', new int[]{1,4}, "v" ), // x
1309 new AllFieldsTestItem( 'V', new int[]{1,2,3,4}, "V" ), // x
1310 new AllFieldsTestItem( 'X', new int[]{1,2,3,4,5}, "X" ), // x
1311 new AllFieldsTestItem( 'x', new int[]{1,2,3,4,5}, "x" ), // x
1313 final int FIELD_LENGTH_MAX = 8;
1315 for (String localeName: localeNames) {
1316 ULocale uloc = new ULocale(localeName);
1317 DateTimePatternGenerator dtpgen = DateTimePatternGenerator.getInstance(uloc);
1318 for (AllFieldsTestItem testItem: testItems) {
1319 char[] skelBuf = new char[FIELD_LENGTH_MAX];
1320 for (int chrIndx = 0; chrIndx < FIELD_LENGTH_MAX; chrIndx++) {
1321 skelBuf[chrIndx] = testItem.patternChar;
1323 for (int lenIndx = 0; lenIndx < testItem.fieldLengths.length; lenIndx++) {
1324 int skelLen = testItem.fieldLengths[lenIndx];
1325 if (skelLen > FIELD_LENGTH_MAX) {
1328 String skeleton = new String(skelBuf, 0, skelLen);
1329 String pattern = dtpgen.getBestPattern(skeleton);
1330 if (pattern.length() <= 0) {
1331 errln("DateTimePatternGenerator getBestPattern for locale " + localeName +
1332 ", skeleton " + skeleton + ", produces 0-length pattern");
1334 // test that resulting pattern has at least one char in mustIncludeOneOf
1335 boolean inQuoted = false;
1336 int patIndx, patLen = pattern.length();
1337 for (patIndx = 0; patIndx < patLen; patIndx++) {
1338 char c = pattern.charAt(patIndx);
1340 inQuoted = !inQuoted;
1341 } else if (!inQuoted && c <= 'z' && c >= 'A') {
1342 if (testItem.mustIncludeOneOf.indexOf(c) >= 0) {
1347 if (patIndx >= patLen) {
1348 errln("DateTimePatternGenerator getBestPattern for locale " + localeName +
1349 ", skeleton " + skeleton +
1350 ", produces pattern without required chars: " + pattern);