• 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) 1997-2016, International Business Machines
6  * Corporation and others. All Rights Reserved.
7  ********************************************************************/
8 
9 #include "unicode/utypes.h"
10 
11 #if !UCONFIG_NO_FORMATTING
12 
13 #include "dtfmttst.h"
14 #include "unicode/localpointer.h"
15 #include "unicode/timezone.h"
16 #include "unicode/gregocal.h"
17 #include "unicode/smpdtfmt.h"
18 #include "unicode/datefmt.h"
19 #include "unicode/dtptngen.h"
20 #include "unicode/simpletz.h"
21 #include "unicode/strenum.h"
22 #include "unicode/dtfmtsym.h"
23 #include "cmemory.h"
24 #include "cstring.h"
25 #include "caltest.h"  // for fieldName
26 #include <stdio.h> // for sprintf
27 
28 #if U_PLATFORM_USES_ONLY_WIN32_API
29 #include "windttst.h"
30 #endif
31 
32 #define ASSERT_OK(status) UPRV_BLOCK_MACRO_BEGIN { \
33     if(U_FAILURE(status)) { \
34         errcheckln(status, #status " = %s @ %s:%d", u_errorName(status), __FILE__, __LINE__); \
35         return; \
36     } \
37 } UPRV_BLOCK_MACRO_END
38 
39 // *****************************************************************************
40 // class DateFormatTest
41 // *****************************************************************************
42 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)43 void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
44 {
45     if(exec) {
46         logln("TestSuite DateFormatTest: ");
47     }
48     TESTCASE_AUTO_BEGIN;
49     TESTCASE_AUTO(TestPatterns);
50     TESTCASE_AUTO(TestEquals);
51     TESTCASE_AUTO(TestTwoDigitYearDSTParse);
52     TESTCASE_AUTO(TestFieldPosition);
53     TESTCASE_AUTO(TestPartialParse994);
54     TESTCASE_AUTO(TestRunTogetherPattern985);
55     TESTCASE_AUTO(TestRunTogetherPattern917);
56     TESTCASE_AUTO(TestCzechMonths459);
57     TESTCASE_AUTO(TestLetterDPattern212);
58     TESTCASE_AUTO(TestDayOfYearPattern195);
59     TESTCASE_AUTO(TestQuotePattern161);
60     TESTCASE_AUTO(TestBadInput135);
61     TESTCASE_AUTO(TestBadInput135a);
62     TESTCASE_AUTO(TestTwoDigitYear);
63     TESTCASE_AUTO(TestDateFormatZone061);
64     TESTCASE_AUTO(TestDateFormatZone146);
65     TESTCASE_AUTO(TestLocaleDateFormat);
66     TESTCASE_AUTO(TestFormattingLocaleTimeSeparator);
67     TESTCASE_AUTO(TestWallyWedel);
68     TESTCASE_AUTO(TestDateFormatCalendar);
69     TESTCASE_AUTO(TestSpaceParsing);
70     TESTCASE_AUTO(TestExactCountFormat);
71     TESTCASE_AUTO(TestWhiteSpaceParsing);
72     TESTCASE_AUTO(TestInvalidPattern);
73     TESTCASE_AUTO(TestGeneral);
74     TESTCASE_AUTO(TestGreekMay);
75     TESTCASE_AUTO(TestGenericTime);
76     TESTCASE_AUTO(TestGenericTimeZoneOrder);
77     TESTCASE_AUTO(TestHost);
78     TESTCASE_AUTO(TestEras);
79     TESTCASE_AUTO(TestNarrowNames);
80     TESTCASE_AUTO(TestShortDays);
81     TESTCASE_AUTO(TestStandAloneDays);
82     TESTCASE_AUTO(TestStandAloneMonths);
83     TESTCASE_AUTO(TestQuarters);
84     TESTCASE_AUTO(TestZTimeZoneParsing);
85     TESTCASE_AUTO(TestRelative);
86     TESTCASE_AUTO(TestRelativeClone);
87     TESTCASE_AUTO(TestHostClone);
88     TESTCASE_AUTO(TestHebrewClone);
89     TESTCASE_AUTO(TestDateFormatSymbolsClone);
90     TESTCASE_AUTO(TestTimeZoneDisplayName);
91     TESTCASE_AUTO(TestRoundtripWithCalendar);
92     TESTCASE_AUTO(Test6338);
93     TESTCASE_AUTO(Test6726);
94     TESTCASE_AUTO(TestGMTParsing);
95     TESTCASE_AUTO(Test6880);
96     TESTCASE_AUTO(TestISOEra);
97     TESTCASE_AUTO(TestFormalChineseDate);
98     TESTCASE_AUTO(TestNumberAsStringParsing);
99     TESTCASE_AUTO(TestStandAloneGMTParse);
100     TESTCASE_AUTO(TestParsePosition);
101     TESTCASE_AUTO(TestMonthPatterns);
102     TESTCASE_AUTO(TestContext);
103     TESTCASE_AUTO(TestNonGregoFmtParse);
104     TESTCASE_AUTO(TestFormatsWithNumberSystems);
105     /*
106     TESTCASE_AUTO(TestRelativeError);
107     TESTCASE_AUTO(TestRelativeOther);
108     */
109     TESTCASE_AUTO(TestDotAndAtLeniency);
110     TESTCASE_AUTO(TestDateFormatLeniency);
111     TESTCASE_AUTO(TestParseMultiPatternMatch);
112 
113     TESTCASE_AUTO(TestParseLeniencyAPIs);
114     TESTCASE_AUTO(TestNumberFormatOverride);
115     TESTCASE_AUTO(TestCreateInstanceForSkeleton);
116     TESTCASE_AUTO(TestCreateInstanceForSkeletonDefault);
117     TESTCASE_AUTO(TestCreateInstanceForSkeletonWithCalendar);
118     TESTCASE_AUTO(TestDFSCreateForLocaleNonGregorianLocale);
119     TESTCASE_AUTO(TestDFSCreateForLocaleWithCalendarInLocale);
120     TESTCASE_AUTO(TestChangeCalendar);
121 
122     TESTCASE_AUTO(TestPatternFromSkeleton);
123 
124     TESTCASE_AUTO(TestAmPmMidnightNoon);
125     TESTCASE_AUTO(TestFlexibleDayPeriod);
126     TESTCASE_AUTO(TestDayPeriodWithLocales);
127     TESTCASE_AUTO(TestMinuteSecondFieldsInOddPlaces);
128     TESTCASE_AUTO(TestDayPeriodParsing);
129     TESTCASE_AUTO(TestParseRegression13744);
130     TESTCASE_AUTO(TestAdoptCalendarLeak);
131     TESTCASE_AUTO(Test20741_ABFields);
132 
133     TESTCASE_AUTO_END;
134 }
135 
TestPatterns()136 void DateFormatTest::TestPatterns() {
137     static const struct {
138         const char *actualPattern;
139         const char *expectedPattern;
140         const char *localeID;
141         const char *expectedLocalPattern;
142     } EXPECTED[] = {
143         {UDAT_YEAR, "y","en","y"},
144 
145         {UDAT_QUARTER, "QQQQ", "en", "QQQQ"},
146         {UDAT_ABBR_QUARTER, "QQQ", "en", "QQQ"},
147         {UDAT_YEAR_QUARTER, "yQQQQ", "en", "QQQQ y"},
148         {UDAT_YEAR_ABBR_QUARTER, "yQQQ", "en", "QQQ y"},
149 
150         {UDAT_NUM_MONTH, "M", "en", "L"},
151         {UDAT_ABBR_MONTH, "MMM", "en", "LLL"},
152         {UDAT_MONTH, "MMMM", "en", "LLLL"},
153         {UDAT_YEAR_NUM_MONTH, "yM","en","M/y"},
154         {UDAT_YEAR_ABBR_MONTH, "yMMM","en","MMM y"},
155         {UDAT_YEAR_MONTH, "yMMMM","en","MMMM y"},
156 
157         {UDAT_DAY, "d","en","d"},
158         {UDAT_YEAR_NUM_MONTH_DAY, "yMd", "en", "M/d/y"},
159         {UDAT_YEAR_ABBR_MONTH_DAY, "yMMMd", "en", "MMM d, y"},
160         {UDAT_YEAR_MONTH_DAY, "yMMMMd", "en", "MMMM d, y"},
161         {UDAT_YEAR_NUM_MONTH_WEEKDAY_DAY, "yMEd", "en", "EEE, M/d/y"},
162         {UDAT_YEAR_ABBR_MONTH_WEEKDAY_DAY, "yMMMEd", "en", "EEE, MMM d, y"},
163         {UDAT_YEAR_MONTH_WEEKDAY_DAY, "yMMMMEEEEd", "en", "EEEE, MMMM d, y"},
164 
165         {UDAT_NUM_MONTH_DAY, "Md","en","M/d"},
166         {UDAT_ABBR_MONTH_DAY, "MMMd","en","MMM d"},
167         {UDAT_MONTH_DAY, "MMMMd","en","MMMM d"},
168         {UDAT_NUM_MONTH_WEEKDAY_DAY, "MEd","en","EEE, M/d"},
169         {UDAT_ABBR_MONTH_WEEKDAY_DAY, "MMMEd","en","EEE, MMM d"},
170         {UDAT_MONTH_WEEKDAY_DAY, "MMMMEEEEd","en","EEEE, MMMM d"},
171 
172         {UDAT_HOUR, "j", "en", "h a"}, // (fixed expected result per ticket 6872<-6626)
173         {UDAT_HOUR24, "H", "en", "HH"}, // (fixed expected result per ticket 6872<-6626
174 
175         {UDAT_MINUTE, "m", "en", "m"},
176         {UDAT_HOUR_MINUTE, "jm","en","h:mm a"}, // (fixed expected result per ticket 6872<-7180)
177         {UDAT_HOUR24_MINUTE, "Hm", "en", "HH:mm"}, // (fixed expected result per ticket 6872<-6626)
178 
179         {UDAT_SECOND, "s", "en", "s"},
180         {UDAT_HOUR_MINUTE_SECOND, "jms","en","h:mm:ss a"}, // (fixed expected result per ticket 6872<-7180)
181         {UDAT_HOUR24_MINUTE_SECOND, "Hms","en","HH:mm:ss"}, // (fixed expected result per ticket 6872<-6626)
182         {UDAT_MINUTE_SECOND, "ms", "en", "mm:ss"}, // (fixed expected result per ticket 6872<-6626)
183 
184         {UDAT_LOCATION_TZ, "VVVV", "en", "VVVV"},
185         {UDAT_GENERIC_TZ, "vvvv", "en", "vvvv"},
186         {UDAT_ABBR_GENERIC_TZ, "v", "en", "v"},
187         {UDAT_SPECIFIC_TZ, "zzzz", "en", "zzzz"},
188         {UDAT_ABBR_SPECIFIC_TZ, "z", "en", "z"},
189         {UDAT_ABBR_UTC_TZ, "ZZZZ", "en", "ZZZZ"},
190 
191         {UDAT_YEAR_NUM_MONTH_DAY UDAT_ABBR_UTC_TZ, "yMdZZZZ", "en", "M/d/y, ZZZZ"},
192         {UDAT_MONTH_DAY UDAT_LOCATION_TZ, "MMMMdVVVV", "en", "MMMM d, VVVV"}
193     };
194 
195     IcuTestErrorCode errorCode(*this, "TestPatterns()");
196     for (int32_t i = 0; i < UPRV_LENGTHOF(EXPECTED); i++) {
197         // Verify that patterns have the correct values
198         UnicodeString actualPattern(EXPECTED[i].actualPattern, -1, US_INV);
199         UnicodeString expectedPattern(EXPECTED[i].expectedPattern, -1, US_INV);
200         Locale locale(EXPECTED[i].localeID);
201         if (actualPattern != expectedPattern) {
202             errln("FAILURE! Expected pattern: " + expectedPattern +
203                     " but was: " + actualPattern);
204         }
205 
206         // Verify that DataFormat instances produced contain the correct
207         // localized patterns
208         // TODO: use DateFormat::getInstanceForSkeleton(), ticket #9029
209         // Java test code:
210         // DateFormat date1 = DateFormat.getPatternInstance(actualPattern,
211         //         locale);
212         // DateFormat date2 = DateFormat.getPatternInstance(Calendar.getInstance(locale),
213         //         actualPattern, locale);
214         LocalPointer<DateTimePatternGenerator> generator(
215                 DateTimePatternGenerator::createInstance(locale, errorCode));
216         if(errorCode.errDataIfFailureAndReset("DateTimePatternGenerator::createInstance() failed for locale ID \"%s\"", EXPECTED[i].localeID)) {
217             continue;
218         }
219         UnicodeString pattern = generator->getBestPattern(actualPattern, errorCode);
220         SimpleDateFormat date1(pattern, locale, errorCode);
221         SimpleDateFormat date2(pattern, locale, errorCode);
222         date2.adoptCalendar(Calendar::createInstance(locale, errorCode));
223         if(errorCode.errIfFailureAndReset("DateFormat::getInstanceForSkeleton() failed")) {
224             errln("  for actualPattern \"%s\" & locale ID \"%s\"",
225                   EXPECTED[i].actualPattern, EXPECTED[i].localeID);
226             continue;
227         }
228 
229         UnicodeString expectedLocalPattern(EXPECTED[i].expectedLocalPattern, -1, US_INV);
230         UnicodeString actualLocalPattern1;
231         UnicodeString actualLocalPattern2;
232         date1.toLocalizedPattern(actualLocalPattern1, errorCode);
233         date2.toLocalizedPattern(actualLocalPattern2, errorCode);
234         if (actualLocalPattern1 != expectedLocalPattern) {
235             errln("FAILURE! Expected local pattern: " + expectedLocalPattern
236                     + " but was: " + actualLocalPattern1);
237         }
238         if (actualLocalPattern2 != expectedLocalPattern) {
239             errln("FAILURE! Expected local pattern: " + expectedLocalPattern
240                     + " but was: " + actualLocalPattern2);
241         }
242     }
243 }
244 
245 // Test written by Wally Wedel and emailed to me.
TestWallyWedel()246 void DateFormatTest::TestWallyWedel()
247 {
248     UErrorCode status = U_ZERO_ERROR;
249     /*
250      * Instantiate a TimeZone so we can get the ids.
251      */
252     TimeZone *tz = new SimpleTimeZone(7,"");
253     /*
254      * Computational variables.
255      */
256     int32_t offset, hours, minutes, seconds;
257     /*
258      * Instantiate a SimpleDateFormat set up to produce a full time
259      zone name.
260      */
261     SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)"zzzz", status);
262     /*
263      * A String array for the time zone ids.
264      */
265     int32_t ids_length;
266     StringEnumeration* ids = TimeZone::createEnumeration();
267     if (ids == NULL) {
268         dataerrln("Unable to create TimeZone enumeration.");
269         if (sdf != NULL) {
270             delete sdf;
271         }
272         return;
273     }
274     ids_length = ids->count(status);
275     /*
276      * How many ids do we have?
277      */
278     logln("Time Zone IDs size: %d", ids_length);
279     /*
280      * Column headings (sort of)
281      */
282     logln("Ordinal ID offset(h:m) name");
283     /*
284      * Loop through the tzs.
285      */
286     UDate today = Calendar::getNow();
287     Calendar *cal = Calendar::createInstance(status);
288     for (int32_t i = 0; i < ids_length; i++) {
289         // logln(i + " " + ids[i]);
290         const UnicodeString* id = ids->snext(status);
291         TimeZone *ttz = TimeZone::createTimeZone(*id);
292         // offset = ttz.getRawOffset();
293         cal->setTimeZone(*ttz);
294         cal->setTime(today, status);
295         offset = cal->get(UCAL_ZONE_OFFSET, status) + cal->get(UCAL_DST_OFFSET, status);
296         // logln(i + " " + ids[i] + " offset " + offset);
297         const char* sign = "+";
298         if (offset < 0) {
299             sign = "-";
300             offset = -offset;
301         }
302         hours = offset/3600000;
303         minutes = (offset%3600000)/60000;
304         seconds = (offset%60000)/1000;
305         UnicodeString dstOffset = (UnicodeString)"" + sign + (hours < 10 ? "0" : "") +
306             (int32_t)hours + ":" + (minutes < 10 ? "0" : "") + (int32_t)minutes;
307         if (seconds != 0) {
308             dstOffset = dstOffset + ":" + (seconds < 10 ? "0" : "") + seconds;
309         }
310         /*
311          * Instantiate a date so we can display the time zone name.
312          */
313         sdf->setTimeZone(*ttz);
314         /*
315          * Format the output.
316          */
317         UnicodeString fmtOffset;
318         FieldPosition pos(FieldPosition::DONT_CARE);
319         sdf->format(today,fmtOffset, pos);
320         // UnicodeString fmtOffset = tzS.toString();
321         UnicodeString *fmtDstOffset = 0;
322         if (fmtOffset.startsWith("GMT") && fmtOffset.length() != 3)
323         {
324             //fmtDstOffset = fmtOffset->substring(3);
325             fmtDstOffset = new UnicodeString();
326             fmtOffset.extract(3, fmtOffset.length(), *fmtDstOffset);
327         }
328         /*
329          * Show our result.
330          */
331         UBool ok = fmtDstOffset == 0 || *fmtDstOffset == dstOffset;
332         if (ok)
333         {
334             logln(UnicodeString() + i + " " + *id + " " + dstOffset +
335                   " " + fmtOffset +
336                   (fmtDstOffset != 0 ? " ok" : " ?"));
337         }
338         else
339         {
340             errln(UnicodeString() + i + " " + *id + " " + dstOffset +
341                   " " + fmtOffset + " *** FAIL ***");
342         }
343         delete ttz;
344         delete fmtDstOffset;
345     }
346     delete cal;
347     //  delete ids;   // TODO:  BAD API
348     delete ids;
349     delete sdf;
350     delete tz;
351 }
352 
353 // -------------------------------------
354 
355 /**
356  * Test operator==
357  */
358 void
TestEquals()359 DateFormatTest::TestEquals()
360 {
361     DateFormat* fmtA = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL);
362     DateFormat* fmtB = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL);
363     if ( fmtA == NULL || fmtB == NULL){
364         dataerrln("Error calling DateFormat::createDateTimeInstance");
365         delete fmtA;
366         delete fmtB;
367         return;
368     }
369 
370     if (!(*fmtA == *fmtB)) errln((UnicodeString)"FAIL");
371     delete fmtA;
372     delete fmtB;
373 
374     TimeZone* test = TimeZone::createTimeZone("PDT");
375     delete test;
376 }
377 
378 // -------------------------------------
379 
380 /**
381  * Test the parsing of 2-digit years.
382  */
383 void
TestTwoDigitYearDSTParse(void)384 DateFormatTest::TestTwoDigitYearDSTParse(void)
385 {
386     UErrorCode status = U_ZERO_ERROR;
387     SimpleDateFormat fullFmt((UnicodeString)"EEE MMM dd HH:mm:ss.SSS zzz yyyy G", status);
388     SimpleDateFormat fmt((UnicodeString)"dd-MMM-yy h:mm:ss 'o''clock' a z", Locale::getEnglish(), status);
389     //DateFormat* fmt = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL, Locale::ENGLISH);
390     UnicodeString s(u"03-Apr-04 2:20:47 o'clock AM PST");
391     LocalPointer<TimeZone> defaultTZ(TimeZone::createDefault());
392     LocalPointer<TimeZone> PST(TimeZone::createTimeZone("PST"));
393     int32_t defaultOffset = defaultTZ->getRawOffset();
394     int32_t PSTOffset = PST->getRawOffset();
395     int32_t hour = 2 + (defaultOffset - PSTOffset) / (60*60*1000);
396     // hour is the expected hour of day, in units of seconds
397     hour = ((hour < 0) ? hour + 24 : hour) * 60*60;
398 
399     UnicodeString str;
400 
401     if(U_FAILURE(status)) {
402         dataerrln("Could not set up test. exitting - %s", u_errorName(status));
403         return;
404     }
405 
406     UDate d = fmt.parse(s, status);
407     logln(s + " P> " + fullFmt.format(d, str));
408     int32_t y, m, day, hr, min, sec;
409     dateToFields(d, y, m, day, hr, min, sec);
410     hour += defaultTZ->inDaylightTime(d, status) ? 1 : 0;
411     hr = hr*60*60;
412     if (hr != hour)
413         errln((UnicodeString)"FAIL: Should parse to hour " + hour + " but got " + hr);
414 
415     if (U_FAILURE(status))
416         errln((UnicodeString)"FAIL: " + (int32_t)status);
417 }
418 
419 // -------------------------------------
420 
toHexString(int32_t i)421 UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
422 
423 UnicodeString&
escape(UnicodeString & s)424 DateFormatTest::escape(UnicodeString& s)
425 {
426     UnicodeString buf;
427     for (int32_t i=0; i<s.length(); ++i)
428     {
429         UChar c = s[(int32_t)i];
430         if (c <= (UChar)0x7F) buf += c;
431         else {
432             buf += (UChar)0x5c; buf += (UChar)0x55;
433             buf += toHexString((c & 0xF000) >> 12);
434             buf += toHexString((c & 0x0F00) >> 8);
435             buf += toHexString((c & 0x00F0) >> 4);
436             buf += toHexString(c & 0x000F);
437         }
438     }
439     return (s = buf);
440 }
441 
442 // -------------------------------------
443 
444 /**
445  * This MUST be kept in sync with DateFormatSymbols.gPatternChars.
446  */
447 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
448 static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:";
449 #else
450 static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB";
451 #endif
452 
453 /**
454  * A list of the names of all the fields in DateFormat.
455  * This MUST be kept in sync with DateFormat.
456  */
457 static const char* DATEFORMAT_FIELD_NAMES[] = {
458     "ERA_FIELD",
459     "YEAR_FIELD",
460     "MONTH_FIELD",
461     "DATE_FIELD",
462     "HOUR_OF_DAY1_FIELD",
463     "HOUR_OF_DAY0_FIELD",
464     "MINUTE_FIELD",
465     "SECOND_FIELD",
466     "MILLISECOND_FIELD",
467     "DAY_OF_WEEK_FIELD",
468     "DAY_OF_YEAR_FIELD",
469     "DAY_OF_WEEK_IN_MONTH_FIELD",
470     "WEEK_OF_YEAR_FIELD",
471     "WEEK_OF_MONTH_FIELD",
472     "AM_PM_FIELD",
473     "HOUR1_FIELD",
474     "HOUR0_FIELD",
475     "TIMEZONE_FIELD",
476     "YEAR_WOY_FIELD",
477     "DOW_LOCAL_FIELD",
478     "EXTENDED_YEAR_FIELD",
479     "JULIAN_DAY_FIELD",
480     "MILLISECONDS_IN_DAY_FIELD",
481     "TIMEZONE_RFC_FIELD",
482     "GENERIC_TIMEZONE_FIELD",
483     "STAND_ALONE_DAY_FIELD",
484     "STAND_ALONE_MONTH_FIELD",
485     "QUARTER_FIELD",
486     "STAND_ALONE_QUARTER_FIELD",
487     "TIMEZONE_SPECIAL_FIELD",
488     "YEAR_NAME_FIELD",
489     "TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD",
490     "TIMEZONE_ISO_FIELD",
491     "TIMEZONE_ISO_LOCAL_FIELD",
492     "RELATED_YEAR_FIELD",
493     "AM_PM_MIDNIGHT_NOON_FIELD",
494     "FLEXIBLE_DAY_PERIOD_FIELD",
495     "UDAT_TIME_SEPARATOR_FIELD",
496 };
497 
498 static const int32_t DATEFORMAT_FIELD_NAMES_LENGTH =
499     UPRV_LENGTHOF(DATEFORMAT_FIELD_NAMES);
500 
501 /**
502  * Verify that returned field position indices are correct.
503  */
TestFieldPosition()504 void DateFormatTest::TestFieldPosition() {
505     UErrorCode ec = U_ZERO_ERROR;
506     int32_t i, j, exp;
507     UnicodeString buf;
508 
509     // Verify data
510     DateFormatSymbols rootSyms(Locale(""), ec);
511     if (U_FAILURE(ec)) {
512         dataerrln("Unable to create DateFormatSymbols - %s", u_errorName(ec));
513         return;
514     }
515 
516     // local pattern chars data is not longer loaded
517     // from icu locale bundle
518     assertEquals("patternChars", PATTERN_CHARS, rootSyms.getLocalPatternChars(buf));
519     assertEquals("patternChars", PATTERN_CHARS, DateFormatSymbols::getPatternUChars());
520     assertTrue("DATEFORMAT_FIELD_NAMES", DATEFORMAT_FIELD_NAMES_LENGTH == UDAT_FIELD_COUNT);
521 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
522     assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS));
523 #else
524     assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS) + 1); // +1 for missing TIME_SEPARATOR pattern char
525 #endif
526 
527     // Create test formatters
528     const int32_t COUNT = 4;
529     DateFormat* dateFormats[COUNT];
530     dateFormats[0] = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale::getUS());
531     dateFormats[1] = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale::getFrance());
532     // Make the pattern "G y M d..."
533     buf.remove().append(PATTERN_CHARS);
534     for (j=buf.length()-1; j>=0; --j) buf.insert(j, (UChar)32/*' '*/);
535     dateFormats[2] = new SimpleDateFormat(buf, Locale::getUS(), ec);
536     // Make the pattern "GGGG yyyy MMMM dddd..."
537     for (j=buf.length()-1; j>=0; j-=2) {
538         for (i=0; i<3; ++i) {
539             buf.insert(j, buf.charAt(j));
540         }
541     }
542     dateFormats[3] = new SimpleDateFormat(buf, Locale::getUS(), ec);
543     if(U_FAILURE(ec)){
544         errln(UnicodeString("Could not create SimpleDateFormat object for locale en_US. Error: " )+ UnicodeString(u_errorName(ec)));
545         return;
546     }
547     UDate aug13 = 871508052513.0;
548 
549     // Expected output field values for above DateFormats on aug13
550     // Fields are given in order of DateFormat field number
551     const char* EXPECTED[] = {
552         "", "1997", "August", "13", "", "", "34", "12", "", "Wednesday",
553         "", "", "", "", "PM", "2", "", "Pacific Daylight Time", "", "",
554         "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
555 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
556         ":",
557 #else
558         "",
559 #endif
560 
561         "", "1997", "ao\\u00FBt", "13", "", "14", "34", "12", "", "mercredi",
562         "", "", "", "", "", "", "", "heure d\\u2019\\u00E9t\\u00E9 du Pacifique", "", "",
563         "", "", "", "", "",  "", "", "", "", "", "", "", "", "", "", "", "",
564 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
565         ":",
566 #else
567         "",
568 #endif
569 
570         "AD", "1997", "8", "13", "14", "14", "34", "12", "5", "Wed",
571         "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4",
572         "1997", "2450674", "52452513", "-0700", "PT",  "4", "8", "3", "3", "uslax",
573         "1997", "GMT-7", "-07", "-07", "1997", "PM", "in the afternoon",
574 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
575         ":",
576 #else
577         "",
578 #endif
579 
580         "Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130", "Wednesday",
581         "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday",
582         "1997", "2450674", "52452513", "GMT-07:00", "Pacific Time",  "Wednesday", "August", "3rd quarter", "3rd quarter", "Los Angeles Time",
583         "1997", "GMT-07:00", "-0700", "-0700", "1997", "PM", "in the afternoon",
584 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
585         ":",
586 #else
587         "",
588 #endif
589     };
590 
591     const int32_t EXPECTED_LENGTH = UPRV_LENGTHOF(EXPECTED);
592 
593     assertTrue("data size", EXPECTED_LENGTH == COUNT * UDAT_FIELD_COUNT);
594 
595     TimeZone* PT = TimeZone::createTimeZone("America/Los_Angeles");
596     for (j = 0, exp = 0; j < COUNT; ++j) {
597         //  String str;
598         DateFormat* df = dateFormats[j];
599         df->setTimeZone(*PT);
600         SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(df);
601         if (sdtfmt != NULL) {
602             logln(" Pattern = " + sdtfmt->toPattern(buf.remove()));
603         } else {
604             logln(" Pattern = ? (not a SimpleDateFormat)");
605         }
606         logln((UnicodeString)"  Result = " + df->format(aug13, buf.remove()));
607 
608         int32_t expBase = exp; // save for later
609         for (i = 0; i < UDAT_FIELD_COUNT; ++i, ++exp) {
610             FieldPosition pos(i);
611             buf.remove();
612             df->format(aug13, buf, pos);
613             UnicodeString field;
614             buf.extractBetween(pos.getBeginIndex(), pos.getEndIndex(), field);
615             assertEquals((UnicodeString)"field #" + i + " " + DATEFORMAT_FIELD_NAMES[i],
616                          ctou(EXPECTED[exp]), field);
617         }
618 
619         // test FieldPositionIterator API
620         logln("FieldPositionIterator");
621         {
622           UErrorCode status = U_ZERO_ERROR;
623           FieldPositionIterator posIter;
624           FieldPosition fp;
625 
626           buf.remove();
627           df->format(aug13, buf, &posIter, status);
628           while (posIter.next(fp)) {
629             int32_t i = fp.getField();
630             UnicodeString field;
631             buf.extractBetween(fp.getBeginIndex(), fp.getEndIndex(), field);
632             assertEquals((UnicodeString)"field #" + i + " " + DATEFORMAT_FIELD_NAMES[i],
633                          ctou(EXPECTED[expBase + i]), field);
634           }
635 
636         }
637     }
638 
639 
640     // test null posIter
641     buf.remove();
642     UErrorCode status = U_ZERO_ERROR;
643     dateFormats[0]->format(aug13, buf, NULL, status);
644     // if we didn't crash, we succeeded.
645 
646     for (i=0; i<COUNT; ++i) {
647         delete dateFormats[i];
648     }
649     delete PT;
650 }
651 
652 // -------------------------------------
653 
654 /**
655  * General parse/format tests.  Add test cases as needed.
656  */
TestGeneral()657 void DateFormatTest::TestGeneral() {
658     const char* DATA[] = {
659         "yyyy MM dd HH:mm:ss.SSS",
660 
661         // Milliseconds are left-justified, since they format as fractions of a second
662         "y/M/d H:mm:ss.S", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5", "2004 03 10 16:36:31.500",
663         "y/M/d H:mm:ss.SS", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.56", "2004 03 10 16:36:31.560",
664         "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567",
665         "y/M/d H:mm:ss.SSSS", "pf", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5670",
666     };
667     expect(DATA, UPRV_LENGTHOF(DATA), Locale("en", "", ""));
668 }
669 
670 // -------------------------------------
671 
672 /**
673  * Verify that strings which contain incomplete specifications are parsed
674  * correctly.  In some instances, this means not being parsed at all, and
675  * returning an appropriate error.
676  */
677 void
TestPartialParse994()678 DateFormatTest::TestPartialParse994()
679 {
680     UErrorCode status = U_ZERO_ERROR;
681     SimpleDateFormat* f = new SimpleDateFormat(status);
682     if (U_FAILURE(status)) {
683         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
684         delete f;
685         return;
686     }
687     UDate null = 0;
688     tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:11:42", date(97, 1 - 1, 17, 10, 11, 42));
689     tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:", null);
690     tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10", null);
691     tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 ", null);
692     tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17", null);
693     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
694     delete f;
695 }
696 
697 // -------------------------------------
698 
699 void
tryPat994(SimpleDateFormat * format,const char * pat,const char * str,UDate expected)700 DateFormatTest::tryPat994(SimpleDateFormat* format, const char* pat, const char* str, UDate expected)
701 {
702     UErrorCode status = U_ZERO_ERROR;
703     UDate null = 0;
704     logln(UnicodeString("Pattern \"") + pat + "\"   String \"" + str + "\"");
705     //try {
706         format->applyPattern(pat);
707         UDate date = format->parse(str, status);
708         if (U_FAILURE(status) || date == null)
709         {
710             logln((UnicodeString)"ParseException: " + (int32_t)status);
711             if (expected != null) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
712         }
713         else
714         {
715             UnicodeString f;
716             ((DateFormat*)format)->format(date, f);
717             logln(UnicodeString(" parse(") + str + ") -> " + dateToString(date));
718             logln((UnicodeString)" format -> " + f);
719             if (expected == null ||
720                 !(date == expected)) errln((UnicodeString)"FAIL: Expected null");//" + expected);
721             if (!(f == str)) errln(UnicodeString("FAIL: Expected ") + str);
722         }
723     //}
724     //catch(ParseException e) {
725     //    logln((UnicodeString)"ParseException: " + e.getMessage());
726     //    if (expected != null) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
727     //}
728     //catch(Exception e) {
729     //    errln((UnicodeString)"*** Exception:");
730     //    e.printStackTrace();
731     //}
732 }
733 
734 // -------------------------------------
735 
736 /**
737  * Verify the behavior of patterns in which digits for different fields run together
738  * without intervening separators.
739  */
740 void
TestRunTogetherPattern985()741 DateFormatTest::TestRunTogetherPattern985()
742 {
743     UErrorCode status = U_ZERO_ERROR;
744     UnicodeString format("yyyyMMddHHmmssSSS");
745     UnicodeString now, then;
746     //UBool flag;
747     SimpleDateFormat *formatter = new SimpleDateFormat(format, status);
748     if (U_FAILURE(status)) {
749         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
750         delete formatter;
751         return;
752     }
753     UDate date1 = Calendar::getNow();
754     ((DateFormat*)formatter)->format(date1, now);
755     logln(now);
756     ParsePosition pos(0);
757     UDate date2 = formatter->parse(now, pos);
758     if (date2 == 0) then = UnicodeString("Parse stopped at ") + pos.getIndex();
759     else ((DateFormat*)formatter)->format(date2, then);
760     logln(then);
761     if (!(date2 == date1)) errln((UnicodeString)"FAIL");
762     delete formatter;
763     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
764 }
765 
766 // -------------------------------------
767 
768 /**
769  * Verify the behavior of patterns in which digits for different fields run together
770  * without intervening separators.
771  */
772 void
TestRunTogetherPattern917()773 DateFormatTest::TestRunTogetherPattern917()
774 {
775     UErrorCode status = U_ZERO_ERROR;
776     SimpleDateFormat* fmt;
777     UnicodeString myDate;
778     fmt = new SimpleDateFormat((UnicodeString)"yyyy/MM/dd", status);
779     if (U_FAILURE(status)) {
780         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
781         delete fmt;
782         return;
783     }
784     myDate = "1997/02/03";
785     testIt917(fmt, myDate, date(97, 2 - 1, 3));
786     delete fmt;
787     fmt = new SimpleDateFormat((UnicodeString)"yyyyMMdd", status);
788     myDate = "19970304";
789     testIt917(fmt, myDate, date(97, 3 - 1, 4));
790     delete fmt;
791     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
792 }
793 
794 // -------------------------------------
795 
796 void
testIt917(SimpleDateFormat * fmt,UnicodeString & str,UDate expected)797 DateFormatTest::testIt917(SimpleDateFormat* fmt, UnicodeString& str, UDate expected)
798 {
799     UErrorCode status = U_ZERO_ERROR;
800     UnicodeString pattern;
801     logln((UnicodeString)"pattern=" + fmt->toPattern(pattern) + "   string=" + str);
802     Formattable o;
803     //try {
804         ((Format*)fmt)->parseObject(str, o, status);
805     //}
806     if (U_FAILURE(status)) return;
807     //catch(ParseException e) {
808     //    e.printStackTrace();
809     //    return;
810     //}
811     logln((UnicodeString)"Parsed object: " + dateToString(o.getDate()));
812     if (!(o.getDate() == expected)) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
813     UnicodeString formatted; ((Format*)fmt)->format(o, formatted, status);
814     logln((UnicodeString)"Formatted string: " + formatted);
815     if (!(formatted == str)) errln((UnicodeString)"FAIL: Expected " + str);
816     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
817 }
818 
819 // -------------------------------------
820 
821 /**
822  * Verify the handling of Czech June and July, which have the unique attribute that
823  * one is a proper prefix substring of the other.
824  */
825 void
TestCzechMonths459()826 DateFormatTest::TestCzechMonths459()
827 {
828     UErrorCode status = U_ZERO_ERROR;
829     DateFormat* fmt = DateFormat::createDateInstance(DateFormat::FULL, Locale("cs", "", ""));
830     if (fmt == NULL){
831         dataerrln("Error calling DateFormat::createDateInstance()");
832         return;
833     }
834 
835     UnicodeString pattern;
836     logln((UnicodeString)"Pattern " + ((SimpleDateFormat*) fmt)->toPattern(pattern));
837     UDate june = date(97, UCAL_JUNE, 15);
838     UDate july = date(97, UCAL_JULY, 15);
839     UnicodeString juneStr; fmt->format(june, juneStr);
840     UnicodeString julyStr; fmt->format(july, julyStr);
841     //try {
842         logln((UnicodeString)"format(June 15 1997) = " + juneStr);
843         UDate d = fmt->parse(juneStr, status);
844         UnicodeString s; fmt->format(d, s);
845         int32_t month,yr,day,hr,min,sec; dateToFields(d,yr,month,day,hr,min,sec);
846         logln((UnicodeString)"  -> parse -> " + s + " (month = " + month + ")");
847         if (month != UCAL_JUNE) errln((UnicodeString)"FAIL: Month should be June");
848         logln((UnicodeString)"format(July 15 1997) = " + julyStr);
849         d = fmt->parse(julyStr, status);
850         fmt->format(d, s);
851         dateToFields(d,yr,month,day,hr,min,sec);
852         logln((UnicodeString)"  -> parse -> " + s + " (month = " + month + ")");
853         if (month != UCAL_JULY) errln((UnicodeString)"FAIL: Month should be July");
854     //}
855     //catch(ParseException e) {
856     if (U_FAILURE(status))
857         errln((UnicodeString)"Exception: " + (int32_t)status);
858     //}
859     delete fmt;
860 }
861 
862 // -------------------------------------
863 
864 /**
865  * Test the handling of 'D' in patterns.
866  */
867 void
TestLetterDPattern212()868 DateFormatTest::TestLetterDPattern212()
869 {
870     UErrorCode status = U_ZERO_ERROR;
871     UnicodeString dateString("1995-040.05:01:29");
872     UnicodeString bigD("yyyy-DDD.hh:mm:ss");
873     UnicodeString littleD("yyyy-ddd.hh:mm:ss");
874     UDate expLittleD = date(95, 0, 1, 5, 1, 29);
875     UDate expBigD = expLittleD + 39 * 24 * 3600000.0;
876     expLittleD = expBigD; // Expect the same, with default lenient parsing
877     logln((UnicodeString)"dateString= " + dateString);
878     SimpleDateFormat *formatter = new SimpleDateFormat(bigD, status);
879     if (U_FAILURE(status)) {
880         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
881         delete formatter;
882         return;
883     }
884     ParsePosition pos(0);
885     UDate myDate = formatter->parse(dateString, pos);
886     logln((UnicodeString)"Using " + bigD + " -> " + myDate);
887     if (myDate != expBigD) errln((UnicodeString)"FAIL: bigD - Expected " + dateToString(expBigD));
888     delete formatter;
889     formatter = new SimpleDateFormat(littleD, status);
890     ASSERT_OK(status);
891     pos = ParsePosition(0);
892     myDate = formatter->parse(dateString, pos);
893     logln((UnicodeString)"Using " + littleD + " -> " + dateToString(myDate));
894     if (myDate != expLittleD) errln((UnicodeString)"FAIL: littleD - Expected " + dateToString(expLittleD));
895     delete formatter;
896     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
897 }
898 
899 // -------------------------------------
900 
901 /**
902  * Test the day of year pattern.
903  */
904 void
TestDayOfYearPattern195()905 DateFormatTest::TestDayOfYearPattern195()
906 {
907     UErrorCode status = U_ZERO_ERROR;
908     UDate today = Calendar::getNow();
909     int32_t year,month,day,hour,min,sec; dateToFields(today,year,month,day,hour,min,sec);
910     UDate expected = date(year, month, day);
911     logln((UnicodeString)"Test Date: " + dateToString(today));
912     SimpleDateFormat* sdf = (SimpleDateFormat*)DateFormat::createDateInstance();
913     if (sdf == NULL){
914         dataerrln("Error calling DateFormat::createDateInstance()");
915         return;
916     }
917     tryPattern(*sdf, today, 0, expected);
918     tryPattern(*sdf, today, "G yyyy DDD", expected);
919     delete sdf;
920     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
921 }
922 
923 // -------------------------------------
924 
925 void
tryPattern(SimpleDateFormat & sdf,UDate d,const char * pattern,UDate expected)926 DateFormatTest::tryPattern(SimpleDateFormat& sdf, UDate d, const char* pattern, UDate expected)
927 {
928     UErrorCode status = U_ZERO_ERROR;
929     if (pattern != 0) sdf.applyPattern(pattern);
930     UnicodeString thePat;
931     logln((UnicodeString)"pattern: " + sdf.toPattern(thePat));
932     UnicodeString formatResult; (*(DateFormat*)&sdf).format(d, formatResult);
933     logln((UnicodeString)" format -> " + formatResult);
934     // try {
935         UDate d2 = sdf.parse(formatResult, status);
936         logln((UnicodeString)" parse(" + formatResult + ") -> " + dateToString(d2));
937         if (d2 != expected) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
938         UnicodeString format2; (*(DateFormat*)&sdf).format(d2, format2);
939         logln((UnicodeString)" format -> " + format2);
940         if (!(formatResult == format2)) errln((UnicodeString)"FAIL: Round trip drift");
941     //}
942     //catch(Exception e) {
943     if (U_FAILURE(status))
944         errln((UnicodeString)"Error: " + (int32_t)status);
945     //}
946 }
947 
948 // -------------------------------------
949 
950 /**
951  * Test the handling of single quotes in patterns.
952  */
953 void
TestQuotePattern161()954 DateFormatTest::TestQuotePattern161()
955 {
956     UErrorCode status = U_ZERO_ERROR;
957     SimpleDateFormat* formatter = new SimpleDateFormat((UnicodeString)"MM/dd/yyyy 'at' hh:mm:ss a zzz", status);
958     if (U_FAILURE(status)) {
959         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
960         delete formatter;
961         return;
962     }
963     UDate currentTime_1 = date(97, UCAL_AUGUST, 13, 10, 42, 28);
964     UnicodeString dateString; ((DateFormat*)formatter)->format(currentTime_1, dateString);
965     UnicodeString exp("08/13/1997 at 10:42:28 AM ");
966     logln((UnicodeString)"format(" + dateToString(currentTime_1) + ") = " + dateString);
967     if (0 != dateString.compareBetween(0, exp.length(), exp, 0, exp.length())) errln((UnicodeString)"FAIL: Expected " + exp);
968     delete formatter;
969     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
970 }
971 
972 // -------------------------------------
973 
974 /**
975  * Verify the correct behavior when handling invalid input strings.
976  */
977 void
TestBadInput135()978 DateFormatTest::TestBadInput135()
979 {
980     UErrorCode status = U_ZERO_ERROR;
981     DateFormat::EStyle looks[] = {
982         DateFormat::SHORT, DateFormat::MEDIUM, DateFormat::LONG, DateFormat::FULL
983     };
984     int32_t looks_length = UPRV_LENGTHOF(looks);
985     const char* strings[] = {
986         "Mar 15", "Mar 15 1997", "asdf", "3/1/97 1:23:", "3/1/00 1:23:45 AM"
987     };
988     int32_t strings_length = UPRV_LENGTHOF(strings);
989     DateFormat *full = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::LONG);
990     if(full==NULL) {
991       dataerrln("could not create date time instance");
992       return;
993     }
994     UnicodeString expected("March 1, 2000 at 1:23:45 AM ");
995     for (int32_t i = 0; i < strings_length;++i) {
996         const char* text = strings[i];
997         for (int32_t j = 0; j < looks_length;++j) {
998             DateFormat::EStyle dateLook = looks[j];
999             for (int32_t k = 0; k < looks_length;++k) {
1000                 DateFormat::EStyle timeLook = looks[k];
1001                 DateFormat *df = DateFormat::createDateTimeInstance(dateLook, timeLook);
1002                 if (df == NULL){
1003                     dataerrln("Error calling DateFormat::createDateTimeInstance()");
1004                     continue;
1005                 }
1006                 UnicodeString prefix = UnicodeString(text) + ", " + dateLook + "/" + timeLook + ": ";
1007                 //try {
1008                     UDate when = df->parse(text, status);
1009                     if (when == 0 && U_SUCCESS(status)) {
1010                         errln(prefix + "SHOULD NOT HAPPEN: parse returned 0.");
1011                         continue;
1012                     }
1013                     if (U_SUCCESS(status))
1014                     {
1015                         UnicodeString format;
1016                         UnicodeString pattern;
1017                         SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(df);
1018                         if (sdtfmt != NULL) {
1019                             sdtfmt->toPattern(pattern);
1020                         }
1021                         full->format(when, format);
1022                         logln(prefix + "OK: " + format);
1023                         if (0!=format.compareBetween(0, expected.length(), expected, 0, expected.length()))
1024                             errln((UnicodeString)"FAIL: Parse \"" + text + "\", pattern \"" + pattern + "\", expected " + expected + " got " + format);
1025                     }
1026                 //}
1027                 //catch(ParseException e) {
1028                     else
1029                         status = U_ZERO_ERROR;
1030                 //}
1031                 //catch(StringIndexOutOfBoundsException e) {
1032                 //    errln(prefix + "SHOULD NOT HAPPEN: " + (int)status);
1033                 //}
1034                 delete df;
1035             }
1036         }
1037     }
1038     delete full;
1039     if (U_FAILURE(status))
1040         errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
1041 }
1042 
1043 static const char* const parseFormats[] = {
1044     "MMMM d, yyyy",
1045     "MMMM d yyyy",
1046     "M/d/yy",
1047     "d MMMM, yyyy",
1048     "d MMMM yyyy",
1049     "d MMMM",
1050     "MMMM d",
1051     "yyyy",
1052     "h:mm a MMMM d, yyyy"
1053 };
1054 
1055 #if 0
1056 // strict inputStrings
1057 static const char* const inputStrings[] = {
1058     "bogus string", 0, 0, 0, 0, 0, 0, 0, 0, 0,
1059     "April 1, 1997", "April 1, 1997", 0, 0, 0, 0, 0, "April 1", 0, 0,
1060     "Jan 1, 1970", "January 1, 1970", 0, 0, 0, 0, 0, "January 1", 0, 0,
1061     "Jan 1 2037", 0, "January 1 2037", 0, 0, 0, 0, "January 1", 0, 0,
1062     "1/1/70", 0, 0, "1/1/70", 0, 0, 0, 0, "0001", 0,
1063     "5 May 1997", 0, 0, 0, 0, "5 May 1997", "5 May", 0, "0005", 0,
1064     "16 May", 0, 0, 0, 0, 0, "16 May", 0, "0016", 0,
1065     "April 30", 0, 0, 0, 0, 0, 0, "April 30", 0, 0,
1066     "1998", 0, 0, 0, 0, 0, 0, 0, "1998", 0,
1067     "1", 0, 0, 0, 0, 0, 0, 0, "0001", 0,
1068     "3:00 pm Jan 1, 1997", 0, 0, 0, 0, 0, 0, 0, "0003", "3:00 PM January 1, 1997",
1069 };
1070 #else
1071 // lenient inputStrings
1072 static const char* const inputStrings[] = {
1073     "bogus string", 0, 0, 0, 0, 0, 0, 0, 0, 0,
1074     "April 1, 1997", "April 1, 1997", "April 1 1997", "4/1/97", 0, 0, 0, "April 1", 0, 0,
1075     "Jan 1, 1970", "January 1, 1970", "January 1 1970", "1/1/70", 0, 0, 0, "January 1", 0, 0,
1076     "Jan 1 2037", "January 1, 2037", "January 1 2037", "1/1/37", 0, 0, 0, "January 1", 0, 0,
1077     "1/1/70", "January 1, 0070", "January 1 0070", "1/1/70", "1 January, 0070", "1 January 0070", "1 January", "January 1", "0001", 0,
1078     "5 May 1997", 0, 0, 0, "5 May, 1997", "5 May 1997", "5 May", 0, "0005", 0,
1079     "16 May", 0, 0, 0, 0, 0, "16 May", 0, "0016", 0,
1080     "April 30", 0, 0, 0, 0, 0, 0, "April 30", 0, 0,
1081     "1998", 0, 0, 0, 0, 0, 0, 0, "1998", 0,
1082     "1", 0, 0, 0, 0, 0, 0, 0, "0001", 0,
1083     "3:00 pm Jan 1, 1997", 0, 0, 0, 0, 0, 0, 0, "0003", "3:00 PM January 1, 1997",
1084 };
1085 #endif
1086 
1087 // -------------------------------------
1088 
1089 /**
1090  * Verify the correct behavior when parsing an array of inputs against an
1091  * array of patterns, with known results.  The results are encoded after
1092  * the input strings in each row.
1093  */
1094 void
TestBadInput135a()1095 DateFormatTest::TestBadInput135a()
1096 {
1097   UErrorCode status = U_ZERO_ERROR;
1098   SimpleDateFormat* dateParse = new SimpleDateFormat(status);
1099   if(U_FAILURE(status)) {
1100     dataerrln("Failed creating SimpleDateFormat with %s. Quitting test", u_errorName(status));
1101     delete dateParse;
1102     return;
1103   }
1104   const char* s;
1105   UDate date;
1106   const uint32_t PF_LENGTH = UPRV_LENGTHOF(parseFormats);
1107   const uint32_t INPUT_LENGTH = UPRV_LENGTHOF(inputStrings);
1108 
1109   dateParse->applyPattern("d MMMM, yyyy");
1110   dateParse->adoptTimeZone(TimeZone::createDefault());
1111   s = "not parseable";
1112   UnicodeString thePat;
1113   logln(UnicodeString("Trying to parse \"") + s + "\" with " + dateParse->toPattern(thePat));
1114   //try {
1115   date = dateParse->parse(s, status);
1116   if (U_SUCCESS(status))
1117     errln((UnicodeString)"FAIL: Expected exception during parse");
1118   //}
1119   //catch(Exception ex) {
1120   else
1121     logln((UnicodeString)"Exception during parse: " + (int32_t)status);
1122   status = U_ZERO_ERROR;
1123   //}
1124   for (uint32_t i = 0; i < INPUT_LENGTH; i += (PF_LENGTH + 1)) {
1125     ParsePosition parsePosition(0);
1126     UnicodeString s( inputStrings[i]);
1127     for (uint32_t index = 0; index < PF_LENGTH;++index) {
1128       const char* expected = inputStrings[i + 1 + index];
1129       dateParse->applyPattern(parseFormats[index]);
1130       dateParse->adoptTimeZone(TimeZone::createDefault());
1131       //try {
1132       parsePosition.setIndex(0);
1133       date = dateParse->parse(s, parsePosition);
1134       if (parsePosition.getIndex() != 0) {
1135         UnicodeString s1, s2;
1136         s.extract(0, parsePosition.getIndex(), s1);
1137         s.extract(parsePosition.getIndex(), s.length(), s2);
1138         if (date == 0) {
1139           errln((UnicodeString)"ERROR: null result fmt=\"" +
1140                      parseFormats[index] +
1141                      "\" pos=" + parsePosition.getIndex() + " " +
1142                      s1 + "|" + s2);
1143         }
1144         else {
1145           UnicodeString result;
1146           ((DateFormat*)dateParse)->format(date, result);
1147           logln((UnicodeString)"Parsed \"" + s + "\" using \"" + dateParse->toPattern(thePat) + "\" to: " + result);
1148           if (expected == 0)
1149             errln((UnicodeString)"FAIL: Expected parse failure, got " + result);
1150           else if (!(result == expected))
1151             errln(UnicodeString("FAIL: Parse \"") + s + UnicodeString("\", expected ") + expected + UnicodeString(", got ") + result);
1152         }
1153       }
1154       else if (expected != 0) {
1155         errln(UnicodeString("FAIL: Expected ") + expected + " from \"" +
1156                      s + "\" with \"" + dateParse->toPattern(thePat) + "\"");
1157       }
1158       //}
1159       //catch(Exception ex) {
1160       if (U_FAILURE(status))
1161         errln((UnicodeString)"An exception was thrown during parse: " + (int32_t)status);
1162       //}
1163     }
1164   }
1165   delete dateParse;
1166   if (U_FAILURE(status))
1167     errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
1168 }
1169 
1170 // -------------------------------------
1171 
1172 /**
1173  * Test the parsing of two-digit years.
1174  */
1175 void
TestTwoDigitYear()1176 DateFormatTest::TestTwoDigitYear()
1177 {
1178     UErrorCode ec = U_ZERO_ERROR;
1179     SimpleDateFormat fmt("dd/MM/yy", Locale::getUK(), ec);
1180     if (U_FAILURE(ec)) {
1181         dataerrln("FAIL: SimpleDateFormat constructor - %s", u_errorName(ec));
1182         return;
1183     }
1184     parse2DigitYear(fmt, "5/6/30", date(130, UCAL_JUNE, 5));
1185     parse2DigitYear(fmt, "4/6/50", date(50, UCAL_JUNE, 4));
1186 }
1187 
1188 // -------------------------------------
1189 
1190 void
parse2DigitYear(DateFormat & fmt,const char * str,UDate expected)1191 DateFormatTest::parse2DigitYear(DateFormat& fmt, const char* str, UDate expected)
1192 {
1193     UErrorCode status = U_ZERO_ERROR;
1194     //try {
1195         UDate d = fmt.parse(str, status);
1196         UnicodeString thePat;
1197         logln(UnicodeString("Parsing \"") + str + "\" with " + ((SimpleDateFormat*)&fmt)->toPattern(thePat) +
1198             "  => " + dateToString(d));
1199         if (d != expected) errln((UnicodeString)"FAIL: Expected " + expected);
1200     //}
1201     //catch(ParseException e) {
1202         if (U_FAILURE(status))
1203         errln((UnicodeString)"FAIL: Got exception");
1204     //}
1205 }
1206 
1207 // -------------------------------------
1208 
1209 /**
1210  * Test the formatting of time zones.
1211  */
1212 void
TestDateFormatZone061()1213 DateFormatTest::TestDateFormatZone061()
1214 {
1215     UErrorCode status = U_ZERO_ERROR;
1216     UDate date;
1217     DateFormat *formatter;
1218     date= 859248000000.0;
1219     logln((UnicodeString)"Date 1997/3/25 00:00 GMT: " + date);
1220     formatter = new SimpleDateFormat((UnicodeString)"dd-MMM-yyyyy HH:mm", Locale::getUK(), status);
1221     if(U_FAILURE(status)) {
1222       dataerrln("Failed creating SimpleDateFormat with %s. Quitting test", u_errorName(status));
1223       delete formatter;
1224       return;
1225     }
1226     formatter->adoptTimeZone(TimeZone::createTimeZone("GMT"));
1227     UnicodeString temp; formatter->format(date, temp);
1228     logln((UnicodeString)"Formatted in GMT to: " + temp);
1229     //try {
1230         UDate tempDate = formatter->parse(temp, status);
1231         logln((UnicodeString)"Parsed to: " + dateToString(tempDate));
1232         if (tempDate != date) errln((UnicodeString)"FAIL: Expected " + dateToString(date));
1233     //}
1234     //catch(Throwable t) {
1235     if (U_FAILURE(status))
1236         errln((UnicodeString)"Date Formatter throws: " + (int32_t)status);
1237     //}
1238     delete formatter;
1239 }
1240 
1241 // -------------------------------------
1242 
1243 /**
1244  * Test the formatting of time zones.
1245  */
1246 void
TestDateFormatZone146()1247 DateFormatTest::TestDateFormatZone146()
1248 {
1249     TimeZone *saveDefault = TimeZone::createDefault();
1250 
1251         //try {
1252     TimeZone *thedefault = TimeZone::createTimeZone("GMT");
1253     TimeZone::setDefault(*thedefault);
1254             // java.util.Locale.setDefault(new java.util.Locale("ar", "", ""));
1255 
1256             // check to be sure... its GMT all right
1257         TimeZone *testdefault = TimeZone::createDefault();
1258         UnicodeString testtimezone;
1259         testdefault->getID(testtimezone);
1260         if (testtimezone == "GMT")
1261             logln("Test timezone = " + testtimezone);
1262         else
1263             dataerrln("Test timezone should be GMT, not " + testtimezone);
1264 
1265         UErrorCode status = U_ZERO_ERROR;
1266         // now try to use the default GMT time zone
1267         GregorianCalendar *greenwichcalendar =
1268             new GregorianCalendar(1997, 3, 4, 23, 0, status);
1269         if (U_FAILURE(status)) {
1270             dataerrln("Fail new GregorianCalendar: %s", u_errorName(status));
1271         } else {
1272             //*****************************greenwichcalendar.setTimeZone(TimeZone.getDefault());
1273             //greenwichcalendar.set(1997, 3, 4, 23, 0);
1274             // try anything to set hour to 23:00 !!!
1275             greenwichcalendar->set(UCAL_HOUR_OF_DAY, 23);
1276             // get time
1277             UDate greenwichdate = greenwichcalendar->getTime(status);
1278             // format every way
1279             UnicodeString DATA [] = {
1280                 UnicodeString("simple format:  "), UnicodeString("04/04/97 23:00 GMT"),
1281                     UnicodeString("MM/dd/yy HH:mm z"),
1282                 UnicodeString("full format:    "), UnicodeString("Friday, April 4, 1997 11:00:00 o'clock PM GMT"),
1283                     UnicodeString("EEEE, MMMM d, yyyy h:mm:ss 'o''clock' a z"),
1284                 UnicodeString("long format:    "), UnicodeString("April 4, 1997 11:00:00 PM GMT"),
1285                     UnicodeString("MMMM d, yyyy h:mm:ss a z"),
1286                 UnicodeString("default format: "), UnicodeString("04-Apr-97 11:00:00 PM"),
1287                     UnicodeString("dd-MMM-yy h:mm:ss a"),
1288                 UnicodeString("short format:   "), UnicodeString("4/4/97 11:00 PM"),
1289                     UnicodeString("M/d/yy h:mm a")
1290             };
1291             int32_t DATA_length = UPRV_LENGTHOF(DATA);
1292 
1293             for (int32_t i=0; i<DATA_length; i+=3) {
1294                 SimpleDateFormat fmt(DATA[i+2], Locale::getEnglish(), status);
1295                 if (U_FAILURE(status)) {
1296                     dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
1297                     break;
1298                 }
1299                 fmt.setCalendar(*greenwichcalendar);
1300                 UnicodeString result;
1301                 result = fmt.format(greenwichdate, result);
1302                 logln(DATA[i] + result);
1303                 if (result != DATA[i+1])
1304                     errln("FAIL: Expected " + DATA[i+1] + ", got " + result);
1305             }
1306         }
1307     //}
1308     //finally {
1309         TimeZone::adoptDefault(saveDefault);
1310     //}
1311         delete testdefault;
1312         delete greenwichcalendar;
1313         delete thedefault;
1314 
1315 
1316 }
1317 
1318 // -------------------------------------
1319 
1320 /**
1321  * Test the formatting of dates in different locales.
1322  */
1323 void
TestLocaleDateFormat()1324 DateFormatTest::TestLocaleDateFormat() // Bug 495
1325 {
1326     UDate testDate = date(97, UCAL_SEPTEMBER, 15);
1327     DateFormat *dfFrench = DateFormat::createDateTimeInstance(DateFormat::FULL,
1328         DateFormat::FULL, Locale::getFrench());
1329     DateFormat *dfUS = DateFormat::createDateTimeInstance(DateFormat::FULL,
1330         DateFormat::FULL, Locale::getUS());
1331     UnicodeString expectedFRENCH ( "lundi 15 septembre 1997 \\u00E0 00:00:00 heure d\\u2019\\u00E9t\\u00E9 du Pacifique", -1, US_INV );
1332     expectedFRENCH = expectedFRENCH.unescape();
1333     UnicodeString expectedUS ( "Monday, September 15, 1997 at 12:00:00 AM Pacific Daylight Time" );
1334     logln((UnicodeString)"Date set to : " + dateToString(testDate));
1335     UnicodeString out;
1336     if (dfUS == NULL || dfFrench == NULL){
1337         dataerrln("Error calling DateFormat::createDateTimeInstance)");
1338         delete dfUS;
1339         delete dfFrench;
1340         return;
1341     }
1342 
1343     dfFrench->format(testDate, out);
1344     logln((UnicodeString)"Date Formated with French Locale " + out);
1345     if (!(out == expectedFRENCH))
1346         errln((UnicodeString)"FAIL: Expected " + expectedFRENCH);
1347     out.truncate(0);
1348     dfUS->format(testDate, out);
1349     logln((UnicodeString)"Date Formated with US Locale " + out);
1350     if (!(out == expectedUS))
1351         errln((UnicodeString)"FAIL: Expected " + expectedUS);
1352     delete dfUS;
1353     delete dfFrench;
1354 }
1355 
1356 void
TestFormattingLocaleTimeSeparator()1357 DateFormatTest::TestFormattingLocaleTimeSeparator()
1358 {
1359     // This test not as useful as it once was, since timeSeparator
1360     // in the Arabic locale is changed back to ":" in CLDR 28.
1361     const UDate testDate = 874266720000.;  // Sun Sep 14 21:52:00 CET 1997
1362     logln((UnicodeString)"Date set to : " + dateToString(testDate));
1363 
1364     const LocalPointer<const TimeZone> tz(TimeZone::createTimeZone("CET"));
1365 
1366     const LocalPointer<DateFormat> dfArab(DateFormat::createTimeInstance(
1367             DateFormat::SHORT, Locale("ar", "EG")));
1368 
1369     const LocalPointer<DateFormat> dfLatn(DateFormat::createTimeInstance(
1370             DateFormat::SHORT, Locale("ar", "EG", NULL, "numbers=latn")));
1371 
1372     if (dfLatn.isNull() || dfArab.isNull()) {
1373         dataerrln("Error calling DateFormat::createTimeInstance()");
1374         return;
1375     }
1376 
1377     dfArab->setTimeZone(*tz);
1378     dfLatn->setTimeZone(*tz);
1379 
1380     const UnicodeString expectedArab = UnicodeString(
1381             "\\u0669:\\u0665\\u0662 \\u0645", -1, US_INV).unescape();
1382 
1383     const UnicodeString expectedLatn = UnicodeString(
1384             "9:52 \\u0645", -1, US_INV).unescape();
1385 
1386     UnicodeString actualArab;
1387     UnicodeString actualLatn;
1388 
1389     dfArab->format(testDate, actualArab);
1390     dfLatn->format(testDate, actualLatn);
1391 
1392     assertEquals("Arab", expectedArab, actualArab);
1393     assertEquals("Latn", expectedLatn, actualLatn);
1394 }
1395 
1396 /**
1397  * Test DateFormat(Calendar) API
1398  */
TestDateFormatCalendar()1399 void DateFormatTest::TestDateFormatCalendar() {
1400     DateFormat *date=0, *time=0, *full=0;
1401     Calendar *cal=0;
1402     UnicodeString str;
1403     ParsePosition pos;
1404     UDate when;
1405     UErrorCode ec = U_ZERO_ERROR;
1406 
1407     /* Create a formatter for date fields. */
1408     date = DateFormat::createDateInstance(DateFormat::kShort, Locale::getUS());
1409     if (date == NULL) {
1410         dataerrln("FAIL: createDateInstance failed");
1411         goto FAIL;
1412     }
1413 
1414     /* Create a formatter for time fields. */
1415     time = DateFormat::createTimeInstance(DateFormat::kShort, Locale::getUS());
1416     if (time == NULL) {
1417         errln("FAIL: createTimeInstance failed");
1418         goto FAIL;
1419     }
1420 
1421     /* Create a full format for output */
1422     full = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull,
1423                                               Locale::getUS());
1424     if (full == NULL) {
1425         errln("FAIL: createInstance failed");
1426         goto FAIL;
1427     }
1428 
1429     /* Create a calendar */
1430     cal = Calendar::createInstance(Locale::getUS(), ec);
1431     if (cal == NULL || U_FAILURE(ec)) {
1432         errln((UnicodeString)"FAIL: Calendar::createInstance failed with " +
1433               u_errorName(ec));
1434         goto FAIL;
1435     }
1436 
1437     /* Parse the date */
1438     cal->clear();
1439     str = UnicodeString("4/5/2001", "");
1440     pos.setIndex(0);
1441     date->parse(str, *cal, pos);
1442     if (pos.getIndex() != str.length()) {
1443         errln((UnicodeString)"FAIL: DateFormat::parse(4/5/2001) failed at " +
1444               pos.getIndex());
1445         goto FAIL;
1446     }
1447 
1448     /* Parse the time */
1449     str = UnicodeString("5:45 PM", "");
1450     pos.setIndex(0);
1451     time->parse(str, *cal, pos);
1452     if (pos.getIndex() != str.length()) {
1453         errln((UnicodeString)"FAIL: DateFormat::parse(17:45) failed at " +
1454               pos.getIndex());
1455         goto FAIL;
1456     }
1457 
1458     /* Check result */
1459     when = cal->getTime(ec);
1460     if (U_FAILURE(ec)) {
1461         errln((UnicodeString)"FAIL: cal->getTime() failed with " + u_errorName(ec));
1462         goto FAIL;
1463     }
1464     str.truncate(0);
1465     full->format(when, str);
1466     // Thursday, April 5, 2001 5:45:00 PM PDT 986517900000
1467     if (when == 986517900000.0) {
1468         logln("Ok: Parsed result: " + str);
1469     } else {
1470         errln("FAIL: Parsed result: " + str + ", exp 4/5/2001 5:45 PM");
1471     }
1472 
1473  FAIL:
1474     delete date;
1475     delete time;
1476     delete full;
1477     delete cal;
1478 }
1479 
1480 /**
1481  * Test DateFormat's parsing of space characters.  See jitterbug 1916.
1482  */
TestSpaceParsing()1483 void DateFormatTest::TestSpaceParsing() {
1484     const char* DATA[] = {
1485         "yyyy MM dd HH:mm:ss",
1486 
1487         // pattern, input, expected parse or NULL if expect parse failure
1488         "MMMM d yy", " 04 05 06",  "2006 04 05 00:00:00",
1489         NULL,        "04 05 06",   "2006 04 05 00:00:00",
1490 
1491         "MM d yy",   " 04 05 06",    "2006 04 05 00:00:00",
1492         NULL,        "04 05 06",     "2006 04 05 00:00:00",
1493         NULL,        "04/05/06",     "2006 04 05 00:00:00",
1494         NULL,        "04-05-06",     "2006 04 05 00:00:00",
1495         NULL,        "04.05.06",     "2006 04 05 00:00:00",
1496         NULL,        "04 / 05 / 06", "2006 04 05 00:00:00",
1497         NULL,        "Apr / 05/ 06", "2006 04 05 00:00:00",
1498         NULL,        "Apr-05-06",    "2006 04 05 00:00:00",
1499         NULL,        "Apr 05, 2006", "2006 04 05 00:00:00",
1500 
1501         "MMMM d yy", " Apr 05 06", "2006 04 05 00:00:00",
1502         NULL,        "Apr 05 06",  "2006 04 05 00:00:00",
1503         NULL,        "Apr05 06",   "2006 04 05 00:00:00",
1504 
1505         "hh:mm:ss a", "12:34:56 PM", "1970 01 01 12:34:56",
1506         NULL,         "12:34:56PM",  "1970 01 01 12:34:56",
1507         NULL,         "12.34.56PM",  "1970 01 01 12:34:56",
1508         NULL,         "12 : 34 : 56  PM", "1970 01 01 12:34:56",
1509 
1510         "MM d yy 'at' hh:mm:ss a", "04/05/06 12:34:56 PM", "2006 04 05 12:34:56",
1511 
1512         "MMMM dd yyyy hh:mm a", "September 27, 1964 21:56 PM", "1964 09 28 09:56:00",
1513         NULL,                   "November 4, 2008 0:13 AM",    "2008 11 04 00:13:00",
1514 
1515         "HH'h'mm'min'ss's'", "12h34min56s", "1970 01 01 12:34:56",
1516         NULL,                "12h34mi56s",  "1970 01 01 12:34:56",
1517         NULL,                "12h34m56s",   "1970 01 01 12:34:56",
1518         NULL,                "12:34:56",    "1970 01 01 12:34:56"
1519     };
1520     const int32_t DATA_len = UPRV_LENGTHOF(DATA);
1521 
1522     expectParse(DATA, DATA_len, Locale("en"));
1523 }
1524 
1525 /**
1526  * Test handling of "HHmmss" pattern.
1527  */
TestExactCountFormat()1528 void DateFormatTest::TestExactCountFormat() {
1529     const char* DATA[] = {
1530         "yyyy MM dd HH:mm:ss",
1531 
1532         // pattern, input, expected parse or NULL if expect parse failure
1533         "HHmmss", "123456", "1970 01 01 12:34:56",
1534         NULL,     "12345",  "1970 01 01 01:23:45",
1535         NULL,     "1234",   NULL,
1536         NULL,     "00-05",  NULL,
1537         NULL,     "12-34",  NULL,
1538         NULL,     "00+05",  NULL,
1539         "ahhmm",  "PM730",  "1970 01 01 19:30:00",
1540     };
1541     const int32_t DATA_len = UPRV_LENGTHOF(DATA);
1542 
1543     expectParse(DATA, DATA_len, Locale("en"));
1544 }
1545 
1546 /**
1547  * Test handling of white space.
1548  */
TestWhiteSpaceParsing()1549 void DateFormatTest::TestWhiteSpaceParsing() {
1550     const char* DATA[] = {
1551         "yyyy MM dd",
1552 
1553         // pattern, input, expected parse or null if expect parse failure
1554 
1555         // Pattern space run should parse input text space run
1556         "MM   d yy",   " 04 01 03",    "2003 04 01",
1557         NULL,          " 04  01   03 ", "2003 04 01",
1558     };
1559     const int32_t DATA_len = UPRV_LENGTHOF(DATA);
1560 
1561     expectParse(DATA, DATA_len, Locale("en"));
1562 }
1563 
1564 
TestInvalidPattern()1565 void DateFormatTest::TestInvalidPattern() {
1566     UErrorCode ec = U_ZERO_ERROR;
1567     SimpleDateFormat f(UnicodeString("Yesterday"), ec);
1568     if (U_FAILURE(ec)) {
1569         dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
1570         return;
1571     }
1572     UnicodeString out;
1573     FieldPosition pos;
1574     f.format((UDate)0, out, pos);
1575     logln(out);
1576     // The bug is that the call to format() will crash.  By not
1577     // crashing, the test passes.
1578 }
1579 
TestGreekMay()1580 void DateFormatTest::TestGreekMay() {
1581     UErrorCode ec = U_ZERO_ERROR;
1582     UDate date = -9896080848000.0;
1583     SimpleDateFormat fmt("EEEE, dd MMMM yyyy h:mm:ss a", Locale("el", "", ""), ec);
1584     if (U_FAILURE(ec)) {
1585         dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
1586         return;
1587     }
1588     UnicodeString str;
1589     fmt.format(date, str);
1590     ParsePosition pos(0);
1591     UDate d2 = fmt.parse(str, pos);
1592     if (date != d2) {
1593         errln("FAIL: unable to parse strings where case-folding changes length");
1594     }
1595 }
1596 
TestStandAloneMonths()1597 void DateFormatTest::TestStandAloneMonths()
1598 {
1599     const char *EN_DATA[] = {
1600         "yyyy MM dd HH:mm:ss",
1601 
1602         "yyyy LLLL dd H:mm:ss", "fp", "2004 03 10 16:36:31", "2004 March 10 16:36:31", "2004 03 10 16:36:31",
1603         "yyyy LLL dd H:mm:ss",  "fp", "2004 03 10 16:36:31", "2004 Mar 10 16:36:31",   "2004 03 10 16:36:31",
1604         "yyyy LLLL dd H:mm:ss", "F",  "2004 03 10 16:36:31", "2004 March 10 16:36:31",
1605         "yyyy LLL dd H:mm:ss",  "pf", "2004 Mar 10 16:36:31", "2004 03 10 16:36:31", "2004 Mar 10 16:36:31",
1606 
1607         "LLLL", "fp", "1970 01 01 0:00:00", "January",   "1970 01 01 0:00:00",
1608         "LLLL", "fp", "1970 02 01 0:00:00", "February",  "1970 02 01 0:00:00",
1609         "LLLL", "fp", "1970 03 01 0:00:00", "March",     "1970 03 01 0:00:00",
1610         "LLLL", "fp", "1970 04 01 0:00:00", "April",     "1970 04 01 0:00:00",
1611         "LLLL", "fp", "1970 05 01 0:00:00", "May",       "1970 05 01 0:00:00",
1612         "LLLL", "fp", "1970 06 01 0:00:00", "June",      "1970 06 01 0:00:00",
1613         "LLLL", "fp", "1970 07 01 0:00:00", "July",      "1970 07 01 0:00:00",
1614         "LLLL", "fp", "1970 08 01 0:00:00", "August",    "1970 08 01 0:00:00",
1615         "LLLL", "fp", "1970 09 01 0:00:00", "September", "1970 09 01 0:00:00",
1616         "LLLL", "fp", "1970 10 01 0:00:00", "October",   "1970 10 01 0:00:00",
1617         "LLLL", "fp", "1970 11 01 0:00:00", "November",  "1970 11 01 0:00:00",
1618         "LLLL", "fp", "1970 12 01 0:00:00", "December",  "1970 12 01 0:00:00",
1619 
1620         "LLL", "fp", "1970 01 01 0:00:00", "Jan", "1970 01 01 0:00:00",
1621         "LLL", "fp", "1970 02 01 0:00:00", "Feb", "1970 02 01 0:00:00",
1622         "LLL", "fp", "1970 03 01 0:00:00", "Mar", "1970 03 01 0:00:00",
1623         "LLL", "fp", "1970 04 01 0:00:00", "Apr", "1970 04 01 0:00:00",
1624         "LLL", "fp", "1970 05 01 0:00:00", "May", "1970 05 01 0:00:00",
1625         "LLL", "fp", "1970 06 01 0:00:00", "Jun", "1970 06 01 0:00:00",
1626         "LLL", "fp", "1970 07 01 0:00:00", "Jul", "1970 07 01 0:00:00",
1627         "LLL", "fp", "1970 08 01 0:00:00", "Aug", "1970 08 01 0:00:00",
1628         "LLL", "fp", "1970 09 01 0:00:00", "Sep", "1970 09 01 0:00:00",
1629         "LLL", "fp", "1970 10 01 0:00:00", "Oct", "1970 10 01 0:00:00",
1630         "LLL", "fp", "1970 11 01 0:00:00", "Nov", "1970 11 01 0:00:00",
1631         "LLL", "fp", "1970 12 01 0:00:00", "Dec", "1970 12 01 0:00:00",
1632     };
1633 
1634     const char *CS_DATA[] = {
1635         "yyyy MM dd HH:mm:ss",
1636 
1637         "yyyy LLLL dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 duben 10 16:36:31", "2004 04 10 16:36:31",
1638         "yyyy MMMM dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31", "2004 04 10 16:36:31",
1639         "yyyy LLL dd H:mm:ss",  "fp", "2004 04 10 16:36:31", "2004 dub 10 16:36:31",   "2004 04 10 16:36:31",
1640         "yyyy LLLL dd H:mm:ss", "F",  "2004 04 10 16:36:31", "2004 duben 10 16:36:31",
1641         "yyyy MMMM dd H:mm:ss", "F",  "2004 04 10 16:36:31", "2004 dubna 10 16:36:31",
1642         "yyyy LLLL dd H:mm:ss", "pf", "2004 duben 10 16:36:31", "2004 04 10 16:36:31", "2004 duben 10 16:36:31",
1643         "yyyy MMMM dd H:mm:ss", "pf", "2004 dubna 10 16:36:31", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31",
1644 
1645         "LLLL", "fp", "1970 01 01 0:00:00", "leden",               "1970 01 01 0:00:00",
1646         "LLLL", "fp", "1970 02 01 0:00:00", "\\u00FAnor",           "1970 02 01 0:00:00",
1647         "LLLL", "fp", "1970 03 01 0:00:00", "b\\u0159ezen",         "1970 03 01 0:00:00",
1648         "LLLL", "fp", "1970 04 01 0:00:00", "duben",               "1970 04 01 0:00:00",
1649         "LLLL", "fp", "1970 05 01 0:00:00", "kv\\u011Bten",         "1970 05 01 0:00:00",
1650         "LLLL", "fp", "1970 06 01 0:00:00", "\\u010Derven",         "1970 06 01 0:00:00",
1651         "LLLL", "fp", "1970 07 01 0:00:00", "\\u010Dervenec",       "1970 07 01 0:00:00",
1652         "LLLL", "fp", "1970 08 01 0:00:00", "srpen",               "1970 08 01 0:00:00",
1653         "LLLL", "fp", "1970 09 01 0:00:00", "z\\u00E1\\u0159\\u00ED", "1970 09 01 0:00:00",
1654         "LLLL", "fp", "1970 10 01 0:00:00", "\\u0159\\u00EDjen",     "1970 10 01 0:00:00",
1655         "LLLL", "fp", "1970 11 01 0:00:00", "listopad",            "1970 11 01 0:00:00",
1656         "LLLL", "fp", "1970 12 01 0:00:00", "prosinec",            "1970 12 01 0:00:00",
1657 
1658         "LLL", "fp", "1970 01 01 0:00:00", "led",  "1970 01 01 0:00:00",
1659         "LLL", "fp", "1970 02 01 0:00:00", "\\u00FAno",  "1970 02 01 0:00:00",
1660         "LLL", "fp", "1970 03 01 0:00:00", "b\\u0159e",  "1970 03 01 0:00:00",
1661         "LLL", "fp", "1970 04 01 0:00:00", "dub",  "1970 04 01 0:00:00",
1662         "LLL", "fp", "1970 05 01 0:00:00", "kv\\u011B",  "1970 05 01 0:00:00",
1663         "LLL", "fp", "1970 06 01 0:00:00", "\\u010Dvn",  "1970 06 01 0:00:00",
1664         "LLL", "fp", "1970 07 01 0:00:00", "\\u010Dvc",  "1970 07 01 0:00:00",
1665         "LLL", "fp", "1970 08 01 0:00:00", "srp",  "1970 08 01 0:00:00",
1666         "LLL", "fp", "1970 09 01 0:00:00", "z\\u00E1\\u0159",  "1970 09 01 0:00:00",
1667         "LLL", "fp", "1970 10 01 0:00:00", "\\u0159\\u00EDj", "1970 10 01 0:00:00",
1668         "LLL", "fp", "1970 11 01 0:00:00", "lis", "1970 11 01 0:00:00",
1669         "LLL", "fp", "1970 12 01 0:00:00", "pro", "1970 12 01 0:00:00",
1670     };
1671 
1672     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1673     expect(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
1674 }
1675 
TestStandAloneDays()1676 void DateFormatTest::TestStandAloneDays()
1677 {
1678     const char *EN_DATA[] = {
1679         "yyyy MM dd HH:mm:ss",
1680 
1681         "cccc", "fp", "1970 01 04 0:00:00", "Sunday",    "1970 01 04 0:00:00",
1682         "cccc", "fp", "1970 01 05 0:00:00", "Monday",    "1970 01 05 0:00:00",
1683         "cccc", "fp", "1970 01 06 0:00:00", "Tuesday",   "1970 01 06 0:00:00",
1684         "cccc", "fp", "1970 01 07 0:00:00", "Wednesday", "1970 01 07 0:00:00",
1685         "cccc", "fp", "1970 01 01 0:00:00", "Thursday",  "1970 01 01 0:00:00",
1686         "cccc", "fp", "1970 01 02 0:00:00", "Friday",    "1970 01 02 0:00:00",
1687         "cccc", "fp", "1970 01 03 0:00:00", "Saturday",  "1970 01 03 0:00:00",
1688 
1689         "ccc", "fp", "1970 01 04 0:00:00", "Sun", "1970 01 04 0:00:00",
1690         "ccc", "fp", "1970 01 05 0:00:00", "Mon", "1970 01 05 0:00:00",
1691         "ccc", "fp", "1970 01 06 0:00:00", "Tue", "1970 01 06 0:00:00",
1692         "ccc", "fp", "1970 01 07 0:00:00", "Wed", "1970 01 07 0:00:00",
1693         "ccc", "fp", "1970 01 01 0:00:00", "Thu", "1970 01 01 0:00:00",
1694         "ccc", "fp", "1970 01 02 0:00:00", "Fri", "1970 01 02 0:00:00",
1695         "ccc", "fp", "1970 01 03 0:00:00", "Sat", "1970 01 03 0:00:00",
1696     };
1697 
1698     const char *CS_DATA[] = {
1699         "yyyy MM dd HH:mm:ss",
1700 
1701         "cccc", "fp", "1970 01 04 0:00:00", "ned\\u011Ble",       "1970 01 04 0:00:00",
1702         "cccc", "fp", "1970 01 05 0:00:00", "pond\\u011Bl\\u00ED", "1970 01 05 0:00:00",
1703         "cccc", "fp", "1970 01 06 0:00:00", "\\u00FAter\\u00FD",   "1970 01 06 0:00:00",
1704         "cccc", "fp", "1970 01 07 0:00:00", "st\\u0159eda",       "1970 01 07 0:00:00",
1705         "cccc", "fp", "1970 01 01 0:00:00", "\\u010Dtvrtek",      "1970 01 01 0:00:00",
1706         "cccc", "fp", "1970 01 02 0:00:00", "p\\u00E1tek",        "1970 01 02 0:00:00",
1707         "cccc", "fp", "1970 01 03 0:00:00", "sobota",            "1970 01 03 0:00:00",
1708 
1709         "ccc", "fp", "1970 01 04 0:00:00", "ne",      "1970 01 04 0:00:00",
1710         "ccc", "fp", "1970 01 05 0:00:00", "po",      "1970 01 05 0:00:00",
1711         "ccc", "fp", "1970 01 06 0:00:00", "\\u00FAt", "1970 01 06 0:00:00",
1712         "ccc", "fp", "1970 01 07 0:00:00", "st",      "1970 01 07 0:00:00",
1713         "ccc", "fp", "1970 01 01 0:00:00", "\\u010Dt", "1970 01 01 0:00:00",
1714         "ccc", "fp", "1970 01 02 0:00:00", "p\\u00E1", "1970 01 02 0:00:00",
1715         "ccc", "fp", "1970 01 03 0:00:00", "so",      "1970 01 03 0:00:00",
1716     };
1717 
1718     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1719     expect(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
1720 }
1721 
TestShortDays()1722 void DateFormatTest::TestShortDays()
1723 {
1724     const char *EN_DATA[] = {
1725         "yyyy MM dd HH:mm:ss",
1726 
1727         "EEEEEE, MMM d y", "fp", "2013 01 13 0:00:00", "Su, Jan 13 2013", "2013 01 13 0:00:00",
1728         "EEEEEE, MMM d y", "fp", "2013 01 16 0:00:00", "We, Jan 16 2013", "2013 01 16 0:00:00",
1729         "EEEEEE d",        "fp", "1970 01 17 0:00:00", "Sa 17",           "1970 01 17 0:00:00",
1730         "cccccc d",        "fp", "1970 01 17 0:00:00", "Sa 17",           "1970 01 17 0:00:00",
1731         "cccccc",          "fp", "1970 01 03 0:00:00", "Sa",              "1970 01 03 0:00:00",
1732     };
1733     const char *SV_DATA[] = {
1734         "yyyy MM dd HH:mm:ss",
1735 
1736         "EEEEEE d MMM y",  "fp", "2013 01 13 0:00:00", "s\\u00F6 13 jan. 2013", "2013 01 13 0:00:00",
1737         "EEEEEE d MMM y",  "fp", "2013 01 16 0:00:00", "on 16 jan. 2013",       "2013 01 16 0:00:00",
1738         "EEEEEE d",        "fp", "1970 01 17 0:00:00", "l\\u00F6 17",          "1970 01 17 0:00:00",
1739         "cccccc d",        "fp", "1970 01 17 0:00:00", "l\\u00F6 17",          "1970 01 17 0:00:00",
1740         "cccccc",          "fp", "1970 01 03 0:00:00", "l\\u00F6",             "1970 01 03 0:00:00",
1741     };
1742     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1743     expect(SV_DATA, UPRV_LENGTHOF(SV_DATA), Locale("sv", "", ""));
1744 }
1745 
TestNarrowNames()1746 void DateFormatTest::TestNarrowNames()
1747 {
1748     const char *EN_DATA[] = {
1749             "yyyy MM dd HH:mm:ss",
1750 
1751             "yyyy MMMMM dd H:mm:ss", "2004 03 10 16:36:31", "2004 M 10 16:36:31",
1752             "yyyy LLLLL dd H:mm:ss",  "2004 03 10 16:36:31", "2004 M 10 16:36:31",
1753 
1754             "MMMMM", "1970 01 01 0:00:00", "J",
1755             "MMMMM", "1970 02 01 0:00:00", "F",
1756             "MMMMM", "1970 03 01 0:00:00", "M",
1757             "MMMMM", "1970 04 01 0:00:00", "A",
1758             "MMMMM", "1970 05 01 0:00:00", "M",
1759             "MMMMM", "1970 06 01 0:00:00", "J",
1760             "MMMMM", "1970 07 01 0:00:00", "J",
1761             "MMMMM", "1970 08 01 0:00:00", "A",
1762             "MMMMM", "1970 09 01 0:00:00", "S",
1763             "MMMMM", "1970 10 01 0:00:00", "O",
1764             "MMMMM", "1970 11 01 0:00:00", "N",
1765             "MMMMM", "1970 12 01 0:00:00", "D",
1766 
1767             "LLLLL", "1970 01 01 0:00:00", "J",
1768             "LLLLL", "1970 02 01 0:00:00", "F",
1769             "LLLLL", "1970 03 01 0:00:00", "M",
1770             "LLLLL", "1970 04 01 0:00:00", "A",
1771             "LLLLL", "1970 05 01 0:00:00", "M",
1772             "LLLLL", "1970 06 01 0:00:00", "J",
1773             "LLLLL", "1970 07 01 0:00:00", "J",
1774             "LLLLL", "1970 08 01 0:00:00", "A",
1775             "LLLLL", "1970 09 01 0:00:00", "S",
1776             "LLLLL", "1970 10 01 0:00:00", "O",
1777             "LLLLL", "1970 11 01 0:00:00", "N",
1778             "LLLLL", "1970 12 01 0:00:00", "D",
1779 
1780             "EEEEE", "1970 01 04 0:00:00", "S",
1781             "EEEEE", "1970 01 05 0:00:00", "M",
1782             "EEEEE", "1970 01 06 0:00:00", "T",
1783             "EEEEE", "1970 01 07 0:00:00", "W",
1784             "EEEEE", "1970 01 01 0:00:00", "T",
1785             "EEEEE", "1970 01 02 0:00:00", "F",
1786             "EEEEE", "1970 01 03 0:00:00", "S",
1787 
1788             "ccccc", "1970 01 04 0:00:00", "S",
1789             "ccccc", "1970 01 05 0:00:00", "M",
1790             "ccccc", "1970 01 06 0:00:00", "T",
1791             "ccccc", "1970 01 07 0:00:00", "W",
1792             "ccccc", "1970 01 01 0:00:00", "T",
1793             "ccccc", "1970 01 02 0:00:00", "F",
1794             "ccccc", "1970 01 03 0:00:00", "S",
1795 
1796             "h:mm a",     "2015 01 01 10:00:00", "10:00 AM",
1797             "h:mm a",     "2015 01 01 22:00:00", "10:00 PM",
1798             "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 a",
1799             "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 p",
1800         };
1801 
1802         const char *CS_DATA[] = {
1803             "yyyy MM dd HH:mm:ss",
1804 
1805             "yyyy LLLLL dd H:mm:ss", "2004 04 10 16:36:31", "2004 4 10 16:36:31",
1806             "yyyy MMMMM dd H:mm:ss", "2004 04 10 16:36:31", "2004 4 10 16:36:31",
1807 
1808             "MMMMM", "1970 01 01 0:00:00", "1",
1809             "MMMMM", "1970 02 01 0:00:00", "2",
1810             "MMMMM", "1970 03 01 0:00:00", "3",
1811             "MMMMM", "1970 04 01 0:00:00", "4",
1812             "MMMMM", "1970 05 01 0:00:00", "5",
1813             "MMMMM", "1970 06 01 0:00:00", "6",
1814             "MMMMM", "1970 07 01 0:00:00", "7",
1815             "MMMMM", "1970 08 01 0:00:00", "8",
1816             "MMMMM", "1970 09 01 0:00:00", "9",
1817             "MMMMM", "1970 10 01 0:00:00", "10",
1818             "MMMMM", "1970 11 01 0:00:00", "11",
1819             "MMMMM", "1970 12 01 0:00:00", "12",
1820 
1821             "LLLLL", "1970 01 01 0:00:00", "1",
1822             "LLLLL", "1970 02 01 0:00:00", "2",
1823             "LLLLL", "1970 03 01 0:00:00", "3",
1824             "LLLLL", "1970 04 01 0:00:00", "4",
1825             "LLLLL", "1970 05 01 0:00:00", "5",
1826             "LLLLL", "1970 06 01 0:00:00", "6",
1827             "LLLLL", "1970 07 01 0:00:00", "7",
1828             "LLLLL", "1970 08 01 0:00:00", "8",
1829             "LLLLL", "1970 09 01 0:00:00", "9",
1830             "LLLLL", "1970 10 01 0:00:00", "10",
1831             "LLLLL", "1970 11 01 0:00:00", "11",
1832             "LLLLL", "1970 12 01 0:00:00", "12",
1833 
1834             "EEEEE", "1970 01 04 0:00:00", "N",
1835             "EEEEE", "1970 01 05 0:00:00", "P",
1836             "EEEEE", "1970 01 06 0:00:00", "\\u00DA",
1837             "EEEEE", "1970 01 07 0:00:00", "S",
1838             "EEEEE", "1970 01 01 0:00:00", "\\u010C",
1839             "EEEEE", "1970 01 02 0:00:00", "P",
1840             "EEEEE", "1970 01 03 0:00:00", "S",
1841 
1842             "ccccc", "1970 01 04 0:00:00", "N",
1843             "ccccc", "1970 01 05 0:00:00", "P",
1844             "ccccc", "1970 01 06 0:00:00", "\\u00DA",
1845             "ccccc", "1970 01 07 0:00:00", "S",
1846             "ccccc", "1970 01 01 0:00:00", "\\u010C",
1847             "ccccc", "1970 01 02 0:00:00", "P",
1848             "ccccc", "1970 01 03 0:00:00", "S",
1849 
1850             "h:mm a",     "2015 01 01 10:00:00", "10:00 dop.",
1851             "h:mm a",     "2015 01 01 22:00:00", "10:00 odp.",
1852             "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 dop.",
1853             "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 odp.",
1854         };
1855 
1856         const char *CA_DATA[] = {
1857             "yyyy MM dd HH:mm:ss",
1858 
1859             "h:mm a",     "2015 01 01 10:00:00", "10:00 a.\\u00A0m.",
1860             "h:mm a",     "2015 01 01 22:00:00", "10:00 p.\\u00A0m.",
1861             "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 a.\\u00A0m.",
1862             "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 p.\\u00A0m.",
1863         };
1864 
1865       expectFormat(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1866       expectFormat(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
1867       expectFormat(CA_DATA, UPRV_LENGTHOF(CA_DATA), Locale("ca", "", ""));
1868 }
1869 
TestEras()1870 void DateFormatTest::TestEras()
1871 {
1872     const char *EN_DATA[] = {
1873         "yyyy MM dd",
1874 
1875         "MMMM dd yyyy G",    "fp", "1951 07 17", "July 17 1951 AD",          "1951 07 17",
1876         "MMMM dd yyyy GG",   "fp", "1951 07 17", "July 17 1951 AD",          "1951 07 17",
1877         "MMMM dd yyyy GGG",  "fp", "1951 07 17", "July 17 1951 AD",          "1951 07 17",
1878         "MMMM dd yyyy GGGG", "fp", "1951 07 17", "July 17 1951 Anno Domini", "1951 07 17",
1879 
1880         "MMMM dd yyyy G",    "fp", "-438 07 17", "July 17 0439 BC",            "-438 07 17",
1881         "MMMM dd yyyy GG",   "fp", "-438 07 17", "July 17 0439 BC",            "-438 07 17",
1882         "MMMM dd yyyy GGG",  "fp", "-438 07 17", "July 17 0439 BC",            "-438 07 17",
1883         "MMMM dd yyyy GGGG", "fp", "-438 07 17", "July 17 0439 Before Christ", "-438 07 17",
1884     };
1885 
1886     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1887 }
1888 
TestQuarters()1889 void DateFormatTest::TestQuarters()
1890 {
1891     const char *EN_DATA[] = {
1892         "yyyy MM dd",
1893 
1894         "Q",    "fp", "1970 01 01", "1",           "1970 01 01",
1895         "QQ",   "fp", "1970 04 01", "02",          "1970 04 01",
1896         "QQQ",  "fp", "1970 07 01", "Q3",          "1970 07 01",
1897         "QQQQ", "fp", "1970 10 01", "4th quarter", "1970 10 01",
1898 
1899         "q",    "fp", "1970 01 01", "1",           "1970 01 01",
1900         "qq",   "fp", "1970 04 01", "02",          "1970 04 01",
1901         "qqq",  "fp", "1970 07 01", "Q3",          "1970 07 01",
1902         "qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
1903 
1904         "Qyy",  "fp", "2015 04 01", "215",         "2015 04 01",
1905         "QQyy", "fp", "2015 07 01", "0315",        "2015 07 01",
1906     };
1907 
1908     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1909 }
1910 
1911 /**
1912  * Test parsing.  Input is an array that starts with the following
1913  * header:
1914  *
1915  * [0]   = pattern string to parse [i+2] with
1916  *
1917  * followed by test cases, each of which is 3 array elements:
1918  *
1919  * [i]   = pattern, or NULL to reuse prior pattern
1920  * [i+1] = input string
1921  * [i+2] = expected parse result (parsed with pattern [0])
1922  *
1923  * If expect parse failure, then [i+2] should be NULL.
1924  */
expectParse(const char ** data,int32_t data_length,const Locale & loc)1925 void DateFormatTest::expectParse(const char** data, int32_t data_length,
1926                                  const Locale& loc) {
1927     const UDate FAIL = (UDate) -1;
1928     const UnicodeString FAIL_STR("parse failure");
1929     int32_t i = 0;
1930 
1931     UErrorCode ec = U_ZERO_ERROR;
1932     SimpleDateFormat fmt("", loc, ec);
1933     SimpleDateFormat ref(data[i++], loc, ec);
1934     SimpleDateFormat gotfmt("G yyyy MM dd HH:mm:ss z", loc, ec);
1935     if (U_FAILURE(ec)) {
1936         dataerrln("FAIL: SimpleDateFormat constructor - %s", u_errorName(ec));
1937         return;
1938     }
1939 
1940     const char* currentPat = NULL;
1941     while (i<data_length) {
1942         const char* pattern  = data[i++];
1943         const char* input    = data[i++];
1944         const char* expected = data[i++];
1945 
1946         ec = U_ZERO_ERROR;
1947         if (pattern != NULL) {
1948             fmt.applyPattern(pattern);
1949             currentPat = pattern;
1950         }
1951         UDate got = fmt.parse(input, ec);
1952         UnicodeString gotstr(FAIL_STR);
1953         if (U_FAILURE(ec)) {
1954             got = FAIL;
1955         } else {
1956             gotstr.remove();
1957             gotfmt.format(got, gotstr);
1958         }
1959 
1960         UErrorCode ec2 = U_ZERO_ERROR;
1961         UDate exp = FAIL;
1962         UnicodeString expstr(FAIL_STR);
1963         if (expected != NULL) {
1964             expstr = expected;
1965             exp = ref.parse(expstr, ec2);
1966             if (U_FAILURE(ec2)) {
1967                 // This only happens if expected is in wrong format --
1968                 // should never happen once test is debugged.
1969                 errln("FAIL: Internal test error");
1970                 return;
1971             }
1972         }
1973 
1974         if (got == exp) {
1975             logln((UnicodeString)"Ok: " + input + " x " +
1976                   currentPat + " => " + gotstr);
1977         } else {
1978             errln((UnicodeString)"FAIL: " + input + " x " +
1979                   currentPat + " => " + gotstr + ", expected " +
1980                   expstr);
1981         }
1982     }
1983 }
1984 
1985 /**
1986  * Test formatting and parsing.  Input is an array that starts
1987  * with the following header:
1988  *
1989  * [0]   = pattern string to parse [i+2] with
1990  *
1991  * followed by test cases, each of which is 3 array elements:
1992  *
1993  * [i]   = pattern, or null to reuse prior pattern
1994  * [i+1] = control string, either "fp", "pf", or "F".
1995  * [i+2..] = data strings
1996  *
1997  * The number of data strings depends on the control string.
1998  * Examples:
1999  * 1. "y/M/d H:mm:ss.SS", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.56", "2004 03 10 16:36:31.560",
2000  * 'f': Format date [i+2] (as parsed using pattern [0]) and expect string [i+3].
2001  * 'p': Parse string [i+3] and expect date [i+4].
2002  *
2003  * 2. "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567"
2004  * 'F': Format date [i+2] and expect string [i+3],
2005  *      then parse string [i+3] and expect date [i+2].
2006  *
2007  * 3. "y/M/d H:mm:ss.SSSS", "pf", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5670",
2008  * 'p': Parse string [i+2] and expect date [i+3].
2009  * 'f': Format date [i+3] and expect string [i+4].
2010  */
expect(const char ** data,int32_t data_length,const Locale & loc)2011 void DateFormatTest::expect(const char** data, int32_t data_length,
2012                             const Locale& loc) {
2013     int32_t i = 0;
2014     UErrorCode ec = U_ZERO_ERROR;
2015     UnicodeString str, str2;
2016     SimpleDateFormat fmt("", loc, ec);
2017     SimpleDateFormat ref(data[i++], loc, ec);
2018     SimpleDateFormat univ("EE G yyyy MM dd HH:mm:ss.SSS z", loc, ec);
2019     if (U_FAILURE(ec)) {
2020         dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
2021         return;
2022     }
2023 
2024     UnicodeString currentPat;
2025     while (i<data_length) {
2026         const char* pattern  = data[i++];
2027         if (pattern != NULL) {
2028             fmt.applyPattern(pattern);
2029             currentPat = pattern;
2030         }
2031 
2032         const char* control = data[i++];
2033 
2034         if (uprv_strcmp(control, "fp") == 0) {
2035             // 'f'
2036             const char* datestr = data[i++];
2037             const char* string = data[i++];
2038             UDate date = ref.parse(ctou(datestr), ec);
2039             if (!assertSuccess("parse", ec)) return;
2040             assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
2041                          ctou(string),
2042                          fmt.format(date, str.remove()));
2043             // 'p'
2044             datestr = data[i++];
2045             date = ref.parse(ctou(datestr), ec);
2046             if (!assertSuccess("parse", ec)) return;
2047             UDate parsedate = fmt.parse(ctou(string), ec);
2048             if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
2049                 assertEquals((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")",
2050                              univ.format(date, str.remove()),
2051                              univ.format(parsedate, str2.remove()));
2052             }
2053         }
2054 
2055         else if (uprv_strcmp(control, "pf") == 0) {
2056             // 'p'
2057             const char* string = data[i++];
2058             const char* datestr = data[i++];
2059             UDate date = ref.parse(ctou(datestr), ec);
2060             if (!assertSuccess("parse", ec)) return;
2061             UDate parsedate = fmt.parse(ctou(string), ec);
2062             if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
2063                 assertEquals((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")",
2064                              univ.format(date, str.remove()),
2065                              univ.format(parsedate, str2.remove()));
2066             }
2067             // 'f'
2068             string = data[i++];
2069             assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
2070                          ctou(string),
2071                          fmt.format(date, str.remove()));
2072         }
2073 
2074         else if (uprv_strcmp(control, "F") == 0) {
2075             const char* datestr  = data[i++];
2076             const char* string   = data[i++];
2077             UDate date = ref.parse(ctou(datestr), ec);
2078             if (!assertSuccess("parse", ec)) return;
2079             assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
2080                          ctou(string),
2081                          fmt.format(date, str.remove()));
2082 
2083             UDate parsedate = fmt.parse(string, ec);
2084             if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
2085                 assertEquals((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")",
2086                              univ.format(date, str.remove()),
2087                              univ.format(parsedate, str2.remove()));
2088             }
2089         }
2090 
2091         else {
2092             errln((UnicodeString)"FAIL: Invalid control string " + control);
2093             return;
2094         }
2095     }
2096 }
2097 
2098 /**
2099  * Test formatting.  Input is an array that starts
2100  * with the following header:
2101  *
2102  * [0]   = pattern string to parse [i+2] with
2103  *
2104  * followed by test cases, each of which is 3 array elements:
2105  *
2106  * [i]   = pattern, or null to reuse prior pattern
2107  * [i+1] = data string a
2108  * [i+2] = data string b
2109  *
2110  * Examples:
2111  * Format date [i+1] and expect string [i+2].
2112  *
2113  * "y/M/d H:mm:ss.SSSS", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567"
2114  */
expectFormat(const char ** data,int32_t data_length,const Locale & loc)2115 void DateFormatTest::expectFormat(const char** data, int32_t data_length,
2116                             const Locale& loc) {
2117     int32_t i = 0;
2118     UErrorCode ec = U_ZERO_ERROR;
2119     UnicodeString str, str2;
2120     SimpleDateFormat fmt("", loc, ec);
2121     SimpleDateFormat ref(data[i++], loc, ec);
2122     SimpleDateFormat univ("EE G yyyy MM dd HH:mm:ss.SSS z", loc, ec);
2123     if (U_FAILURE(ec)) {
2124         dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
2125         return;
2126     }
2127 
2128     UnicodeString currentPat;
2129 
2130     while (i<data_length) {
2131         const char* pattern  = data[i++];
2132         if (pattern != NULL) {
2133             fmt.applyPattern(pattern);
2134             currentPat = pattern;
2135         }
2136 
2137         const char* datestr = data[i++];
2138         const char* string = data[i++];
2139         UDate date = ref.parse(ctou(datestr), ec);
2140         if (!assertSuccess("parse", ec)) return;
2141         assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
2142                         ctou(string),
2143                         fmt.format(date, str.remove()));
2144     }
2145 }
2146 
TestGenericTime()2147 void DateFormatTest::TestGenericTime() {
2148   const Locale en("en");
2149   // Note: We no longer parse strings in different styles.
2150 /*
2151   const char* ZDATA[] = {
2152         "yyyy MM dd HH:mm zzz",
2153         // round trip
2154         "y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
2155         "y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2156         "y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2157         "y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
2158         // non-generic timezone string influences dst offset even if wrong for date/time
2159         "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 PST",
2160         "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 Pacific Time",
2161         "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 PDT",
2162         "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 Pacific Time",
2163         // generic timezone generates dst offset appropriate for local time
2164         "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2165         "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2166         "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
2167         "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
2168         // daylight savings time transition edge cases.
2169         // time to parse does not really exist, PT interpreted as earlier time
2170         "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
2171         "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
2172         "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PST",
2173         "y/M/d H:mm v", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
2174         "y/M/d H:mm v", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
2175         "y/M/d H:mm v", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PT",
2176         "y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
2177         // time to parse is ambiguous, PT interpreted as later time
2178         "y/M/d H:mm zzz", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PST",
2179         "y/M/d H:mm v", "pf", "2005/10/30 1:30 PT", "2005 10 30  01:30 PST", "2005/10/30 1:30 PT",
2180         "y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
2181 
2182         "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
2183         "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
2184         "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PDT",
2185         "y/M/d H:mm v", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
2186         "y/M/d H:mm v", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
2187         "y/M/d H:mm v", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PT",
2188         "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
2189   };
2190 */
2191   const char* ZDATA[] = {
2192         "yyyy MM dd HH:mm zzz",
2193         // round trip
2194         "y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
2195         "y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2196         "y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2197         "y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
2198         // non-generic timezone string influences dst offset even if wrong for date/time
2199         "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 PST",
2200         "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 PDT",
2201         // generic timezone generates dst offset appropriate for local time
2202         "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PST", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2203         "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 Pacific Time", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2204         "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PDT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
2205         "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 Pacific Time", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
2206         // daylight savings time transition edge cases.
2207         // time to parse does not really exist, PT interpreted as earlier time
2208         "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
2209         "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PST",
2210         "y/M/d H:mm v", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
2211         "y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
2212         // time to parse is ambiguous, PT interpreted as later time
2213         "y/M/d H:mm v", "pf", "2005/10/30 1:30 PT", "2005 10 30  01:30 PST", "2005/10/30 1:30 PT",
2214         "y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
2215 
2216         "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
2217         "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PDT",
2218         "y/M/d H:mm v", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
2219         "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
2220   };
2221 
2222   const int32_t ZDATA_length = UPRV_LENGTHOF(ZDATA);
2223   expect(ZDATA, ZDATA_length, en);
2224 
2225   UErrorCode status = U_ZERO_ERROR;
2226 
2227   logln("cross format/parse tests");    // Note: We no longer support cross format/parse
2228   UnicodeString basepat("yy/MM/dd H:mm ");
2229   SimpleDateFormat formats[] = {
2230     SimpleDateFormat(basepat + "vvv", en, status),
2231     SimpleDateFormat(basepat + "vvvv", en, status),
2232     SimpleDateFormat(basepat + "zzz", en, status),
2233     SimpleDateFormat(basepat + "zzzz", en, status)
2234   };
2235   if (U_FAILURE(status)) {
2236     dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(status));
2237     return;
2238   }
2239   const int32_t formats_length = UPRV_LENGTHOF(formats);
2240 
2241   UnicodeString test;
2242   SimpleDateFormat univ("yyyy MM dd HH:mm zzz", en, status);
2243   ASSERT_OK(status);
2244   const UnicodeString times[] = {
2245     "2004 01 02 03:04 PST",
2246     "2004 07 08 09:10 PDT"
2247   };
2248   int32_t times_length = UPRV_LENGTHOF(times);
2249   for (int i = 0; i < times_length; ++i) {
2250     UDate d = univ.parse(times[i], status);
2251     logln(UnicodeString("\ntime: ") + d);
2252     for (int j = 0; j < formats_length; ++j) {
2253       test.remove();
2254       formats[j].format(d, test);
2255       logln("\ntest: '" + test + "'");
2256       for (int k = 0; k < formats_length; ++k) {
2257         UDate t = formats[k].parse(test, status);
2258         if (U_SUCCESS(status)) {
2259           if (d != t) {
2260             errln((UnicodeString)"FAIL: format " + k +
2261                   " incorrectly parsed output of format " + j +
2262                   " (" + test + "), returned " +
2263                   dateToString(t) + " instead of " + dateToString(d));
2264           } else {
2265             logln((UnicodeString)"OK: format " + k + " parsed ok");
2266           }
2267         } else if (status == U_PARSE_ERROR) {
2268           errln((UnicodeString)"FAIL: format " + k +
2269                 " could not parse output of format " + j +
2270                 " (" + test + ")");
2271         }
2272       }
2273     }
2274   }
2275 }
2276 
TestGenericTimeZoneOrder()2277 void DateFormatTest::TestGenericTimeZoneOrder() {
2278   // generic times should parse the same no matter what the placement of the time zone string
2279 
2280   // Note: We no longer support cross style format/parse
2281 
2282   //const char* XDATA[] = {
2283   //  "yyyy MM dd HH:mm zzz",
2284   //  // standard time, explicit daylight/standard
2285   //  "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2286   //  "y/M/d zzz H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 PST 1:00",
2287   //  "zzz y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "PST 2004/1/1 1:00",
2288 
2289   //  // standard time, generic
2290   //  "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2291   //  "y/M/d vvvv H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 Pacific Time 1:00",
2292   //  "vvvv y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "Pacific Time 2004/1/1 1:00",
2293 
2294   //  // dahylight time, explicit daylight/standard
2295   //  "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
2296   //  "y/M/d zzz H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PDT 1:00",
2297   //  "zzz y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PDT 2004/7/1 1:00",
2298 
2299   //  // daylight time, generic
2300   //  "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
2301   //  "y/M/d vvvv H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 Pacific Time 1:00",
2302   //  "vvvv y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "Pacific Time 2004/7/1 1:00",
2303   //};
2304   const char* XDATA[] = {
2305     "yyyy MM dd HH:mm zzz",
2306     // standard time, explicit daylight/standard
2307     "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PST", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2308     "y/M/d zzz H:mm", "pf", "2004/1/1 PST 1:00", "2004 01 01 01:00 PST", "2004/1/1 PST 1:00",
2309     "zzz y/M/d H:mm", "pf", "PST 2004/1/1 1:00", "2004 01 01 01:00 PST", "PST 2004/1/1 1:00",
2310 
2311     // standard time, generic
2312     "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 Pacific Time", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2313     "y/M/d vvvv H:mm", "pf", "2004/1/1 Pacific Time 1:00", "2004 01 01 01:00 PST", "2004/1/1 Pacific Time 1:00",
2314     "vvvv y/M/d H:mm", "pf", "Pacific Time 2004/1/1 1:00", "2004 01 01 01:00 PST", "Pacific Time 2004/1/1 1:00",
2315 
2316     // dahylight time, explicit daylight/standard
2317     "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PDT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
2318     "y/M/d zzz H:mm", "pf", "2004/7/1 PDT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PDT 1:00",
2319     "zzz y/M/d H:mm", "pf", "PDT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PDT 2004/7/1 1:00",
2320 
2321     // daylight time, generic
2322     "y/M/d H:mm v", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PT",
2323     "y/M/d v H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PT 1:00",
2324     "v y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PT 2004/7/1 1:00",
2325   };
2326   const int32_t XDATA_length = UPRV_LENGTHOF(XDATA);
2327   Locale en("en");
2328   expect(XDATA, XDATA_length, en);
2329 }
2330 
TestZTimeZoneParsing(void)2331 void DateFormatTest::TestZTimeZoneParsing(void) {
2332     UErrorCode status = U_ZERO_ERROR;
2333     const Locale en("en");
2334     UnicodeString test;
2335     //SimpleDateFormat univ("yyyy-MM-dd'T'HH:mm Z", en, status);
2336     SimpleDateFormat univ("HH:mm Z", en, status);
2337     if (failure(status, "construct SimpleDateFormat", TRUE)) return;
2338     const TimeZone *t = TimeZone::getGMT();
2339     univ.setTimeZone(*t);
2340 
2341     univ.setLenient(false);
2342     ParsePosition pp(0);
2343     struct {
2344         UnicodeString input;
2345         UnicodeString expected_result;
2346     } tests[] = {
2347         { "11:00 -0200", "13:00 +0000" },
2348         { "11:00 +0200", "09:00 +0000" },
2349         { "11:00 +0400", "07:00 +0000" },
2350         { "11:00 +0530", "05:30 +0000" }
2351     };
2352 
2353     UnicodeString result;
2354     int32_t tests_length = UPRV_LENGTHOF(tests);
2355     for (int i = 0; i < tests_length; ++i) {
2356         pp.setIndex(0);
2357         UDate d = univ.parse(tests[i].input, pp);
2358         if(pp.getIndex() != tests[i].input.length()){
2359             errln("Test %i: setZoneString() did not succeed. Consumed: %i instead of %i",
2360                   i, pp.getIndex(), tests[i].input.length());
2361             return;
2362         }
2363         result.remove();
2364         univ.format(d, result);
2365         if(result != tests[i].expected_result) {
2366             errln("Expected " + tests[i].expected_result
2367                   + " got " + result);
2368             return;
2369         }
2370         logln("SUCCESS: Parsed " + tests[i].input
2371               + " got " + result
2372               + " expected " + tests[i].expected_result);
2373     }
2374 }
2375 
TestHost(void)2376 void DateFormatTest::TestHost(void)
2377 {
2378 #if U_PLATFORM_USES_ONLY_WIN32_API
2379     Win32DateTimeTest::testLocales(this);
2380 #endif
2381 }
2382 
2383 // Relative Date Tests
2384 
TestRelative(int daysdelta,const Locale & loc,const char * expectChars)2385 void DateFormatTest::TestRelative(int daysdelta,
2386                                   const Locale& loc,
2387                                   const char *expectChars) {
2388     char banner[25];
2389     sprintf(banner, "%d", daysdelta);
2390     UnicodeString bannerStr(banner, "");
2391 
2392     UErrorCode status = U_ZERO_ERROR;
2393 
2394     FieldPosition pos(FieldPosition::DONT_CARE);
2395     UnicodeString test;
2396     Locale en("en");
2397     DateFormat *fullrelative = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
2398 
2399     if (fullrelative == NULL) {
2400         dataerrln("DateFormat::createDateInstance(DateFormat::kFullRelative, %s) returned NULL", loc.getName());
2401         return;
2402     }
2403 
2404     DateFormat *full         = DateFormat::createDateInstance(DateFormat::kFull        , loc);
2405 
2406     if (full == NULL) {
2407         errln("DateFormat::createDateInstance(DateFormat::kFull, %s) returned NULL", loc.getName());
2408         return;
2409     }
2410 
2411     DateFormat *en_full =         DateFormat::createDateInstance(DateFormat::kFull,         en);
2412 
2413     if (en_full == NULL) {
2414         errln("DateFormat::createDateInstance(DateFormat::kFull, en) returned NULL");
2415         return;
2416     }
2417 
2418     DateFormat *en_fulltime =         DateFormat::createDateTimeInstance(DateFormat::kFull,DateFormat::kFull,en);
2419 
2420     if (en_fulltime == NULL) {
2421         errln("DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, en) returned NULL");
2422         return;
2423     }
2424 
2425     UnicodeString result;
2426     UnicodeString normalResult;
2427     UnicodeString expect;
2428     UnicodeString parseResult;
2429 
2430     Calendar *c = Calendar::createInstance(status);
2431 
2432     // Today = Today
2433     c->setTime(Calendar::getNow(), status);
2434     if(daysdelta != 0) {
2435         c->add(Calendar::DATE,daysdelta,status);
2436     }
2437     ASSERT_OK(status);
2438 
2439     // calculate the expected string
2440     if(expectChars != NULL) {
2441         expect = expectChars;
2442     } else {
2443         full->format(*c, expect, pos); // expected = normal full
2444     }
2445 
2446     fullrelative   ->format(*c, result, pos);
2447     en_full        ->format(*c, normalResult, pos);
2448 
2449     if(result != expect) {
2450         errln("FAIL: Relative Format ["+bannerStr+"] of "+normalResult+" failed, expected "+expect+" but got " + result);
2451     } else {
2452         logln("PASS: Relative Format ["+bannerStr+"] of "+normalResult+" got " + result);
2453     }
2454 
2455 
2456     //verify
2457     UDate d = fullrelative->parse(result, status);
2458     ASSERT_OK(status);
2459 
2460     UnicodeString parseFormat; // parse rel->format full
2461     en_full->format(d, parseFormat, status);
2462 
2463     UnicodeString origFormat;
2464     en_full->format(*c, origFormat, pos);
2465 
2466     if(parseFormat!=origFormat) {
2467         errln("FAIL: Relative Parse ["+bannerStr+"] of "+result+" failed, expected "+parseFormat+" but got "+origFormat);
2468     } else {
2469         logln("PASS: Relative Parse ["+bannerStr+"] of "+result+" passed, got "+parseFormat);
2470     }
2471 
2472     delete full;
2473     delete fullrelative;
2474     delete en_fulltime;
2475     delete en_full;
2476     delete c;
2477 }
2478 
2479 
TestRelative(void)2480 void DateFormatTest::TestRelative(void)
2481 {
2482     Locale en("en");
2483     TestRelative( 0, en, "today");
2484     TestRelative(-1, en, "yesterday");
2485     TestRelative( 1, en, "tomorrow");
2486     TestRelative( 2, en, NULL);
2487     TestRelative( -2, en, NULL);
2488     TestRelative( 3, en, NULL);
2489     TestRelative( -3, en, NULL);
2490     TestRelative( 300, en, NULL);
2491     TestRelative( -300, en, NULL);
2492 }
2493 
TestRelativeClone(void)2494 void DateFormatTest::TestRelativeClone(void)
2495 {
2496     /*
2497     Verify that a cloned formatter gives the same results
2498     and is useable after the original has been deleted.
2499     */
2500     UErrorCode status = U_ZERO_ERROR;
2501     Locale loc("en");
2502     UDate now = Calendar::getNow();
2503     DateFormat *full = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
2504     if (full == NULL) {
2505         dataerrln("FAIL: Can't create Relative date instance");
2506         return;
2507     }
2508     UnicodeString result1;
2509     full->format(now, result1, status);
2510     Format *fullClone = full->clone();
2511     delete full;
2512     full = NULL;
2513 
2514     UnicodeString result2;
2515     fullClone->format(now, result2, status);
2516     ASSERT_OK(status);
2517     if (result1 != result2) {
2518         errln("FAIL: Clone returned different result from non-clone.");
2519     }
2520     delete fullClone;
2521 }
2522 
TestHostClone(void)2523 void DateFormatTest::TestHostClone(void)
2524 {
2525     /*
2526     Verify that a cloned formatter gives the same results
2527     and is useable after the original has been deleted.
2528     */
2529     // This is mainly important on Windows.
2530     UErrorCode status = U_ZERO_ERROR;
2531     Locale loc("en_US@compat=host");
2532     UDate now = Calendar::getNow();
2533     DateFormat *full = DateFormat::createDateInstance(DateFormat::kFull, loc);
2534     if (full == NULL) {
2535         dataerrln("FAIL: Can't create host date instance");
2536         return;
2537     }
2538     UnicodeString result1;
2539     full->format(now, result1, status);
2540     Format *fullClone = full->clone();
2541     delete full;
2542     full = NULL;
2543 
2544     UnicodeString result2;
2545     fullClone->format(now, result2, status);
2546     ASSERT_OK(status);
2547     if (result1 != result2) {
2548         errln("FAIL: Clone returned different result from non-clone.");
2549     }
2550     delete fullClone;
2551 }
2552 
TestHebrewClone(void)2553 void DateFormatTest::TestHebrewClone(void)
2554 {
2555     /*
2556     Verify that a cloned formatter gives the same results
2557     and is useable after the original has been deleted.
2558     */
2559     UErrorCode status = U_ZERO_ERROR;
2560     Locale loc("he@calendar=hebrew");
2561     UDate now = Calendar::getNow();
2562     LocalPointer<DateFormat> fmt(
2563             DateFormat::createDateInstance(DateFormat::kLong, loc));
2564     if (fmt.isNull()) {
2565         dataerrln("FAIL: Can't create Hebrew date instance");
2566         return;
2567     }
2568     UnicodeString result1;
2569     fmt->format(now, result1, status);
2570     LocalPointer<Format> fmtClone(fmt->clone());
2571 
2572     // free fmt to be sure that fmtClone is independent of fmt.
2573     fmt.adoptInstead(NULL);
2574 
2575     UnicodeString result2;
2576     fmtClone->format(now, result2, status);
2577     ASSERT_OK(status);
2578     if (result1 != result2) {
2579         errln("FAIL: Clone returned different result from non-clone.");
2580     }
2581 }
2582 
getActualAndValidLocales(const Format & fmt,Locale & valid,Locale & actual)2583 static UBool getActualAndValidLocales(
2584         const Format &fmt, Locale &valid, Locale &actual) {
2585     const SimpleDateFormat* dat = dynamic_cast<const SimpleDateFormat*>(&fmt);
2586     if (dat == NULL) {
2587         return FALSE;
2588     }
2589     const DateFormatSymbols *sym = dat->getDateFormatSymbols();
2590     if (sym == NULL) {
2591         return FALSE;
2592     }
2593     UErrorCode status = U_ZERO_ERROR;
2594     valid = sym->getLocale(ULOC_VALID_LOCALE, status);
2595     actual = sym->getLocale(ULOC_ACTUAL_LOCALE, status);
2596     return U_SUCCESS(status);
2597 }
2598 
TestDateFormatSymbolsClone(void)2599 void DateFormatTest::TestDateFormatSymbolsClone(void)
2600 {
2601     /*
2602     Verify that a cloned formatter gives the same results
2603     and is useable after the original has been deleted.
2604     */
2605     Locale loc("de_CH_LUCERNE");
2606     LocalPointer<DateFormat> fmt(
2607             DateFormat::createDateInstance(DateFormat::kDefault, loc));
2608     if (fmt.isNull()) {
2609         dataerrln("FAIL: DateFormat::createDateInstance failed for %s", loc.getName());
2610         return;
2611     }
2612     Locale valid1;
2613     Locale actual1;
2614     if (!getActualAndValidLocales(*fmt, valid1, actual1)) {
2615         dataerrln("FAIL: Could not fetch valid + actual locales");
2616         return;
2617     }
2618     LocalPointer<Format> fmtClone(fmt->clone());
2619 
2620     // Free fmt to be sure that fmtClone is really independent of fmt.
2621     fmt.adoptInstead(NULL);
2622     Locale valid2;
2623     Locale actual2;
2624     if (!getActualAndValidLocales(*fmtClone, valid2, actual2)) {
2625         errln("FAIL: Could not fetch valid + actual locales");
2626         return;
2627     }
2628     if (valid1 != valid2 || actual1 != actual2) {
2629         errln("Date format symbol locales of clone don't match original");
2630     }
2631 }
2632 
TestTimeZoneDisplayName()2633 void DateFormatTest::TestTimeZoneDisplayName()
2634 {
2635     // This test data was ported from ICU4J.  Don't know why the 6th column in there because it's not being
2636     // used currently.
2637     const char *fallbackTests[][6]  = {
2638         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2639         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2640         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZZ", "-08:00", "-8:00" },
2641         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "PST", "America/Los_Angeles" },
2642         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Pacific Standard Time", "America/Los_Angeles" },
2643         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2644         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2645         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "PDT", "America/Los_Angeles" },
2646         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Pacific Daylight Time", "America/Los_Angeles" },
2647         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "PT", "America/Los_Angeles" },
2648         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Pacific Time", "America/Los_Angeles" },
2649         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "Los Angeles Time", "America/Los_Angeles" },
2650         { "en_GB", "America/Los_Angeles", "2004-01-15T12:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
2651         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "Z", "-0700", "-7:00" },
2652         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2653         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "z", "MST", "America/Phoenix" },
2654         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
2655         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2656         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2657         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "z", "MST", "America/Phoenix" },
2658         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
2659         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "v", "MST", "America/Phoenix" },
2660         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "vvvv", "Mountain Standard Time", "America/Phoenix" },
2661         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "VVVV", "Phoenix Time", "America/Phoenix" },
2662 
2663         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2664         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2665         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2666         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2667         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2668         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2669         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2670         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2671         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
2672         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
2673         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Buenos Aires Time", "America/Buenos_Aires" },
2674 
2675         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2676         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2677         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2678         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2679         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2680         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2681         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2682         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2683         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
2684         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
2685         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Buenos Aires Time", "America/Buenos_Aires" },
2686 
2687         { "en", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
2688         { "en", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
2689         { "en", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
2690         { "en", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Cuba Standard Time", "-5:00" },
2691         { "en", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
2692         { "en", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
2693         { "en", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
2694         { "en", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Cuba Daylight Time", "-4:00" },
2695         { "en", "America/Havana", "2004-07-15T00:00:00Z", "v", "Cuba Time", "America/Havana" },
2696         { "en", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Cuba Time", "America/Havana" },
2697         { "en", "America/Havana", "2004-07-15T00:00:00Z", "VVVV", "Cuba Time", "America/Havana" },
2698 
2699         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2700         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2701         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2702         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
2703         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2704         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2705         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2706         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
2707         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
2708         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
2709         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "VVVV", "Sydney Time", "Australia/Sydney" },
2710 
2711         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2712         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2713         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2714         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
2715         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2716         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2717         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2718         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
2719         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
2720         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
2721         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "VVVV", "Sydney Time", "Australia/Sydney" },
2722 
2723         { "en", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
2724         { "en", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2725         { "en", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2726         { "en", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Greenwich Mean Time", "+0:00" },
2727         { "en", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
2728         { "en", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
2729         { "en", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "Europe/London" },
2730         { "en", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "British Summer Time", "Europe/London" },
2731     // icu en.txt has exemplar city for this time zone
2732         { "en", "Europe/London", "2004-07-15T00:00:00Z", "v", "United Kingdom Time", "Europe/London" },
2733         { "en", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "United Kingdom Time", "Europe/London" },
2734         { "en", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "United Kingdom Time", "Europe/London" },
2735 
2736         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2737         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2738         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2739         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2740         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2741         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2742         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2743         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2744         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
2745         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
2746 
2747         // JB#5150
2748         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
2749         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2750         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
2751         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
2752         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
2753         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2754         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
2755         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
2756         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "India Time", "Asia/Calcutta" },
2757         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "India Standard Time", "Asia/Calcutta" },
2758 
2759         // Proper CLDR primary zone support #9733
2760         { "en", "America/Santiago", "2013-01-01T00:00:00Z", "VVVV", "Chile Time", "America/Santiago" },
2761         { "en", "Pacific/Easter", "2013-01-01T00:00:00Z", "VVVV", "Easter Time", "Pacific/Easter" },
2762 
2763         // ==========
2764 
2765         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2766         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2767         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
2768         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\\u00fcsten-Normalzeit", "-8:00" },
2769         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2770         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2771         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
2772         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\\u00fcsten-Sommerzeit", "-7:00" },
2773         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Los Angeles Zeit", "America/Los_Angeles" },
2774         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Nordamerikanische Westk\\u00fcstenzeit", "America/Los_Angeles" },
2775 
2776         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2777         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2778         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2779         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2780         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2781         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2782         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2783         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2784         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Zeit", "America/Buenos_Aires" },
2785         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
2786 
2787         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2788         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2789         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2790         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2791         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2792         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2793         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2794         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2795         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Zeit", "America/Buenos_Aires" },
2796         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
2797 
2798         { "de", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
2799         { "de", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
2800         { "de", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
2801         { "de", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Kubanische Normalzeit", "-5:00" },
2802         { "de", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
2803         { "de", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
2804         { "de", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
2805         { "de", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Kubanische Sommerzeit", "-4:00" },
2806         { "de", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba Zeit", "America/Havana" },
2807         { "de", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kubanische Zeit", "America/Havana" },
2808         // added to test proper fallback of country name
2809         { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba Zeit", "America/Havana" },
2810         { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kubanische Zeit", "America/Havana" },
2811 
2812         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2813         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2814         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2815         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
2816         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2817         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2818         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2819         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
2820         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney Zeit", "Australia/Sydney" },
2821         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
2822 
2823         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2824         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2825         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2826         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
2827         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2828         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2829         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2830         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
2831         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney Zeit", "Australia/Sydney" },
2832         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
2833 
2834         { "de", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
2835         { "de", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2836         { "de", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2837         { "de", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Mittlere Greenwich-Zeit", "+0:00" },
2838         { "de", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
2839         { "de", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
2840         { "de", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
2841         { "de", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "Britische Sommerzeit", "+1:00" },
2842         { "de", "Europe/London", "2004-07-15T00:00:00Z", "v", "Vereinigtes K\\u00f6nigreich Zeit", "Europe/London" },
2843         { "de", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "Vereinigtes K\\u00f6nigreich Zeit", "Europe/London" },
2844 
2845         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2846         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2847         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2848         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2849         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2850         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2851         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2852         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2853         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
2854         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
2855 
2856         // JB#5150
2857         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
2858         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2859         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
2860         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "Indische Zeit", "+5:30" },
2861         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
2862         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2863         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
2864         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "Indische Zeit", "+5:30" },
2865         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "Indien Zeit", "Asia/Calcutta" },
2866         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "Indische Zeit", "Asia/Calcutta" },
2867 
2868         // ==========
2869 
2870         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2871         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2872         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
2873         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u6807\\u51c6\\u65f6\\u95f4", "America/Los_Angeles" },
2874         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2875         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2876         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "America/Los_Angeles" },
2877         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u590f\\u4ee4\\u65f6\\u95f4", "America/Los_Angeles" },
2878     // icu zh.txt has exemplar city for this time zone
2879         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u6D1B\\u6749\\u77F6\\u65F6\\u95F4", "America/Los_Angeles" },
2880         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u65f6\\u95f4", "America/Los_Angeles" },
2881 
2882         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2883         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2884         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2885         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2886         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2887         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2888         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2889         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2890         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u5E03\\u5B9C\\u8BFA\\u65AF\\u827E\\u5229\\u65AF\\u65F6\\u95F4", "America/Buenos_Aires" },
2891         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "America/Buenos_Aires" },
2892 
2893         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2894         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2895         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2896         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2897         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2898         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2899         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2900         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2901         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u5E03\\u5B9C\\u8BFA\\u65AF\\u827E\\u5229\\u65AF\\u65F6\\u95F4", "America/Buenos_Aires" },
2902         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "America/Buenos_Aires" },
2903 
2904         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
2905         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
2906         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
2907         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u53e4\\u5df4\\u6807\\u51c6\\u65f6\\u95f4", "-5:00" },
2908         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
2909         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
2910         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
2911         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u53e4\\u5df4\\u590f\\u4ee4\\u65f6\\u95f4", "-4:00" },
2912         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u53e4\\u5df4\\u65f6\\u95f4", "America/Havana" },
2913         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u53e4\\u5df4\\u65f6\\u95f4", "America/Havana" },
2914 
2915         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2916         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2917         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2918         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
2919         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2920         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2921         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2922         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u6807\\u51c6\\u65f6\\u95f4", "+10:00" },
2923     // icu zh.txt does not have info for this time zone
2924         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u6089\\u5C3C\\u65F6\\u95F4", "Australia/Sydney" },
2925         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u65f6\\u95f4", "Australia/Sydney" },
2926 
2927         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2928         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2929         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2930         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
2931         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2932         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2933         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2934         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u6807\\u51c6\\u65f6\\u95f4", "+10:00" },
2935         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u6089\\u5C3C\\u65F6\\u95F4", "Australia/Sydney" },
2936         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u65f6\\u95f4", "Australia/Sydney" },
2937 
2938         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
2939         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2940         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2941         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2942         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2943         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u683C\\u6797\\u5C3C\\u6CBB\\u6807\\u51C6\\u65F6\\u95F4", "+0:00" },
2944         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
2945         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
2946         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
2947         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u82f1\\u56fd\\u590f\\u4ee4\\u65f6\\u95f4", "+1:00" },
2948         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
2949         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
2950         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
2951 
2952         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2953         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2954         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2955         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2956         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2957         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2958         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2959         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2960         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
2961         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
2962 
2963         // JB#5150
2964         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
2965         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2966         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
2967         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u5370\\u5ea6\\u65f6\\u95f4", "+5:30" },
2968         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
2969         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2970         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
2971         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u5370\\u5ea6\\u65f6\\u95f4", "+5:30" },
2972         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u5370\\u5ea6\\u65f6\\u95f4", "Asia/Calcutta" },
2973         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u5370\\u5ea6\\u65f6\\u95f4", "Asia/Calcutta" },
2974 
2975         // ==========
2976 
2977         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2978         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2979         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
2980         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u0909\\u0924\\u094d\\u0924\\u0930\\u0940 \\u0905\\u092e\\u0947\\u0930\\u093f\\u0915\\u0940 \\u092a\\u094d\\u0930\\u0936\\u093e\\u0902\\u0924 \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "-8:00" },
2981         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2982         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2983         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
2984         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u0909\\u0924\\u094d\\u0924\\u0930\\u0940 \\u0905\\u092e\\u0947\\u0930\\u093f\\u0915\\u0940 \\u092a\\u094d\\u0930\\u0936\\u093e\\u0902\\u0924 \\u0921\\u0947\\u0932\\u093e\\u0907\\u091f \\u0938\\u092e\\u092f", "-7:00" },
2985         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v",  "\\u0932\\u0949\\u0938 \\u090f\\u0902\\u091c\\u093f\\u0932\\u094d\\u0938 \\u0938\\u092e\\u092f", "America/Los_Angeles" },
2986         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u0909\\u0924\\u094d\\u0924\\u0930\\u0940 \\u0905\\u092e\\u0947\\u0930\\u093f\\u0915\\u0940 \\u092a\\u094d\\u0930\\u0936\\u093e\\u0902\\u0924 \\u0938\\u092e\\u092f", "America/Los_Angeles" },
2987 
2988         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2989         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2990         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2991         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
2992         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2993         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2994         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2995         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
2996         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u092C\\u094D\\u092F\\u0942\\u0928\\u0938 \\u0906\\u092F\\u0930\\u0938 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
2997         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
2998 
2999         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3000         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3001         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3002         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
3003         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3004         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3005         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3006         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
3007         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u092C\\u094D\\u092F\\u0942\\u0928\\u0938 \\u0906\\u092F\\u0930\\u0938 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
3008         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
3009 
3010         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3011         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
3012         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
3013         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "-5:00" },
3014         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3015         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
3016         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
3017         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0921\\u0947\\u0932\\u093e\\u0907\\u091f \\u0938\\u092e\\u092f", "-4:00" },
3018         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0938\\u092E\\u092F", "America/Havana" },
3019         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0938\\u092e\\u092f", "America/Havana" },
3020 
3021         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3022         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3023         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3024         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094d\\u200d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e\\u0908 \\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u0921\\u0947\\u0932\\u093e\\u0907\\u091f \\u0938\\u092e\\u092f", "+11:00" },
3025         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3026         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3027         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3028         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094d\\u200d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e\\u0908 \\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "+10:00" },
3029         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0938\\u093F\\u0921\\u0928\\u0940 \\u0938\\u092E\\u092F", "Australia/Sydney" },
3030         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u0911\\u0938\\u094d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e \\u0938\\u092e\\u092f", "Australia/Sydney" },
3031 
3032         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3033         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3034         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3035         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094d\\u200d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e\\u0908 \\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u0921\\u0947\\u0932\\u093e\\u0907\\u091f \\u0938\\u092e\\u092f", "+11:00" },
3036         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3037         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3038         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3039         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094d\\u200d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e\\u0908 \\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "+10:00" },
3040         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0938\\u093F\\u0921\\u0928\\u0940 \\u0938\\u092E\\u092F", "Australia/Sydney" },
3041         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u0911\\u0938\\u094d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e \\u0938\\u092e\\u092f", "Australia/Sydney" },
3042 
3043         { "hi", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3044         { "hi", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
3045         { "hi", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
3046         { "hi", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u0917\\u094d\\u0930\\u0940\\u0928\\u0935\\u093f\\u091a \\u092e\\u0940\\u0928 \\u091f\\u093e\\u0907\\u092e", "+0:00" },
3047         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3048         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
3049         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
3050         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u092c\\u094d\\u0930\\u093f\\u091f\\u093f\\u0936 \\u0917\\u094d\\u0930\\u0940\\u0937\\u094d\\u092e\\u0915\\u093e\\u0932\\u0940\\u0928 \\u0938\\u092e\\u092f", "+1:00" },
3051         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u092f\\u0942\\u0928\\u093e\\u0907\\u091f\\u0947\\u0921 \\u0915\\u093f\\u0902\\u0917\\u0921\\u092e \\u0938\\u092e\\u092f", "Europe/London" },
3052         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u092f\\u0942\\u0928\\u093e\\u0907\\u091f\\u0947\\u0921 \\u0915\\u093f\\u0902\\u0917\\u0921\\u092e \\u0938\\u092e\\u092f", "Europe/London" },
3053 
3054         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3055         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3056         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3057         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3058         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3059         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3060         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3061         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3062         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
3063         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
3064 
3065         { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3066         { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3067         { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "IST", "+5:30" },
3068         { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "+5:30" },
3069         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3070         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3071         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "IST", "+05:30" },
3072         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "+5:30" },
3073         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "IST", "Asia/Calcutta" },
3074         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "Asia/Calcutta" },
3075 
3076         // ==========
3077 
3078         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
3079         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-08:00", "-8:00" },
3080         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-8", "America/Los_Angeles" },
3081         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u0421\\u0435\\u0432\\u0435\\u0440\\u043d\\u043e\\u0430\\u043c\\u0435\\u0440\\u0438\\u043a\\u0430\\u043d\\u0441\\u043a\\u043e \\u0442\\u0438\\u0445\\u043e\\u043e\\u043a\\u0435\\u0430\\u043d\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Los_Angeles" },
3082         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
3083         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-07:00", "-7:00" },
3084         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-7", "America/Los_Angeles" },
3085         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u0421\\u0435\\u0432\\u0435\\u0440\\u043d\\u043e\\u0430\\u043c\\u0435\\u0440\\u0438\\u043a\\u0430\\u043d\\u0441\\u043a\\u043e \\u0442\\u0438\\u0445\\u043e\\u043e\\u043a\\u0435\\u0430\\u043d\\u0441\\u043a\\u043e \\u043b\\u044f\\u0442\\u043d\\u043e \\u0447\\u0430\\u0441\\u043e\\u0432\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Los_Angeles" },
3086     // icu bg.txt has exemplar city for this time zone
3087         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u041B\\u043E\\u0441 \\u0410\\u043D\\u0434\\u0436\\u0435\\u043B\\u0438\\u0441", "America/Los_Angeles" },
3088         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u0421\\u0435\\u0432\\u0435\\u0440\\u043d\\u043e\\u0430\\u043c\\u0435\\u0440\\u0438\\u043a\\u0430\\u043d\\u0441\\u043a\\u043e \\u0442\\u0438\\u0445\\u043e\\u043e\\u043a\\u0435\\u0430\\u043d\\u0441\\u043a\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Los_Angeles" },
3089         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\\u041B\\u043E\\u0441 \\u0410\\u043D\\u0434\\u0436\\u0435\\u043B\\u0438\\u0441", "America/Los_Angeles" },
3090 
3091         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3092         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3093         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3094         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
3095         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3096         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3097         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3098         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
3099         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441", "America/Buenos_Aires" },
3100         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Buenos_Aires" },
3101 
3102         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3103         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3104         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3105         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
3106         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3107         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3108         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3109         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
3110     // icu bg.txt does not have info for this time zone
3111         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441", "America/Buenos_Aires" },
3112         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Buenos_Aires" },
3113 
3114         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3115         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-05:00", "-5:00" },
3116         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-5", "-5:00" },
3117         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-5:00" },
3118         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3119         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-04:00", "-4:00" },
3120         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-4", "-4:00" },
3121         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u043b\\u044f\\u0442\\u043d\\u043e \\u0447\\u0430\\u0441\\u043e\\u0432\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-4:00" },
3122         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u041a\\u0443\\u0431\\u0430", "America/Havana" },
3123         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u0432\\u0440\\u0435\\u043C\\u0435", "America/Havana" },
3124 
3125         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3126         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11:00", "+11:00" },
3127         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11", "+11:00" },
3128         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u043B\\u044F\\u0442\\u043D\\u043E \\u0447\\u0430\\u0441\\u043E\\u0432\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+11:00" },
3129         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3130         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10:00", "+10:00" },
3131         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10", "+10:00" },
3132         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u0441\\u0442\\u0430\\u043D\\u0434\\u0430\\u0440\\u0442\\u043D\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+10:00" },
3133         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0421\\u0438\\u0434\\u043D\\u0438", "Australia/Sydney" },
3134         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "Australia/Sydney" },
3135 
3136         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3137         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11:00", "+11:00" },
3138         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11", "+11:00" },
3139         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u043B\\u044F\\u0442\\u043D\\u043E \\u0447\\u0430\\u0441\\u043E\\u0432\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+11:00" },
3140         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3141         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10:00", "+10:00" },
3142         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10", "+10:00" },
3143         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u0441\\u0442\\u0430\\u043D\\u0434\\u0430\\u0440\\u0442\\u043D\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+10:00" },
3144         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0421\\u0438\\u0434\\u043D\\u0438", "Australia/Sydney" },
3145         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "Australia/Sydney" },
3146 
3147         { "bg", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3148         { "bg", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
3149         { "bg", "Europe/London", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
3150         { "bg", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u0421\\u0440\\u0435\\u0434\\u043d\\u043e \\u0433\\u0440\\u0438\\u043d\\u0443\\u0438\\u0447\\u043a\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "+0:00" },
3151         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3152         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+01:00", "+1:00" },
3153         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+1", "+1:00" },
3154         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u0411\\u0440\\u0438\\u0442\\u0430\\u043d\\u0441\\u043a\\u043e \\u043b\\u044f\\u0442\\u043d\\u043e \\u0447\\u0430\\u0441\\u043e\\u0432\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "+1:00" },
3155         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u041E\\u0431\\u0435\\u0434\\u0438\\u043D\\u0435\\u043D\\u043E\\u0442\\u043E \\u043A\\u0440\\u0430\\u043B\\u0441\\u0442\\u0432\\u043E", "Europe/London" },
3156         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u041E\\u0431\\u0435\\u0434\\u0438\\u043D\\u0435\\u043D\\u043E\\u0442\\u043E \\u043A\\u0440\\u0430\\u043B\\u0441\\u0442\\u0432\\u043E", "Europe/London" },
3157 
3158         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3159         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3160         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3161         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3162         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3163         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3164         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3165         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3166         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3167         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3168 
3169         // JB#5150
3170         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3171         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+05:30", "+5:30" },
3172         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+5:30", "+5:30" },
3173         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u0418\\u043D\\u0434\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043c\\u0435", "+5:30" },
3174         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3175         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+05:30", "+5:30" },
3176         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+5:30", "+05:30" },
3177         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u0418\\u043D\\u0434\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043c\\u0435", "+5:30" },
3178         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u0418\\u043D\\u0434\\u0438\\u044F", "Asia/Calcutta" },
3179         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u0418\\u043D\\u0434\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043c\\u0435", "Asia/Calcutta" },
3180     // ==========
3181 
3182         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
3183         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
3184         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
3185         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u30a2\\u30e1\\u30ea\\u30ab\\u592a\\u5e73\\u6d0b\\u6a19\\u6e96\\u6642", "America/Los_Angeles" },
3186         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-700" },
3187         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
3188         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "America/Los_Angeles" },
3189         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u30a2\\u30e1\\u30ea\\u30ab\\u592a\\u5e73\\u6d0b\\u590f\\u6642\\u9593", "America/Los_Angeles" },
3190     // icu ja.txt has exemplar city for this time zone
3191         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u30ED\\u30B5\\u30F3\\u30BC\\u30EB\\u30B9\\u6642\\u9593", "America/Los_Angeles" },
3192         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30E1\\u30EA\\u30AB\\u592A\\u5e73\\u6D0B\\u6642\\u9593", "America/Los_Angeles" },
3193         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\\u30ED\\u30B5\\u30F3\\u30BC\\u30EB\\u30B9\\u6642\\u9593", "America/Los_Angeles" },
3194 
3195         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3196         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3197         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3198         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3199         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3200         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3201         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3202         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3203     // icu ja.txt does not have info for this time zone
3204         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9\\u6642\\u9593", "America/Buenos_Aires" },
3205         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "America/Buenos_Aires" },
3206 
3207         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3208         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3209         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3210         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3211         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3212         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3213         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3214         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3215         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9\\u6642\\u9593", "America/Buenos_Aires" },
3216         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "America/Buenos_Aires" },
3217 
3218         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3219         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
3220         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
3221         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u30AD\\u30E5\\u30FC\\u30D0\\u6A19\\u6E96\\u6642", "-5:00" },
3222         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3223         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
3224         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
3225         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u30AD\\u30E5\\u30FC\\u30D0\\u590F\\u6642\\u9593", "-4:00" },
3226         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
3227         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
3228 
3229         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3230         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3231         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3232         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u590F\\u6642\\u9593", "+11:00" },
3233         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3234         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3235         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3236         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6A19\\u6E96\\u6642", "+10:00" },
3237     // icu ja.txt does not have info for this time zone
3238         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u30B7\\u30C9\\u30CB\\u30FC\\u6642\\u9593", "Australia/Sydney" },
3239         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6642\\u9593", "Australia/Sydney" },
3240 
3241         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3242         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3243         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3244         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u590F\\u6642\\u9593", "+11:00" },
3245         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3246         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3247         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3248         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6A19\\u6E96\\u6642", "+10:00" },
3249         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u30B7\\u30C9\\u30CB\\u30FC\\u6642\\u9593", "Australia/Sydney" },
3250         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6642\\u9593", "Australia/Sydney" },
3251 
3252         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3253         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
3254         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
3255         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u30B0\\u30EA\\u30CB\\u30C3\\u30B8\\u6A19\\u6E96\\u6642", "+0:00" },
3256         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3257         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
3258         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
3259         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u82f1\\u56fd\\u590f\\u6642\\u9593", "+1:00" },
3260         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
3261         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
3262         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
3263 
3264         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3265         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3266         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3267         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3268         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3269         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3270         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3271         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3272         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
3273         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
3274 
3275         // JB#5150
3276         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3277         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3278         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
3279         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u30A4\\u30F3\\u30C9\\u6A19\\u6E96\\u6642", "+5:30" },
3280         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3281         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3282         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
3283         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u30A4\\u30F3\\u30C9\\u6A19\\u6E96\\u6642", "+5:30" },
3284         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u30A4\\u30F3\\u30C9\\u6642\\u9593", "Asia/Calcutta" },
3285         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u30A4\\u30F3\\u30C9\\u6A19\\u6E96\\u6642", "Asia/Calcutta" },
3286 
3287     // ==========
3288 
3289         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
3290         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
3291         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
3292         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "GMT-08:00", "-8:00" },
3293         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
3294         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
3295         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
3296         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "GMT-07:00", "-7:00" },
3297         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Los Angeles", "America/Los_Angeles" },
3298         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Los Angeles", "America/Los_Angeles" },
3299 
3300         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3301         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3302         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3303         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3304         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3305         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3306         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3307         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3308         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires", "America/Buenos_Aires" },
3309         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Buenos Aires", "America/Buenos_Aires" },
3310 
3311         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3312         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3313         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3314         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3315         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3316         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3317         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3318         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3319         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires", "America/Buenos_Aires" },
3320         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Buenos Aires", "America/Buenos_Aires" },
3321 
3322         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3323         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
3324         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
3325         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-05:00", "-5:00" },
3326         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3327         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
3328         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
3329         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-04:00", "-4:00" },
3330         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u12A9\\u1263", "America/Havana" },
3331         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u12A9\\u1263", "America/Havana" },
3332 
3333         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3334         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3335         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3336         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
3337         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3338         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3339         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3340         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
3341         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney", "Australia/Sydney" },
3342         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Sydney", "Australia/Sydney" },
3343 
3344         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3345         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3346         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3347         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
3348         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3349         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3350         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3351         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
3352         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney", "Australia/Sydney" },
3353         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Sydney", "Australia/Sydney" },
3354 
3355         { "ti", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3356         { "ti", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
3357         { "ti", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
3358         { "ti", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT", "+0:00" },
3359         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3360         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
3361         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
3362         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+01:00", "+1:00" },
3363         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u12A5\\u1295\\u130D\\u120A\\u12DD", "Europe/London" },
3364         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u12A5\\u1295\\u130D\\u120A\\u12DD", "Europe/London" },
3365 
3366         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3367         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3368         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3369         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3370         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3371         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3372         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3373         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3374         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
3375         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
3376 
3377         // JB#5150
3378         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3379         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3380         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
3381         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
3382         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3383         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3384         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
3385         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
3386         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u1205\\u1295\\u12F2", "Alna/Calcutta" },
3387         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u1205\\u1295\\u12F2", "Asia/Calcutta" },
3388 
3389         // Ticket#8589 Partial location name to use country name if the zone is the golden
3390         // zone for the time zone's country.
3391         { "en_MX", "America/Chicago", "1995-07-15T00:00:00Z", "vvvv", "Central Time (United States)", "America/Chicago"},
3392 
3393         // Tests proper handling of time zones that should have empty sets when inherited from the parent.
3394         // For example, en_GB understands CET as Central European Time, but en_HK, which inherits from en_GB
3395         // does not
3396         { "en_GB", "Europe/Paris", "2004-01-15T00:00:00Z", "zzzz", "Central European Standard Time", "+1:00"},
3397         { "en_GB", "Europe/Paris", "2004-07-15T00:00:00Z", "zzzz", "Central European Summer Time", "+2:00"},
3398         { "en_GB", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "CET", "+1:00"},
3399         { "en_GB", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "CEST", "+2:00"},
3400         { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "zzzz", "Central European Standard Time", "+1:00"},
3401         { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "zzzz", "Central European Summer Time", "+2:00"},
3402         { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "GMT+1", "+1:00"},
3403         { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "GMT+2", "+2:00"},
3404 
3405         { NULL, NULL, NULL, NULL, NULL, NULL },
3406     };
3407 
3408     UErrorCode status = U_ZERO_ERROR;
3409     LocalPointer<Calendar> cal(GregorianCalendar::createInstance(status));
3410     if (failure(status, "GregorianCalendar::createInstance", TRUE)) return;
3411     SimpleDateFormat testfmt(UnicodeString("yyyy-MM-dd'T'HH:mm:ss'Z'"), status);
3412     if (failure(status, "SimpleDateFormat constructor", TRUE)) return;
3413     testfmt.setTimeZone(*TimeZone::getGMT());
3414 
3415     for (int i = 0; fallbackTests[i][0]; i++) {
3416         const char **testLine = fallbackTests[i];
3417         UnicodeString info[5];
3418         for ( int j = 0 ; j < 5 ; j++ ) {
3419             info[j] = UnicodeString(testLine[j], -1, US_INV);
3420         }
3421         info[4] = info[4].unescape();
3422         logln("%s;%s;%s;%s", testLine[0], testLine[1], testLine[2], testLine[3]);
3423 
3424         TimeZone *tz = TimeZone::createTimeZone(info[1]);
3425 
3426         UDate d = testfmt.parse(testLine[2], status);
3427         cal->setTime(d, status);
3428         if (U_FAILURE(status)) {
3429             errln(UnicodeString("Failed to set date: ") + testLine[2]);
3430         }
3431 
3432         SimpleDateFormat fmt(info[3], Locale(testLine[0]),status);
3433         ASSERT_OK(status);
3434         cal->adoptTimeZone(tz);
3435         UnicodeString result;
3436         FieldPosition pos(FieldPosition::DONT_CARE);
3437         fmt.format(*cal.getAlias(), result,pos);
3438         if (result != info[4]) {
3439             errln(info[0] + ";" + info[1] + ";" + info[2] + ";" + info[3] + " expected: '" +
3440                   info[4] + "' but got: '" + result + "'");
3441         }
3442     }
3443 }
3444 
TestRoundtripWithCalendar(void)3445 void DateFormatTest::TestRoundtripWithCalendar(void) {
3446     UErrorCode status = U_ZERO_ERROR;
3447 
3448     TimeZone *tz = TimeZone::createTimeZone("Europe/Paris");
3449     TimeZone *gmt = TimeZone::createTimeZone("Etc/GMT");
3450 
3451     Calendar *calendars[] = {
3452         Calendar::createInstance(*tz, Locale("und@calendar=gregorian"), status),
3453         Calendar::createInstance(*tz, Locale("und@calendar=buddhist"), status),
3454 //        Calendar::createInstance(*tz, Locale("und@calendar=hebrew"), status),
3455         Calendar::createInstance(*tz, Locale("und@calendar=islamic"), status),
3456         Calendar::createInstance(*tz, Locale("und@calendar=japanese"), status),
3457         NULL
3458     };
3459     if (U_FAILURE(status)) {
3460         dataerrln("Failed to initialize calendars: %s", u_errorName(status));
3461         for (int i = 0; calendars[i] != NULL; i++) {
3462             delete calendars[i];
3463         }
3464         return;
3465     }
3466 
3467     //FIXME The formatters commented out below are currently failing because of
3468     // the calendar calculation problem reported by #6691
3469 
3470     // The order of test formatters must match the order of calendars above.
3471     DateFormat *formatters[] = {
3472         DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("en_US")), //calendar=gregorian
3473         DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("th_TH")), //calendar=buddhist
3474 //        DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("he_IL@calendar=hebrew")),
3475         DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("ar_EG@calendar=islamic")),
3476 //        DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("ja_JP@calendar=japanese")),
3477         NULL
3478     };
3479 
3480     UDate d = Calendar::getNow();
3481     UnicodeString buf;
3482     FieldPosition fpos;
3483     ParsePosition ppos;
3484 
3485     for (int i = 0; formatters[i] != NULL; i++) {
3486         buf.remove();
3487         fpos.setBeginIndex(0);
3488         fpos.setEndIndex(0);
3489         calendars[i]->setTime(d, status);
3490 
3491         // Normal case output - the given calendar matches the calendar
3492         // used by the formatter
3493         formatters[i]->format(*calendars[i], buf, fpos);
3494         UnicodeString refStr(buf);
3495 
3496         for (int j = 0; calendars[j] != NULL; j++) {
3497             if (j == i) {
3498                 continue;
3499             }
3500             buf.remove();
3501             fpos.setBeginIndex(0);
3502             fpos.setEndIndex(0);
3503             calendars[j]->setTime(d, status);
3504 
3505             // Even the different calendar type is specified,
3506             // we should get the same result.
3507             formatters[i]->format(*calendars[j], buf, fpos);
3508             if (refStr != buf) {
3509                 errln((UnicodeString)"FAIL: Different format result with a different calendar for the same time -"
3510                         + "\n Reference calendar type=" + calendars[i]->getType()
3511                         + "\n Another calendar type=" + calendars[j]->getType()
3512                         + "\n Expected result=" + refStr
3513                         + "\n Actual result=" + buf);
3514             }
3515         }
3516 
3517         calendars[i]->setTimeZone(*gmt);
3518         calendars[i]->clear();
3519         ppos.setErrorIndex(-1);
3520         ppos.setIndex(0);
3521 
3522         // Normal case parse result - the given calendar matches the calendar
3523         // used by the formatter
3524         formatters[i]->parse(refStr, *calendars[i], ppos);
3525 
3526         for (int j = 0; calendars[j] != NULL; j++) {
3527             if (j == i) {
3528                 continue;
3529             }
3530             calendars[j]->setTimeZone(*gmt);
3531             calendars[j]->clear();
3532             ppos.setErrorIndex(-1);
3533             ppos.setIndex(0);
3534 
3535             // Even the different calendar type is specified,
3536             // we should get the same time and time zone.
3537             formatters[i]->parse(refStr, *calendars[j], ppos);
3538             if (calendars[i]->getTime(status) != calendars[j]->getTime(status)
3539                 || calendars[i]->getTimeZone() != calendars[j]->getTimeZone()) {
3540                 UnicodeString tzid;
3541                 errln((UnicodeString)"FAIL: Different parse result with a different calendar for the same string -"
3542                         + "\n Reference calendar type=" + calendars[i]->getType()
3543                         + "\n Another calendar type=" + calendars[j]->getType()
3544                         + "\n Date string=" + refStr
3545                         + "\n Expected time=" + calendars[i]->getTime(status)
3546                         + "\n Expected time zone=" + calendars[i]->getTimeZone().getID(tzid)
3547                         + "\n Actual time=" + calendars[j]->getTime(status)
3548                         + "\n Actual time zone=" + calendars[j]->getTimeZone().getID(tzid));
3549             }
3550         }
3551         if (U_FAILURE(status)) {
3552             errln((UnicodeString)"FAIL: " + u_errorName(status));
3553             break;
3554         }
3555     }
3556 
3557     delete tz;
3558     delete gmt;
3559     for (int i = 0; calendars[i] != NULL; i++) {
3560         delete calendars[i];
3561     }
3562     for (int i = 0; formatters[i] != NULL; i++) {
3563         delete formatters[i];
3564     }
3565 }
3566 
3567 /*
3568 void DateFormatTest::TestRelativeError(void)
3569 {
3570     UErrorCode status;
3571     Locale en("en");
3572 
3573     DateFormat *en_reltime_reldate =         DateFormat::createDateTimeInstance(DateFormat::kFullRelative,DateFormat::kFullRelative,en);
3574     if(en_reltime_reldate == NULL) {
3575         logln("PASS: rel date/rel time failed");
3576     } else {
3577         errln("FAIL: rel date/rel time created, should have failed.");
3578         delete en_reltime_reldate;
3579     }
3580 }
3581 
3582 void DateFormatTest::TestRelativeOther(void)
3583 {
3584     logln("Nothing in this test. When we get more data from CLDR, put in some tests of -2, +2, etc. ");
3585 }
3586 */
3587 
Test6338(void)3588 void DateFormatTest::Test6338(void)
3589 {
3590     UErrorCode status = U_ZERO_ERROR;
3591 
3592     SimpleDateFormat fmt1(UnicodeString(u"y-M-d"), Locale("ar"), status);
3593     if (failure(status, "new SimpleDateFormat", TRUE)) return;
3594 
3595     UDate dt1 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3596     UnicodeString str1;
3597     str1 = fmt1.format(dt1, str1);
3598     logln(str1);
3599 
3600     UDate dt11 = fmt1.parse(str1, status);
3601     failure(status, "fmt->parse");
3602 
3603     UnicodeString str11;
3604     str11 = fmt1.format(dt11, str11);
3605     logln(str11);
3606 
3607     if (str1 != str11) {
3608         errln((UnicodeString)"FAIL: Different dates str1:" + str1
3609             + " str2:" + str11);
3610     }
3611 
3612     /////////////////
3613 
3614     status = U_ZERO_ERROR;
3615     SimpleDateFormat fmt2(UnicodeString(u"y M d"), Locale("ar"), status);
3616     failure(status, "new SimpleDateFormat");
3617 
3618     UDate dt2 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3619     UnicodeString str2;
3620     str2 = fmt2.format(dt2, str2);
3621     logln(str2);
3622 
3623     UDate dt22 = fmt2.parse(str2, status);
3624     failure(status, "fmt->parse");
3625 
3626     UnicodeString str22;
3627     str22 = fmt2.format(dt22, str22);
3628     logln(str22);
3629 
3630     if (str2 != str22) {
3631         errln((UnicodeString)"FAIL: Different dates str1:" + str2
3632             + " str2:" + str22);
3633     }
3634 
3635     /////////////////
3636 
3637     status = U_ZERO_ERROR;
3638     SimpleDateFormat fmt3(UnicodeString("y-M-d"), Locale("en-us"), status);
3639     failure(status, "new SimpleDateFormat");
3640 
3641     UDate dt3 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3642     UnicodeString str3;
3643     str3 = fmt3.format(dt3, str3);
3644     logln(str3);
3645 
3646     UDate dt33 = fmt3.parse(str3, status);
3647     failure(status, "fmt->parse");
3648 
3649     UnicodeString str33;
3650     str33 = fmt3.format(dt33, str33);
3651     logln(str33);
3652 
3653     if (str3 != str33) {
3654         errln((UnicodeString)"FAIL: Different dates str1:" + str3
3655             + " str2:" + str33);
3656     }
3657 
3658     /////////////////
3659 
3660     status = U_ZERO_ERROR;
3661     SimpleDateFormat fmt4(UnicodeString("y M  d"), Locale("en-us"), status);
3662     failure(status, "new SimpleDateFormat");
3663 
3664     UDate dt4 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3665     UnicodeString str4;
3666     str4 = fmt4.format(dt4, str4);
3667     logln(str4);
3668 
3669     UDate dt44 = fmt4.parse(str4, status);
3670     failure(status, "fmt->parse");
3671 
3672     UnicodeString str44;
3673     str44 = fmt4.format(dt44, str44);
3674     logln(str44);
3675 
3676     if (str4 != str44) {
3677         errln((UnicodeString)"FAIL: Different dates str1:" + str4
3678             + " str2:" + str44);
3679     }
3680 
3681 }
3682 
Test6726(void)3683 void DateFormatTest::Test6726(void)
3684 {
3685     // status
3686 //    UErrorCode status = U_ZERO_ERROR;
3687 
3688     // fmtf, fmtl, fmtm, fmts;
3689     UnicodeString strf, strl, strm, strs;
3690     UDate dt = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3691 
3692     Locale loc("ja");
3693     DateFormat* fmtf = DateFormat::createDateTimeInstance(DateFormat::FULL, DateFormat::FULL, loc);
3694     DateFormat* fmtl = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::FULL, loc);
3695     DateFormat* fmtm = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL, loc);
3696     DateFormat* fmts = DateFormat::createDateTimeInstance(DateFormat::SHORT, DateFormat::FULL, loc);
3697     if (fmtf == NULL || fmtl == NULL || fmtm == NULL || fmts == NULL) {
3698         dataerrln("Unable to create DateFormat. got NULL.");
3699         /* It may not be true that if one is NULL all is NULL.  Just to be safe. */
3700         delete fmtf;
3701         delete fmtl;
3702         delete fmtm;
3703         delete fmts;
3704 
3705         return;
3706     }
3707     strf = fmtf->format(dt, strf);
3708     strl = fmtl->format(dt, strl);
3709     strm = fmtm->format(dt, strm);
3710     strs = fmts->format(dt, strs);
3711 
3712 
3713     logln("strm.charAt(10)=%04X wanted 0x20\n", strm.charAt(10));
3714     if (strm.charAt(10) != UChar(0x0020)) {
3715       errln((UnicodeString)"FAIL: Improper formatted date: " + strm );
3716     }
3717     logln("strs.charAt(10)=%04X wanted 0x20\n", strs.charAt(8));
3718     if (strs.charAt(10)  != UChar(0x0020)) {
3719         errln((UnicodeString)"FAIL: Improper formatted date: " + strs);
3720     }
3721 
3722     delete fmtf;
3723     delete fmtl;
3724     delete fmtm;
3725     delete fmts;
3726 
3727     return;
3728 }
3729 
3730 /**
3731  * Test DateFormat's parsing of default GMT variants.  See ticket#6135
3732  */
TestGMTParsing()3733 void DateFormatTest::TestGMTParsing() {
3734     const char* DATA[] = {
3735         "HH:mm:ss Z",
3736 
3737         // pattern, input, expected output (in quotes)
3738         "HH:mm:ss Z",       "10:20:30 GMT+03:00",   "10:20:30 +0300",
3739         "HH:mm:ss Z",       "10:20:30 UT-02:00",    "10:20:30 -0200",
3740         "HH:mm:ss Z",       "10:20:30 GMT",         "10:20:30 +0000",
3741         "HH:mm:ss vvvv",    "10:20:30 UT+10:00",    "10:20:30 +1000",
3742         "HH:mm:ss zzzz",    "10:20:30 UTC",         "10:20:30 +0000",   // standalone "UTC"
3743         "ZZZZ HH:mm:ss",    "UT 10:20:30",          "10:20:30 +0000",
3744         "z HH:mm:ss",       "UT+0130 10:20:30",     "10:20:30 +0130",
3745         "z HH:mm:ss",       "UTC+0130 10:20:30",    "10:20:30 +0130",
3746         // Note: GMT-1100 no longer works because of the introduction of the short
3747         // localized GMT support. Previous implementation support this level of
3748         // leniency (no separator char in localized GMT format), but the new
3749         // implementation handles GMT-11 as the legitimate short localized GMT format
3750         // and stop at there. Otherwise, roundtrip would be broken.
3751         //"HH mm Z ss",       "10 20 GMT-1100 30",    "10:20:30 -1100",
3752         "HH mm Z ss",       "10 20 GMT-11 30",    "10:20:30 -1100",
3753         "HH:mm:ssZZZZZ",    "14:25:45Z",            "14:25:45 +0000",
3754         "HH:mm:ssZZZZZ",    "15:00:00-08:00",       "15:00:00 -0800",
3755     };
3756     const int32_t DATA_len = UPRV_LENGTHOF(DATA);
3757     expectParse(DATA, DATA_len, Locale("en"));
3758 }
3759 
3760 // Test case for localized GMT format parsing
3761 // with no delimitters in offset format (Chinese locale)
Test6880()3762 void DateFormatTest::Test6880() {
3763     UErrorCode status = U_ZERO_ERROR;
3764     UDate d1, d2, dp1, dp2, dexp1, dexp2;
3765     UnicodeString s1, s2;
3766 
3767     TimeZone *tz = TimeZone::createTimeZone("Asia/Shanghai");
3768     GregorianCalendar gcal(*tz, status);
3769     if (failure(status, "construct GregorianCalendar", TRUE)) return;
3770 
3771     gcal.clear();
3772     gcal.set(1900, UCAL_JULY, 1, 12, 00);   // offset 8:05:43
3773     d1 = gcal.getTime(status);
3774 
3775     gcal.clear();
3776     gcal.set(1950, UCAL_JULY, 1, 12, 00);   // offset 8:00
3777     d2 = gcal.getTime(status);
3778 
3779     gcal.clear();
3780     gcal.set(1970, UCAL_JANUARY, 1, 12, 00);
3781     dexp2 = gcal.getTime(status);
3782     dexp1 = dexp2 - (5*60 + 43)*1000;   // subtract 5m43s
3783 
3784     if (U_FAILURE(status)) {
3785         errln("FAIL: Gregorian calendar error");
3786     }
3787 
3788     DateFormat *fmt = DateFormat::createTimeInstance(DateFormat::kFull, Locale("zh"));
3789     if (fmt == NULL) {
3790         dataerrln("Unable to create DateFormat. Got NULL.");
3791         return;
3792     }
3793     fmt->adoptTimeZone(tz);
3794 
3795     fmt->format(d1, s1);
3796     fmt->format(d2, s2);
3797 
3798     dp1 = fmt->parse(s1, status);
3799     dp2 = fmt->parse(s2, status);
3800 
3801     if (U_FAILURE(status)) {
3802         errln("FAIL: Parse failure");
3803     }
3804 
3805     if (dp1 != dexp1) {
3806         errln("FAIL: Failed to parse " + s1 + " parsed: " + dp1 + " expected: " + dexp1);
3807     }
3808     if (dp2 != dexp2) {
3809         errln("FAIL: Failed to parse " + s2 + " parsed: " + dp2 + " expected: " + dexp2);
3810     }
3811 
3812     delete fmt;
3813 }
3814 
3815 typedef struct {
3816     const char * localeStr;
3817     UBool        lenient;
3818     UBool        expectFail;
3819     UnicodeString datePattern;
3820     UnicodeString dateString;
3821 } NumAsStringItem;
3822 
TestNumberAsStringParsing()3823 void DateFormatTest::TestNumberAsStringParsing()
3824 {
3825     const NumAsStringItem items[] = {
3826         // loc lenient fail?  datePattern                                         dateString
3827         { "",   FALSE, TRUE,  UnicodeString("y MMMM d HH:mm:ss"),                 UnicodeString("2009 7 14 08:43:57") },
3828         { "",   TRUE,  FALSE, UnicodeString("y MMMM d HH:mm:ss"),                 UnicodeString("2009 7 14 08:43:57") },
3829         { "en", FALSE, FALSE, UnicodeString("MMM d, y"),                          UnicodeString("Jul 14, 2009") },
3830         { "en", TRUE,  FALSE, UnicodeString("MMM d, y"),                          UnicodeString("Jul 14, 2009") },
3831         { "en", FALSE, TRUE,  UnicodeString("MMM d, y"),                          UnicodeString("7 14, 2009") },
3832         { "en", TRUE,  FALSE, UnicodeString("MMM d, y"),                          UnicodeString("7 14, 2009") },
3833         { "ja", FALSE, FALSE, UnicodeString("yyyy/MM/dd"),                        UnicodeString("2009/07/14")         },
3834         { "ja", TRUE,  FALSE, UnicodeString("yyyy/MM/dd"),                        UnicodeString("2009/07/14")         },
3835       //{ "ja", FALSE, FALSE, UnicodeString("yyyy/MMMMM/d"),                      UnicodeString("2009/7/14")          }, // #8860 covers test failure
3836         { "ja", TRUE,  FALSE, UnicodeString("yyyy/MMMMM/d"),                      UnicodeString("2009/7/14")          },
3837         { "ja", FALSE, FALSE, CharsToUnicodeString("y\\u5E74M\\u6708d\\u65E5"),   CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5")   },
3838         { "ja", TRUE,  FALSE, CharsToUnicodeString("y\\u5E74M\\u6708d\\u65E5"),   CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5")   },
3839         { "ja", FALSE, FALSE, CharsToUnicodeString("y\\u5E74MMMd\\u65E5"),        CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5")   },
3840         { "ja", TRUE,  FALSE, CharsToUnicodeString("y\\u5E74MMMd\\u65E5"),        CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5")   }, // #8820 fixes test failure
3841         { "ko", FALSE, FALSE, UnicodeString("yyyy. M. d."),                       UnicodeString("2009. 7. 14.")       },
3842         { "ko", TRUE,  FALSE, UnicodeString("yyyy. M. d."),                       UnicodeString("2009. 7. 14.")       },
3843         { "ko", FALSE, FALSE, UnicodeString("yyyy. MMMMM d."),                    CharsToUnicodeString("2009. 7\\uC6D4 14.")             },
3844         { "ko", TRUE,  FALSE, UnicodeString("yyyy. MMMMM d."),                    CharsToUnicodeString("2009. 7\\uC6D4 14.")             }, // #8820 fixes test failure
3845         { "ko", FALSE, FALSE, CharsToUnicodeString("y\\uB144 M\\uC6D4 d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
3846         { "ko", TRUE,  FALSE, CharsToUnicodeString("y\\uB144 M\\uC6D4 d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
3847         { "ko", FALSE, FALSE, CharsToUnicodeString("y\\uB144 MMM d\\uC77C"),      CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
3848         { "ko", TRUE,  FALSE, CharsToUnicodeString("y\\uB144 MMM d\\uC77C"),      CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") }, // #8820 fixes test failure
3849         { NULL, FALSE, FALSE, UnicodeString(""),                                  UnicodeString("")                   }
3850     };
3851     const NumAsStringItem * itemPtr;
3852     for (itemPtr = items; itemPtr->localeStr != NULL; itemPtr++ ) {
3853         Locale locale = Locale::createFromName(itemPtr->localeStr);
3854         UErrorCode status = U_ZERO_ERROR;
3855         SimpleDateFormat formatter(itemPtr->datePattern, locale, status);
3856         if (U_FAILURE(status)) {
3857             dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
3858             return;
3859         }
3860 
3861         formatter.setLenient(itemPtr->lenient);
3862         formatter.setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->lenient, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->lenient, status);
3863         UDate date1 = formatter.parse(itemPtr->dateString, status);
3864         if (U_FAILURE(status)) {
3865             if (!itemPtr->expectFail) {
3866                 errln("FAIL, err when expected success: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
3867                         ": using pattern \"" + itemPtr->datePattern + "\", could not parse \"" + itemPtr->dateString + "\"; err: " + u_errorName(status) );
3868             }
3869         } else if (itemPtr->expectFail) {
3870                 errln("FAIL, expected err but got none: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
3871                         ": using pattern \"" + itemPtr->datePattern + "\", did parse \"" + itemPtr->dateString + "\"." );
3872         } else if (!itemPtr->lenient) {
3873             UnicodeString formatted;
3874             formatter.format(date1, formatted);
3875             if (formatted != itemPtr->dateString) {
3876                 errln("FAIL, mismatch formatting parsed date: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
3877                         ": using pattern \"" + itemPtr->datePattern + "\", did parse \"" + itemPtr->dateString + "\", formatted result \"" + formatted + "\".");
3878             }
3879         }
3880     }
3881 }
3882 
TestISOEra()3883 void DateFormatTest::TestISOEra() {
3884 
3885     const char* data[] = {
3886     // input, output
3887     "BC 4004-10-23T07:00:00Z", "BC 4004-10-23T07:00:00Z",
3888     "AD 4004-10-23T07:00:00Z", "AD 4004-10-23T07:00:00Z",
3889     "-4004-10-23T07:00:00Z"  , "BC 4005-10-23T07:00:00Z",
3890     "4004-10-23T07:00:00Z"   , "AD 4004-10-23T07:00:00Z",
3891     };
3892 
3893     int32_t numData = 8;
3894 
3895     UErrorCode status = U_ZERO_ERROR;
3896 
3897     // create formatter
3898     SimpleDateFormat *fmt1 = new SimpleDateFormat(UnicodeString("GGG yyyy-MM-dd'T'HH:mm:ss'Z"), status);
3899     failure(status, "new SimpleDateFormat", TRUE);
3900     if (status == U_MISSING_RESOURCE_ERROR) {
3901         if (fmt1 != NULL) {
3902             delete fmt1;
3903         }
3904         return;
3905     }
3906     for(int i=0; i < numData; i+=2) {
3907         // create input string
3908         UnicodeString in = data[i];
3909 
3910         // parse string to date
3911         UDate dt1 = fmt1->parse(in, status);
3912         failure(status, "fmt->parse", TRUE);
3913 
3914         // format date back to string
3915         UnicodeString out;
3916         out = fmt1->format(dt1, out);
3917         logln(out);
3918 
3919         // check that roundtrip worked as expected
3920         UnicodeString expected = data[i+1];
3921         if (out != expected) {
3922             dataerrln((UnicodeString)"FAIL: " + in + " -> " + out + " expected -> " + expected);
3923         }
3924     }
3925 
3926     delete fmt1;
3927 }
TestFormalChineseDate()3928 void DateFormatTest::TestFormalChineseDate() {
3929 
3930     UErrorCode status = U_ZERO_ERROR;
3931     UnicodeString pattern(u"y\u5e74M\u6708d\u65e5");
3932     UnicodeString numsys_override(u"y=hanidec;M=hans;d=hans");
3933 
3934     // create formatter
3935     SimpleDateFormat sdf(pattern, numsys_override, Locale::getChina(),status);
3936     if (failure(status, "new SimpleDateFormat with override", true)) {
3937         return;
3938     }
3939 
3940     UDate thedate = date(2009-1900, UCAL_JULY, 28);
3941     FieldPosition pos(FieldPosition::DONT_CARE);
3942     UnicodeString result;
3943     sdf.format(thedate,result,pos);
3944 
3945     UnicodeString expected = "\\u4e8c\\u3007\\u3007\\u4e5d\\u5e74\\u4e03\\u6708\\u4e8c\\u5341\\u516b\\u65e5";
3946     expected = expected.unescape();
3947     if (result != expected) {
3948         dataerrln((UnicodeString)"FAIL: -> " + result + " expected -> " + expected);
3949     }
3950 
3951     UDate parsedate = sdf.parse(expected,status);
3952     if ( parsedate != thedate ) {
3953         UnicodeString pat1 ("yyyy-MM-dd'T'HH:mm:ss'Z'", -1, US_INV );
3954         SimpleDateFormat usf(pat1, Locale::getEnglish(), status);
3955         UnicodeString parsedres,expres;
3956         usf.format(parsedate,parsedres,pos);
3957         usf.format(thedate,expres,pos);
3958         dataerrln((UnicodeString)"FAIL: parsed -> " + parsedres + " expected -> " + expres);
3959     }
3960 }
3961 
3962 // Test case for #8675
3963 // Incorrect parse offset with stand alone GMT string on 2nd or later iteration.
TestStandAloneGMTParse()3964 void DateFormatTest::TestStandAloneGMTParse() {
3965     UErrorCode status = U_ZERO_ERROR;
3966     SimpleDateFormat sdf("ZZZZ", Locale(""), status);
3967 
3968     if (U_SUCCESS(status)) {
3969 
3970         UnicodeString inText(u"GMT$$$");
3971         for (int32_t i = 0; i < 10; i++) {
3972             ParsePosition pos(0);
3973             sdf.parse(inText, pos);
3974             if (pos.getIndex() != 3) {
3975                 errln((UnicodeString)"FAIL: Incorrect output parse position: actual=" + pos.getIndex() + " expected=3");
3976             }
3977         }
3978 
3979     } else {
3980         dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
3981     }
3982 }
3983 
TestParsePosition()3984 void DateFormatTest::TestParsePosition() {
3985     const char* TestData[][4] = {
3986         // {<pattern>, <lead>, <date string>, <trail>}
3987         {"yyyy-MM-dd HH:mm:ssZ", "", "2010-01-10 12:30:00+0500", ""},
3988         {"yyyy-MM-dd HH:mm:ss ZZZZ", "", "2010-01-10 12:30:00 GMT+05:00", ""},
3989         {"Z HH:mm:ss", "", "-0100 13:20:30", ""},
3990         {"y-M-d Z", "", "2011-8-25 -0400", " Foo"},
3991         {"y/M/d H:mm:ss z", "", "2011/7/1 12:34:00 PDT", ""},
3992         {"y/M/d H:mm:ss z", "+123", "2011/7/1 12:34:00 PDT", " PST"},
3993         {"vvvv a h:mm:ss", "", "Pacific Time AM 10:21:45", ""},
3994         {"HH:mm v M/d", "111", "14:15 PT 8/10", " 12345"},
3995         {"'time zone:' VVVV 'date:' yyyy-MM-dd", "xxxx", "time zone: Los Angeles Time date: 2010-02-25", "xxxx"},
3996         {"yG", "", "2012AD", ""},
3997         {"yG", "", "2012", "x"},
3998         {0, 0, 0, 0},
3999     };
4000 
4001     for (int32_t i = 0; TestData[i][0]; i++) {
4002         UErrorCode status = U_ZERO_ERROR;
4003         SimpleDateFormat sdf(UnicodeString(TestData[i][0]), status);
4004         if (failure(status, "new SimpleDateFormat", TRUE)) return;
4005 
4006         int32_t startPos, resPos;
4007 
4008         // lead text
4009         UnicodeString input(TestData[i][1]);
4010         startPos = input.length();
4011 
4012         // date string
4013         input += TestData[i][2];
4014         resPos = input.length();
4015 
4016         // trail text
4017         input += TestData[i][3];
4018 
4019         ParsePosition pos(startPos);
4020         //UDate d = sdf->parse(input, pos);
4021         (void)sdf.parse(input, pos);
4022 
4023         if (pos.getIndex() != resPos) {
4024             errln(UnicodeString("FAIL: Parsing [") + input + "] with pattern [" + TestData[i][0] + "] returns position - "
4025                 + pos.getIndex() + ", expected - " + resPos);
4026         }
4027     }
4028 }
4029 
4030 
4031 typedef struct {
4032     int32_t era;
4033     int32_t year;
4034     int32_t month; // 1-based
4035     int32_t isLeapMonth;
4036     int32_t day;
4037 } ChineseCalTestDate;
4038 
4039 #define NUM_TEST_DATES 3
4040 
4041 typedef struct {
4042     const char *   locale;
4043     int32_t        style; // <0 => custom
4044     UnicodeString  dateString[NUM_TEST_DATES];
4045 } MonthPatternItem;
4046 
TestMonthPatterns()4047 void DateFormatTest::TestMonthPatterns()
4048 {
4049     const ChineseCalTestDate dates[NUM_TEST_DATES] = {
4050         // era yr mo lp da
4051         {  78, 29, 4, 0, 2 }, // (in chinese era 78) gregorian 2012-4-22
4052         {  78, 29, 4, 1, 2 }, // (in chinese era 78) gregorian 2012-5-22
4053         {  78, 29, 5, 0, 2 }, // (in chinese era 78) gregorian 2012-6-20
4054     };
4055 
4056     const MonthPatternItem items[] = {
4057         // locale                     date style;           expected formats for the 3 dates above
4058         { "root@calendar=chinese",    DateFormat::kLong,  { UnicodeString("2012(ren-chen) M04 2"),  UnicodeString("2012(ren-chen) M04bis 2"),  UnicodeString("2012(ren-chen) M05 2") } },
4059         { "root@calendar=chinese",    DateFormat::kShort, { UnicodeString("2012-04-02"),    UnicodeString("2012-04bis-02"),         UnicodeString("2012-05-02") } },
4060         { "root@calendar=chinese",    -1,                 { UnicodeString("29-4-2"),        UnicodeString("29-4bis-2"),             UnicodeString("29-5-2") } },
4061         { "root@calendar=chinese",    -2,                 { UnicodeString("78x29-4-2"),     UnicodeString("78x29-4bis-2"),          UnicodeString("78x29-5-2") } },
4062         { "root@calendar=chinese",    -3,                 { UnicodeString("ren-chen-4-2"),  UnicodeString("ren-chen-4bis-2"),       UnicodeString("ren-chen-5-2") } },
4063         { "root@calendar=chinese",    -4,                 { UnicodeString("ren-chen M04 2"),  UnicodeString("ren-chen M04bis 2"),   UnicodeString("ren-chen M05 2") } },
4064         { "en@calendar=gregorian",    -3,                 { UnicodeString("2012-4-22"),     UnicodeString("2012-5-22"),             UnicodeString("2012-6-20") } },
4065         { "en@calendar=chinese",      DateFormat::kLong,  { UnicodeString("Fourth Month 2, 2012(ren-chen)"), UnicodeString("Fourth Monthbis 2, 2012(ren-chen)"), UnicodeString("Fifth Month 2, 2012(ren-chen)") } },
4066         { "en@calendar=chinese",      DateFormat::kShort, { UnicodeString("4/2/2012"),      UnicodeString("4bis/2/2012"),           UnicodeString("5/2/2012") } },
4067         { "zh@calendar=chinese",      DateFormat::kLong,  { CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u521D\\u4E8C"),
4068                                                             CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u95F0\\u56DB\\u6708\\u521D\\u4E8C"),
4069                                                             CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u4E94\\u6708\\u521D\\u4E8C") } },
4070         { "zh@calendar=chinese",      DateFormat::kShort, { CharsToUnicodeString("2012/4/2"),
4071                                                             CharsToUnicodeString("2012/\\u95F04/2"),
4072                                                             CharsToUnicodeString("2012/5/2") } },
4073         { "zh@calendar=chinese",      -3,                 { CharsToUnicodeString("\\u58EC\\u8FB0-4-2"),
4074                                                             CharsToUnicodeString("\\u58EC\\u8FB0-\\u95F04-2"),
4075                                                             CharsToUnicodeString("\\u58EC\\u8FB0-5-2") } },
4076         { "zh@calendar=chinese",      -4,                 { CharsToUnicodeString("\\u58EC\\u8FB0 \\u56DB\\u6708 2"),
4077                                                             CharsToUnicodeString("\\u58EC\\u8FB0 \\u95F0\\u56DB\\u6708 2"),
4078                                                             CharsToUnicodeString("\\u58EC\\u8FB0 \\u4E94\\u6708 2") } },
4079         { "zh_Hant@calendar=chinese", DateFormat::kLong,  { CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u521D\\u4E8C"),
4080                                                             CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u958F\\u56DB\\u6708\\u521D\\u4E8C"),
4081                                                             CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u4E94\\u6708\\u521D\\u4E8C") } },
4082         { "zh_Hant@calendar=chinese", DateFormat::kShort, { CharsToUnicodeString("2012/4/2"),
4083                                                             CharsToUnicodeString("2012/\\u958F4/2"),
4084                                                             CharsToUnicodeString("2012/5/2") } },
4085         { "fr@calendar=chinese",      DateFormat::kLong,  { CharsToUnicodeString("2 s\\u00ECyu\\u00E8 ren-chen"),
4086                                                             CharsToUnicodeString("2 s\\u00ECyu\\u00E8bis ren-chen"),
4087                                                             CharsToUnicodeString("2 w\\u01D4yu\\u00E8 ren-chen") } },
4088         { "fr@calendar=chinese",      DateFormat::kShort, { UnicodeString("2/4/29"),        UnicodeString("2/4bis/29"),             UnicodeString("2/5/29") } },
4089         { "en@calendar=dangi",        DateFormat::kLong,  { UnicodeString("Third Monthbis 2, 2012(ren-chen)"),  UnicodeString("Fourth Month 2, 2012(ren-chen)"),       UnicodeString("Fifth Month 1, 2012(ren-chen)") } },
4090         { "en@calendar=dangi",        DateFormat::kShort, { UnicodeString("3bis/2/2012"),   UnicodeString("4/2/2012"),              UnicodeString("5/1/2012") } },
4091         { "en@calendar=dangi",        -2,                 { UnicodeString("78x29-3bis-2"),  UnicodeString("78x29-4-2"),             UnicodeString("78x29-5-1") } },
4092         { "ko@calendar=dangi",        DateFormat::kLong,  { CharsToUnicodeString("\\uC784\\uC9C4\\uB144 \\uC7243\\uC6D4 2\\uC77C"),
4093                                                             CharsToUnicodeString("\\uC784\\uC9C4\\uB144 4\\uC6D4 2\\uC77C"),
4094                                                             CharsToUnicodeString("\\uC784\\uC9C4\\uB144 5\\uC6D4 1\\uC77C") } },
4095         { "ko@calendar=dangi",        DateFormat::kShort, { CharsToUnicodeString("29. \\uC7243. 2."),
4096                                                             CharsToUnicodeString("29. 4. 2."),
4097                                                             CharsToUnicodeString("29. 5. 1.") } },
4098         // terminator
4099         { NULL,                       0,                  { UnicodeString(""), UnicodeString(""), UnicodeString("") } }
4100     };
4101 
4102     //.                               style: -1        -2            -3       -4
4103     const UnicodeString customPatterns[] = { "y-Ml-d", "G'x'y-Ml-d", "U-M-d", "U MMM d" }; // like old root pattern, using 'l'
4104 
4105     UErrorCode status = U_ZERO_ERROR;
4106     Locale rootChineseCalLocale = Locale::createFromName("root@calendar=chinese");
4107     Calendar * rootChineseCalendar = Calendar::createInstance(rootChineseCalLocale, status);
4108     if (U_SUCCESS(status)) {
4109         const MonthPatternItem * itemPtr;
4110         for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
4111             Locale locale = Locale::createFromName(itemPtr->locale);
4112             DateFormat * dmft = (itemPtr->style >= 0)?
4113                     DateFormat::createDateInstance((DateFormat::EStyle)itemPtr->style, locale):
4114                     new SimpleDateFormat(customPatterns[-itemPtr->style - 1], locale, status);
4115             if ( dmft != NULL ) {
4116                 if (U_SUCCESS(status)) {
4117                     const ChineseCalTestDate * datePtr = dates;
4118                     int32_t idate;
4119                     for (idate = 0; idate < NUM_TEST_DATES; idate++, datePtr++) {
4120                         rootChineseCalendar->clear();
4121                         rootChineseCalendar->set(UCAL_ERA, datePtr->era);
4122                         rootChineseCalendar->set(datePtr->year, datePtr->month-1, datePtr->day);
4123                         rootChineseCalendar->set(UCAL_IS_LEAP_MONTH, datePtr->isLeapMonth);
4124                         UnicodeString result;
4125                         FieldPosition fpos(FieldPosition::DONT_CARE);
4126                         dmft->format(*rootChineseCalendar, result, fpos);
4127                         if ( result.compare(itemPtr->dateString[idate]) != 0 ) {
4128                             errln( UnicodeString("FAIL: Chinese calendar format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
4129                                     ", expected \"" + itemPtr->dateString[idate] + "\", got \"" + result + "\"");
4130                         } else {
4131                             // formatted OK, try parse
4132                             ParsePosition ppos(0);
4133                             // ensure we are really parsing the fields we should be
4134                             rootChineseCalendar->set(UCAL_YEAR, 1);
4135                             rootChineseCalendar->set(UCAL_MONTH, 0);
4136                             rootChineseCalendar->set(UCAL_IS_LEAP_MONTH, 0);
4137                             rootChineseCalendar->set(UCAL_DATE, 1);
4138                             //
4139                             dmft->parse(result, *rootChineseCalendar, ppos);
4140                             int32_t year = rootChineseCalendar->get(UCAL_YEAR, status);
4141                             int32_t month = rootChineseCalendar->get(UCAL_MONTH, status) + 1;
4142                             int32_t isLeapMonth = rootChineseCalendar->get(UCAL_IS_LEAP_MONTH, status);
4143                             int32_t day = rootChineseCalendar->get(UCAL_DATE, status);
4144                             if ( ppos.getIndex() < result.length() || year != datePtr->year || month != datePtr->month || isLeapMonth != datePtr->isLeapMonth || day != datePtr->day ) {
4145                                 errln( UnicodeString("FAIL: Chinese calendar parse for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
4146                                     ", string \"" + result + "\", expected " + datePtr->year +"-"+datePtr->month+"("+datePtr->isLeapMonth+")-"+datePtr->day + ", got pos " +
4147                                     ppos.getIndex() + " " + year +"-"+month+"("+isLeapMonth+")-"+day);
4148                             }
4149                         }
4150                     }
4151                 } else {
4152                     dataerrln("Error creating SimpleDateFormat for Chinese calendar- %s", u_errorName(status));
4153                 }
4154                 delete dmft;
4155             } else {
4156                 dataerrln("FAIL: Unable to create DateFormat for Chinese calendar- %s", u_errorName(status));
4157             }
4158         }
4159         delete rootChineseCalendar;
4160     } else {
4161         errln(UnicodeString("FAIL: Unable to create Calendar for root@calendar=chinese"));
4162     }
4163 }
4164 
4165 typedef struct {
4166     const char * locale;
4167     UnicodeString pattern;
4168     UDisplayContext capitalizationContext;
4169     UnicodeString expectedFormat;
4170 } TestContextItem;
4171 
TestContext()4172 void DateFormatTest::TestContext()
4173 {
4174     const UDate july022008 = 1215000001979.0;
4175     const TestContextItem items[] = {
4176         //locale              pattern    capitalizationContext                              expected formatted date
4177         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_NONE,                      UnicodeString("juillet 2008") },
4178 #if !UCONFIG_NO_BREAK_ITERATION
4179         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    UnicodeString("juillet 2008") },
4180         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UnicodeString("Juillet 2008") },
4181         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       UnicodeString("juillet 2008") },
4182         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            UnicodeString("Juillet 2008") },
4183 #endif
4184         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_NONE,                      CharsToUnicodeString("\\u010Dervenec 2008") },
4185 #if !UCONFIG_NO_BREAK_ITERATION
4186         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    CharsToUnicodeString("\\u010Dervenec 2008") },
4187         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, CharsToUnicodeString("\\u010Cervenec 2008") },
4188         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       CharsToUnicodeString("\\u010Cervenec 2008") },
4189         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            CharsToUnicodeString("\\u010Dervenec 2008") },
4190 #endif
4191         // terminator
4192         { NULL, UnicodeString(""),       (UDisplayContext)0, UnicodeString("") }
4193     };
4194     UErrorCode status = U_ZERO_ERROR;
4195     Calendar* cal = Calendar::createInstance(status);
4196     if (U_FAILURE(status)) {
4197         dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
4198     } else {
4199         cal->setTime(july022008, status);
4200         const TestContextItem * itemPtr;
4201         for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
4202            Locale locale = Locale::createFromName(itemPtr->locale);
4203            status = U_ZERO_ERROR;
4204            SimpleDateFormat * sdmft = new SimpleDateFormat(itemPtr->pattern, locale, status);
4205            if (U_FAILURE(status)) {
4206                 dataerrln(UnicodeString("FAIL: Unable to create SimpleDateFormat for specified pattern with locale ") + UnicodeString(itemPtr->locale));
4207            } else {
4208                sdmft->setContext(itemPtr->capitalizationContext, status);
4209                UnicodeString result;
4210                FieldPosition pos(FieldPosition::DONT_CARE);
4211                sdmft->format(*cal, result, pos);
4212                if (result.compare(itemPtr->expectedFormat) != 0) {
4213                    errln(UnicodeString("FAIL: format for locale ") + UnicodeString(itemPtr->locale) +
4214                            ", status " + (int)status +
4215                            ", capitalizationContext " + (int)itemPtr->capitalizationContext +
4216                            ", expected " + itemPtr->expectedFormat + ", got " + result);
4217                }
4218            }
4219            if (sdmft) {
4220                delete sdmft;
4221            }
4222         }
4223     }
4224     if (cal) {
4225         delete cal;
4226     }
4227 }
4228 
4229 // test item for a particular locale + calendar and date format
4230 typedef struct {
4231     int32_t era;
4232     int32_t year;
4233     int32_t month;
4234     int32_t day;
4235     int32_t hour;
4236     int32_t minute;
4237     UnicodeString formattedDate;
4238 } CalAndFmtTestItem;
4239 
4240 // test item giving locale + calendar, date format, and CalAndFmtTestItems
4241 typedef struct {
4242     const char * locale; // with calendar
4243     DateFormat::EStyle style;
4244     UnicodeString pattern; // ignored unless style == DateFormat::kNone
4245     const CalAndFmtTestItem *caftItems;
4246 } TestNonGregoItem;
4247 
TestNonGregoFmtParse()4248 void DateFormatTest::TestNonGregoFmtParse()
4249 {
4250     // test items for he@calendar=hebrew, long date format
4251     const CalAndFmtTestItem cafti_he_hebrew_long[] = {
4252         {  0, 4999, 12, 29, 12, 0, CharsToUnicodeString("\\u05DB\\u05F4\\u05D8 \\u05D1\\u05D0\\u05DC\\u05D5\\u05DC \\u05D3\\u05F3\\u05EA\\u05EA\\u05E7\\u05E6\\u05F4\\u05D8") },
4253         {  0, 5100,  0,  1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05EA\\u05E9\\u05E8\\u05D9 \\u05E7\\u05F3") },
4254         {  0, 5774,  5,  1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05D0\\u05D3\\u05E8 \\u05D0\\u05F3 \\u05EA\\u05E9\\u05E2\\u05F4\\u05D3") },
4255         {  0, 5999, 12, 29, 12, 0, CharsToUnicodeString("\\u05DB\\u05F4\\u05D8 \\u05D1\\u05D0\\u05DC\\u05D5\\u05DC \\u05EA\\u05EA\\u05E7\\u05E6\\u05F4\\u05D8") },
4256         {  0, 6100,  0,  1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05EA\\u05E9\\u05E8\\u05D9 \\u05D5\\u05F3\\u05E7\\u05F3") },
4257         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4258     };
4259     const CalAndFmtTestItem cafti_zh_chinese_custU[] = {
4260         { 78,   31,  0,  1, 12, 0, CharsToUnicodeString("2014\\u7532\\u5348\\u5E74\\u6B63\\u67081") },
4261         { 77,   31,  0,  1, 12, 0, CharsToUnicodeString("1954\\u7532\\u5348\\u5E74\\u6B63\\u67081") },
4262         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4263     };
4264     const CalAndFmtTestItem cafti_zh_chinese_custNoU[] = {
4265         { 78,   31,  0,  1, 12, 0, CharsToUnicodeString("2014\\u5E74\\u6B63\\u67081") },
4266         { 77,   31,  0,  1, 12, 0, CharsToUnicodeString("1954\\u5E74\\u6B63\\u67081") },
4267         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4268     };
4269     const CalAndFmtTestItem cafti_ja_japanese_custGy[] = {
4270         {235,   26,  2,  5, 12, 0, CharsToUnicodeString("2014(\\u5E73\\u621026)\\u5E743\\u67085\\u65E5") },
4271         {234,   60,  2,  5, 12, 0, CharsToUnicodeString("1985(\\u662D\\u548C60)\\u5E743\\u67085\\u65E5") },
4272         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4273     };
4274     const CalAndFmtTestItem cafti_ja_japanese_custNoGy[] = {
4275         {235,   26,  2,  5, 12, 0, CharsToUnicodeString("2014\\u5E743\\u67085\\u65E5") },
4276         {234,   60,  2,  5, 12, 0, CharsToUnicodeString("1985\\u5E743\\u67085\\u65E5") },
4277         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4278     };
4279     const CalAndFmtTestItem cafti_en_islamic_cust[] = {
4280         {  0, 1384,  0,  1, 12, 0, UnicodeString("1 Muh. 1384 AH, 1964") },
4281         {  0, 1436,  0,  1, 12, 0, UnicodeString("1 Muh. 1436 AH, 2014") },
4282         {  0, 1487,  0,  1, 12, 0, UnicodeString("1 Muh. 1487 AH, 2064") },
4283         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4284     };
4285     // overal test items
4286     const TestNonGregoItem items[] = {
4287         { "he@calendar=hebrew",   DateFormat::kLong, UnicodeString(""),                 cafti_he_hebrew_long },
4288         { "zh@calendar=chinese",  DateFormat::kNone, CharsToUnicodeString("rU\\u5E74MMMd"),                cafti_zh_chinese_custU },
4289         { "zh@calendar=chinese",  DateFormat::kNone, CharsToUnicodeString("r\\u5E74MMMd"),                 cafti_zh_chinese_custNoU },
4290         { "ja@calendar=japanese", DateFormat::kNone, CharsToUnicodeString("r(Gy)\\u5E74M\\u6708d\\u65E5"), cafti_ja_japanese_custGy },
4291         { "ja@calendar=japanese", DateFormat::kNone, CharsToUnicodeString("r\\u5E74M\\u6708d\\u65E5"),     cafti_ja_japanese_custNoGy },
4292         { "en@calendar=islamic",  DateFormat::kNone, UnicodeString("d MMM y G, r"),     cafti_en_islamic_cust },
4293         { NULL, DateFormat::kNone, UnicodeString(""), NULL } // terminator
4294     };
4295     const TestNonGregoItem * itemPtr;
4296     for (itemPtr = items; itemPtr->locale != NULL; itemPtr++) {
4297         Locale locale = Locale::createFromName(itemPtr->locale);
4298         LocalPointer<DateFormat> dfmt;
4299         UErrorCode status = U_ZERO_ERROR;
4300         if (itemPtr->style != DateFormat::kNone) {
4301             dfmt.adoptInstead(DateFormat::createDateInstance(itemPtr->style, locale));
4302         } else {
4303             dfmt.adoptInstead(new SimpleDateFormat(itemPtr->pattern, locale, status));
4304         }
4305         if (U_FAILURE(status)) {
4306             dataerrln("new SimpleDateFormat fails for locale %s", itemPtr->locale);
4307         } else  if (!dfmt.isValid()) {
4308             dataerrln("DateFormat::createDateInstance fails for locale %s", itemPtr->locale);
4309         } else {
4310             LocalPointer<Calendar>cal((dfmt->getCalendar())->clone());
4311             if (!cal.isValid()) {
4312                 dataerrln("(DateFormat::getCalendar)->clone() fails for locale %s", itemPtr->locale);
4313             } else {
4314                 const CalAndFmtTestItem * caftItemPtr;
4315                 for (caftItemPtr = itemPtr->caftItems; caftItemPtr->year != 0; caftItemPtr++) {
4316                     cal->clear();
4317                     cal->set(UCAL_ERA,    caftItemPtr->era);
4318                     cal->set(UCAL_YEAR,   caftItemPtr->year);
4319                     cal->set(UCAL_MONTH,  caftItemPtr->month);
4320                     cal->set(UCAL_DATE,   caftItemPtr->day);
4321                     cal->set(UCAL_HOUR_OF_DAY, caftItemPtr->hour);
4322                     cal->set(UCAL_MINUTE, caftItemPtr->minute);
4323                     UnicodeString result;
4324                     FieldPosition fpos(FieldPosition::DONT_CARE);
4325                     dfmt->format(*cal, result, fpos);
4326                     if ( result.compare(caftItemPtr->formattedDate) != 0 ) {
4327                         errln( UnicodeString("FAIL: date format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
4328                                 ", expected \"" + caftItemPtr->formattedDate + "\", got \"" + result + "\"");
4329                     } else {
4330                         // formatted OK, try parse
4331                         ParsePosition ppos(0);
4332                         dfmt->parse(result, *cal, ppos);
4333                         status = U_ZERO_ERROR;
4334                         int32_t era = cal->get(UCAL_ERA, status);
4335                         int32_t year = cal->get(UCAL_YEAR, status);
4336                         int32_t month = cal->get(UCAL_MONTH, status);
4337                         int32_t day = cal->get(UCAL_DATE, status);
4338                         if ( U_FAILURE(status) || ppos.getIndex() < result.length() || era != caftItemPtr->era ||
4339                                 year != caftItemPtr->year || month != caftItemPtr->month || day != caftItemPtr->day ) {
4340                             errln( UnicodeString("FAIL: date parse for locale ") + UnicodeString(itemPtr->locale) +
4341                                 ", style " + itemPtr->style + ", string \"" + result + "\", expected " +
4342                                 caftItemPtr->era +":"+caftItemPtr->year +"-"+caftItemPtr->month+"-"+caftItemPtr->day + ", got pos " +
4343                                 ppos.getIndex() + " " + year +"-"+month+"-"+day + " status " + UnicodeString(u_errorName(status)) );
4344                         }
4345                     }
4346                 }
4347             }
4348         }
4349     }
4350 }
4351 
4352 typedef struct {
4353     const char*         localeID;
4354     DateFormat::EStyle  style;
4355     UnicodeString       expectPattern;
4356     UnicodeString       expectFormat;
4357 } TestFmtWithNumSysItem;
4358 enum { kBBufMax = 128 };
TestFormatsWithNumberSystems()4359 void DateFormatTest::TestFormatsWithNumberSystems()
4360 {
4361     LocalPointer<TimeZone> zone(TimeZone::createTimeZone(UnicodeString("UTC")));
4362     const UDate date = 1451556000000.0; // for UTC: grego 31-Dec-2015 10 AM, hebrew 19 tevet 5776, chinese yi-wei 11mo 21day
4363     const TestFmtWithNumSysItem items[] = {
4364         { "haw@calendar=gregorian", DateFormat::kShort, UnicodeString("d/M/yy"),               UnicodeString("31/xii/15") },
4365         { "he@calendar=hebrew",     DateFormat::kLong, CharsToUnicodeString("d \\u05D1MMMM y"), CharsToUnicodeString("\\u05D9\\u05F4\\u05D8 \\u05D1\\u05D8\\u05D1\\u05EA \\u05EA\\u05E9\\u05E2\\u05F4\\u05D5") },
4366         { "zh@calendar=chinese",      DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u5341\\u4E00\\u6708\\u5EFF\\u4E00") },
4367         { "zh_Hant@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u51AC\\u6708\\u5EFF\\u4E00") },
4368         { "ja@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("U\\u5E74MMMd\\u65E5"), CharsToUnicodeString("\\u4E59\\u672A\\u5E74\\u5341\\u4E00\\u6708\\u4E8C\\u4E00\\u65E5") },
4369         { NULL, DateFormat::kNone, UnicodeString(""), UnicodeString("") },
4370     };
4371     const TestFmtWithNumSysItem * itemPtr;
4372     for (itemPtr = items; itemPtr->localeID != NULL; itemPtr++) {
4373         char bExpected[kBBufMax];
4374         char bResult[kBBufMax];
4375         UErrorCode status = U_ZERO_ERROR;
4376         Locale locale = Locale::createFromName(itemPtr->localeID);
4377         LocalPointer<Calendar> cal(Calendar::createInstance(zone.orphan(), locale, status));
4378         if (U_FAILURE(status)) {
4379             dataerrln("Calendar::createInstance fails for locale %s, status %s", itemPtr->localeID, u_errorName(status));
4380             continue;
4381         }
4382         cal->setTime(date, status);
4383         if (U_FAILURE(status)) {
4384             dataerrln("Calendar::setTime fails for locale %s, date %.1f, status %s", itemPtr->localeID, date, u_errorName(status));
4385             continue;
4386         }
4387         LocalPointer<SimpleDateFormat> sdfmt(static_cast<SimpleDateFormat *>(DateFormat::createDateInstance(itemPtr->style, locale)));
4388         if (sdfmt.isNull()) {
4389             dataerrln("DateFormat::createDateInstance fails for locale %s", itemPtr->localeID);
4390             continue;
4391         }
4392         UnicodeString getFormat;
4393         sdfmt->format(*(cal.getAlias()), getFormat, NULL, status);
4394         if (U_FAILURE(status)) {
4395             errln("DateFormat::format fails for locale %s, status %s", itemPtr->localeID, u_errorName(status));
4396             continue;
4397         }
4398         if (getFormat.compare(itemPtr->expectFormat) != 0) {
4399             itemPtr->expectFormat.extract(0, itemPtr->expectFormat.length(), bExpected, kBBufMax);
4400             getFormat.extract(0, getFormat.length(), bResult, kBBufMax);
4401             errln("DateFormat::format for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult);
4402         }
4403         UnicodeString getPattern;
4404         sdfmt->toPattern(getPattern);
4405         if (getPattern.compare(itemPtr->expectPattern) != 0) {
4406             itemPtr->expectPattern.extract(0, itemPtr->expectPattern.length(), bExpected, kBBufMax);
4407             getPattern.extract(0, getPattern.length(), bResult, kBBufMax);
4408             errln("DateFormat::toPattern() for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult);
4409         }
4410     }
4411 }
4412 
4413 static const UDate TEST_DATE = 1326585600000.;  // 2012-jan-15
4414 
TestDotAndAtLeniency()4415 void DateFormatTest::TestDotAndAtLeniency() {
4416     // Test for date/time parsing regression with CLDR 22.1/ICU 50 pattern strings.
4417     // For details see http://bugs.icu-project.org/trac/ticket/9789
4418     static const char *locales[] = { "en", "fr" };
4419     for (int32_t i = 0; i < UPRV_LENGTHOF(locales); ++i) {
4420         Locale locale(locales[i]);
4421 
4422         for (DateFormat::EStyle dateStyle = DateFormat::FULL; dateStyle <= DateFormat::SHORT;
4423                   dateStyle = static_cast<DateFormat::EStyle>(dateStyle + 1)) {
4424             LocalPointer<DateFormat> dateFormat(DateFormat::createDateInstance(dateStyle, locale));
4425 
4426             for (DateFormat::EStyle timeStyle = DateFormat::FULL; timeStyle <= DateFormat::SHORT;
4427                       timeStyle = static_cast<DateFormat::EStyle>(timeStyle + 1)) {
4428                 LocalPointer<DateFormat> format(DateFormat::createDateTimeInstance(dateStyle, timeStyle, locale));
4429                 LocalPointer<DateFormat> timeFormat(DateFormat::createTimeInstance(timeStyle, locale));
4430                 UnicodeString formattedString;
4431                 if (format.isNull()) {
4432                     dataerrln("Unable to create DateFormat");
4433                     continue;
4434                 }
4435                 format->format(TEST_DATE, formattedString);
4436 
4437                 if (!showParse(*format, formattedString)) {
4438                     errln(UnicodeString("    with date-time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4439                 }
4440 
4441                 UnicodeString ds, ts;
4442                 formattedString = dateFormat->format(TEST_DATE, ds) + "  " + timeFormat->format(TEST_DATE, ts);
4443                 if (!showParse(*format, formattedString)) {
4444                     errln(UnicodeString("    with date sp sp time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4445                 }
4446                 if (formattedString.indexOf("n ") >= 0) { // will add "." after the end of text ending in 'n', like Jan.
4447                     UnicodeString plusDot(formattedString);
4448                     plusDot.findAndReplace("n ", "n. ").append(".");
4449                     if (!showParse(*format, plusDot)) {
4450                         errln(UnicodeString("    with date plus-dot time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4451                     }
4452                 }
4453                 if (formattedString.indexOf(". ") >= 0) { // will subtract "." at the end of strings.
4454                     UnicodeString minusDot(formattedString);
4455                     minusDot.findAndReplace(". ", " ");
4456                     if (!showParse(*format, minusDot)) {
4457                         errln(UnicodeString("    with date minus-dot time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4458                     }
4459                 }
4460             }
4461         }
4462     }
4463 }
4464 
showParse(DateFormat & format,const UnicodeString & formattedString)4465 UBool DateFormatTest::showParse(DateFormat &format, const UnicodeString &formattedString) {
4466     ParsePosition parsePosition;
4467     UDate parsed = format.parse(formattedString, parsePosition);
4468     UBool ok = TEST_DATE == parsed && parsePosition.getIndex() == formattedString.length();
4469     UnicodeString pattern;
4470     static_cast<SimpleDateFormat &>(format).toPattern(pattern);
4471     if (ok) {
4472         logln(pattern + "  parsed: " + formattedString);
4473     } else {
4474         errln(pattern + "  fails to parse: " + formattedString);
4475     }
4476     return ok;
4477 }
4478 
4479 
4480 typedef struct {
4481     const char * locale;
4482     UBool leniency;
4483     UnicodeString parseString;
4484     UnicodeString pattern;
4485     UnicodeString expectedResult;       // empty string indicates expected error
4486 } TestDateFormatLeniencyItem;
4487 
TestDateFormatLeniency()4488 void DateFormatTest::TestDateFormatLeniency() {
4489     // For details see http://bugs.icu-project.org/trac/ticket/10261
4490 
4491     const UDate july022008 = 1215000001979.0;
4492     const TestDateFormatLeniencyItem items[] = {
4493         //locale    leniency    parse String                    pattern                             expected result
4494         { "en",     true,       UnicodeString("2008-07 02"),    UnicodeString("yyyy-LLLL dd"),      UnicodeString("2008-July 02") },
4495         { "en",     false,      UnicodeString("2008-07 02"),    UnicodeString("yyyy-LLLL dd"),      UnicodeString("") },
4496         { "en",     true,       UnicodeString("2008-Jan 02"),   UnicodeString("yyyy-LLL. dd"),      UnicodeString("2008-Jan. 02") },
4497         { "en",     false,      UnicodeString("2008-Jan 02"),   UnicodeString("yyyy-LLL. dd"),      UnicodeString("") },
4498         { "en",     true,       UnicodeString("2008-Jan--02"),  UnicodeString("yyyy-MMM' -- 'dd"),  UnicodeString("2008-Jan -- 02") },
4499         { "en",     false,      UnicodeString("2008-Jan--02"),  UnicodeString("yyyy-MMM' -- 'dd"),  UnicodeString("") },
4500         // terminator
4501         { NULL,     true,       UnicodeString(""),              UnicodeString(""),                  UnicodeString("") }
4502     };
4503     UErrorCode status = U_ZERO_ERROR;
4504     LocalPointer<Calendar> cal(Calendar::createInstance(status));
4505     if (U_FAILURE(status)) {
4506         dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
4507         return;
4508     }
4509     cal->setTime(july022008, status);
4510     const TestDateFormatLeniencyItem * itemPtr;
4511     LocalPointer<SimpleDateFormat> sdmft;
4512     for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
4513 
4514        Locale locale = Locale::createFromName(itemPtr->locale);
4515        status = U_ZERO_ERROR;
4516        ParsePosition pos(0);
4517        sdmft.adoptInsteadAndCheckErrorCode(new SimpleDateFormat(itemPtr->pattern, locale, status), status);
4518        if (U_FAILURE(status)) {
4519            dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
4520            continue;
4521        }
4522        sdmft->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->leniency, status).
4523               setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->leniency, status).
4524               setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, itemPtr->leniency, status);
4525        UDate d = sdmft->parse(itemPtr->parseString, pos);
4526 
4527        if(itemPtr->expectedResult.length() == 0) {
4528            if(pos.getErrorIndex() != -1) {
4529                continue;
4530            } else {
4531                 errln("error: unexpected parse success - " + itemPtr->parseString +
4532                     " - pattern " + itemPtr->pattern +
4533                     " - error index " + pos.getErrorIndex() +
4534                     " - leniency " + itemPtr->leniency);
4535                 continue;
4536            }
4537        }
4538        if(pos.getErrorIndex() != -1) {
4539            errln("error: parse error for string - "  + itemPtr->parseString +
4540                  " - pattern " + itemPtr->pattern +
4541                  " - idx " + pos.getIndex() +
4542                  " - error index "+pos.getErrorIndex() +
4543                  " - leniency " + itemPtr->leniency);
4544             continue;
4545         }
4546 
4547        UnicodeString formatResult("");
4548        sdmft->format(d, formatResult);
4549        if(formatResult.compare(itemPtr->expectedResult) != 0) {
4550            errln("error: unexpected format result. pattern["+itemPtr->pattern+"] expected[" + itemPtr->expectedResult + "]  but result was[" + formatResult + "]");
4551            continue;
4552         } else {
4553             logln("formatted results match! - " + formatResult);
4554         }
4555 
4556     }
4557 }
4558 
4559 
4560 typedef struct {
4561     UBool leniency;
4562     UnicodeString parseString;
4563     UnicodeString pattern;
4564     UnicodeString expectedResult;       // empty string indicates expected error
4565 } TestMultiPatternMatchItem;
4566 
TestParseMultiPatternMatch()4567 void DateFormatTest::TestParseMultiPatternMatch() {
4568         // For details see http://bugs.icu-project.org/trac/ticket/10336
4569     const TestMultiPatternMatchItem items[] = {
4570           // leniency    parse String                                 pattern                               expected result
4571             {true,       UnicodeString("2013-Sep 13"),                UnicodeString("yyyy-MMM dd"),         UnicodeString("2013-Sep 13")},
4572             {true,       UnicodeString("2013-September 14"),          UnicodeString("yyyy-MMM dd"),         UnicodeString("2013-Sep 14")},
4573             {false,      UnicodeString("2013-September 15"),          UnicodeString("yyyy-MMM dd"),         UnicodeString("")},
4574             {false,      UnicodeString("2013-September 16"),          UnicodeString("yyyy-MMMM dd"),        UnicodeString("2013-September 16")},
4575             {true,       UnicodeString("2013-Sep 17"),                UnicodeString("yyyy-LLL dd"),         UnicodeString("2013-Sep 17")},
4576             {true,       UnicodeString("2013-September 18"),          UnicodeString("yyyy-LLL dd"),         UnicodeString("2013-Sep 18")},
4577             {false,      UnicodeString("2013-September 19"),          UnicodeString("yyyy-LLL dd"),         UnicodeString("")},
4578             {false,      UnicodeString("2013-September 20"),          UnicodeString("yyyy-LLLL dd"),        UnicodeString("2013-September 20")},
4579             {true,       UnicodeString("2013 Sat Sep 21"),            UnicodeString("yyyy EEE MMM dd"),     UnicodeString("2013 Sat Sep 21")},
4580             {true,       UnicodeString("2013 Sunday Sep 22"),         UnicodeString("yyyy EEE MMM dd"),     UnicodeString("2013 Sun Sep 22")},
4581             {false,      UnicodeString("2013 Monday Sep 23"),         UnicodeString("yyyy EEE MMM dd"),     UnicodeString("")},
4582             {false,      UnicodeString("2013 Tuesday Sep 24"),        UnicodeString("yyyy EEEE MMM dd"),    UnicodeString("2013 Tuesday Sep 24")},
4583             {true,       UnicodeString("2013 Wed Sep 25"),            UnicodeString("yyyy eee MMM dd"),     UnicodeString("2013 Wed Sep 25")},
4584             {true,       UnicodeString("2013 Thu Sep 26"),            UnicodeString("yyyy eee MMM dd"),     UnicodeString("2013 Thu Sep 26")},
4585             {false,      UnicodeString("2013 Friday Sep 27"),         UnicodeString("yyyy eee MMM dd"),     UnicodeString("")},
4586             {false,      UnicodeString("2013 Saturday Sep 28"),       UnicodeString("yyyy eeee MMM dd"),    UnicodeString("2013 Saturday Sep 28")},
4587             {true,       UnicodeString("2013 Sun Sep 29"),            UnicodeString("yyyy ccc MMM dd"),     UnicodeString("2013 Sun Sep 29")},
4588             {true,       UnicodeString("2013 Monday Sep 30"),         UnicodeString("yyyy ccc MMM dd"),     UnicodeString("2013 Mon Sep 30")},
4589             {false,      UnicodeString("2013 Sunday Oct 13"),         UnicodeString("yyyy ccc MMM dd"),     UnicodeString("")},
4590             {false,      UnicodeString("2013 Monday Oct 14"),         UnicodeString("yyyy cccc MMM dd"),    UnicodeString("2013 Monday Oct 14")},
4591             {true,       UnicodeString("2013 Oct 15 Q4"),             UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 15 Q4")},
4592             {true,       UnicodeString("2013 Oct 16 4th quarter"),    UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 16 Q4")},
4593             {false,      UnicodeString("2013 Oct 17 4th quarter"),    UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("")},
4594             {false,      UnicodeString("2013 Oct 18 Q4"),             UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 18 Q4")},
4595             {true,       UnicodeString("2013 Oct 19 Q4"),             UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 19 4th quarter")},
4596             {true,       UnicodeString("2013 Oct 20 4th quarter"),    UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 20 4th quarter")},
4597             {false,      UnicodeString("2013 Oct 21 Q4"),             UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("")},
4598             {false,      UnicodeString("2013 Oct 22 4th quarter"),    UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 22 4th quarter")},
4599             {false,      UnicodeString("--end--"),                    UnicodeString(""),                    UnicodeString("")},
4600     };
4601 
4602     UErrorCode status = U_ZERO_ERROR;
4603     LocalPointer<Calendar> cal(Calendar::createInstance(status));
4604     if (U_FAILURE(status)) {
4605         dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
4606         return;
4607     }
4608     const TestMultiPatternMatchItem * itemPtr;
4609     DateFormat* sdmft = DateFormat::createDateInstance();
4610     if (sdmft == NULL) {
4611         dataerrln(UnicodeString("FAIL: Unable to create DateFormat"));
4612         return;
4613     }
4614     for (itemPtr = items; itemPtr->parseString != "--end--"; itemPtr++ ) {
4615        status = U_ZERO_ERROR;
4616        ParsePosition pos(0);
4617        ((SimpleDateFormat*) sdmft)->applyPattern(itemPtr->pattern);
4618        if (U_FAILURE(status)) {
4619            dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
4620            continue;
4621        }
4622        sdmft->setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, itemPtr->leniency, status);
4623        UDate d = sdmft->parse(itemPtr->parseString, pos);
4624 
4625        if(itemPtr->expectedResult.length() == 0) {
4626            if(pos.getErrorIndex() != -1) {
4627                continue;
4628            } else {
4629                 errln("error: unexpected parse success - " + itemPtr->parseString +
4630                     " - error index " + pos.getErrorIndex() +
4631                     " - leniency " + itemPtr->leniency);
4632                 continue;
4633            }
4634         }
4635         if(pos.getErrorIndex() != -1) {
4636             errln("error: parse error for string - " +itemPtr->parseString + " -- idx["+pos.getIndex()+"] errIdx["+pos.getErrorIndex()+"]");
4637             continue;
4638         }
4639 
4640         UnicodeString formatResult("");
4641         sdmft->format(d, formatResult);
4642         if(formatResult.compare(itemPtr->expectedResult) != 0) {
4643             errln("error: unexpected format result. expected[" + itemPtr->expectedResult + "]  but result was[" + formatResult + "]");
4644         } else {
4645             logln("formatted results match! - " + formatResult);
4646         }
4647     }
4648     delete sdmft;
4649 }
4650 
TestParseLeniencyAPIs()4651 void DateFormatTest::TestParseLeniencyAPIs() {
4652     UErrorCode status = U_ZERO_ERROR;
4653     LocalPointer<DateFormat> dateFormat(DateFormat::createDateInstance());
4654     DateFormat *fmt = dateFormat.getAlias();
4655     if (fmt == NULL) {
4656         dataerrln("Failed calling dateFormat.getAlias()");
4657         return;
4658     }
4659 
4660     assertTrue("isLenient default", fmt->isLenient());
4661     assertTrue("isCalendarLenient default", fmt->isCalendarLenient());
4662     assertTrue("ALLOW_WHITESPACE default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4663     assertTrue("ALLOW_NUMERIC default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4664     assertTrue("PARTIAL_MATCH default", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status));
4665     assertTrue("MULTIPLE_PATTERNS default", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status));
4666 
4667     // Set calendar to strict
4668     fmt->setCalendarLenient(FALSE);
4669 
4670     assertFalse("isLeninent after setCalendarLenient(FALSE)", fmt->isLenient());
4671     assertFalse("isCalendarLenient after setCalendarLenient(FALSE)", fmt->isCalendarLenient());
4672     assertTrue("ALLOW_WHITESPACE after setCalendarLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4673     assertTrue("ALLOW_NUMERIC  after setCalendarLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4674 
4675     // Set to strict
4676     fmt->setLenient(FALSE);
4677 
4678     assertFalse("isLeninent after setLenient(FALSE)", fmt->isLenient());
4679     assertFalse("isCalendarLenient after setLenient(FALSE)", fmt->isCalendarLenient());
4680     assertFalse("ALLOW_WHITESPACE after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4681     assertFalse("ALLOW_NUMERIC  after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4682     // These two boolean attributes are NOT affected according to the API specification
4683     assertTrue("PARTIAL_MATCH after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status));
4684     assertTrue("MULTIPLE_PATTERNS after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status));
4685 
4686     // Allow white space leniency
4687     fmt->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, TRUE, status);
4688 
4689     assertFalse("isLeninent after ALLOW_WHITESPACE/TRUE", fmt->isLenient());
4690     assertFalse("isCalendarLenient after ALLOW_WHITESPACE/TRUE", fmt->isCalendarLenient());
4691     assertTrue("ALLOW_WHITESPACE after ALLOW_WHITESPACE/TRUE", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4692     assertFalse("ALLOW_NUMERIC  after ALLOW_WHITESPACE/TRUE", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4693 
4694     // Set to lenient
4695     fmt->setLenient(TRUE);
4696 
4697     assertTrue("isLenient after setLenient(TRUE)", fmt->isLenient());
4698     assertTrue("isCalendarLenient after setLenient(TRUE)", fmt->isCalendarLenient());
4699     assertTrue("ALLOW_WHITESPACE after setLenient(TRUE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4700     assertTrue("ALLOW_NUMERIC after setLenient(TRUE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4701 }
4702 
TestNumberFormatOverride()4703 void DateFormatTest::TestNumberFormatOverride() {
4704     UErrorCode status = U_ZERO_ERROR;
4705     UnicodeString fields = (UnicodeString) "M";
4706 
4707     LocalPointer<SimpleDateFormat> fmt;
4708     fmt.adoptInsteadAndCheckErrorCode(new SimpleDateFormat((UnicodeString)"MM d", status), status);
4709     if (!assertSuccess("SimpleDateFormat with pattern MM d", status)) {
4710         return;
4711     }
4712 
4713 
4714     for(int i=0; i<3; i++){
4715         NumberFormat* check_nf = NumberFormat::createInstance(Locale("en_US"), status);
4716         assertSuccess("NumberFormat en_US", status);
4717         fmt->adoptNumberFormat(fields, check_nf, status);
4718         assertSuccess("adoptNumberFormat check_nf", status);
4719 
4720         const NumberFormat* get_nf = fmt->getNumberFormatForField((UChar)0x004D /*'M'*/);
4721         if (get_nf != check_nf) errln("FAIL: getter and setter do not work");
4722     }
4723     NumberFormat* check_nf = NumberFormat::createInstance(Locale("en_US"), status);
4724     assertSuccess("NumberFormat en_US", status);
4725     fmt->adoptNumberFormat(check_nf); // make sure using the same NF will not crash
4726 
4727     const char * DATA [][2] = {
4728         { "", "\\u521D\\u516D \\u5341\\u4E94"},
4729         { "M", "\\u521D\\u516D 15"},
4730         { "Mo", "\\u521D\\u516D 15"},
4731         { "Md", "\\u521D\\u516D \\u5341\\u4E94"},
4732         { "MdMMd", "\\u521D\\u516D \\u5341\\u4E94"},
4733         { "mixed", "\\u521D\\u516D \\u5341\\u4E94"}
4734     };
4735 
4736     UDate test_date = date(97, 6 - 1, 15);
4737 
4738     for(int i=0; i < UPRV_LENGTHOF(DATA); i++){
4739         fields = DATA[i][0];
4740 
4741         LocalPointer<SimpleDateFormat> fmt;
4742         fmt.adoptInsteadAndCheckErrorCode(new SimpleDateFormat((UnicodeString)"MM d", status), status);
4743         assertSuccess("SimpleDateFormat with pattern MM d", status);
4744         NumberFormat* overrideNF = NumberFormat::createInstance(Locale::createFromName("zh@numbers=hanidays"),status);
4745         assertSuccess("NumberFormat zh@numbers=hanidays", status);
4746         if (U_FAILURE(status)) {
4747             status = U_ZERO_ERROR;
4748             continue;
4749         }
4750 
4751         if (fields == (UnicodeString) "") { // use the one w/o fields
4752             fmt->adoptNumberFormat(overrideNF);
4753         } else if (fields == (UnicodeString) "mixed") { // set 1 field at first but then full override, both(M & d) should be override
4754             NumberFormat* singleOverrideNF = NumberFormat::createInstance(Locale::createFromName("en@numbers=hebr"),status);
4755             assertSuccess("NumberFormat en@numbers=hebr", status);
4756 
4757             fields = (UnicodeString) "M";
4758             fmt->adoptNumberFormat(fields, singleOverrideNF, status);
4759             assertSuccess("adoptNumberFormat singleOverrideNF", status);
4760 
4761             fmt->adoptNumberFormat(overrideNF);
4762         } else if (fields == (UnicodeString) "Mo"){ // o is invlid field
4763             fmt->adoptNumberFormat(fields, overrideNF, status);
4764             if(status == U_INVALID_FORMAT_ERROR) {
4765                 status = U_ZERO_ERROR;
4766                 continue;
4767             }
4768         } else {
4769             fmt->adoptNumberFormat(fields, overrideNF, status);
4770             assertSuccess("adoptNumberFormat overrideNF", status);
4771         }
4772 
4773         UnicodeString result;
4774         FieldPosition pos(FieldPosition::DONT_CARE);
4775         fmt->format(test_date,result, pos);
4776 
4777         UnicodeString expected = ((UnicodeString)DATA[i][1]).unescape();
4778 
4779         if (result != expected)
4780             errln("FAIL: Expected " + expected + " get: " + result);
4781     }
4782 }
4783 
TestCreateInstanceForSkeleton()4784 void DateFormatTest::TestCreateInstanceForSkeleton() {
4785     UErrorCode status = U_ZERO_ERROR;
4786     LocalPointer<DateFormat> fmt(DateFormat::createInstanceForSkeleton(
4787             "yMMMMd", "en", status));
4788     if (!assertSuccess("Create with pattern yMMMMd", status)) {
4789         return;
4790     }
4791     UnicodeString result;
4792     FieldPosition pos(FieldPosition::DONT_CARE);
4793     fmt->format(date(98, 5-1, 25), result, pos);
4794     assertEquals("format yMMMMd", "May 25, 1998", result);
4795     fmt.adoptInstead(DateFormat::createInstanceForSkeleton(
4796             "yMd", "en", status));
4797     if (!assertSuccess("Create with pattern yMd", status)) {
4798         return;
4799     }
4800     result.remove();
4801     fmt->format(date(98, 5-1, 25), result, pos);
4802     assertEquals("format yMd", "5/25/1998", result);
4803 }
4804 
TestCreateInstanceForSkeletonDefault()4805 void DateFormatTest::TestCreateInstanceForSkeletonDefault() {
4806     UErrorCode status = U_ZERO_ERROR;
4807     Locale savedLocale;
4808     Locale::setDefault(Locale::getUS(), status);
4809     LocalPointer<DateFormat> fmt(DateFormat::createInstanceForSkeleton(
4810             "yMMMd", status));
4811     Locale::setDefault(savedLocale, status);
4812     if (!assertSuccess("Create with pattern yMMMd", status)) {
4813         return;
4814     }
4815     UnicodeString result;
4816     FieldPosition pos(FieldPosition::DONT_CARE);
4817     fmt->format(date(98, 5-1, 25), result, pos);
4818     assertEquals("format yMMMd", "May 25, 1998", result);
4819 }
4820 
TestCreateInstanceForSkeletonWithCalendar()4821 void DateFormatTest::TestCreateInstanceForSkeletonWithCalendar() {
4822     UErrorCode status = U_ZERO_ERROR;
4823     LocalPointer<DateFormat> fmt(
4824             DateFormat::createInstanceForSkeleton(
4825                     Calendar::createInstance(
4826                             TimeZone::createTimeZone("GMT-3:00"),
4827                             status),
4828                     "yMdHm", "en", status));
4829     if (!assertSuccess("Create with pattern yMMMMd", status)) {
4830         return;
4831     }
4832     UnicodeString result;
4833     FieldPosition pos(FieldPosition::DONT_CARE);
4834 
4835     LocalPointer<Calendar> cal(Calendar::createInstance(
4836         TimeZone::createTimeZone("GMT-7:00"),
4837         status));
4838     if (!assertSuccess("Creating GMT-7 time zone failed", status)) {
4839         return;
4840     }
4841     cal->clear();
4842     cal->set(1998, 5-1, 25, 0, 0, 0);
4843 
4844     // date format time zone should be 4 hours ahead.
4845     fmt->format(cal->getTime(status), result, pos);
4846     assertEquals("format yMdHm", "5/25/1998, 04:00", result);
4847     assertSuccess("", status);
4848 }
4849 
TestDFSCreateForLocaleNonGregorianLocale()4850 void DateFormatTest::TestDFSCreateForLocaleNonGregorianLocale() {
4851     UErrorCode status = U_ZERO_ERROR;
4852     Locale fa("fa");
4853     LocalPointer<DateFormatSymbols> sym(
4854             DateFormatSymbols::createForLocale(fa, status));
4855     if (!assertSuccess("", status)) {
4856         return;
4857     }
4858 
4859     // Farsi should default to the persian calendar, not gregorian
4860     int32_t count;
4861     const UnicodeString *months = sym->getShortMonths(count);
4862 
4863     // First persian month.
4864     UnicodeString expected("\\u0641\\u0631\\u0648\\u0631\\u062f\\u06cc\\u0646");
4865     assertEquals("", expected.unescape(), months[0]);
4866 }
4867 
TestDFSCreateForLocaleWithCalendarInLocale()4868 void DateFormatTest::TestDFSCreateForLocaleWithCalendarInLocale() {
4869     UErrorCode status = U_ZERO_ERROR;
4870     Locale en_heb("en@calendar=hebrew");
4871     LocalPointer<DateFormatSymbols> sym(
4872             DateFormatSymbols::createForLocale(en_heb, status));
4873     if (!assertSuccess("", status)) {
4874         return;
4875     }
4876 
4877     // We should get the months of the hebrew calendar, not the gregorian
4878     // calendar.
4879     int32_t count;
4880     const UnicodeString *months = sym->getShortMonths(count);
4881 
4882     // First hebrew month.
4883     UnicodeString expected("Tishri");
4884     assertEquals("", expected, months[0]);
4885 }
4886 
TestChangeCalendar()4887 void DateFormatTest::TestChangeCalendar() {
4888     UErrorCode status = U_ZERO_ERROR;
4889     Locale en("en");
4890     Locale en_heb("en@calendar=hebrew");
4891     LocalPointer<DateFormat> fmt(
4892             DateFormat::createInstanceForSkeleton("yMMMd", en, status));
4893     if (!assertSuccess("", status)) {
4894         return;
4895     }
4896     fmt->adoptCalendar(Calendar::createInstance(en_heb, status));
4897     if (!assertSuccess("", status)) {
4898         return;
4899     }
4900     UnicodeString result;
4901     FieldPosition pos(FieldPosition::DONT_CARE);
4902     fmt->format(date(98, 5-1, 25), result, pos);
4903     assertEquals("format yMMMd", "Iyar 29, 5758", result);
4904 }
4905 
TestPatternFromSkeleton()4906 void DateFormatTest::TestPatternFromSkeleton() {
4907     static const struct {
4908         const Locale& locale;
4909         const char* const skeleton;
4910         const char* const pattern;
4911     } TESTDATA[] = {
4912         // Ticket #11985
4913         {Locale::getEnglish(), "jjmm", "h:mm a"},
4914         {Locale::getEnglish(), "JJmm", "hh:mm"},
4915         {Locale::getGerman(), "jjmm", "HH:mm"},
4916         {Locale::getGerman(), "JJmm", "HH:mm"},
4917         // Ticket #20739
4918         // minutes+milliseconds, seconds missing, should be repaired
4919         {Locale::getEnglish(), "SSSSm", "mm:ss.SSSS"},
4920         {Locale::getEnglish(), "mSSSS", "mm:ss.SSSS"},
4921         {Locale::getEnglish(), "SSSm", "mm:ss.SSS"},
4922         {Locale::getEnglish(), "mSSS", "mm:ss.SSS"},
4923         {Locale::getEnglish(), "SSm", "mm:ss.SS"},
4924         {Locale::getEnglish(), "mSS", "mm:ss.SS"},
4925         {Locale::getEnglish(), "Sm", "mm:ss.S"},
4926         {Locale::getEnglish(), "mS", "mm:ss.S"},
4927         // only milliseconds, untouched, no repairs
4928         {Locale::getEnglish(), "S", "S"},
4929         {Locale::getEnglish(), "SS", "SS"},
4930         {Locale::getEnglish(), "SSS", "SSS"},
4931         {Locale::getEnglish(), "SSSS", "SSSS"},
4932         // hour:minute+seconds+milliseconds, correct, no repairs, proper pattern
4933         {Locale::getEnglish(), "jmsSSS", "h:mm:ss.SSS a"},
4934         {Locale::getEnglish(), "jmSSS", "h:mm:ss.SSS a"},
4935         // Ticket #20738
4936         // seconds+milliseconds, correct, no repairs, proper pattern
4937         {Locale::getEnglish(), "sS", "s.S"},
4938         {Locale::getEnglish(), "sSS", "s.SS"},
4939         {Locale::getEnglish(), "sSSS", "s.SSS"},
4940         {Locale::getEnglish(), "sSSSS", "s.SSSS"},
4941         {Locale::getEnglish(), "sS", "s.S"},
4942         // minutes+seconds+milliseconds, correct, no repairs, proper pattern
4943         {Locale::getEnglish(), "msS", "mm:ss.S"},
4944         {Locale::getEnglish(), "msSS", "mm:ss.SS"},
4945         {Locale::getEnglish(), "msSSS", "mm:ss.SSS"},
4946         {Locale::getEnglish(), "msSSSS", "mm:ss.SSSS"}
4947     };
4948 
4949     for (size_t i = 0; i < UPRV_LENGTHOF(TESTDATA); i++) {
4950         UErrorCode status = U_ZERO_ERROR;
4951         LocalPointer<DateFormat> fmt(
4952                 DateFormat::createInstanceForSkeleton(
4953                         TESTDATA[i].skeleton, TESTDATA[i].locale, status));
4954         if (!assertSuccess("createInstanceForSkeleton", status)) {
4955             return;
4956         }
4957         UnicodeString pattern;
4958         static_cast<const SimpleDateFormat*>(fmt.getAlias())->toPattern(pattern);
4959         assertEquals("Format pattern", TESTDATA[i].pattern, pattern);
4960     }
4961 }
4962 
TestAmPmMidnightNoon()4963 void DateFormatTest::TestAmPmMidnightNoon() {
4964     // Some times on 2015-11-13 (UTC+0).
4965     UDate k000000 = 1447372800000.0;
4966     UDate k000030 = 1447372830000.0;
4967     UDate k003000 = 1447374600000.0;
4968     UDate k060000 = 1447394400000.0;
4969     UDate k120000 = 1447416000000.0;
4970     UDate k180000 = 1447437600000.0;
4971 
4972     UErrorCode errorCode = U_ZERO_ERROR;
4973     SimpleDateFormat sdf(UnicodeString(), errorCode);
4974     if (U_FAILURE(errorCode)) {
4975         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
4976         return;
4977     }
4978     const TimeZone *tz = TimeZone::getGMT();
4979     sdf.setTimeZone(*tz);
4980     UnicodeString out;
4981 
4982     // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
4983     // For ICU 57 output of "midnight" is temporarily suppressed.
4984 
4985     // Short.
4986     sdf.applyPattern(UnicodeString("hh:mm:ss bbb"));
4987 
4988     // assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
4989     assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
4990     assertEquals("hh:mm:ss bbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
4991     assertEquals("hh:mm:ss bbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
4992     assertEquals("hh:mm:ss bbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
4993     assertEquals("hh:mm:ss bbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
4994     assertEquals("hh:mm:ss bbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
4995 
4996     sdf.applyPattern(UnicodeString("hh:mm bbb"));
4997 
4998     // assertEquals("hh:mm bbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
4999     assertEquals("hh:mm bbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
5000     // assertEquals("hh:mm bbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5001     assertEquals("hh:mm bbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
5002     assertEquals("hh:mm bbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
5003 
5004     sdf.applyPattern(UnicodeString("hh bbb"));
5005 
5006     // assertEquals("hh bbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5007     assertEquals("hh bbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
5008     // assertEquals("hh bbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5009     assertEquals("hh bbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
5010     // assertEquals("hh bbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
5011     assertEquals("hh bbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
5012 
5013     // Wide.
5014     sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
5015 
5016     // assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5017     assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
5018     assertEquals("hh:mm:ss bbbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
5019     assertEquals("hh:mm:ss bbbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
5020     assertEquals("hh:mm:ss bbbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
5021     assertEquals("hh:mm:ss bbbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5022     assertEquals("hh:mm:ss bbbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
5023 
5024     sdf.applyPattern(UnicodeString("hh:mm bbbb"));
5025 
5026     // assertEquals("hh:mm bbbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5027     assertEquals("hh:mm bbbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
5028     // assertEquals("hh:mm bbbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5029     assertEquals("hh:mm bbbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
5030     assertEquals("hh:mm bbbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
5031 
5032     sdf.applyPattern(UnicodeString("hh bbbb"));
5033 
5034     // assertEquals("hh bbbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5035     assertEquals("hh bbbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
5036     // assertEquals("hh bbbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5037     assertEquals("hh bbbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
5038     // assertEquals("hh bbbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
5039     assertEquals("hh bbbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
5040 
5041     // Narrow.
5042     sdf.applyPattern(UnicodeString("hh:mm:ss bbbbb"));
5043 
5044     // assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
5045     assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 a", sdf.format(k000000, out.remove()));
5046     assertEquals("hh:mm:ss bbbbb | 00:00:30", "12:00:30 a", sdf.format(k000030, out.remove()));
5047     assertEquals("hh:mm:ss bbbbb | 00:30:00", "12:30:00 a", sdf.format(k003000, out.remove()));
5048     assertEquals("hh:mm:ss bbbbb | 06:00:00", "06:00:00 a", sdf.format(k060000, out.remove()));
5049     assertEquals("hh:mm:ss bbbbb | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
5050     assertEquals("hh:mm:ss bbbbb | 18:00:00", "06:00:00 p", sdf.format(k180000, out.remove()));
5051 
5052     sdf.applyPattern(UnicodeString("hh:mm bbbbb"));
5053 
5054     // assertEquals("hh:mm bbbbb | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
5055     assertEquals("hh:mm bbbbb | 00:00:00", "12:00 a", sdf.format(k000000, out.remove()));
5056     // assertEquals("hh:mm bbbbb | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
5057     assertEquals("hh:mm bbbbb | 00:00:30", "12:00 a", sdf.format(k000030, out.remove()));
5058     assertEquals("hh:mm bbbbb | 00:30:00", "12:30 a", sdf.format(k003000, out.remove()));
5059 
5060     sdf.applyPattern(UnicodeString("hh bbbbb"));
5061 
5062     // assertEquals("hh bbbbb | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
5063     assertEquals("hh bbbbb | 00:00:00", "12 a", sdf.format(k000000, out.remove()));
5064     // assertEquals("hh bbbbb | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
5065     assertEquals("hh bbbbb | 00:00:30", "12 a", sdf.format(k000030, out.remove()));
5066     // assertEquals("hh bbbbb | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
5067     assertEquals("hh bbbbb | 00:30:00", "12 a", sdf.format(k003000, out.remove()));
5068 }
5069 
TestFlexibleDayPeriod()5070 void DateFormatTest::TestFlexibleDayPeriod() {
5071     // Some times on 2015-11-13 (UTC+0).
5072     UDate k000000 = 1447372800000.0;
5073     UDate k000030 = 1447372830000.0;
5074     UDate k003000 = 1447374600000.0;
5075     UDate k060000 = 1447394400000.0;
5076     UDate k120000 = 1447416000000.0;
5077     UDate k180000 = 1447437600000.0;
5078 
5079     UErrorCode errorCode = U_ZERO_ERROR;
5080     SimpleDateFormat sdf(UnicodeString(), errorCode);
5081     if (U_FAILURE(errorCode)) {
5082         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5083         return;
5084     }
5085     const TimeZone *tz = TimeZone::getGMT();
5086     sdf.setTimeZone(*tz);
5087     UnicodeString out;
5088 
5089     // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5090     // For ICU 57 output of "midnight" is temporarily suppressed.
5091 
5092     // Short.
5093     sdf.applyPattern(UnicodeString("hh:mm:ss BBB"));
5094 
5095     // assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5096     assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
5097     assertEquals("hh:mm:ss BBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
5098     assertEquals("hh:mm:ss BBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
5099     assertEquals("hh:mm:ss BBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
5100     assertEquals("hh:mm:ss BBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5101     assertEquals("hh:mm:ss BBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
5102 
5103     sdf.applyPattern(UnicodeString("hh:mm BBB"));
5104 
5105     // assertEquals("hh:mm BBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5106     assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5107     // assertEquals("hh:mm BBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5108     assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5109     assertEquals("hh:mm BBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
5110 
5111     sdf.applyPattern(UnicodeString("hh BBB"));
5112 
5113     // assertEquals("hh BBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5114     assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
5115     // assertEquals("hh BBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5116     assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
5117     // assertEquals("hh BBB | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
5118     assertEquals("hh BBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
5119 
5120     // Wide.
5121     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5122 
5123     // assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5124     assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
5125     assertEquals("hh:mm:ss BBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
5126     assertEquals("hh:mm:ss BBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
5127     assertEquals("hh:mm:ss BBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
5128     assertEquals("hh:mm:ss BBBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5129     assertEquals("hh:mm:ss BBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
5130 
5131     sdf.applyPattern(UnicodeString("hh:mm BBBB"));
5132 
5133     // assertEquals("hh:mm BBBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5134     assertEquals("hh:mm BBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5135     // assertEquals("hh:mm BBBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5136     assertEquals("hh:mm BBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
5137     assertEquals("hh:mm BBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
5138 
5139     sdf.applyPattern(UnicodeString("hh BBBB"));
5140 
5141     // assertEquals("hh BBBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5142     assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5143     // assertEquals("hh BBBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5144     assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5145     // assertEquals("hh BBBB | 00:80:00", "12 midnight", sdf.format(k003000, out.remove()));
5146     assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5147 
5148     // Narrow.
5149     sdf.applyPattern(UnicodeString("hh:mm:ss BBBBB"));
5150 
5151     // assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
5152     assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
5153     assertEquals("hh:mm:ss BBBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
5154     assertEquals("hh:mm:ss BBBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
5155     assertEquals("hh:mm:ss BBBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
5156     assertEquals("hh:mm:ss BBBBB | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
5157     assertEquals("hh:mm:ss BBBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
5158 
5159     sdf.applyPattern(UnicodeString("hh:mm BBBBB"));
5160 
5161     // assertEquals("hh:mm BBBBB | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
5162     assertEquals("hh:mm BBBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5163     // assertEquals("hh:mm BBBBB | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
5164     assertEquals("hh:mm BBBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
5165     assertEquals("hh:mm BBBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
5166 
5167     sdf.applyPattern(UnicodeString("hh BBBBB"));
5168 
5169     // assertEquals("hh BBBBB | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
5170     assertEquals("hh BBBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5171     // assertEquals("hh BBBBB | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
5172     assertEquals("hh BBBBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
5173     // assertEquals("hh BBBBB | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
5174     assertEquals("hh BBBBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
5175 }
5176 
TestDayPeriodWithLocales()5177 void DateFormatTest::TestDayPeriodWithLocales() {
5178     // Some times on 2015-11-13 (UTC+0).
5179     UDate k000000 = 1447372800000.0;
5180     UDate k010000 = 1447376400000.0;
5181     UDate k120000 = 1447416000000.0;
5182     UDate k220000 = 1447452000000.0;
5183 
5184     UErrorCode errorCode = U_ZERO_ERROR;
5185     const TimeZone *tz = TimeZone::getGMT();
5186     UnicodeString out;
5187 
5188     // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5189     // For ICU 57 output of "midnight" and its localized equivalentns is temporarily suppressed.
5190 
5191     // Locale de has a word for midnight, but not noon.
5192     SimpleDateFormat sdf(UnicodeString(), Locale::getGermany(), errorCode);
5193     if (U_FAILURE(errorCode)) {
5194         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5195         return;
5196     }
5197     sdf.setTimeZone(*tz);
5198 
5199     sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
5200 
5201     // assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 Mitternacht",
5202     //     sdf.format(k000000, out.remove()));
5203     assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 AM",
5204         sdf.format(k000000, out.remove()));
5205     assertEquals("hh:mm:ss bbbb | 12:00:00 | de", "12:00:00 PM",
5206         sdf.format(k120000, out.remove()));
5207 
5208     // Locale ee has a rule that wraps around midnight (21h - 4h).
5209     sdf = SimpleDateFormat(UnicodeString(), Locale("ee"), errorCode);
5210     sdf.setTimeZone(*tz);
5211 
5212     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5213 
5214     assertEquals("hh:mm:ss BBBB | 22:00:00 | ee", UnicodeString("10:00:00 z\\u00E3").unescape(),
5215         sdf.format(k220000, out.remove()));
5216     assertEquals("hh:mm:ss BBBB | 00:00:00 | ee", UnicodeString("12:00:00 z\\u00E3").unescape(),
5217         sdf.format(k000000, out.remove()));
5218     assertEquals("hh:mm:ss BBBB | 01:00:00 | ee", UnicodeString("01:00:00 z\\u00E3").unescape(),
5219         sdf.format(k010000, out.remove()));
5220 
5221     // Locale root has rules for AM/PM only.
5222     sdf = SimpleDateFormat(UnicodeString(), Locale("root"), errorCode);
5223     sdf.setTimeZone(*tz);
5224 
5225     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5226 
5227     assertEquals("hh:mm:ss BBBB | 00:00:00 | root", "12:00:00 AM",
5228         sdf.format(k000000, out.remove()));
5229     assertEquals("hh:mm:ss BBBB | 12:00:00 | root", "12:00:00 PM",
5230         sdf.format(k120000, out.remove()));
5231 
5232     // Empty string should behave exactly as root.
5233     sdf = SimpleDateFormat(UnicodeString(), Locale(""), errorCode);
5234     sdf.setTimeZone(*tz);
5235 
5236     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5237 
5238     assertEquals("hh:mm:ss BBBB | 00:00:00 | \"\" (root)", "12:00:00 AM",
5239         sdf.format(k000000, out.remove()));
5240     assertEquals("hh:mm:ss BBBB | 12:00:00 | \"\" (root)", "12:00:00 PM",
5241         sdf.format(k120000, out.remove()));
5242 
5243     // Locale en_US should fall back to en.
5244     sdf = SimpleDateFormat(UnicodeString(), Locale("en_US"), errorCode);
5245     sdf.setTimeZone(*tz);
5246 
5247     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5248 
5249     // assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 midnight",
5250     //     sdf.format(k000000, out.remove()));
5251     assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 at night",
5252          sdf.format(k000000, out.remove()));
5253     assertEquals("hh:mm:ss BBBB | 01:00:00 | en_US", "01:00:00 at night",
5254         sdf.format(k010000, out.remove()));
5255     assertEquals("hh:mm:ss BBBB | 12:00:00 | en_US", "12:00:00 noon",
5256         sdf.format(k120000, out.remove()));
5257 
5258     // Locale es_CO should not fall back to es and should have a
5259     // different string for 1 in the morning.
5260     // (es_CO: "de la manana" (first n has a tilde) vs. es: "de la madrugada")
5261     sdf = SimpleDateFormat(UnicodeString(), Locale("es_CO"), errorCode);
5262     sdf.setTimeZone(*tz);
5263 
5264     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5265     assertEquals("hh:mm:ss BBBB | 01:00:00 | es_CO", u"01:00:00 de la mañana",
5266         sdf.format(k010000, out.remove()));
5267 
5268     sdf = SimpleDateFormat(UnicodeString(), Locale("es"), errorCode);
5269     sdf.setTimeZone(*tz);
5270 
5271     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5272     assertEquals("hh:mm:ss BBBB | 01:00:00 | es", "01:00:00 de la madrugada",
5273         sdf.format(k010000, out.remove()));
5274 
5275     // #13215: for locales with keywords, check hang in DayPeriodRules""getInstance(const Locale, ...),
5276     // which is called in SimpleDateFormat::format for patterns that include 'B'.
5277     sdf = SimpleDateFormat(UnicodeString(), Locale("en@calendar=buddhist"), errorCode);
5278     sdf.setTimeZone(*tz);
5279 
5280     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5281     assertEquals("hh:mm:ss BBBB | 01:00:00 | en@calendar=buddhist", "01:00:00 at night",
5282         sdf.format(k010000, out.remove()));
5283 }
5284 
TestMinuteSecondFieldsInOddPlaces()5285 void DateFormatTest::TestMinuteSecondFieldsInOddPlaces() {
5286     // Some times on 2015-11-13 (UTC+0).
5287     UDate k000000 = 1447372800000.0;
5288     UDate k000030 = 1447372830000.0;
5289     UDate k003000 = 1447374600000.0;
5290     UDate k060030 = 1447394430000.0;
5291     UDate k063000 = 1447396200000.0;
5292 
5293     UErrorCode errorCode = U_ZERO_ERROR;
5294     const TimeZone *tz = TimeZone::getGMT();
5295     UnicodeString out;
5296 
5297     // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5298     // For ICU 57 output of "midnight" is temporarily suppressed.
5299 
5300     // Seconds field is not present.
5301 
5302     // Apply pattern through constructor to make sure parsePattern() is called during initialization.
5303     SimpleDateFormat sdf(UnicodeString("hh:mm 'ss' bbbb"), errorCode);
5304     if (U_FAILURE(errorCode)) {
5305         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5306         return;
5307     }
5308     sdf.setTimeZone(*tz);
5309 
5310     // assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss midnight",
5311     //     sdf.format(k000030, out.remove()));
5312     assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss AM",
5313         sdf.format(k000030, out.remove()));
5314     assertEquals("hh:mm 'ss' bbbb | 06:00:30", "06:00 ss AM",
5315         sdf.format(k060030, out.remove()));
5316 
5317     sdf.applyPattern(UnicodeString("hh:mm 'ss' BBBB"));
5318 
5319     // assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss midnight",
5320     //     sdf.format(k000030, out.remove()));
5321     assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss at night",
5322         sdf.format(k000030, out.remove()));
5323     assertEquals("hh:mm 'ss' BBBB | 06:00:30", "06:00 ss in the morning",
5324         sdf.format(k060030, out.remove()));
5325 
5326     // Minutes field is not present.
5327     sdf.applyPattern(UnicodeString("hh 'mm ss' bbbb"));
5328 
5329     // assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss midnight",
5330     //     sdf.format(k003000, out.remove()));
5331     assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss AM",
5332         sdf.format(k003000, out.remove()));
5333     assertEquals("hh 'mm ss' bbbb | 06:30:00", "06 mm ss AM",
5334         sdf.format(k063000, out.remove()));
5335 
5336     sdf.applyPattern(UnicodeString("hh 'mm ss' BBBB"));
5337 
5338     // assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss midnight",
5339     //     sdf.format(k003000, out.remove()));
5340     assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss at night",
5341         sdf.format(k003000, out.remove()));
5342     assertEquals("hh 'mm ss' BBBB | 06:30:00", "06 mm ss in the morning",
5343         sdf.format(k063000, out.remove()));
5344 
5345     // Minutes and seconds fields appear after day periods.
5346     sdf.applyPattern(UnicodeString("bbbb hh:mm:ss"));
5347 
5348     // assertEquals("bbbb hh:mm:ss | 00:00:00", "midnight 12:00:00",
5349     //     sdf.format(k000000, out.remove()));
5350     assertEquals("bbbb hh:mm:ss | 00:00:00", "AM 12:00:00",
5351         sdf.format(k000000, out.remove()));
5352     assertEquals("bbbb hh:mm:ss | 00:00:30", "AM 12:00:30",
5353         sdf.format(k000030, out.remove()));
5354     assertEquals("bbbb hh:mm:ss | 00:30:00", "AM 12:30:00",
5355         sdf.format(k003000, out.remove()));
5356 
5357     sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
5358 
5359     // assertEquals("BBBB hh:mm:ss | 00:00:00", "midnight 12:00:00",
5360     //     sdf.format(k000000, out.remove()));
5361     assertEquals("BBBB hh:mm:ss | 00:00:00", "at night 12:00:00",
5362         sdf.format(k000000, out.remove()));
5363     assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
5364         sdf.format(k000030, out.remove()));
5365     assertEquals("BBBB hh:mm:ss | 00:30:00", "at night 12:30:00",
5366         sdf.format(k003000, out.remove()));
5367 
5368     // Confirm applyPattern() reparses the pattern string.
5369     sdf.applyPattern(UnicodeString("BBBB hh"));
5370     // assertEquals("BBBB hh | 00:00:30", "midnight 12",
5371     //     sdf.format(k000030, out.remove()));
5372     assertEquals("BBBB hh | 00:00:30", "at night 12",
5373          sdf.format(k000030, out.remove()));
5374 
5375     sdf.applyPattern(UnicodeString("BBBB hh:mm:'ss'"));
5376     // assertEquals("BBBB hh:mm:'ss' | 00:00:30", "midnight 12:00:ss",
5377     //     sdf.format(k000030, out.remove()));
5378     assertEquals("BBBB hh | 00:00:30", "at night 12:00:ss",
5379         sdf.format(k000030, out.remove()));
5380 
5381     sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
5382     assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
5383         sdf.format(k000030, out.remove()));
5384 }
5385 
TestDayPeriodParsing()5386 void DateFormatTest::TestDayPeriodParsing() {
5387     // Some times on 2015-11-13 (UTC+0).
5388     UDate k000000 = 1447372800000.0;
5389     UDate k003700 = 1447375020000.0;
5390     UDate k010000 = 1447376400000.0;
5391     UDate k013000 = 1447378200000.0;
5392     UDate k030000 = 1447383600000.0;
5393     UDate k090000 = 1447405200000.0;
5394     UDate k120000 = 1447416000000.0;
5395     UDate k130000 = 1447419600000.0;
5396     UDate k133700 = 1447421820000.0;
5397     UDate k150000 = 1447426800000.0;
5398     UDate k190000 = 1447441200000.0;
5399     UDate k193000 = 1447443000000.0;
5400     UDate k200000 = 1447444800000.0;
5401     UDate k210000 = 1447448400000.0;
5402 
5403     UErrorCode errorCode = U_ZERO_ERROR;
5404     SimpleDateFormat sdf(UnicodeString(), errorCode);
5405     if (U_FAILURE(errorCode)) {
5406         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5407         return;
5408     }
5409     const TimeZone *tz = TimeZone::getGMT();
5410     sdf.setTimeZone(*tz);
5411     UnicodeString out;
5412 
5413     // 'B' -- flexible day periods
5414     // A day period on its own parses to the center of that period.
5415     sdf.applyPattern(UnicodeString("yyyy-MM-dd B"));
5416     assertEquals("yyyy-MM-dd B | 2015-11-13 midnight",
5417         k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
5418     assertEquals("yyyy-MM-dd B | 2015-11-13 noon",
5419         k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
5420     assertEquals("yyyy-MM-dd B | 2015-11-13 in the afternoon",
5421         k150000, sdf.parse(UnicodeString("2015-11-13 in the afternoon"), errorCode));
5422     assertEquals("yyyy-MM-dd B | 2015-11-13 in the evening",
5423         k193000, sdf.parse(UnicodeString("2015-11-13 in the evening"), errorCode));
5424     assertEquals("yyyy-MM-dd B | 2015-11-13 at night",
5425         k013000, sdf.parse(UnicodeString("2015-11-13 at night"), errorCode));
5426 
5427     // If time and day period are consistent with each other then time is parsed accordingly.
5428     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
5429     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 midnight",
5430         k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
5431     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 noon",
5432         k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
5433     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 at night",
5434         k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
5435     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 in the afternoon",
5436         k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
5437     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 in the morning",
5438         k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
5439     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 at night",
5440         k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
5441 
5442     // If the hour is 13 thru 23 then day period has no effect on time (since time is assumed
5443     // to be in 24-hour format).
5444     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
5445     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 midnight",
5446         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
5447     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 noon",
5448         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
5449     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
5450         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
5451     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the afternoon",
5452         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the afternoon"), errorCode));
5453     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the morning",
5454         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the morning"), errorCode));
5455     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
5456         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
5457 
5458     // Hour 0 is synonymous with hour 12 when parsed with 'h'.
5459     // This unfortunately means we have to tolerate "0 noon" as it's synonymous with "12 noon".
5460     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
5461     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 midnight",
5462         k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
5463     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 noon",
5464         k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
5465 
5466     // But when parsed with 'H', 0 indicates a 24-hour time, therefore we disregard the day period.
5467     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
5468     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 midnight",
5469         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
5470     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 noon",
5471         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
5472     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
5473         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
5474     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the afternoon",
5475         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the afternoon"), errorCode));
5476     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the morning",
5477         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the morning"), errorCode));
5478     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
5479         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
5480 
5481     // Even when parsed with 'H', hours 1 thru 12 are considered 12-hour time and takes
5482     // day period into account in parsing.
5483     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
5484     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 midnight",
5485         k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
5486     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 noon",
5487         k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
5488     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 at night",
5489         k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
5490     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 in the afternoon",
5491         k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
5492     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 in the morning",
5493         k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
5494     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 at night",
5495         k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
5496 
5497     // If a 12-hour time and the day period don't agree with each other, time is parsed as close
5498     // to the given day period as possible.
5499     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
5500 
5501     // AFTERNOON1 is [12, 18), but "7 in the afternoon" parses to 19:00.
5502     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 07:00 in the afternoon",
5503         k190000, sdf.parse(UnicodeString("2015-11-13 07:00 in the afternoon"), errorCode));
5504     // NIGHT1 is [21, 6), but "8 at night" parses to 20:00.
5505     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 08:00 at night",
5506         k200000, sdf.parse(UnicodeString("2015-11-13 08:00 at night"), errorCode));
5507 
5508     // 'b' -- fixed day periods (AM, PM, midnight, noon)
5509     // On their own, "midnight" parses to 00:00 and "noon" parses to 12:00.
5510     // AM and PM are handled by the 'a' parser (which doesn't handle this case well).
5511     sdf.applyPattern(UnicodeString("yyyy-MM-dd b"));
5512     assertEquals("yyyy-MM-dd b | 2015-11-13 midnight",
5513         k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
5514     assertEquals("yyyy-MM-dd b | 2015-11-13 noon",
5515         k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
5516 
5517     // For 12-hour times, AM and PM should be parsed as if with pattern character 'a'.
5518     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
5519     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 AM",
5520         k010000, sdf.parse(UnicodeString("2015-11-13 01:00 AM"), errorCode));
5521     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 PM",
5522         k130000, sdf.parse(UnicodeString("2015-11-13 01:00 PM"), errorCode));
5523 
5524     // 12 midnight parses to 00:00, and 12 noon parses to 12:00.
5525     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 midnight",
5526         k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
5527     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 noon",
5528         k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
5529 
5530     // Hours 13-23 indicate 24-hour time so we disregard "midnight" or "noon".
5531     // Again, AM and PM are handled by the 'a' parser which doesn't handle this case well.
5532     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
5533     assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 midnight",
5534         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
5535     assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 noon",
5536         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
5537 
5538     // Hour 0 is synonymous with hour 12 when parsed with 'h'.
5539     // Again, this means we have to tolerate "0 noon" as it's synonymous with "12 noon".
5540     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
5541     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 midnight",
5542         k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
5543     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 noon",
5544         k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
5545 
5546     // With 'H' though 0 indicates a 24-hour time, therefore we disregard the day period.
5547     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
5548     assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 midnight",
5549         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
5550     assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 noon",
5551         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
5552 
5553     // If "midnight" or "noon" is parsed with a 12-hour time other than 12:00, choose
5554     // the version that's closer to the period given.
5555     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
5556     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 midnight",
5557         k030000, sdf.parse(UnicodeString("2015-11-13 03:00 midnight"), errorCode));
5558     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 noon",
5559         k150000, sdf.parse(UnicodeString("2015-11-13 03:00 noon"), errorCode));
5560 }
5561 
TestParseRegression13744()5562 void DateFormatTest::TestParseRegression13744() {
5563     LocalPointer<DateFormat> dfmt(DateFormat::createDateTimeInstance(
5564             DateFormat::SHORT, DateFormat::SHORT, Locale("en", "US")));
5565     if (dfmt.isNull()) {
5566         dataerrln("DateFormat::createDateTimeInstance() failed");
5567         return;
5568     }
5569     ParsePosition pos(0);
5570     UnicodeString inDate("4/27/18");
5571     dfmt->parse(inDate, pos);
5572     assertEquals("Error index", inDate.length(), pos.getErrorIndex());
5573 }
5574 
TestAdoptCalendarLeak()5575 void DateFormatTest::TestAdoptCalendarLeak() {
5576     UErrorCode status = U_ZERO_ERROR;
5577     // This test relies on the locale fullName exceeding ULOC_FULLNAME_CAPACITY
5578     // in order for setKeywordValue to fail.
5579     SimpleDateFormat sdf(
5580         "d.M.y",
5581         Locale("de__POSIX@colstrength=primary;currency=eur;em=default;"
5582                "hours=h23;lb=strict;lw=normal;measure=metric;numbers=latn;"
5583                "rg=atzzzz;sd=atat1;ss=none;timezone=Europe/Vienna"),
5584         status);
5585     ASSERT_OK(status);
5586     sdf.adoptCalendar(Calendar::createInstance(status));
5587 }
5588 
5589 /**
5590  * Test that 'a' and 'B' fields are not duplicated in the field position iterator.
5591  */
Test20741_ABFields()5592 void DateFormatTest::Test20741_ABFields() {
5593     IcuTestErrorCode status(*this, "Test20741_ABFields");
5594 
5595     const char16_t timeZone[] = u"PST8PDT";
5596 
5597     UnicodeString skeletons[] = {u"EEEEEBBBBB", u"EEEEEbbbbb"};
5598 
5599     for (int32_t j = 0; j < 2; j++) {
5600         UnicodeString skeleton = skeletons[j];
5601 
5602         int32_t count = 0;
5603         const Locale* locales = Locale::getAvailableLocales(count);
5604         for (int32_t i = 0; i < count; i++) {
5605             if (quick && (i % 17) != 0) { continue; }
5606 
5607             const Locale locale = locales[i];
5608             LocalPointer<DateTimePatternGenerator> gen(DateTimePatternGenerator::createInstance(locale, status));
5609             UnicodeString pattern = gen->getBestPattern(skeleton, status);
5610 
5611             SimpleDateFormat dateFormat(pattern, locale, status);
5612             FieldPositionIterator fpositer;
5613             UnicodeString result;
5614             LocalPointer<Calendar> calendar(Calendar::createInstance(TimeZone::createTimeZone(timeZone), status));
5615             calendar->setTime(UDate(0), status);
5616             dateFormat.format(*calendar, result, &fpositer, status);
5617 
5618             FieldPosition curFieldPosition;
5619             FieldPosition lastFieldPosition;
5620             lastFieldPosition.setBeginIndex(-1);
5621             lastFieldPosition.setEndIndex(-1);
5622             while(fpositer.next(curFieldPosition)) {
5623                 assertFalse("Field missing on pattern", pattern.indexOf(PATTERN_CHARS[curFieldPosition.getField()]) == -1);
5624                 if (curFieldPosition.getBeginIndex() == lastFieldPosition.getBeginIndex() && curFieldPosition.getEndIndex() == lastFieldPosition.getEndIndex()) {
5625                     assertEquals("Different fields at same position", PATTERN_CHARS[curFieldPosition.getField()], PATTERN_CHARS[lastFieldPosition.getField()]);
5626                 }
5627 
5628                 lastFieldPosition = curFieldPosition;
5629             }
5630         }
5631     }
5632 }
5633 
5634 #endif /* #if !UCONFIG_NO_FORMATTING */
5635 
5636 //eof
5637